From fcc4fc62ea8693cd6712229d232e7eddd347d63c Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 16 Feb 2023 08:41:52 -0800 Subject: [PATCH 01/34] update rules.csv --- rules.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rules.csv b/rules.csv index ef6fee41d7..fa22eecfc1 100644 --- a/rules.csv +++ b/rules.csv @@ -755,9 +755,9 @@ c,MISRA-C-2012,RULE-21-9,Yes,Required,,,The Standard Library functions bsearch a c,MISRA-C-2012,RULE-21-10,Yes,Required,,,The Standard Library time and date functions shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-11,Yes,Required,,,The standard header file shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-12,Yes,Advisory,,,The exception handling features of should not be used,,Banned,Easy, -c,MISRA-C-2012,RULE-21-13,Yes,Mandatory,,,Any value passed to a function in shall be representable as an unsigned char or be the value EOF,,Types,Medium, +c,MISRA-C-2012,RULE-21-13,Yes,Mandatory,,,Any value passed to a function in shall be representable as an unsigned char or be the value EOF,,StandardLibraryFunctionTypes,Medium, c,MISRA-C-2012,RULE-21-14,Yes,Required,,,The Standard Library function memcmp shall not be used to compare null terminated strings,,Types,Hard, -c,MISRA-C-2012,RULE-21-15,Yes,Required,,,"The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers to qualified or unqualified versions of compatible types",,Types,Medium, +c,MISRA-C-2012,RULE-21-15,Yes,Required,,,"The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers to qualified or unqualified versions of compatible types",,StandardLibraryFunctionTypes,Medium, c,MISRA-C-2012,RULE-21-16,Yes,Required,,,"The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type",,Types,Medium, c,MISRA-C-2012,RULE-21-17,Yes,Mandatory,,,Use of the string handling functions from shall not result in accesses beyond the bounds of the objects referenced by their pointer parameters,,Memory2,Hard, c,MISRA-C-2012,RULE-21-18,Yes,Mandatory,,,The size_t argument passed to any function in shall have an appropriate value,,OutOfBounds,Hard, From 05d577f309e12bba6ffab230faedb3aea765901d Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 16 Feb 2023 15:43:34 -0800 Subject: [PATCH 02/34] Update rule package description file --- .../c/StandardLibraryFunctionTypes.json | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 rule_packages/c/StandardLibraryFunctionTypes.json diff --git a/rule_packages/c/StandardLibraryFunctionTypes.json b/rule_packages/c/StandardLibraryFunctionTypes.json new file mode 100644 index 0000000000..274eadbced --- /dev/null +++ b/rule_packages/c/StandardLibraryFunctionTypes.json @@ -0,0 +1,38 @@ +{ + "MISRA-C-2012": { + "RULE-21-13": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Passing arguments to functions outside the range of unsigned char or EOF causes undefined behavior.", + "kind": "problem", + "name": " function arguments shall be represented as unsigned char", + "precision": "very-high", + "severity": "error", + "short_name": "CtypeFunctionArgNotUnsignedCharOrEof", + "tags": [] + } + ], + "title": "Any value passed to a function in shall be representable as an unsigned char or be the value EOF" + }, + "RULE-21-15": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Passing pointers to incompatible types as arguments to memcpy, memmove and memcmp indicates programmers' confusion.", + "kind": "problem", + "name": "The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers", + "precision": "very-high", + "severity": "error", + "short_name": "MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes", + "tags": [] + } + ], + "title": "The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers to qualified or unqualified versions of compatible types" + } + } +} \ No newline at end of file From 13feea82bff0e9f4706ab0a65e27be07a6b45a74 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 16 Feb 2023 16:31:52 -0800 Subject: [PATCH 03/34] Create rule files --- .../CtypeFunctionArgNotUnsignedCharOrEof.ql | 19 ++++++++ ...veMemcmpArgNotPointersToCompatibleTypes.ql | 19 ++++++++ ...peFunctionArgNotUnsignedCharOrEof.expected | 1 + ...CtypeFunctionArgNotUnsignedCharOrEof.qlref | 1 + ...mpArgNotPointersToCompatibleTypes.expected | 1 + ...emcmpArgNotPointersToCompatibleTypes.qlref | 1 + .../cpp/exclusions/c/RuleMetadata.qll | 3 ++ .../c/StandardLibraryFunctionTypes.qll | 46 +++++++++++++++++++ 8 files changed, 91 insertions(+) create mode 100644 c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql create mode 100644 c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql create mode 100644 c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected create mode 100644 c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.qlref create mode 100644 c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected create mode 100644 c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.qlref create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/StandardLibraryFunctionTypes.qll diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql new file mode 100644 index 0000000000..4e539b0028 --- /dev/null +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -0,0 +1,19 @@ +/** + * @id c/misra/ctype-function-arg-not-unsigned-char-or-eof + * @name RULE-21-13: function arguments shall be represented as unsigned char + * @description Passing arguments to functions outside the range of unsigned char or EOF + * causes undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-13 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra + +from +where + not isExcluded(x, StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) and +select diff --git a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql new file mode 100644 index 0000000000..a2f68bedec --- /dev/null +++ b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql @@ -0,0 +1,19 @@ +/** + * @id c/misra/memcpy-memmove-memcmp-arg-not-pointers-to-compatible-types + * @name RULE-21-15: The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers + * @description Passing pointers to incompatible types as arguments to memcpy, memmove and memcmp + * indicates programmers' confusion. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-15 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from +where + not isExcluded(x, StandardLibraryFunctionTypesPackage::memcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery()) and +select diff --git a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.qlref b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.qlref new file mode 100644 index 0000000000..be454538c7 --- /dev/null +++ b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.qlref @@ -0,0 +1 @@ +rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected b/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.qlref b/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.qlref new file mode 100644 index 0000000000..8acf3deee7 --- /dev/null +++ b/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.qlref @@ -0,0 +1 @@ +rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index aba37072e5..9f0a816411 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -42,6 +42,7 @@ import Preprocessor5 import Preprocessor6 import SideEffects1 import SideEffects2 +import StandardLibraryFunctionTypes import Strings1 import Strings2 import Strings3 @@ -89,6 +90,7 @@ newtype TCQuery = TPreprocessor6PackageQuery(Preprocessor6Query q) or TSideEffects1PackageQuery(SideEffects1Query q) or TSideEffects2PackageQuery(SideEffects2Query q) or + TStandardLibraryFunctionTypesPackageQuery(StandardLibraryFunctionTypesQuery q) or TStrings1PackageQuery(Strings1Query q) or TStrings2PackageQuery(Strings2Query q) or TStrings3PackageQuery(Strings3Query q) or @@ -136,6 +138,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isPreprocessor6QueryMetadata(query, queryId, ruleId, category) or isSideEffects1QueryMetadata(query, queryId, ruleId, category) or isSideEffects2QueryMetadata(query, queryId, ruleId, category) or + isStandardLibraryFunctionTypesQueryMetadata(query, queryId, ruleId, category) or isStrings1QueryMetadata(query, queryId, ruleId, category) or isStrings2QueryMetadata(query, queryId, ruleId, category) or isStrings3QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/StandardLibraryFunctionTypes.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/StandardLibraryFunctionTypes.qll new file mode 100644 index 0000000000..0d86bd9014 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/StandardLibraryFunctionTypes.qll @@ -0,0 +1,46 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype StandardLibraryFunctionTypesQuery = + TCtypeFunctionArgNotUnsignedCharOrEofQuery() or + TMemcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery() + +predicate isStandardLibraryFunctionTypesQueryMetadata( + Query query, string queryId, string ruleId, string category +) { + query = + // `Query` instance for the `ctypeFunctionArgNotUnsignedCharOrEof` query + StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery() and + queryId = + // `@id` for the `ctypeFunctionArgNotUnsignedCharOrEof` query + "c/misra/ctype-function-arg-not-unsigned-char-or-eof" and + ruleId = "RULE-21-13" and + category = "mandatory" + or + query = + // `Query` instance for the `memcpyMemmoveMemcmpArgNotPointersToCompatibleTypes` query + StandardLibraryFunctionTypesPackage::memcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery() and + queryId = + // `@id` for the `memcpyMemmoveMemcmpArgNotPointersToCompatibleTypes` query + "c/misra/memcpy-memmove-memcmp-arg-not-pointers-to-compatible-types" and + ruleId = "RULE-21-15" and + category = "required" +} + +module StandardLibraryFunctionTypesPackage { + Query ctypeFunctionArgNotUnsignedCharOrEofQuery() { + //autogenerate `Query` type + result = + // `Query` type for `ctypeFunctionArgNotUnsignedCharOrEof` query + TQueryC(TStandardLibraryFunctionTypesPackageQuery(TCtypeFunctionArgNotUnsignedCharOrEofQuery())) + } + + Query memcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `memcpyMemmoveMemcmpArgNotPointersToCompatibleTypes` query + TQueryC(TStandardLibraryFunctionTypesPackageQuery(TMemcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery())) + } +} From ea40969d4117ca9c3fb7548c8e28c40be271034d Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 16 Feb 2023 17:10:09 -0800 Subject: [PATCH 04/34] update ql files and add test.c for RULE-21-13 --- .../CtypeFunctionArgNotUnsignedCharOrEof.ql | 33 +++++++++++++++++-- ...veMemcmpArgNotPointersToCompatibleTypes.ql | 5 +-- c/misra/test/rules/RULE-21-13/test.c | 11 +++++++ 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 c/misra/test/rules/RULE-21-13/test.c diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index 4e539b0028..b2e1e11fa1 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -12,8 +12,37 @@ import cpp import codingstandards.c.misra +import codingstandards.cpp.ReadErrorsAndEOF +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils +import semmle.code.cpp.dataflow.DataFlow // TODO use this... -from +query predicate isCtypeFunction(Function function) { + function.getADeclaration().getAFile().(HeaderFile).getShortName() = "_ctype" // TODO: change it back to `ctype` +} + +query predicate isInUnsignedCharRange(Expr var) { + // TODO: shouldn't be an Expr, instead get it as an argument from a FunctionCall that isCtypeFunction + exists(UnsignedCharType unsignedChar | + // Consider cases where the argument's value is cast to some smaller type, clipping the range. + typeLowerBound(unsignedChar) <= lowerBound(var.getFullyConverted()) and + upperBound(var.getFullyConverted()) <= typeUpperBound(unsignedChar) + ) +} + +// Uh oh, this is empty +query predicate isEOFInvocation(EOFInvocation eof) { + any() +} + +/* very early draft */ +query predicate equivToEOF(FunctionCall fc, EOFInvocation eof) { + // var is a param of ctypefunctioncall + isCtypeFunction(fc.getTarget()) and + DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), DataFlow::exprNode(fc.getArgument(0))) +} +from Element x where not isExcluded(x, StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) and -select + any() +select 1 diff --git a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql index a2f68bedec..672ba37ae7 100644 --- a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql +++ b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql @@ -13,7 +13,8 @@ import cpp import codingstandards.c.misra -from +from Element x where not isExcluded(x, StandardLibraryFunctionTypesPackage::memcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery()) and -select + any() +select 1 \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-13/test.c b/c/misra/test/rules/RULE-21-13/test.c new file mode 100644 index 0000000000..2417b7d74a --- /dev/null +++ b/c/misra/test/rules/RULE-21-13/test.c @@ -0,0 +1,11 @@ +#include +#include + +void sample() { + unsigned char c1 = 'c'; + int r1 = isalnum(c1); // compliant + unsigned char c2 = EOF; + int r2 = isalnum(c2); // compliant +} + +int main() { return 0; } From cf0d756d3e6dc950dbb9aed13177cbd0a0e6b31b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 17 Feb 2023 12:03:04 -0800 Subject: [PATCH 05/34] Implement RULE-21-13 --- .../CtypeFunctionArgNotUnsignedCharOrEof.ql | 44 ++++++++++--------- c/misra/test/rules/RULE-21-13/test.c | 15 +++++-- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index b2e1e11fa1..6269d3dcd3 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -15,34 +15,36 @@ import codingstandards.c.misra import codingstandards.cpp.ReadErrorsAndEOF import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils -import semmle.code.cpp.dataflow.DataFlow // TODO use this... -query predicate isCtypeFunction(Function function) { - function.getADeclaration().getAFile().(HeaderFile).getShortName() = "_ctype" // TODO: change it back to `ctype` +class CtypeFunction extends Function { + CtypeFunction() { this.getADeclaration().getAFile().(HeaderFile).getShortName() = "_ctype" } } -query predicate isInUnsignedCharRange(Expr var) { - // TODO: shouldn't be an Expr, instead get it as an argument from a FunctionCall that isCtypeFunction +predicate unsignedCharRange(int lower, int upper, EOFInvocation eof) { exists(UnsignedCharType unsignedChar | - // Consider cases where the argument's value is cast to some smaller type, clipping the range. - typeLowerBound(unsignedChar) <= lowerBound(var.getFullyConverted()) and - upperBound(var.getFullyConverted()) <= typeUpperBound(unsignedChar) + lower = typeLowerBound(unsignedChar) and + upper = upperBound(eof.getExpr()) and + typeLowerBound(unsignedChar) <= lowerBound(eof.getExpr()) and + upperBound(eof.getExpr()) <= typeUpperBound(unsignedChar) ) } -// Uh oh, this is empty -query predicate isEOFInvocation(EOFInvocation eof) { - any() +predicate isEquivToEOF(Expr expr) { + exists(EOFInvocation eof | DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), DataFlow::exprNode(expr))) } -/* very early draft */ -query predicate equivToEOF(FunctionCall fc, EOFInvocation eof) { - // var is a param of ctypefunctioncall - isCtypeFunction(fc.getTarget()) and - DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), DataFlow::exprNode(fc.getArgument(0))) -} -from Element x +from FunctionCall ctypeCall where - not isExcluded(x, StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) and - any() -select 1 + not isExcluded(ctypeCall, + StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) and + exists(CtypeFunction ctype, UnsignedCharType unsignedChar | + ctypeCall = ctype.getACallToThisFunction() + | + /* The argument's value should be in the `unsigned char` range. */ + typeLowerBound(unsignedChar) <= lowerBound(ctypeCall.getAnArgument().getExplicitlyConverted()) and // consider casts + upperBound(ctypeCall.getAnArgument().getExplicitlyConverted()) <= typeUpperBound(unsignedChar) + or + /* The argument's value is reachable from EOF. */ + exists(EOFInvocation eof | DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), DataFlow::exprNode(ctypeCall.getAnArgument()))) + ) +select ctypeCall, ctypeCall.getAnArgument() diff --git a/c/misra/test/rules/RULE-21-13/test.c b/c/misra/test/rules/RULE-21-13/test.c index 2417b7d74a..7b0873cdd1 100644 --- a/c/misra/test/rules/RULE-21-13/test.c +++ b/c/misra/test/rules/RULE-21-13/test.c @@ -3,9 +3,16 @@ void sample() { unsigned char c1 = 'c'; - int r1 = isalnum(c1); // compliant - unsigned char c2 = EOF; - int r2 = isalnum(c2); // compliant + int r1 = isalnum(c1); // COMPLIANT: ASCII 99 is within unsigned char range of [0, 255] + unsigned char x1 = EOF; + unsigned char x2 = x1; + unsigned char c2 = x2 + 1; + int r2 = isdigit(c2); // COMPLIANT: EOF (-1) + + int x3 = 256; + int x4 = x3; + int c3 = x4; + int r3 = islower(c3); // NON_COMPLIANT: is outside unsigned char range of[0, 255] } -int main() { return 0; } +int main() { return 0; } \ No newline at end of file From 5104114cd91e54cb1f254584d7f4c498ac7c72cd Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 17 Feb 2023 13:06:22 -0800 Subject: [PATCH 06/34] Refine RULE-21-13 and its unit test --- .../CtypeFunctionArgNotUnsignedCharOrEof.ql | 28 +++++++------------ c/misra/test/rules/RULE-21-13/test.c | 7 ++++- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index 6269d3dcd3..76dadc9cec 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -20,31 +20,23 @@ class CtypeFunction extends Function { CtypeFunction() { this.getADeclaration().getAFile().(HeaderFile).getShortName() = "_ctype" } } -predicate unsignedCharRange(int lower, int upper, EOFInvocation eof) { - exists(UnsignedCharType unsignedChar | - lower = typeLowerBound(unsignedChar) and - upper = upperBound(eof.getExpr()) and - typeLowerBound(unsignedChar) <= lowerBound(eof.getExpr()) and - upperBound(eof.getExpr()) <= typeUpperBound(unsignedChar) - ) -} - -predicate isEquivToEOF(Expr expr) { - exists(EOFInvocation eof | DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), DataFlow::exprNode(expr))) -} - from FunctionCall ctypeCall where not isExcluded(ctypeCall, StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) and - exists(CtypeFunction ctype, UnsignedCharType unsignedChar | + not exists(CtypeFunction ctype, UnsignedCharType unsignedChar | ctypeCall = ctype.getACallToThisFunction() | - /* The argument's value should be in the `unsigned char` range. */ + /* The argument's value should be in the `unsigned char` range. */ typeLowerBound(unsignedChar) <= lowerBound(ctypeCall.getAnArgument().getExplicitlyConverted()) and // consider casts upperBound(ctypeCall.getAnArgument().getExplicitlyConverted()) <= typeUpperBound(unsignedChar) or - /* The argument's value is reachable from EOF. */ - exists(EOFInvocation eof | DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), DataFlow::exprNode(ctypeCall.getAnArgument()))) + /* The argument's value is reachable from EOF. */ + exists(EOFInvocation eof | + DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), + DataFlow::exprNode(ctypeCall.getAnArgument())) + ) ) -select ctypeCall, ctypeCall.getAnArgument() +select ctypeCall, + "The function $@ accepts an argument $@ that is not unsigned char nor an EOF.", + ctypeCall, ctypeCall.getTarget(), ctypeCall.getAnArgument(), ctypeCall.getAnArgument().toString() diff --git a/c/misra/test/rules/RULE-21-13/test.c b/c/misra/test/rules/RULE-21-13/test.c index 7b0873cdd1..ef8f0d7487 100644 --- a/c/misra/test/rules/RULE-21-13/test.c +++ b/c/misra/test/rules/RULE-21-13/test.c @@ -6,13 +6,18 @@ void sample() { int r1 = isalnum(c1); // COMPLIANT: ASCII 99 is within unsigned char range of [0, 255] unsigned char x1 = EOF; unsigned char x2 = x1; - unsigned char c2 = x2 + 1; + unsigned char c2 = x2; int r2 = isdigit(c2); // COMPLIANT: EOF (-1) int x3 = 256; int x4 = x3; int c3 = x4; int r3 = islower(c3); // NON_COMPLIANT: is outside unsigned char range of[0, 255] + + unsigned char x5 = EOF; + unsigned char x6 = x5; + int c4 = x6 + 10000; + int r4 = isdigit(c4); // NON_COMPLIANT: is outside unsigned char range of[0, 255] } int main() { return 0; } \ No newline at end of file From e0e01937aa37e7027ced91478869b4ea3b735728 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 17 Feb 2023 14:54:50 -0800 Subject: [PATCH 07/34] Draft of RULE-21-15 --- ...veMemcmpArgNotPointersToCompatibleTypes.ql | 16 +++++++++--- c/misra/test/rules/RULE-21-15/test.c | 25 +++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 c/misra/test/rules/RULE-21-15/test.c diff --git a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql index 672ba37ae7..c6a4a45e61 100644 --- a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql +++ b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql @@ -12,9 +12,17 @@ import cpp import codingstandards.c.misra +import codingstandards.c.Pointers -from Element x +class MemCmpMoveCpy extends BuiltInFunction { + MemCmpMoveCpy() { this.getName().regexpMatch(".+mem(cmp|cpy|move).+") } +} + +from FunctionCall fc where - not isExcluded(x, StandardLibraryFunctionTypesPackage::memcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery()) and - any() -select 1 \ No newline at end of file + not isExcluded(fc, + StandardLibraryFunctionTypesPackage::memcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery()) and + exists(MemCmpMoveCpy memfun | fc.getTarget() = memfun | + fc.getArgument(0).getUnspecifiedType() = fc.getArgument(1).getUnspecifiedType() + ) +select fc, fc.getArgument(0).getUnspecifiedType(), fc.getArgument(1).getUnspecifiedType() diff --git a/c/misra/test/rules/RULE-21-15/test.c b/c/misra/test/rules/RULE-21-15/test.c new file mode 100644 index 0000000000..0b9f2dd9a5 --- /dev/null +++ b/c/misra/test/rules/RULE-21-15/test.c @@ -0,0 +1,25 @@ +#include + +void sample() { + int from1 = 1000000; + char to1; + memcpy(&from1, &to1, 1); // NON_COMPLIANT, the types are not compatible + + int from2 = 1000000; + int to2; + memcpy(&from2, &to2, 2); // COMPLIANT + + char from3[] = "string"; + char to3[6]; + memmove(from3, to3, 6); // COMPLIANT + + char from4[] = "sstringg"; + int to4[2]; + memmove(from4, to4, 8); // NON_COMPLIANT, despite being equal in byte counts + + char from5[] = "STRING"; + char to5[] = "string"; + memcmp(from5, to5, 2); // COMPLIANT +} + +int main() { return 0; } \ No newline at end of file From 31858561f32774fc5f784c8f6af601c6ced3f891 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 17 Feb 2023 15:14:35 -0800 Subject: [PATCH 08/34] Refine RULE-21-15 --- ...veMemcmpArgNotPointersToCompatibleTypes.ql | 24 +++++++++++++++++-- c/misra/test/rules/RULE-21-15/test.c | 4 ++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql index c6a4a45e61..c608d042f2 100644 --- a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql +++ b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql @@ -14,8 +14,21 @@ import cpp import codingstandards.c.misra import codingstandards.c.Pointers -class MemCmpMoveCpy extends BuiltInFunction { - MemCmpMoveCpy() { this.getName().regexpMatch(".+mem(cmp|cpy|move).+") } +class MemCmpMoveCpy extends Function { + // Couldn't extend BuiltInFunction because it misses `memcmp` + MemCmpMoveCpy() { this.getName().regexpMatch("mem(cmp|cpy|move)") } +} + +query predicate memfunArgTypes(FunctionCall fc, Type dstType, Type srcType) { + ( + fc.getArgument(0).getUnspecifiedType() instanceof PointerType and + fc.getArgument(1).getUnspecifiedType() instanceof PointerType + or + fc.getArgument(0).getUnspecifiedType() instanceof ArrayType and + fc.getArgument(1).getUnspecifiedType() instanceof ArrayType + ) and + dstType = fc.getArgument(0).getUnspecifiedType() and + srcType = fc.getArgument(1).getUnspecifiedType() } from FunctionCall fc @@ -23,6 +36,13 @@ where not isExcluded(fc, StandardLibraryFunctionTypesPackage::memcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery()) and exists(MemCmpMoveCpy memfun | fc.getTarget() = memfun | + ( + fc.getArgument(0).getUnspecifiedType() instanceof PointerType and + fc.getArgument(1).getUnspecifiedType() instanceof PointerType + or + fc.getArgument(0).getUnspecifiedType() instanceof ArrayType and + fc.getArgument(1).getUnspecifiedType() instanceof ArrayType + ) and fc.getArgument(0).getUnspecifiedType() = fc.getArgument(1).getUnspecifiedType() ) select fc, fc.getArgument(0).getUnspecifiedType(), fc.getArgument(1).getUnspecifiedType() diff --git a/c/misra/test/rules/RULE-21-15/test.c b/c/misra/test/rules/RULE-21-15/test.c index 0b9f2dd9a5..4a3f233c11 100644 --- a/c/misra/test/rules/RULE-21-15/test.c +++ b/c/misra/test/rules/RULE-21-15/test.c @@ -10,8 +10,8 @@ void sample() { memcpy(&from2, &to2, 2); // COMPLIANT char from3[] = "string"; - char to3[6]; - memmove(from3, to3, 6); // COMPLIANT + char to3[7]; + memmove(from3, to3, 7); // COMPLIANT char from4[] = "sstringg"; int to4[2]; From f9deae51cba91b3f914c5fcc81db4779f3504a32 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 17 Feb 2023 15:18:36 -0800 Subject: [PATCH 09/34] Refine RULE-21-15 --- ...MemmoveMemcmpArgNotPointersToCompatibleTypes.ql | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql index c608d042f2..4799b3be28 100644 --- a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql +++ b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql @@ -35,14 +35,16 @@ from FunctionCall fc where not isExcluded(fc, StandardLibraryFunctionTypesPackage::memcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery()) and - exists(MemCmpMoveCpy memfun | fc.getTarget() = memfun | + exists(MemCmpMoveCpy memfun, Type dstType, Type srcType | fc.getTarget() = memfun | + dstType = fc.getArgument(0).getUnspecifiedType() and + srcType = fc.getArgument(1).getUnspecifiedType() and ( - fc.getArgument(0).getUnspecifiedType() instanceof PointerType and - fc.getArgument(1).getUnspecifiedType() instanceof PointerType + dstType instanceof PointerType and + srcType instanceof PointerType or - fc.getArgument(0).getUnspecifiedType() instanceof ArrayType and - fc.getArgument(1).getUnspecifiedType() instanceof ArrayType + dstType instanceof ArrayType and + srcType instanceof ArrayType ) and - fc.getArgument(0).getUnspecifiedType() = fc.getArgument(1).getUnspecifiedType() + dstType = srcType ) select fc, fc.getArgument(0).getUnspecifiedType(), fc.getArgument(1).getUnspecifiedType() From eca1f2681d2afa88e60709bcd2453fde4f4147dd Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 17 Feb 2023 15:29:37 -0800 Subject: [PATCH 10/34] Refine RULE-21-15 --- .../MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql index 4799b3be28..53b5920842 100644 --- a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql +++ b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql @@ -16,10 +16,13 @@ import codingstandards.c.Pointers class MemCmpMoveCpy extends Function { // Couldn't extend BuiltInFunction because it misses `memcmp` - MemCmpMoveCpy() { this.getName().regexpMatch("mem(cmp|cpy|move)") } + MemCmpMoveCpy() { + this.getName().regexpMatch("mem(cmp|cpy|move)") and + this.getADeclaration().getAFile().(HeaderFile).getBaseName() = "string.h" + } } -query predicate memfunArgTypes(FunctionCall fc, Type dstType, Type srcType) { +predicate memfunArgTypes(FunctionCall fc, Type dstType, Type srcType) { ( fc.getArgument(0).getUnspecifiedType() instanceof PointerType and fc.getArgument(1).getUnspecifiedType() instanceof PointerType From 4064b6bd9a8df6780af6006070e27c13c50cee3b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 17 Feb 2023 16:23:36 -0800 Subject: [PATCH 11/34] Update `.expected` files --- .../RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected | 2 +- ...emcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected index 2ec1a0ac6c..e33707fca6 100644 --- a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected +++ b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected @@ -1 +1 @@ -No expected results have yet been specified \ No newline at end of file +| test.c:15:12:15:22 | call to islower | test.c:15:20:15:21 | c3 | \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected b/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected index 2ec1a0ac6c..4713de6d72 100644 --- a/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected +++ b/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected @@ -1 +1,3 @@ -No expected results have yet been specified \ No newline at end of file +| test.c:10:3:10:8 | call to memcpy | file://:0:0:0:0 | int * | file://:0:0:0:0 | int * | +| test.c:14:3:14:9 | call to memmove | file://:0:0:0:0 | char[7] | file://:0:0:0:0 | char[7] | +| test.c:22:3:22:8 | call to memcmp | file://:0:0:0:0 | char[7] | file://:0:0:0:0 | char[7] | \ No newline at end of file From 9adcc3621f4be68d86b170664558b00d86282976 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 17 Feb 2023 16:57:07 -0800 Subject: [PATCH 12/34] Refine analysis messages --- .../CtypeFunctionArgNotUnsignedCharOrEof.ql | 6 +++--- ...moveMemcmpArgNotPointersToCompatibleTypes.ql | 17 ++++------------- ...typeFunctionArgNotUnsignedCharOrEof.expected | 3 ++- ...mcmpArgNotPointersToCompatibleTypes.expected | 6 +++--- 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index 76dadc9cec..14f983398e 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -17,7 +17,7 @@ import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils class CtypeFunction extends Function { - CtypeFunction() { this.getADeclaration().getAFile().(HeaderFile).getShortName() = "_ctype" } + CtypeFunction() { this.getADeclaration().getAFile().(HeaderFile).getBaseName() = "ctype.h" } } from FunctionCall ctypeCall @@ -38,5 +38,5 @@ where ) ) select ctypeCall, - "The function $@ accepts an argument $@ that is not unsigned char nor an EOF.", - ctypeCall, ctypeCall.getTarget(), ctypeCall.getAnArgument(), ctypeCall.getAnArgument().toString() + "The function " + ctypeCall + " accepts an argument " + + ctypeCall.getAnArgument().toString() + " that is not an unsigned char nor an EOF." diff --git a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql index 53b5920842..783dc8e480 100644 --- a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql +++ b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql @@ -22,18 +22,6 @@ class MemCmpMoveCpy extends Function { } } -predicate memfunArgTypes(FunctionCall fc, Type dstType, Type srcType) { - ( - fc.getArgument(0).getUnspecifiedType() instanceof PointerType and - fc.getArgument(1).getUnspecifiedType() instanceof PointerType - or - fc.getArgument(0).getUnspecifiedType() instanceof ArrayType and - fc.getArgument(1).getUnspecifiedType() instanceof ArrayType - ) and - dstType = fc.getArgument(0).getUnspecifiedType() and - srcType = fc.getArgument(1).getUnspecifiedType() -} - from FunctionCall fc where not isExcluded(fc, @@ -50,4 +38,7 @@ where ) and dstType = srcType ) -select fc, fc.getArgument(0).getUnspecifiedType(), fc.getArgument(1).getUnspecifiedType() +select fc, + "The dest type " + fc.getArgument(0).getUnspecifiedType() + " and src type " + + fc.getArgument(1).getUnspecifiedType() + " of function " + fc.getTarget() + + " are not compatible." diff --git a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected index e33707fca6..8cc86e042f 100644 --- a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected +++ b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected @@ -1 +1,2 @@ -| test.c:15:12:15:22 | call to islower | test.c:15:20:15:21 | c3 | \ No newline at end of file +| test.c:15:12:15:22 | call to islower | The function call to islower accepts an argument c3 that is not an unsigned char nor an EOF. | +| test.c:20:12:20:22 | call to isdigit | The function call to isdigit accepts an argument c4 that is not an unsigned char nor an EOF. | \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected b/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected index 4713de6d72..2e706e7f33 100644 --- a/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected +++ b/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected @@ -1,3 +1,3 @@ -| test.c:10:3:10:8 | call to memcpy | file://:0:0:0:0 | int * | file://:0:0:0:0 | int * | -| test.c:14:3:14:9 | call to memmove | file://:0:0:0:0 | char[7] | file://:0:0:0:0 | char[7] | -| test.c:22:3:22:8 | call to memcmp | file://:0:0:0:0 | char[7] | file://:0:0:0:0 | char[7] | \ No newline at end of file +| test.c:10:3:10:8 | call to memcpy | The dest type int * and src type int * of function memcpy are not compatible. | +| test.c:14:3:14:9 | call to memmove | The dest type char[7] and src type char[7] of function memmove are not compatible. | +| test.c:22:3:22:8 | call to memcmp | The dest type char[7] and src type char[7] of function memcmp are not compatible. | \ No newline at end of file From 75ea8ffa025556416175b42d022b99e115e1eebd Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 17 Feb 2023 17:00:08 -0800 Subject: [PATCH 13/34] Format test.c --- .../CtypeFunctionArgNotUnsignedCharOrEof.expected | 4 ++-- c/misra/test/rules/RULE-21-13/test.c | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected index 8cc86e042f..6d3f237ae7 100644 --- a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected +++ b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected @@ -1,2 +1,2 @@ -| test.c:15:12:15:22 | call to islower | The function call to islower accepts an argument c3 that is not an unsigned char nor an EOF. | -| test.c:20:12:20:22 | call to isdigit | The function call to isdigit accepts an argument c4 that is not an unsigned char nor an EOF. | \ No newline at end of file +| test.c:17:7:17:17 | call to islower | The function call to islower accepts an argument c3 that is not an unsigned char nor an EOF. | +| test.c:23:7:23:17 | call to isdigit | The function call to isdigit accepts an argument c4 that is not an unsigned char nor an EOF. | \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-13/test.c b/c/misra/test/rules/RULE-21-13/test.c index ef8f0d7487..22ad07abdd 100644 --- a/c/misra/test/rules/RULE-21-13/test.c +++ b/c/misra/test/rules/RULE-21-13/test.c @@ -1,9 +1,10 @@ -#include #include +#include void sample() { unsigned char c1 = 'c'; - int r1 = isalnum(c1); // COMPLIANT: ASCII 99 is within unsigned char range of [0, 255] + int r1 = isalnum( + c1); // COMPLIANT: ASCII 99 is within unsigned char range of [0, 255] unsigned char x1 = EOF; unsigned char x2 = x1; unsigned char c2 = x2; @@ -12,12 +13,14 @@ void sample() { int x3 = 256; int x4 = x3; int c3 = x4; - int r3 = islower(c3); // NON_COMPLIANT: is outside unsigned char range of[0, 255] + int r3 = + islower(c3); // NON_COMPLIANT: is outside unsigned char range of[0, 255] unsigned char x5 = EOF; unsigned char x6 = x5; int c4 = x6 + 10000; - int r4 = isdigit(c4); // NON_COMPLIANT: is outside unsigned char range of[0, 255] + int r4 = + isdigit(c4); // NON_COMPLIANT: is outside unsigned char range of[0, 255] } int main() { return 0; } \ No newline at end of file From 9336a3e51981141cb01fa51c99d58062a77652af Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 21 Feb 2023 08:43:46 -0800 Subject: [PATCH 14/34] Some minor comments --- .../rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql | 4 ++-- .../MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index 14f983398e..b7dc3dfba6 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -27,11 +27,11 @@ where not exists(CtypeFunction ctype, UnsignedCharType unsignedChar | ctypeCall = ctype.getACallToThisFunction() | - /* The argument's value should be in the `unsigned char` range. */ + /* Case 1: The argument's value should be in the `unsigned char` range. */ typeLowerBound(unsignedChar) <= lowerBound(ctypeCall.getAnArgument().getExplicitlyConverted()) and // consider casts upperBound(ctypeCall.getAnArgument().getExplicitlyConverted()) <= typeUpperBound(unsignedChar) or - /* The argument's value is reachable from EOF. */ + /* Case 2: EOF flows to this argument without modifications. */ exists(EOFInvocation eof | DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), DataFlow::exprNode(ctypeCall.getAnArgument())) diff --git a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql index 783dc8e480..d1af922682 100644 --- a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql +++ b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql @@ -30,9 +30,11 @@ where dstType = fc.getArgument(0).getUnspecifiedType() and srcType = fc.getArgument(1).getUnspecifiedType() and ( + /* Case 1: dst and src are pointer types */ dstType instanceof PointerType and srcType instanceof PointerType or + /* Case 2: dst and src are array types */ dstType instanceof ArrayType and srcType instanceof ArrayType ) and From f09cc5d4c3087c58103def7f14809e4758d4dd55 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 21 Feb 2023 09:02:34 -0800 Subject: [PATCH 15/34] Minor comment --- .../rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index b7dc3dfba6..b302bf7c37 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -28,7 +28,8 @@ where ctypeCall = ctype.getACallToThisFunction() | /* Case 1: The argument's value should be in the `unsigned char` range. */ - typeLowerBound(unsignedChar) <= lowerBound(ctypeCall.getAnArgument().getExplicitlyConverted()) and // consider casts + // Use `.getExplicitlyConverted` to consider inline argument casts. + typeLowerBound(unsignedChar) <= lowerBound(ctypeCall.getAnArgument().getExplicitlyConverted()) and upperBound(ctypeCall.getAnArgument().getExplicitlyConverted()) <= typeUpperBound(unsignedChar) or /* Case 2: EOF flows to this argument without modifications. */ From ddb85d0c38df5912f79277a86127080567936132 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 21 Feb 2023 09:07:19 -0800 Subject: [PATCH 16/34] Oh no --- .../MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql index d1af922682..2c585d8f10 100644 --- a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql +++ b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql @@ -38,7 +38,7 @@ where dstType instanceof ArrayType and srcType instanceof ArrayType ) and - dstType = srcType + not dstType = srcType ) select fc, "The dest type " + fc.getArgument(0).getUnspecifiedType() + " and src type " + From 9be18f2763c6bdfe51ec21b282e4cffe98bbc694 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 21 Feb 2023 11:20:58 -0800 Subject: [PATCH 17/34] Oh no (2) Forgot the test files --- ...mcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected b/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected index 2e706e7f33..67bb52d079 100644 --- a/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected +++ b/c/misra/test/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.expected @@ -1,3 +1,2 @@ -| test.c:10:3:10:8 | call to memcpy | The dest type int * and src type int * of function memcpy are not compatible. | -| test.c:14:3:14:9 | call to memmove | The dest type char[7] and src type char[7] of function memmove are not compatible. | -| test.c:22:3:22:8 | call to memcmp | The dest type char[7] and src type char[7] of function memcmp are not compatible. | \ No newline at end of file +| test.c:6:3:6:8 | call to memcpy | The dest type int * and src type char * of function memcpy are not compatible. | +| test.c:18:3:18:9 | call to memmove | The dest type char[9] and src type int[2] of function memmove are not compatible. | \ No newline at end of file From 044350b122e763ae32dd5bedf4400be704934161 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 22 Feb 2023 18:31:31 -0800 Subject: [PATCH 18/34] Add `CtypeGetcharFunctions` modelling class --- .../cpp/SimpleRangeAnalysisCustomizations.qll | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll index c06b6584a6..a00186bf46 100644 --- a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll +++ b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll @@ -151,6 +151,28 @@ private class CastEnumToIntegerSimpleRange extends SimpleRangeAnalysisExpr, Cast override predicate dependsOnChild(Expr child) { child = getExpr() } } +/** + * functions that reads a character from the STDIN, + * or returns EOF if it fails to do so. + * Their return type is `int` by their signatures, but + * they actually return either an unsigned char or the EOF. + */ +private class CtypeGetcharFunctionsRange extends SimpleRangeAnalysisExpr, FunctionCall { + CtypeGetcharFunctionsRange() { + this.getFile().(HeaderFile).getBaseName() = "stdio.h" and + this.getTarget().getName().regexpMatch("(fgetc|getc|getchar|)") + } + + /* It can return an EOF, which is -1 on most implementations. */ + override float getLowerBounds() { result = -1 } + + /* Otherwise, it can return any unsigned char. */ + override float getUpperBounds() { result = 255 } + + /* No, its call does not depend on any of its child. */ + override predicate dependsOnChild(Expr expr) { none() } +} + /** * Gets the value of the expression `e`, if it is a constant. * From 71f4dc4455633023bae70e3b3ae5d21715009485 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 23 Feb 2023 09:09:10 -0800 Subject: [PATCH 19/34] Minor comments --- .../cpp/SimpleRangeAnalysisCustomizations.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll index a00186bf46..ab6a34584e 100644 --- a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll +++ b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll @@ -152,10 +152,10 @@ private class CastEnumToIntegerSimpleRange extends SimpleRangeAnalysisExpr, Cast } /** - * functions that reads a character from the STDIN, - * or returns EOF if it fails to do so. + * functions that read a character from the STDIN, + * or return EOF if it fails to do so. * Their return type is `int` by their signatures, but - * they actually return either an unsigned char or the EOF. + * they actually return either an unsigned char or an EOF. */ private class CtypeGetcharFunctionsRange extends SimpleRangeAnalysisExpr, FunctionCall { CtypeGetcharFunctionsRange() { From 4d55a700ec3ec795306d4ebcb928908e3c7c9b5f Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 23 Feb 2023 10:24:41 -0800 Subject: [PATCH 20/34] Modify/Add test cases to 21-13 --- c/misra/test/rules/RULE-21-13/test.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/c/misra/test/rules/RULE-21-13/test.c b/c/misra/test/rules/RULE-21-13/test.c index 22ad07abdd..ed6dd66fd6 100644 --- a/c/misra/test/rules/RULE-21-13/test.c +++ b/c/misra/test/rules/RULE-21-13/test.c @@ -5,22 +5,33 @@ void sample() { unsigned char c1 = 'c'; int r1 = isalnum( c1); // COMPLIANT: ASCII 99 is within unsigned char range of [0, 255] - unsigned char x1 = EOF; - unsigned char x2 = x1; - unsigned char c2 = x2; - int r2 = isdigit(c2); // COMPLIANT: EOF (-1) + int r2 = isdigit(EOF); // COMPLIANT: EOF (-1) int x3 = 256; int x4 = x3; int c3 = x4; int r3 = - islower(c3); // NON_COMPLIANT: is outside unsigned char range of[0, 255] + islower(c3); // NON_COMPLIANT: is outside unsigned char range of [0, 255] unsigned char x5 = EOF; unsigned char x6 = x5; int c4 = x6 + 10000; int r4 = - isdigit(c4); // NON_COMPLIANT: is outside unsigned char range of[0, 255] + isdigit(c4); // NON_COMPLIANT: is outside unsigned char range of [0, 255] + + int c5 = getchar(); + int r5 = isdigit(c5); // COMPLIANT[FALSE_POSITIVE]: library functions like + // getchar needs to be modelled + + unsigned char x7 = 1; + char c6; + if (x7 == 1) { + c6 = EOF; + } else { + c6 = 'c'; + } + int r6 = + isdigit(c6); // COMPLIANT: either control branch make this call compliant. } int main() { return 0; } \ No newline at end of file From a9f2fbec9f46ca5aa6ca80289a7afcda66fce118 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 23 Feb 2023 12:08:45 -0800 Subject: [PATCH 21/34] checkpoint --- .../CtypeFunctionArgNotUnsignedCharOrEof.ql | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index b302bf7c37..01b8334431 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -14,30 +14,34 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.ReadErrorsAndEOF import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils +//import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils class CtypeFunction extends Function { CtypeFunction() { this.getADeclaration().getAFile().(HeaderFile).getBaseName() = "ctype.h" } } +/* TODO Under construction */ from FunctionCall ctypeCall where not isExcluded(ctypeCall, - StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) and - not exists(CtypeFunction ctype, UnsignedCharType unsignedChar | - ctypeCall = ctype.getACallToThisFunction() - | - /* Case 1: The argument's value should be in the `unsigned char` range. */ - // Use `.getExplicitlyConverted` to consider inline argument casts. - typeLowerBound(unsignedChar) <= lowerBound(ctypeCall.getAnArgument().getExplicitlyConverted()) and - upperBound(ctypeCall.getAnArgument().getExplicitlyConverted()) <= typeUpperBound(unsignedChar) - or - /* Case 2: EOF flows to this argument without modifications. */ - exists(EOFInvocation eof | - DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), - DataFlow::exprNode(ctypeCall.getAnArgument())) - ) - ) -select ctypeCall, - "The function " + ctypeCall + " accepts an argument " + - ctypeCall.getAnArgument().toString() + " that is not an unsigned char nor an EOF." + StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) +// and +// not exists(CtypeFunction ctype, Expr ctypeCallArgument | +// ctype = ctypeCall.getTarget() and +// ctypeCallArgument = ctypeCall.getAnArgument().getExplicitlyConverted() +// | +// /* Case 1: The argument's value should be in the `unsigned char` range. */ +// // Use `.getExplicitlyConverted` to consider inline argument casts. +// -1 <= lowerBound(ctypeCallArgument) and +// upperBound(ctypeCallArgument) <= 255 +// or +// /* Case 2: EOF flows to this argument without modifications. */ +// exists(EOFInvocation eof | +// DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), DataFlow::exprNode(ctypeCallArgument)) +// ) +// ) +select ctypeCall.getAnArgument(), lowerBound(ctypeCall.getAnArgument()), + upperBound(ctypeCall.getAnArgument()) +// select ctypeCall, +// "The function " + ctypeCall + " accepts an argument " + +// ctypeCall.getAnArgument().toString() + " that is not an unsigned char nor an EOF." From 0aad1c638b0177f5d0ed6dfe71e0719267885bc6 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 7 Mar 2023 11:50:35 -0800 Subject: [PATCH 22/34] Model getchar, Finalize query --- .../CtypeFunctionArgNotUnsignedCharOrEof.ql | 35 +++++++------------ c/misra/test/rules/RULE-21-13/test.c | 16 +++++---- .../cpp/SimpleRangeAnalysisCustomizations.qll | 2 +- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index 01b8334431..a87910063b 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -15,33 +15,22 @@ import codingstandards.c.misra import codingstandards.cpp.ReadErrorsAndEOF import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -//import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils class CtypeFunction extends Function { CtypeFunction() { this.getADeclaration().getAFile().(HeaderFile).getBaseName() = "ctype.h" } } -/* TODO Under construction */ from FunctionCall ctypeCall where not isExcluded(ctypeCall, - StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) -// and -// not exists(CtypeFunction ctype, Expr ctypeCallArgument | -// ctype = ctypeCall.getTarget() and -// ctypeCallArgument = ctypeCall.getAnArgument().getExplicitlyConverted() -// | -// /* Case 1: The argument's value should be in the `unsigned char` range. */ -// // Use `.getExplicitlyConverted` to consider inline argument casts. -// -1 <= lowerBound(ctypeCallArgument) and -// upperBound(ctypeCallArgument) <= 255 -// or -// /* Case 2: EOF flows to this argument without modifications. */ -// exists(EOFInvocation eof | -// DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), DataFlow::exprNode(ctypeCallArgument)) -// ) -// ) -select ctypeCall.getAnArgument(), lowerBound(ctypeCall.getAnArgument()), - upperBound(ctypeCall.getAnArgument()) -// select ctypeCall, -// "The function " + ctypeCall + " accepts an argument " + -// ctypeCall.getAnArgument().toString() + " that is not an unsigned char nor an EOF." + StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) and + not exists(CtypeFunction ctype, Expr ctypeCallArgument | + ctype = ctypeCall.getTarget() and + ctypeCallArgument = ctypeCall.getAnArgument().getExplicitlyConverted() + | + /* The argument's value should be in the EOF + `unsigned char` range. */ + -1 <= lowerBound(ctypeCallArgument) and upperBound(ctypeCallArgument) <= 255 + ) and + ctypeCall.getBasicBlock().isReachable() +select ctypeCall, + "The function " + ctypeCall + " accepts an argument " + + ctypeCall.getAnArgument().toString() + " that is not an unsigned char nor an EOF." diff --git a/c/misra/test/rules/RULE-21-13/test.c b/c/misra/test/rules/RULE-21-13/test.c index ed6dd66fd6..ab391afc28 100644 --- a/c/misra/test/rules/RULE-21-13/test.c +++ b/c/misra/test/rules/RULE-21-13/test.c @@ -5,33 +5,35 @@ void sample() { unsigned char c1 = 'c'; int r1 = isalnum( c1); // COMPLIANT: ASCII 99 is within unsigned char range of [0, 255] - int r2 = isdigit(EOF); // COMPLIANT: EOF (-1) + int r2 = isalnum(EOF); // COMPLIANT: EOF (-1) int x3 = 256; int x4 = x3; int c3 = x4; int r3 = - islower(c3); // NON_COMPLIANT: is outside unsigned char range of [0, 255] + isalnum(c3); // NON_COMPLIANT: is outside unsigned char range of [0, 255] unsigned char x5 = EOF; unsigned char x6 = x5; int c4 = x6 + 10000; int r4 = - isdigit(c4); // NON_COMPLIANT: is outside unsigned char range of [0, 255] + isalnum(c4); // NON_COMPLIANT: is outside unsigned char range of [0, 255] int c5 = getchar(); - int r5 = isdigit(c5); // COMPLIANT[FALSE_POSITIVE]: library functions like + int r5 = isalnum(c5); // COMPLIANT[FALSE_POSITIVE]: library functions like // getchar needs to be modelled - unsigned char x7 = 1; - char c6; + unsigned char x7; + int c6; if (x7 == 1) { c6 = EOF; } else { c6 = 'c'; } int r6 = - isdigit(c6); // COMPLIANT: either control branch make this call compliant. + isalnum(c6); // COMPLIANT: either control branch make this call compliant + + int r7 = isalnum(EOF); // COMPLIANT: EOF (-1) } int main() { return 0; } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll index ab6a34584e..469fe9a738 100644 --- a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll +++ b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll @@ -159,7 +159,7 @@ private class CastEnumToIntegerSimpleRange extends SimpleRangeAnalysisExpr, Cast */ private class CtypeGetcharFunctionsRange extends SimpleRangeAnalysisExpr, FunctionCall { CtypeGetcharFunctionsRange() { - this.getFile().(HeaderFile).getBaseName() = "stdio.h" and + this.getTarget().getFile().(HeaderFile).getBaseName() = "stdio.h" and this.getTarget().getName().regexpMatch("(fgetc|getc|getchar|)") } From c66a9d65a6df929b1e130d35ea36599ac8074f0b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 14 Mar 2023 10:00:19 -0700 Subject: [PATCH 23/34] Minor comments && Update outdated .expected --- .../rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql | 1 + .../RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected | 4 ++-- c/misra/test/rules/RULE-21-13/test.c | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index a87910063b..e11c882ab1 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -30,6 +30,7 @@ where /* The argument's value should be in the EOF + `unsigned char` range. */ -1 <= lowerBound(ctypeCallArgument) and upperBound(ctypeCallArgument) <= 255 ) and + /* Only report control flow that is feasible (to avoid functions implemented as macro). */ ctypeCall.getBasicBlock().isReachable() select ctypeCall, "The function " + ctypeCall + " accepts an argument " + diff --git a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected index 6d3f237ae7..0a8d568dec 100644 --- a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected +++ b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected @@ -1,2 +1,2 @@ -| test.c:17:7:17:17 | call to islower | The function call to islower accepts an argument c3 that is not an unsigned char nor an EOF. | -| test.c:23:7:23:17 | call to isdigit | The function call to isdigit accepts an argument c4 that is not an unsigned char nor an EOF. | \ No newline at end of file +| test.c:14:7:14:13 | call to isalnum | The function call to isalnum accepts an argument c3 that is not an unsigned char nor an EOF. | +| test.c:20:7:20:13 | call to isalnum | The function call to isalnum accepts an argument c4 that is not an unsigned char nor an EOF. | \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-13/test.c b/c/misra/test/rules/RULE-21-13/test.c index ab391afc28..727ac8ad65 100644 --- a/c/misra/test/rules/RULE-21-13/test.c +++ b/c/misra/test/rules/RULE-21-13/test.c @@ -20,8 +20,8 @@ void sample() { isalnum(c4); // NON_COMPLIANT: is outside unsigned char range of [0, 255] int c5 = getchar(); - int r5 = isalnum(c5); // COMPLIANT[FALSE_POSITIVE]: library functions like - // getchar needs to be modelled + int r5 = isalnum( + c5); // COMPLIANT: source functions like getchar are modelled unsigned char x7; int c6; From a0a2615efce2578057e670694cb166d8ac959baa Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 10 Mar 2023 23:59:39 +0000 Subject: [PATCH 24/34] STR37-C: Handle macros in The commonly implements its APIs using either macros or functions or some combination of the two. Our query only assumed functions were used, whereas macros are practically used by both gcc and clang, and these can vary depending on compiler flags. The CharFunctions.qll library now provides a unified interface from which to get a unique expression for each use of an API in the library, hopefully regardless of whether it is a macro or a function. To do this we have had to hard code assumptions about the structure of the macros, however our matrix compiler testing should flag if these assumptions are broken with a particular version of a supported compiler. --- ...erHandlingFunctionsRepresentableAsUChar.ql | 17 ++- ...lingFunctionsRepresentableAsUChar.expected | 40 +++--- .../src/codingstandards/cpp/CharFunctions.qll | 118 ++++++++++++++---- 3 files changed, 124 insertions(+), 51 deletions(-) diff --git a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql index cb742859cc..8dda9012d2 100644 --- a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql +++ b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql @@ -16,14 +16,11 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.CharFunctions -from FunctionCall fc, Expr arg +from UseOfToOrIsChar useOfCharAPI, Expr arg where - not isExcluded(fc, Strings2Package::toCharacterHandlingFunctionsRepresentableAsUCharQuery()) and - // examine all impacted functions - fc.getTarget() instanceof CToOrIsCharFunction and - arg = fc.getArgument(0).getFullyConverted() and - // report on cases where either the explicit or implicit cast - // on the parameter type is not unsigned - not arg.(CStyleCast).getExpr().getType() instanceof UnsignedCharType -select fc, "$@ to character-handling function may not be representable as an unsigned char.", arg, - "Argument" + not isExcluded(useOfCharAPI, + Strings2Package::toCharacterHandlingFunctionsRepresentableAsUCharQuery()) and + arg = useOfCharAPI.getConvertedArgument() and + not arg.getType() instanceof UnsignedCharType +select useOfCharAPI, + "$@ to character-handling function may not be representable as an unsigned char.", arg, "Argument" diff --git a/c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.expected b/c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.expected index b655289f4e..43008e02d0 100644 --- a/c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.expected +++ b/c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.expected @@ -1,28 +1,28 @@ -| test.c:7:3:7:9 | call to isalnum | $@ to character-handling function may not be representable as an unsigned char. | test.c:7:11:7:12 | (int)... | Argument | -| test.c:8:3:8:13 | call to isalpha | $@ to character-handling function may not be representable as an unsigned char. | test.c:8:11:8:12 | (int)... | Argument | -| test.c:10:3:10:9 | call to isblank | $@ to character-handling function may not be representable as an unsigned char. | test.c:10:11:10:12 | (int)... | Argument | -| test.c:11:3:11:9 | call to iscntrl | $@ to character-handling function may not be representable as an unsigned char. | test.c:11:11:11:12 | (int)... | Argument | -| test.c:12:3:12:13 | call to isdigit | $@ to character-handling function may not be representable as an unsigned char. | test.c:12:11:12:12 | (int)... | Argument | -| test.c:13:3:13:13 | call to isgraph | $@ to character-handling function may not be representable as an unsigned char. | test.c:13:11:13:12 | (int)... | Argument | -| test.c:14:3:14:13 | call to islower | $@ to character-handling function may not be representable as an unsigned char. | test.c:14:11:14:12 | (int)... | Argument | -| test.c:15:3:15:13 | call to isprint | $@ to character-handling function may not be representable as an unsigned char. | test.c:15:11:15:12 | (int)... | Argument | -| test.c:16:3:16:9 | call to ispunct | $@ to character-handling function may not be representable as an unsigned char. | test.c:16:11:16:12 | (int)... | Argument | -| test.c:17:3:17:13 | call to __isspace | $@ to character-handling function may not be representable as an unsigned char. | test.c:17:11:17:12 | (int)... | Argument | -| test.c:18:3:18:13 | call to isupper | $@ to character-handling function may not be representable as an unsigned char. | test.c:18:11:18:12 | (int)... | Argument | -| test.c:19:3:19:10 | call to isxdigit | $@ to character-handling function may not be representable as an unsigned char. | test.c:19:12:19:13 | (int)... | Argument | -| test.c:21:3:21:9 | call to toupper | $@ to character-handling function may not be representable as an unsigned char. | test.c:21:11:21:12 | (int)... | Argument | -| test.c:22:3:22:9 | call to tolower | $@ to character-handling function may not be representable as an unsigned char. | test.c:22:11:22:12 | (int)... | Argument | +| test.c:7:3:7:9 | call to isalnum | $@ to character-handling function may not be representable as an unsigned char. | test.c:7:11:7:12 | * ... | Argument | +| test.c:8:3:8:13 | isalpha(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:8:11:8:12 | * ... | Argument | +| test.c:10:3:10:9 | call to isblank | $@ to character-handling function may not be representable as an unsigned char. | test.c:10:11:10:12 | * ... | Argument | +| test.c:11:3:11:9 | call to iscntrl | $@ to character-handling function may not be representable as an unsigned char. | test.c:11:11:11:12 | * ... | Argument | +| test.c:12:3:12:13 | isdigit(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:12:3:12:13 | (...) | Argument | +| test.c:13:3:13:13 | isgraph(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:13:3:13:13 | (...) | Argument | +| test.c:14:3:14:13 | islower(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:14:3:14:13 | (...) | Argument | +| test.c:15:3:15:13 | isprint(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:15:3:15:13 | (...) | Argument | +| test.c:16:3:16:9 | call to ispunct | $@ to character-handling function may not be representable as an unsigned char. | test.c:16:11:16:12 | * ... | Argument | +| test.c:17:3:17:13 | call to __isspace | $@ to character-handling function may not be representable as an unsigned char. | test.c:17:11:17:12 | * ... | Argument | +| test.c:18:3:18:13 | isupper(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:18:3:18:13 | (...) | Argument | +| test.c:19:3:19:10 | call to isxdigit | $@ to character-handling function may not be representable as an unsigned char. | test.c:19:12:19:13 | * ... | Argument | +| test.c:21:3:21:9 | call to toupper | $@ to character-handling function may not be representable as an unsigned char. | test.c:21:11:21:12 | * ... | Argument | +| test.c:22:3:22:9 | call to tolower | $@ to character-handling function may not be representable as an unsigned char. | test.c:22:11:22:12 | * ... | Argument | | test.c:70:3:70:9 | call to isalnum | $@ to character-handling function may not be representable as an unsigned char. | test.c:70:11:70:11 | t | Argument | -| test.c:71:3:71:12 | call to isalpha | $@ to character-handling function may not be representable as an unsigned char. | test.c:71:11:71:11 | t | Argument | +| test.c:71:3:71:12 | isalpha(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:71:11:71:11 | t | Argument | | test.c:73:3:73:9 | call to isblank | $@ to character-handling function may not be representable as an unsigned char. | test.c:73:11:73:11 | t | Argument | | test.c:74:3:74:9 | call to iscntrl | $@ to character-handling function may not be representable as an unsigned char. | test.c:74:11:74:11 | t | Argument | -| test.c:75:3:75:12 | call to isdigit | $@ to character-handling function may not be representable as an unsigned char. | test.c:75:11:75:11 | t | Argument | -| test.c:76:3:76:12 | call to isgraph | $@ to character-handling function may not be representable as an unsigned char. | test.c:76:11:76:11 | t | Argument | -| test.c:77:3:77:12 | call to islower | $@ to character-handling function may not be representable as an unsigned char. | test.c:77:11:77:11 | t | Argument | -| test.c:78:3:78:12 | call to isprint | $@ to character-handling function may not be representable as an unsigned char. | test.c:78:11:78:11 | t | Argument | +| test.c:75:3:75:12 | isdigit(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:75:3:75:12 | (...) | Argument | +| test.c:76:3:76:12 | isgraph(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:76:3:76:12 | (...) | Argument | +| test.c:77:3:77:12 | islower(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:77:3:77:12 | (...) | Argument | +| test.c:78:3:78:12 | isprint(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:78:3:78:12 | (...) | Argument | | test.c:79:3:79:9 | call to ispunct | $@ to character-handling function may not be representable as an unsigned char. | test.c:79:11:79:11 | t | Argument | | test.c:80:3:80:12 | call to __isspace | $@ to character-handling function may not be representable as an unsigned char. | test.c:80:11:80:11 | t | Argument | -| test.c:81:3:81:12 | call to isupper | $@ to character-handling function may not be representable as an unsigned char. | test.c:81:11:81:11 | t | Argument | +| test.c:81:3:81:12 | isupper(a) | $@ to character-handling function may not be representable as an unsigned char. | test.c:81:3:81:12 | (...) | Argument | | test.c:82:3:82:10 | call to isxdigit | $@ to character-handling function may not be representable as an unsigned char. | test.c:82:12:82:12 | t | Argument | | test.c:84:3:84:9 | call to toupper | $@ to character-handling function may not be representable as an unsigned char. | test.c:84:11:84:11 | t | Argument | | test.c:85:3:85:9 | call to tolower | $@ to character-handling function may not be representable as an unsigned char. | test.c:85:11:85:11 | t | Argument | diff --git a/cpp/common/src/codingstandards/cpp/CharFunctions.qll b/cpp/common/src/codingstandards/cpp/CharFunctions.qll index 352f61858c..7f69c353e5 100644 --- a/cpp/common/src/codingstandards/cpp/CharFunctions.qll +++ b/cpp/common/src/codingstandards/cpp/CharFunctions.qll @@ -1,31 +1,107 @@ import cpp -/** - * Models a class of functions that are either testers of characters - * or standard library conversion functions. - */ -class CToOrIsCharFunction extends Function { - CToOrIsCharFunction() { - this instanceof CIsCharFunction or - this instanceof CToCharFunction - } +private string getCToOrIsName() { + result = + [ + "isalnum", "isalpha", "isascii", "isblank", "iscntrl", "isdigit", "isgraph", "islower", + "isprint", "ispunct", "isspace", "isupper", "isxdigit", "__isspace", "toascii", "toupper", + "tolower" + ] } /** - * Models a class of functions that test characters. + * A use of one of the APIs in the `` header that test or convert characters. + * + * Note: these operations are commonly implemented as either function or a macro. This class + * abstracts away from those details, providing a `getConvertedArgument` predicate to get the + * argument after any conversions specified by the user, excluding any conversions induced by + * the structure of the macro, or */ -class CIsCharFunction extends Function { - CIsCharFunction() { - getName() in [ - "isalnum", "isalpha", "isascii", "isblank", "iscntrl", "isdigit", "isgraph", "islower", - "isprint", "ispunct", "isspace", "isupper", "isxdigit", "__isspace" - ] +abstract class UseOfToOrIsChar extends Element { + /** */ + abstract Expr getConvertedArgument(); +} + +private class CToOrIsCharFunctionCall extends FunctionCall, UseOfToOrIsChar { + CToOrIsCharFunctionCall() { + getTarget().getName() = getCToOrIsName() and + // Some library implementations, such as musl, include a "dead" call to the same function + // that has also been implemented as a macro, in order to retain the right types. We exclude + // this call because it does not appear in the control flow or data flow graph. However, + // isspace directly calls __isspace, which is allowed + ( + getTarget().getName() = "__isspace" or + not any(CToOrIsCharMacroInvocation mi).getAnExpandedElement() = this + ) } + + override Expr getConvertedArgument() { result = getArgument(0).getExplicitlyConverted() } } -/** - * Models a class of functions convert characters. - */ -class CToCharFunction extends Function { - CToCharFunction() { getName() in ["toascii", "toupper", "tolower"] } +private class CToOrIsCharMacroInvocation extends MacroInvocation, UseOfToOrIsChar { + CToOrIsCharMacroInvocation() { getMacroName() = getCToOrIsName() } + + override Expr getConvertedArgument() { + /* + * There is no common approach to how the macros are defined, so we handle + * each compiler/library case individually. Fortunately, there's no conflict + * between different compilers. + */ + + // For the "is" APIs, if clang and gcc use a macro, then it expands to an + // array access on the left hand side of an & + exists(ArrayExpr ae | ae = getExpr().(BitwiseAndExpr).getLeftOperand() | + // Casted to an explicit (int), so we want unwind only a single conversion + result = ae.getArrayOffset().getFullyConverted().(Conversion).getExpr() + ) + or + // For the tolower/toupper cases, a secondary macro is expanded + exists(MacroInvocation mi | + mi.getParentInvocation() = this and + mi.getMacroName() = "__tobody" + | + /* + * tolower and toupper can be defined by macros which: + * - if the size of the type is greater than 1 + * - then check if it's a compile time constant + * - then use c < -128 || c > 255 ? c : (a)[c] + * - else call the function + * - else (a)[c] + */ + + exists(ArrayExpr ae | + ae = mi.getAnExpandedElement() and + result = ae.getArrayOffset() and + // There are two array access, but only one should be reachable + result.getBasicBlock().isReachable() + ) + or + exists(ConditionalExpr ce | + ce = mi.getAnExpandedElement() and + result = ce.getThen() and + result.getBasicBlock().isReachable() + ) + ) + or + // musl uses a conditional expression as the expansion + exists(ConditionalExpr ce | ce = getExpr() | + // for most macro expansions, the else is a subtraction inside a `<` + exists(SubExpr s | + not getMacroName() = "isalpha" and + s = ce.getElse().(LTExpr).getLeftOperand() and + // Casted to an explicit (int), so we want unwind only a single conversion + result = s.getLeftOperand().getFullyConverted().(Conversion).getExpr() + ) + or + // for isalpha, the else is a bitwise or inside a subtraction inside a `<` + exists(BitwiseOrExpr bo | + // Casted to an explicit (unsigned) + getMacroName() = "isalpha" and + bo = ce.getElse().(LTExpr).getLeftOperand().(SubExpr).getLeftOperand() and + // Casted to an explicit (int), so we want unwind only a single conversion + result = + bo.getLeftOperand().getFullyConverted().(Conversion).getExpr().(ParenthesisExpr).getExpr() + ) + ) + } } From 6d477c036485cb84fca577be52136e7b4f63a12b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 15 Mar 2023 14:03:16 -0700 Subject: [PATCH 25/34] remove an empty comment --- cpp/common/src/codingstandards/cpp/CharFunctions.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/CharFunctions.qll b/cpp/common/src/codingstandards/cpp/CharFunctions.qll index 7f69c353e5..bb47f77101 100644 --- a/cpp/common/src/codingstandards/cpp/CharFunctions.qll +++ b/cpp/common/src/codingstandards/cpp/CharFunctions.qll @@ -18,7 +18,6 @@ private string getCToOrIsName() { * the structure of the macro, or */ abstract class UseOfToOrIsChar extends Element { - /** */ abstract Expr getConvertedArgument(); } From 9e60a8ff7d8d3dae8b0c880f535e01e28a333662 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 15 Mar 2023 14:21:27 -0700 Subject: [PATCH 26/34] Use UseOfToOrIsChar from CharFunctions --- .../CtypeFunctionArgNotUnsignedCharOrEof.ql | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index e11c882ab1..ba8d8ed620 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -12,26 +12,19 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.ReadErrorsAndEOF +import codingstandards.cpp.CharFunctions import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -class CtypeFunction extends Function { - CtypeFunction() { this.getADeclaration().getAFile().(HeaderFile).getBaseName() = "ctype.h" } -} - -from FunctionCall ctypeCall +from UseOfToOrIsChar ctypeCall where not isExcluded(ctypeCall, StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) and - not exists(CtypeFunction ctype, Expr ctypeCallArgument | - ctype = ctypeCall.getTarget() and - ctypeCallArgument = ctypeCall.getAnArgument().getExplicitlyConverted() + not exists(Expr ctypeCallArgument | + ctypeCallArgument = ctypeCall.getConvertedArgument().getExplicitlyConverted() | /* The argument's value should be in the EOF + `unsigned char` range. */ -1 <= lowerBound(ctypeCallArgument) and upperBound(ctypeCallArgument) <= 255 - ) and - /* Only report control flow that is feasible (to avoid functions implemented as macro). */ - ctypeCall.getBasicBlock().isReachable() + ) select ctypeCall, "The function " + ctypeCall + " accepts an argument " + - ctypeCall.getAnArgument().toString() + " that is not an unsigned char nor an EOF." + ctypeCall.getConvertedArgument().toString() + " that is not an unsigned char nor an EOF." From 7ee8379b3067147b2328a1ea59f51daab82ae881 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 15 Mar 2023 14:25:48 -0700 Subject: [PATCH 27/34] Remove redundant predicate uses --- .../RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index ba8d8ed620..70ec91e3c1 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -19,12 +19,10 @@ from UseOfToOrIsChar ctypeCall where not isExcluded(ctypeCall, StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) and - not exists(Expr ctypeCallArgument | - ctypeCallArgument = ctypeCall.getConvertedArgument().getExplicitlyConverted() - | + not exists(Expr ctypeCallArgument | ctypeCallArgument = ctypeCall.getConvertedArgument() | /* The argument's value should be in the EOF + `unsigned char` range. */ -1 <= lowerBound(ctypeCallArgument) and upperBound(ctypeCallArgument) <= 255 ) select ctypeCall, - "The function " + ctypeCall + " accepts an argument " + - ctypeCall.getConvertedArgument().toString() + " that is not an unsigned char nor an EOF." + "The function " + ctypeCall + " accepts an argument " + ctypeCall.getConvertedArgument() + + " that is not an unsigned char nor an EOF." From aa3b81f73542cad7b73986376cf39d32f6f83fd3 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 17 Mar 2023 17:10:20 -0700 Subject: [PATCH 28/34] Add .expected for clang and qcc --- .../CtypeFunctionArgNotUnsignedCharOrEof.expected.clang | 2 ++ .../CtypeFunctionArgNotUnsignedCharOrEof.expected.qcc | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected.clang create mode 100644 c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected.qcc diff --git a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected.clang b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected.clang new file mode 100644 index 0000000000..6af28a74db --- /dev/null +++ b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected.clang @@ -0,0 +1,2 @@ +| test.c:14:7:14:17 | isalnum(c) | The function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. | +| test.c:20:7:20:17 | isalnum(c) | The function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. | \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected.qcc b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected.qcc new file mode 100644 index 0000000000..6af28a74db --- /dev/null +++ b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected.qcc @@ -0,0 +1,2 @@ +| test.c:14:7:14:17 | isalnum(c) | The function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. | +| test.c:20:7:20:17 | isalnum(c) | The function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. | \ No newline at end of file From 4c9f1921708aa8da9387f0343fd188b63a3d91cf Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 20 Mar 2023 09:24:32 -0700 Subject: [PATCH 29/34] Add FP suspect case --- cpp/autosar/test/rules/A0-1-1/test.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cpp/autosar/test/rules/A0-1-1/test.cpp b/cpp/autosar/test/rules/A0-1-1/test.cpp index 98c8058219..0871c0bf7c 100644 --- a/cpp/autosar/test/rules/A0-1-1/test.cpp +++ b/cpp/autosar/test/rules/A0-1-1/test.cpp @@ -17,6 +17,18 @@ struct C { int m; }; +template void test() { + T t; + t.g(); +} + +template void call_test() { + // call it with type parameter B to trigger indexing + test(); +} + +void call_call_test() { call_test(); } + int test_useless_assignment(int &x, int p) { x = 0; // COMPLIANT - x is a reference parameter, so is visible by the caller int y = 0; // NON_COMPLIANT - never used From f9f8ecb7d794917f0656f27b0cd9fd93652e0a2f Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 20 Mar 2023 09:28:30 -0700 Subject: [PATCH 30/34] Oops, wrong branch --- cpp/autosar/test/rules/A0-1-1/test.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/cpp/autosar/test/rules/A0-1-1/test.cpp b/cpp/autosar/test/rules/A0-1-1/test.cpp index 0871c0bf7c..98c8058219 100644 --- a/cpp/autosar/test/rules/A0-1-1/test.cpp +++ b/cpp/autosar/test/rules/A0-1-1/test.cpp @@ -17,18 +17,6 @@ struct C { int m; }; -template void test() { - T t; - t.g(); -} - -template void call_test() { - // call it with type parameter B to trigger indexing - test(); -} - -void call_call_test() { call_test(); } - int test_useless_assignment(int &x, int p) { x = 0; // COMPLIANT - x is a reference parameter, so is visible by the caller int y = 0; // NON_COMPLIANT - never used From 3928d06b0fc9c4421a03f7d46a68d93e5a50ebba Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 22 Mar 2023 20:45:30 -0700 Subject: [PATCH 31/34] Add test for gcc --- .../CtypeFunctionArgNotUnsignedCharorEof.expected.gcc | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharorEof.expected.gcc diff --git a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharorEof.expected.gcc b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharorEof.expected.gcc new file mode 100644 index 0000000000..6af28a74db --- /dev/null +++ b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharorEof.expected.gcc @@ -0,0 +1,2 @@ +| test.c:14:7:14:17 | isalnum(c) | The function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. | +| test.c:20:7:20:17 | isalnum(c) | The function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. | \ No newline at end of file From e2ef453326dcb6891da836d2567d2fda5bfc17de Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 24 Mar 2023 10:22:15 -0700 Subject: [PATCH 32/34] Put back StandardLibraryFunctionTypes --- .../src/codingstandards/cpp/exclusions/c/RuleMetadata.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index dc8bdcbae2..1feb3bfea7 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -48,6 +48,7 @@ import Preprocessor5 import Preprocessor6 import SideEffects1 import SideEffects2 +import StandardLibraryFunctionTypes import SignalHandlers import Strings1 import Strings2 @@ -102,6 +103,7 @@ newtype TCQuery = TPreprocessor6PackageQuery(Preprocessor6Query q) or TSideEffects1PackageQuery(SideEffects1Query q) or TSideEffects2PackageQuery(SideEffects2Query q) or + TStandardLibraryFunctionTypesPackageQuery(StandardLibraryFunctionTypesQuery q) or TSignalHandlersPackageQuery(SignalHandlersQuery q) or TStrings1PackageQuery(Strings1Query q) or TStrings2PackageQuery(Strings2Query q) or @@ -156,6 +158,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isPreprocessor6QueryMetadata(query, queryId, ruleId, category) or isSideEffects1QueryMetadata(query, queryId, ruleId, category) or isSideEffects2QueryMetadata(query, queryId, ruleId, category) or + isStandardLibraryFunctionTypesQueryMetadata(query, queryId, ruleId, category) or isSignalHandlersQueryMetadata(query, queryId, ruleId, category) or isStrings1QueryMetadata(query, queryId, ruleId, category) or isStrings2QueryMetadata(query, queryId, ruleId, category) or From 63b12560d4b71ff5d73ff8ac647caa9a1b4cdab8 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 24 Mar 2023 10:28:46 -0700 Subject: [PATCH 33/34] Modify RuleMetadata --- .../src/codingstandards/cpp/exclusions/c/RuleMetadata.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 1feb3bfea7..977123ae5d 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -48,8 +48,8 @@ import Preprocessor5 import Preprocessor6 import SideEffects1 import SideEffects2 -import StandardLibraryFunctionTypes import SignalHandlers +import StandardLibraryFunctionTypes import Strings1 import Strings2 import Strings3 @@ -103,8 +103,8 @@ newtype TCQuery = TPreprocessor6PackageQuery(Preprocessor6Query q) or TSideEffects1PackageQuery(SideEffects1Query q) or TSideEffects2PackageQuery(SideEffects2Query q) or - TStandardLibraryFunctionTypesPackageQuery(StandardLibraryFunctionTypesQuery q) or TSignalHandlersPackageQuery(SignalHandlersQuery q) or + TStandardLibraryFunctionTypesPackageQuery(StandardLibraryFunctionTypesQuery q) or TStrings1PackageQuery(Strings1Query q) or TStrings2PackageQuery(Strings2Query q) or TStrings3PackageQuery(Strings3Query q) or @@ -158,8 +158,8 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isPreprocessor6QueryMetadata(query, queryId, ruleId, category) or isSideEffects1QueryMetadata(query, queryId, ruleId, category) or isSideEffects2QueryMetadata(query, queryId, ruleId, category) or - isStandardLibraryFunctionTypesQueryMetadata(query, queryId, ruleId, category) or isSignalHandlersQueryMetadata(query, queryId, ruleId, category) or + isStandardLibraryFunctionTypesQueryMetadata(query, queryId, ruleId, category) or isStrings1QueryMetadata(query, queryId, ruleId, category) or isStrings2QueryMetadata(query, queryId, ruleId, category) or isStrings3QueryMetadata(query, queryId, ruleId, category) or From 7dba0821b23cee2e2f57c641fa1385afcd2926eb Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 24 Mar 2023 16:47:44 -0700 Subject: [PATCH 34/34] Rename .expected.gcc file --- ...cted.gcc => CtypeFunctionArgNotUnsignedCharOrEof.expected.gcc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename c/misra/test/rules/RULE-21-13/{CtypeFunctionArgNotUnsignedCharorEof.expected.gcc => CtypeFunctionArgNotUnsignedCharOrEof.expected.gcc} (100%) diff --git a/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharorEof.expected.gcc b/c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected.gcc similarity index 100% rename from c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharorEof.expected.gcc rename to c/misra/test/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.expected.gcc