From 8eae9cdd60d619b6b331131f199f732c7cf9ad6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 23 Jan 2018 17:18:47 +0100 Subject: [PATCH] cert.py: Added testcases for EXP42 and fixed the code a little --- addons/cert.py | 39 ++++++++++++++++++++------------------- addons/test/cert-test.c | 41 ++++++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/addons/cert.py b/addons/cert.py index 8a4b7a119..bdc36825f 100644 --- a/addons/cert.py +++ b/addons/cert.py @@ -30,28 +30,29 @@ def simpleMatch(token, pattern): token = token.next return True -def isUnpackedStruct(var): - decl = var.typeStartToken - while decl and decl.isName: - if decl.str == 'struct': - structScope = decl.next.typeScope - if structScope: - linenr = int(structScope.classStart.linenr) - for line in open(structScope.classStart.file): - linenr -= 1 - if linenr == 0: - return True - if re.match(r'#pragma\s+pack\s*\(', line): - return False - break - decl = decl.next - return False +def isUnpackedStruct(token): + if token.valueType is None: + return False + if token.valueType.typeScope is None: + return False; + if token.valueType.typeScope.type != "Struct": + return False + startToken = token.valueType.typeScope.classStart + + linenr = int(startToken.linenr) + for line in open(startToken.file): + linenr -= 1 + if linenr == 0: + return True + if linenr < 3 and re.match(r'#pragma\s+pack\s*\(', line): + return False + return True def isLocalUnpackedStruct(arg): if arg and arg.str == '&' and not arg.astOperand2: arg = arg.astOperand1 - return arg and arg.variable and (arg.variable.isLocal or arg.variable.isArgument) and isUnpackedStruct(arg.variable) + return arg and arg.variable and (arg.variable.isLocal or arg.variable.isArgument) and isUnpackedStruct(arg) def isBitwiseOp(token): @@ -72,7 +73,7 @@ def isCast(expr): # do not compare padding data def exp42(data): for token in data.tokenlist: - if token.str != '(' or not token.astOperand1: + if token.str != '(' or not token.astOperand1 or token.astOperand1.str != 'memcmp': continue arg1 = None @@ -82,7 +83,7 @@ def exp42(data): arg1 = token.astOperand2.astOperand1.astOperand1 arg2 = token.astOperand2.astOperand1.astOperand2 - if token.astOperand1.str == 'memcmp' and (isLocalUnpackedStruct(arg1) or isLocalUnpackedStruct(arg2)): + if isLocalUnpackedStruct(arg1) or isLocalUnpackedStruct(arg2): reportError( token, 'style', "Comparison of struct padding data " + "(fix either by packing the struct using '#pragma pack' or by rewriting the comparison)", 'cert-EXP42-C') diff --git a/addons/test/cert-test.c b/addons/test/cert-test.c index 8eb97d8ed..25ec8cff0 100644 --- a/addons/test/cert-test.c +++ b/addons/test/cert-test.c @@ -1,9 +1,32 @@ -// To test: -// ~/cppcheck/cppcheck --dump cert-test.c && python cert.py -verify cert-test.c.dump - -unsigned char int31(int x) { - x = (unsigned char)1000; // cert-INT31-c - x = (signed char)0xff; // cert-INT31-c - x = (unsigned char)-1; // cert-INT31-c - x = (unsigned long long)-1; // cert-INT31-c -} +// To test: +// ~/cppcheck/cppcheck --dump cert-test.c && python ../cert.py -verify cert-test.c.dump + +struct S { + short a; + short b; +}; + +#pragma pack() +struct PackedStruct { + short a; + short b; +}; + +void exp42() +{ + struct S s1 = {1,2}; + struct S s2 = {1,2}; + memcmp(&s1, &s2, sizeof(struct S)); // cert-EXP42-C + + struct PackedStruct s3 = {1,2}; + struct PackedStruct s4 = {1,2}; + memcmp(&s3, &s4, sizeof(struct S)); +} + +unsigned char int31(int x) +{ + x = (unsigned char)1000; // cert-INT31-c + x = (signed char)0xff; // cert-INT31-c + x = (unsigned char)-1; // cert-INT31-c + x = (unsigned long long)-1; // cert-INT31-c +}