From 72f07c8a33c0a0ac90c003fdbbb6e8945d13a792 Mon Sep 17 00:00:00 2001 From: Georgy Komarov Date: Sat, 26 Oct 2019 09:32:46 +0300 Subject: [PATCH] Add MISRA checks for rules 21.1 and 21.12 (#2284) * Add MISRA 21.1 check This also required add static field for functions in symboldatabase. * Add MISRA R21.12 * Use newer ASSERT macroses in tests --- addons/cppcheckdata.py | 4 ++ addons/misra.py | 48 +++++++++++++++++++++++ addons/test/misra/misra-test.c | 72 ++++++++++++++++++++++++++++++++-- lib/symboldatabase.cpp | 2 + test/testsymboldatabase.cpp | 10 +++++ 5 files changed, 132 insertions(+), 4 deletions(-) diff --git a/addons/cppcheckdata.py b/addons/cppcheckdata.py index 0258b18fb..78c6bdd79 100755 --- a/addons/cppcheckdata.py +++ b/addons/cppcheckdata.py @@ -341,6 +341,7 @@ class Function: tokenDef Token in function definition isVirtual Is this function is virtual isImplicitlyVirtual Is this function is virtual this in the base classes + isStatic Is this function is static """ Id = None @@ -352,6 +353,7 @@ class Function: type = None isVirtual = None isImplicitlyVirtual = None + isStatic = None def __init__(self, element): self.Id = element.get('id') @@ -362,6 +364,8 @@ class Function: self.isVirtual = (isVirtual and isVirtual == 'true') isImplicitlyVirtual = element.get('isImplicitlyVirtual') self.isImplicitlyVirtual = (isImplicitlyVirtual and isImplicitlyVirtual == 'true') + isStatic = element.get('isStatic') + self.isStatic = (isStatic and isStatic == 'true') self.argument = {} self.argumentId = {} diff --git a/addons/misra.py b/addons/misra.py index 4da7fb462..3a137ad8d 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -1937,6 +1937,38 @@ class MisraChecker: ifStack.pop() + def misra_21_1(self, data): + # Reference: n1570 7.1.3 - Reserved identifiers + re_forbidden_macro = re.compile(r'#define (errno|_[_A-Z]+)') + + # Search for forbidden identifiers in macro names + for directive in data.directives: + res = re.search(re_forbidden_macro, directive.str) + if res: + self.reportError(directive, 21, 1) + + # Search for forbidden identifiers + for token in data.tokenlist: + if not token.isName: + continue + if len(token.str) < 2: + continue + if token.str == 'errno': + self.reportError(token, 21, 1) + if token.str[0] == '_': + if (token.str[1] in string.ascii_uppercase) or (token.str[1] == '_'): + self.reportError(token, 21, 1) + + # Allow identifiers with file scope visibility (static) + if token.scope.type == 'Global': + if token.variable and token.variable.isStatic: + continue + if token.function and token.function.isStatic: + continue + + self.reportError(token, 21, 1) + + def misra_21_3(self, data): for token in data.tokenlist: if isFunctionCall(token) and (token.astOperand1.str in ('malloc', 'calloc', 'realloc', 'free')): @@ -1998,6 +2030,20 @@ class MisraChecker: self.reportError(directive, 21, 11) + def misra_21_12(self, data): + if findInclude(data.directives, ''): + for token in data.tokenlist: + if token.str == 'fexcept_t' and token.isName: + self.reportError(token, 21, 12) + if isFunctionCall(token) and (token.astOperand1.str in ( + 'feclearexcept', + 'fegetexceptflag', + 'feraiseexcept', + 'fesetexceptflag', + 'fetestexcept')): + self.reportError(token, 21, 12) + + def get_verify_expected(self): """Return the list of expected violations in the verify test""" return self.verify_expected @@ -2495,6 +2541,7 @@ class MisraChecker: self.misra_20_10(cfg) self.misra_20_13(cfg) self.misra_20_14(cfg) + self.misra_21_1(cfg) self.misra_21_3(cfg) self.misra_21_4(cfg) self.misra_21_5(cfg) @@ -2504,6 +2551,7 @@ class MisraChecker: self.misra_21_9(cfg) self.misra_21_10(cfg) self.misra_21_11(cfg) + self.misra_21_12(cfg) # 22.4 is already covered by Cppcheck writeReadOnlyFile diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 4bd51c5f5..ed80f2ce3 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -11,6 +11,7 @@ #include //21.6 #include // 21.10 #include // 21.11 +#include typedef unsigned char u8; @@ -395,7 +396,7 @@ void misra_14_2() { struct { unsigned int x:1; unsigned int y:1; -} _14_4_struct; +} r14_4_struct; void misra_14_4(bool b) { if (x+4){} // 14.4 else {} @@ -403,7 +404,7 @@ void misra_14_4(bool b) { if (b) {} else {} - if (_14_4_struct.x) {} + if (r14_4_struct.x) {} } void misra_15_1() { @@ -652,12 +653,12 @@ struct { } nested_2; uint8_t data_3[]; // 18.7 } nested_3; -} _18_7_struct; +} r18_7_struct; struct { uint16_t len; uint8_t data_1[ 19 ]; uint8_t data_2[ ]; // 18.7 -} _18_7_struct; +} r18_7_struct; void misra_18_8(int x) { int buf1[10]; @@ -688,6 +689,58 @@ union misra_19_2 { }; // 19.2 # def fun_2013(v) () // 20.13 #endif +#define _Incompatible 0xdeadbeef // 21.1 +#define __Incompatible 0xdeadbeef // 21.1 +#define __starts_with_lower 0xdeadbeef // 21.1 +#define __MY_HEADER_ // 21.1 +#define _starts_with_lower 1 // no warning +static int _file_scope_id_21_1 = 42; // no warning +static int _file_scope_id_21_1_fn() { return 42; } // no warning +static int __file_scope_id_21_1 = 42; // 21.1 +static int __file_scope_id_21_1_fn() { return 42; } // 21.1 +static int _File_scope_id_21_1 = 42; // 21.1 +static int _File_scope_id_21_1_fn() { return 42; } // 21.1 +int _external_scope_id_21_1 = 42; // 21.1 +int _external_scope_id_21_1_fn() { return 42; } // 21.1 +int __external_scope_id_21_1 = 42; // 21.1 +int __external_scope_id_21_1_fn() { return 42; } // 21.1 +int _External_scope_id_21_1 = 42; // 21.1 +int _External_scope_id_21_1_fn() { return 42; } // 21.1 +int errno = 42; // 21.1 +int errno() { // 21.1 + // TODO: 15.5 false positive + return 42; // 15.5 +} + +struct _struct_21_1 { int a; }; // 21.1 +struct _Struct_21_1 { int a; }; // 21.1 +struct __struct_21_1 { int a; }; // 21.1 +typedef struct { int a; } _struct_21_1_t; // 21.1 +typedef struct { int a; } _Struct_21_1_t; // 21.1 +typedef struct { int a; } __struct_21_1_t; // 21.1 + +enum _enum_21_1 { ENUM211_1 }; // 21.1 +enum _Enum_21_1 { ENUM211_2 }; // 21.1 +enum __enum_21_1 { ENUM211_3 }; // 21.1 +enum __enum_21_1 { ENUM211_3 }; // 21.1 +typedef enum { ENUM211_4 } _enum_21_1_t; // 21.1 +typedef enum { ENUM211_5 } _Enum_21_1_t; // 21.1 +typedef enum { ENUM211_6 } __enum_21_1_t; // 21.1 +enum enum_21_1_valid_id { + ENUM211_7, + _ENUM211_8, // 21.1 + __ENUM211_9, // 21.1 + _eNUM211_10, // 21.1 + enum211_11 +}; + +union _union_21_1 { int a; }; // 21.1 19.2 +union _Union_21_1 { int a; }; // 21.1 19.2 +union __union_21_1 { int a; }; // 21.1 19.2 +typedef union { int a; } _union_21_1_t; // 21.1 19.2 +typedef union { int a; } _Union_21_1_t; // 21.1 19.2 +typedef union { int a; } __union_21_1_t; // 21.1 19.2 + void misra_21_3() { p1=malloc(10); // 21.3 p2=calloc(10); // 21.3 @@ -713,3 +766,14 @@ void misra_21_9() { (void)bsearch(key,base,num,size,cmp); // 21.9 qsort(base,num,size,cmp); // 21.9 } + +void misra_21_12() { + int rc; + fexcept_t f; // 21.12 + rc = feclearexcept(1); // 21.12 + rc = fegetexceptflag(&f, 1); // 21.12 + rc = feraiseexcept(1); // 21.12 + rc = fesetexceptflag(&f, 1); // 21.12 + rc = fetestexcept(1); // 21.12 +} + diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 1b5b82d9a..4b5985e3e 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -3225,6 +3225,8 @@ void SymbolDatabase::printXml(std::ostream &out) const else if (function->isImplicitlyVirtual()) out << " isImplicitlyVirtual=\"true\""; } + if (function->isStatic()) + out << " isStatic=\"true\""; if (function->argCount() == 0U) out << "/>" << std::endl; else { diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 23299e3e6..ebaaafe4e 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -221,6 +221,8 @@ private: TEST_CASE(functionImplicitlyVirtual); + TEST_CASE(functionStatic); + TEST_CASE(namespaces1); TEST_CASE(namespaces2); TEST_CASE(namespaces3); // #3854 - unknown macro @@ -2287,6 +2289,14 @@ private: ASSERT_EQUALS(true, function && function->isImplicitlyVirtual(false)); } + void functionStatic() { + GET_SYMBOL_DB("static void fs() { }"); + (void)db; + const Function *func = db->scopeList.back().function; + ASSERT(func); + ASSERT(func->isStatic()); + } + void namespaces1() { GET_SYMBOL_DB("namespace fred {\n" " namespace barney {\n"