diff --git a/c/cert/src/rules/DCL40-C/ExternalIdentifiers.qll b/c/cert/src/rules/DCL40-C/ExternalIdentifiers.qll deleted file mode 100644 index ae63dac5be..0000000000 --- a/c/cert/src/rules/DCL40-C/ExternalIdentifiers.qll +++ /dev/null @@ -1,15 +0,0 @@ -import cpp -import codingstandards.cpp.Linkage - -class ExternalIdentifiers extends Declaration { - ExternalIdentifiers() { - hasExternalLinkage(this) and - getNamespace() instanceof GlobalNamespace and - not this.isFromTemplateInstantiation(_) and - not this.isFromUninstantiatedTemplate(_) and - not this.hasDeclaringType() and - not this instanceof UserType and - not this instanceof Operator and - not this.hasName("main") - } -} diff --git a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql index 3811d4e417..70684d0361 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql +++ b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql @@ -21,42 +21,11 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.types.Compatible -import ExternalIdentifiers +import codingstandards.cpp.rules.incompatiblefunctiondeclaration.IncompatibleFunctionDeclaration -predicate interestedInFunctions( - FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, ExternalIdentifiers d -) { - not f1 = f2 and - d = f1.getDeclaration() and - d = f2.getDeclaration() +module IncompatibleFunctionDeclarationsCppConfig implements IncompatibleFunctionDeclarationConfigSig +{ + Query getQuery() { result = Declarations2Package::incompatibleFunctionDeclarationsQuery() } } -predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { - interestedInFunctions(f1, f2, _) -} - -module FuncDeclEquiv = - FunctionDeclarationTypeEquivalence; - -from ExternalIdentifiers d, FunctionDeclarationEntry f1, FunctionDeclarationEntry f2 -where - not isExcluded(f1, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and - not isExcluded(f2, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and - interestedInFunctions(f1, f2, d) and - ( - //return type check - not FuncDeclEquiv::equalReturnTypes(f1, f2) - or - //parameter type check - not FuncDeclEquiv::equalParameterTypes(f1, f2) - ) and - // Apply ordering on start line, trying to avoid the optimiser applying this join too early - // in the pipeline - exists(int f1Line, int f2Line | - f1.getLocation().hasLocationInfo(_, f1Line, _, _, _) and - f2.getLocation().hasLocationInfo(_, f2Line, _, _, _) and - f1Line >= f2Line - ) -select f1, "The object $@ is not compatible with re-declaration $@", f1, f1.getName(), f2, - f2.getName() +import IncompatibleFunctionDeclaration diff --git a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql index 8e220062d4..5db718a48b 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql +++ b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql @@ -3,7 +3,7 @@ * @name DCL40-C: Do not create incompatible declarations of the same function or object * @description Declaring incompatible objects, in other words same named objects of different * types, then accessing those objects can lead to undefined behaviour. - * @kind problem + * @ kind problem * @precision high * @problem.severity error * @tags external/cert/id/dcl40-c @@ -20,16 +20,10 @@ import cpp import codingstandards.c.cert -import ExternalIdentifiers +import codingstandards.cpp.rules.incompatibleobjectdeclaration.IncompatibleObjectDeclaration -from VariableDeclarationEntry decl1, VariableDeclarationEntry decl2 -where - not isExcluded(decl1, Declarations2Package::incompatibleObjectDeclarationsQuery()) and - not isExcluded(decl2, Declarations2Package::incompatibleObjectDeclarationsQuery()) and - not decl1.getUnspecifiedType() = decl2.getUnspecifiedType() and - decl1.getDeclaration() instanceof ExternalIdentifiers and - decl2.getDeclaration() instanceof ExternalIdentifiers and - decl1.getLocation().getStartLine() >= decl2.getLocation().getStartLine() and - decl1.getVariable().getName() = decl2.getVariable().getName() -select decl1, "The object $@ is not compatible with re-declaration $@", decl1, decl1.getName(), - decl2, decl2.getName() +module IncompatibleObjectDeclarationsCppConfig implements IncompatibleObjectDeclarationConfigSig { + Query getQuery() { result = Declarations2Package::incompatibleObjectDeclarationsQuery() } +} + +import IncompatibleObjectDeclaration diff --git a/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.expected b/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.expected deleted file mode 100644 index f6e330d697..0000000000 --- a/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.expected +++ /dev/null @@ -1,4 +0,0 @@ -| test1.c:4:12:4:12 | declaration of f | The object $@ is not compatible with re-declaration $@ | test1.c:4:12:4:12 | declaration of f | f | test.c:4:6:4:6 | definition of f | f | -| test.c:4:6:4:6 | definition of f | The object $@ is not compatible with re-declaration $@ | test.c:4:6:4:6 | definition of f | f | test1.c:4:12:4:12 | declaration of f | f | -| test.c:8:6:8:7 | declaration of f1 | The object $@ is not compatible with re-declaration $@ | test.c:8:6:8:7 | declaration of f1 | f1 | test1.c:5:13:5:14 | declaration of f1 | f1 | -| test.c:9:6:9:7 | definition of f2 | The object $@ is not compatible with re-declaration $@ | test.c:9:6:9:7 | definition of f2 | f2 | test1.c:6:6:6:7 | definition of f2 | f2 | diff --git a/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.qlref b/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.qlref deleted file mode 100644 index 39e98a0f82..0000000000 --- a/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/DCL40-C/IncompatibleFunctionDeclarations.ql \ No newline at end of file diff --git a/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.testref b/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.testref new file mode 100644 index 0000000000..69f63bfb2f --- /dev/null +++ b/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.testref @@ -0,0 +1 @@ +c/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.ql \ No newline at end of file diff --git a/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.expected b/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.expected deleted file mode 100644 index 30eaf1a416..0000000000 --- a/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test1.c:2:12:2:12 | declaration of i | The object $@ is not compatible with re-declaration $@ | test1.c:2:12:2:12 | declaration of i | i | test.c:1:7:1:7 | definition of i | i | -| test.c:2:5:2:5 | definition of a | The object $@ is not compatible with re-declaration $@ | test.c:2:5:2:5 | definition of a | a | test1.c:1:13:1:13 | declaration of a | a | diff --git a/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.qlref b/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.qlref deleted file mode 100644 index 6648409686..0000000000 --- a/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/DCL40-C/IncompatibleObjectDeclarations.ql \ No newline at end of file diff --git a/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.testref b/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.testref new file mode 100644 index 0000000000..6ae6a4db80 --- /dev/null +++ b/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.testref @@ -0,0 +1 @@ +c/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.ql \ No newline at end of file diff --git a/c/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.expected b/c/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.expected new file mode 100644 index 0000000000..c44bce3178 --- /dev/null +++ b/c/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.expected @@ -0,0 +1,4 @@ +| test1.c:4:12:4:12 | declaration of f | The object is not compatible with a re-declaration $@. | test.c:4:6:4:6 | definition of f | f | +| test.c:4:6:4:6 | definition of f | The object is not compatible with a re-declaration $@. | test1.c:4:12:4:12 | declaration of f | f | +| test.c:8:6:8:7 | declaration of f1 | The object is not compatible with a re-declaration $@. | test1.c:5:13:5:14 | declaration of f1 | f1 | +| test.c:9:6:9:7 | definition of f2 | The object is not compatible with a re-declaration $@. | test1.c:6:6:6:7 | definition of f2 | f2 | diff --git a/c/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.ql b/c/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.ql new file mode 100644 index 0000000000..cbdbf6611b --- /dev/null +++ b/c/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.ql @@ -0,0 +1,8 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.incompatiblefunctiondeclaration.IncompatibleFunctionDeclaration + +module TestFileConfig implements IncompatibleFunctionDeclarationConfigSig { + Query getQuery() { result instanceof TestQuery } +} + +import IncompatibleFunctionDeclaration diff --git a/c/cert/test/rules/DCL40-C/test.c b/c/common/test/rules/incompatiblefunctiondeclaration/test.c similarity index 100% rename from c/cert/test/rules/DCL40-C/test.c rename to c/common/test/rules/incompatiblefunctiondeclaration/test.c diff --git a/c/cert/test/rules/DCL40-C/test1.c b/c/common/test/rules/incompatiblefunctiondeclaration/test1.c similarity index 100% rename from c/cert/test/rules/DCL40-C/test1.c rename to c/common/test/rules/incompatiblefunctiondeclaration/test1.c diff --git a/c/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.expected b/c/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.expected new file mode 100644 index 0000000000..901c1dc2f6 --- /dev/null +++ b/c/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.expected @@ -0,0 +1,2 @@ +| test1.c:2:12:2:12 | declaration of i | The object is not compatible with a re-declaration $@. | test.c:1:7:1:7 | definition of i | i | +| test.c:2:5:2:5 | definition of a | The object is not compatible with a re-declaration $@. | test1.c:1:13:1:13 | declaration of a | a | diff --git a/c/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.ql b/c/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.ql new file mode 100644 index 0000000000..915cbbbc2d --- /dev/null +++ b/c/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.ql @@ -0,0 +1,8 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.incompatibleobjectdeclaration.IncompatibleObjectDeclaration + +module TestFileConfig implements IncompatibleObjectDeclarationConfigSig { + Query getQuery() { result instanceof TestQuery } +} + +import IncompatibleObjectDeclaration diff --git a/c/common/test/rules/incompatibleobjectdeclaration/test.c b/c/common/test/rules/incompatibleobjectdeclaration/test.c new file mode 100644 index 0000000000..53ea630187 --- /dev/null +++ b/c/common/test/rules/incompatibleobjectdeclaration/test.c @@ -0,0 +1,10 @@ +short i; // NON_COMPLIANT +int a[] = {1, 2, 3, 4}; // NON_COMPLIANT + +long f(int a) { // NON_COMPLIANT + return a * 2; +} + +void f1(long a); // NON_COMPLIANT +void f2() {} // NON_COMPLIANT +int f3(); // COMPLIANT \ No newline at end of file diff --git a/c/common/test/rules/incompatibleobjectdeclaration/test1.c b/c/common/test/rules/incompatibleobjectdeclaration/test1.c new file mode 100644 index 0000000000..60178e1439 --- /dev/null +++ b/c/common/test/rules/incompatibleobjectdeclaration/test1.c @@ -0,0 +1,7 @@ +extern int *a; // NON_COMPLIANT +extern int i; // NON_COMPLIANT + +extern int f(int a); // NON_COMPLIANT +extern void f1(int a); // NON_COMPLIANT +void f2(int a, ...) {} // NON_COMPLIANT +int f3(); // COMPLIANT \ No newline at end of file diff --git a/change_notes/2026-03-27-update-compatible-objects-DCL40-C.md b/change_notes/2026-03-27-update-compatible-objects-DCL40-C.md new file mode 100644 index 0000000000..5f1f9681ab --- /dev/null +++ b/change_notes/2026-03-27-update-compatible-objects-DCL40-C.md @@ -0,0 +1,2 @@ + - `DCL40-C` - `IncompatibleObjectDeclarations.ql`: + - Enhanced the query's ability to compare objects with array type, which will reduce false positives. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations2.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations2.qll new file mode 100644 index 0000000000..6f686a1b02 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations2.qll @@ -0,0 +1,61 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Declarations2Query = + TIncompatibleObjectDeclarationsCppQuery() or + TIncompatibleFunctionDeclarationsCppQuery() or + TLocalVariableStaticStorageDurationQuery() + +predicate isDeclarations2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `incompatibleObjectDeclarationsCpp` query + Declarations2Package::incompatibleObjectDeclarationsCppQuery() and + queryId = + // `@id` for the `incompatibleObjectDeclarationsCpp` query + "cpp/misra/incompatible-object-declarations-cpp" and + ruleId = "RULE-6-2-2" and + category = "required" + or + query = + // `Query` instance for the `incompatibleFunctionDeclarationsCpp` query + Declarations2Package::incompatibleFunctionDeclarationsCppQuery() and + queryId = + // `@id` for the `incompatibleFunctionDeclarationsCpp` query + "cpp/misra/incompatible-function-declarations-cpp" and + ruleId = "RULE-6-2-2" and + category = "required" + or + query = + // `Query` instance for the `localVariableStaticStorageDuration` query + Declarations2Package::localVariableStaticStorageDurationQuery() and + queryId = + // `@id` for the `localVariableStaticStorageDuration` query + "cpp/misra/local-variable-static-storage-duration" and + ruleId = "RULE-6-7-1" and + category = "required" +} + +module Declarations2Package { + Query incompatibleObjectDeclarationsCppQuery() { + //autogenerate `Query` type + result = + // `Query` type for `incompatibleObjectDeclarationsCpp` query + TQueryCPP(TDeclarations2PackageQuery(TIncompatibleObjectDeclarationsCppQuery())) + } + + Query incompatibleFunctionDeclarationsCppQuery() { + //autogenerate `Query` type + result = + // `Query` type for `incompatibleFunctionDeclarationsCpp` query + TQueryCPP(TDeclarations2PackageQuery(TIncompatibleFunctionDeclarationsCppQuery())) + } + + Query localVariableStaticStorageDurationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `localVariableStaticStorageDuration` query + TQueryCPP(TDeclarations2PackageQuery(TLocalVariableStaticStorageDurationQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index 737534c36d..1ad3a8cb1a 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -30,6 +30,7 @@ import DeadCode8 import DeadCode9 import Declarations import Declarations1 +import Declarations2 import ExceptionSafety import Exceptions1 import Exceptions2 @@ -123,6 +124,7 @@ newtype TCPPQuery = TDeadCode9PackageQuery(DeadCode9Query q) or TDeclarationsPackageQuery(DeclarationsQuery q) or TDeclarations1PackageQuery(Declarations1Query q) or + TDeclarations2PackageQuery(Declarations2Query q) or TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or TExceptions1PackageQuery(Exceptions1Query q) or TExceptions2PackageQuery(Exceptions2Query q) or @@ -216,6 +218,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isDeadCode9QueryMetadata(query, queryId, ruleId, category) or isDeclarationsQueryMetadata(query, queryId, ruleId, category) or isDeclarations1QueryMetadata(query, queryId, ruleId, category) or + isDeclarations2QueryMetadata(query, queryId, ruleId, category) or isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or isExceptions1QueryMetadata(query, queryId, ruleId, category) or isExceptions2QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.qll b/cpp/common/src/codingstandards/cpp/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.qll new file mode 100644 index 0000000000..2b6afd468d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.qll @@ -0,0 +1,62 @@ +/** + * Provides a configurable module IncompatibleFunctionDeclaration with a `problems` predicate + * for the following issue: + * Declaring incompatible functions, in other words same named function of different + * return types or with different numbers of parameters or parameter types, then + * accessing those functions can lead to undefined behaviour. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Identifiers +import codingstandards.cpp.types.Compatible + +predicate interestedInFunctions( + FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, ExternalIdentifiers d1, + ExternalIdentifiers d2 +) { + not f1 = f2 and + d1 = f1.getDeclaration() and + d2 = f2.getDeclaration() and + f1.getName() = f2.getName() +} + +predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + interestedInFunctions(f1, f2, _, _) +} + +module FuncDeclEquiv = + FunctionDeclarationTypeEquivalence; + +signature module IncompatibleFunctionDeclarationConfigSig { + Query getQuery(); +} + +module IncompatibleFunctionDeclaration { + query predicate problems( + FunctionDeclarationEntry f1, string message, FunctionDeclarationEntry f2, string secondMessage + ) { + exists(ExternalIdentifiers d1, ExternalIdentifiers d2 | + not isExcluded(f1, Config::getQuery()) and + not isExcluded(f2, Config::getQuery()) and + interestedInFunctions(f1, f2, d1, d2) and + ( + //return type check + not FuncDeclEquiv::equalReturnTypes(f1, f2) + or + //parameter type check + not FuncDeclEquiv::equalParameterTypes(f1, f2) + ) and + // Apply ordering on start line, trying to avoid the optimiser applying this join too early + // in the pipeline + exists(int f1Line, int f2Line | + f1.getLocation().hasLocationInfo(_, f1Line, _, _, _) and + f2.getLocation().hasLocationInfo(_, f2Line, _, _, _) and + f1Line >= f2Line + ) and + secondMessage = f2.getName() and + message = "The object is not compatible with a re-declaration $@." + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.qll b/cpp/common/src/codingstandards/cpp/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.qll new file mode 100644 index 0000000000..b234be564c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.qll @@ -0,0 +1,44 @@ +/** + * Provides a configurable module IncompatibleObjectDeclaration with a `problems` predicate + * for the following issue: + * Declaring incompatible objects, in other words same named objects of different + * types, then accessing those objects can lead to undefined behavior. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Identifiers +import codingstandards.cpp.types.Compatible + +signature module IncompatibleObjectDeclarationConfigSig { + Query getQuery(); +} + +predicate relevantTypes(Type a, Type b) { + exists(VariableDeclarationEntry varA, VariableDeclarationEntry varB | + not varA = varB and + varA.getVariable().getName() = varB.getVariable().getName() and + a = varA.getType() and + b = varB.getType() + ) +} + +module IncompatibleObjectDeclaration { + query predicate problems( + VariableDeclarationEntry decl1, string message, VariableDeclarationEntry decl2, + string secondMessage + ) { + not isExcluded(decl1, Config::getQuery()) and + not isExcluded(decl2, Config::getQuery()) and + not TypeEquivalence::equalTypes(decl1.getType(), + decl2.getType()) and + not decl1 = decl2 and + decl1.getDeclaration() instanceof ExternalIdentifiers and + decl2.getDeclaration() instanceof ExternalIdentifiers and + decl1.getLocation().getStartLine() >= decl2.getLocation().getStartLine() and + decl1.getVariable().getName() = decl2.getVariable().getName() and + secondMessage = decl2.getName() and + message = "The object is not compatible with a re-declaration $@." + } +} diff --git a/cpp/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.expected b/cpp/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.expected new file mode 100644 index 0000000000..ec5b2349a4 --- /dev/null +++ b/cpp/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.expected @@ -0,0 +1,5 @@ +| test1.cpp:1:12:1:12 | declaration of f | The object is not compatible with a re-declaration $@. | test.cpp:1:6:1:6 | definition of f | f | +| test.cpp:1:6:1:6 | definition of f | The object is not compatible with a re-declaration $@. | test1.cpp:1:12:1:12 | declaration of f | f | +| test.cpp:5:6:5:7 | declaration of f1 | The object is not compatible with a re-declaration $@. | test1.cpp:2:13:2:14 | declaration of f1 | f1 | +| test.cpp:6:6:6:7 | definition of f2 | The object is not compatible with a re-declaration $@. | test1.cpp:3:6:3:7 | definition of f2 | f2 | +| test.cpp:9:17:9:18 | declaration of f4 | The object is not compatible with a re-declaration $@. | test1.cpp:6:17:6:18 | declaration of f4 | f4 | diff --git a/cpp/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.ql b/cpp/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.ql new file mode 100644 index 0000000000..cbdbf6611b --- /dev/null +++ b/cpp/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.ql @@ -0,0 +1,8 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.incompatiblefunctiondeclaration.IncompatibleFunctionDeclaration + +module TestFileConfig implements IncompatibleFunctionDeclarationConfigSig { + Query getQuery() { result instanceof TestQuery } +} + +import IncompatibleFunctionDeclaration diff --git a/cpp/common/test/rules/incompatiblefunctiondeclaration/test.cpp b/cpp/common/test/rules/incompatiblefunctiondeclaration/test.cpp new file mode 100644 index 0000000000..17be220260 --- /dev/null +++ b/cpp/common/test/rules/incompatiblefunctiondeclaration/test.cpp @@ -0,0 +1,10 @@ +long f(int a) { // NON_COMPLIANT + return a * 2; +} + +void f1(long a); // NON_COMPLIANT +void f2() {} // NON_COMPLIANT +int f3(); // COMPLIANT + +extern "C" long f4(int a); // NON_COMPLIANT +long f5(); // NON_COMPLIANT[FALSE_NEGATIVE] \ No newline at end of file diff --git a/cpp/common/test/rules/incompatiblefunctiondeclaration/test1.cpp b/cpp/common/test/rules/incompatiblefunctiondeclaration/test1.cpp new file mode 100644 index 0000000000..a2efd94ffe --- /dev/null +++ b/cpp/common/test/rules/incompatiblefunctiondeclaration/test1.cpp @@ -0,0 +1,7 @@ +extern int f(int a); // NON_COMPLIANT +extern void f1(int a); // NON_COMPLIANT +void f2(int a, ...) {} // NON_COMPLIANT +int f3(); // COMPLIANT + +extern "C" long f4(char a); // NON_COMPLIANT +long f5() noexcept; // NON_COMPLIANT[FALSE_NEGATIVE] \ No newline at end of file diff --git a/cpp/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.expected b/cpp/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.expected new file mode 100644 index 0000000000..3cf2548791 --- /dev/null +++ b/cpp/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.expected @@ -0,0 +1,4 @@ +| test1.cpp:1:12:1:12 | declaration of i | The object is not compatible with a re-declaration $@. | test.cpp:1:7:1:7 | definition of i | i | +| test1.cpp:2:13:2:13 | declaration of a | The object is not compatible with a re-declaration $@. | test.cpp:2:5:2:5 | definition of a | a | +| test.cpp:1:7:1:7 | definition of i | The object is not compatible with a re-declaration $@. | test1.cpp:1:12:1:12 | declaration of i | i | +| test.cpp:2:5:2:5 | definition of a | The object is not compatible with a re-declaration $@. | test1.cpp:2:13:2:13 | declaration of a | a | diff --git a/cpp/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.ql b/cpp/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.ql new file mode 100644 index 0000000000..915cbbbc2d --- /dev/null +++ b/cpp/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.ql @@ -0,0 +1,8 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.incompatibleobjectdeclaration.IncompatibleObjectDeclaration + +module TestFileConfig implements IncompatibleObjectDeclarationConfigSig { + Query getQuery() { result instanceof TestQuery } +} + +import IncompatibleObjectDeclaration diff --git a/cpp/common/test/rules/incompatibleobjectdeclaration/test.cpp b/cpp/common/test/rules/incompatibleobjectdeclaration/test.cpp new file mode 100644 index 0000000000..9a9b4bcb91 --- /dev/null +++ b/cpp/common/test/rules/incompatibleobjectdeclaration/test.cpp @@ -0,0 +1,5 @@ +short i; // NON_COMPLIANT +int a[] = {1, 2, 3, 4}; // NON_COMPLIANT +long b; // NON_COMPLIANT[FALSE_NEGATIVE] -- compiler does not extract c linkage +extern int c[]; // COMPLIANT +extern int d; // COMPLIANT \ No newline at end of file diff --git a/cpp/common/test/rules/incompatibleobjectdeclaration/test1.cpp b/cpp/common/test/rules/incompatibleobjectdeclaration/test1.cpp new file mode 100644 index 0000000000..faf3b50bcc --- /dev/null +++ b/cpp/common/test/rules/incompatibleobjectdeclaration/test1.cpp @@ -0,0 +1,6 @@ +extern int i; // NON_COMPLIANT +extern int *a; // NON_COMPLIANT +extern "C" long + b; // NON_COMPLIANT[FALSE_NEGATIVE] -- compiler does not extract c linkage +extern int c[1]; // COMPLIANT +extern int d{1}; // COMPLIANT \ No newline at end of file diff --git a/cpp/misra/src/rules/RULE-6-2-2/IncompatibleFunctionDeclarationsCpp.ql b/cpp/misra/src/rules/RULE-6-2-2/IncompatibleFunctionDeclarationsCpp.ql new file mode 100644 index 0000000000..d69fbe7434 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-2-2/IncompatibleFunctionDeclarationsCpp.ql @@ -0,0 +1,27 @@ +/** + * @id cpp/misra/incompatible-function-declarations-cpp + * @name RULE-6-2-2: Do not create incompatible declarations of the same function or object + * @description Declaring incompatible functions, in other words same named function of different + * return types or with different numbers of parameters or parameter types, then + * accessing those functions can lead to undefined behaviour. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-6-2-2 + * correctness + * maintainability + * readability + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.incompatiblefunctiondeclaration.IncompatibleFunctionDeclaration + +module IncompatibleFunctionDeclarationsCppConfig implements IncompatibleFunctionDeclarationConfigSig +{ + Query getQuery() { result = Declarations2Package::incompatibleFunctionDeclarationsCppQuery() } +} + +import IncompatibleFunctionDeclaration diff --git a/cpp/misra/src/rules/RULE-6-2-2/IncompatibleObjectDeclarationsCpp.ql b/cpp/misra/src/rules/RULE-6-2-2/IncompatibleObjectDeclarationsCpp.ql new file mode 100644 index 0000000000..4ad68cd40d --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-2-2/IncompatibleObjectDeclarationsCpp.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/incompatible-object-declarations-cpp + * @name RULE-6-2-2: Do not create incompatible declarations of the same function or object + * @description Declaring incompatible objects, in other words same named objects of different + * types, then accessing those objects can lead to undefined behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-6-2-2 + * correctness + * maintainability + * readability + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.incompatibleobjectdeclaration.IncompatibleObjectDeclaration + +module IncompatibleObjectDeclarationsCppConfig implements IncompatibleObjectDeclarationConfigSig { + Query getQuery() { result = Declarations2Package::incompatibleObjectDeclarationsCppQuery() } +} + +import IncompatibleObjectDeclaration diff --git a/cpp/misra/test/rules/RULE-6-2-2/IncompatibleFunctionDeclarations.testref b/cpp/misra/test/rules/RULE-6-2-2/IncompatibleFunctionDeclarations.testref new file mode 100644 index 0000000000..4d1b3b33d5 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-2/IncompatibleFunctionDeclarations.testref @@ -0,0 +1 @@ +cpp/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-2/IncompatibleFunctionDeclarationsCpp.testref b/cpp/misra/test/rules/RULE-6-2-2/IncompatibleFunctionDeclarationsCpp.testref new file mode 100644 index 0000000000..4d1b3b33d5 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-2/IncompatibleFunctionDeclarationsCpp.testref @@ -0,0 +1 @@ +cpp/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-2/IncompatibleObjectDeclarations.testref b/cpp/misra/test/rules/RULE-6-2-2/IncompatibleObjectDeclarations.testref new file mode 100644 index 0000000000..d082ae2823 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-2/IncompatibleObjectDeclarations.testref @@ -0,0 +1 @@ +cpp/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-2/IncompatibleObjectDeclarationsCpp.testref b/cpp/misra/test/rules/RULE-6-2-2/IncompatibleObjectDeclarationsCpp.testref new file mode 100644 index 0000000000..d082ae2823 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-2/IncompatibleObjectDeclarationsCpp.testref @@ -0,0 +1 @@ +cpp/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.ql \ No newline at end of file diff --git a/rule_packages/c/Declarations2.json b/rule_packages/c/Declarations2.json index c5b827e682..806ea94e7f 100644 --- a/rule_packages/c/Declarations2.json +++ b/rule_packages/c/Declarations2.json @@ -61,6 +61,7 @@ "precision": "high", "severity": "error", "short_name": "IncompatibleObjectDeclarations", + "shared_implementation_short_name": "IncompatibleObjectDeclaration", "tags": [ "correctness", "maintainability", @@ -79,6 +80,7 @@ "precision": "high", "severity": "error", "short_name": "IncompatibleFunctionDeclarations", + "shared_implementation_short_name": "IncompatibleFunctionDeclaration", "tags": [ "correctness", "maintainability", diff --git a/rule_packages/cpp/Declarations2.json b/rule_packages/cpp/Declarations2.json new file mode 100644 index 0000000000..4ec7f49fda --- /dev/null +++ b/rule_packages/cpp/Declarations2.json @@ -0,0 +1,70 @@ +{ + "MISRA-C++-2023": { + "RULE-6-2-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Declaring incompatible objects, in other words same named objects of different types, then accessing those objects can lead to undefined behavior.", + "kind": "problem", + "name": "Do not create incompatible declarations of the same function or object", + "precision": "high", + "severity": "error", + "short_name": "IncompatibleObjectDeclarationsCpp", + "shared_implementation_short_name": "IncompatibleObjectDeclaration", + "tags": [ + "correctness", + "maintainability", + "readability" + ], + "implementation_scope": { + "description": "This query does not detect variables designated with C linkage as distinct as that is something that is not currently extracted by CodeQL." + } + }, + { + "description": "Declaring incompatible functions, in other words same named function of different return types or with different numbers of parameters or parameter types, then accessing those functions can lead to undefined behaviour.", + "kind": "problem", + "name": "Do not create incompatible declarations of the same function or object", + "precision": "high", + "severity": "error", + "short_name": "IncompatibleFunctionDeclarationsCpp", + "shared_implementation_short_name": "IncompatibleFunctionDeclaration", + "tags": [ + "correctness", + "maintainability", + "readability" + ], + "implementation_scope": { + "description": "This query does not currently consider function return exception status as a factor of return type and therefore it will have false negatives for cases where a function is noexcept and another is not." + } + } + ], + "title": "All declarations of a variable or function shall have the same type" + }, + "RULE-6-7-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Local variables that have static storage duration can be harder to reason about and can lead to undefined behavior.", + "kind": "problem", + "name": "Local variables shall not have static storage duration", + "precision": "very-high", + "severity": "error", + "short_name": "LocalVariableStaticStorageDuration", + "tags": [ + "correctness", + "maintainability", + "readability", + "scope/single-translation-unit" + ] + } + ], + "title": "Local variables shall not have static storage duration" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index a56ad6b48f..5497aa5ddd 100644 --- a/rules.csv +++ b/rules.csv @@ -849,13 +849,13 @@ cpp,MISRA-C++-2023,RULE-5-13-4,Yes,Required,Decidable,Single Translation Unit,Un cpp,MISRA-C++-2023,RULE-5-13-5,Yes,Required,Decidable,Single Translation Unit,The lowercase form of L shall not be used as the first character in a literal suffix,RULE-7-3,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-5-13-6,Yes,Required,Decidable,Single Translation Unit,An integer-literal of type long long shall not use a single L or l in any suffix,,Expressions2,Easy, cpp,MISRA-C++-2023,RULE-5-13-7,No,Required,Decidable,Single Translation Unit,String literals with different encoding prefixes shall not be concatenated,A2-13-2,,, -cpp,MISRA-C++-2023,RULE-6-0-1,Yes,Required,Decidable,Single Translation Unit,Block scope declarations shall not be visually ambiguous,"M3-1-2,DCL53-CPP",Declarations2,Easy, +cpp,MISRA-C++-2023,RULE-6-0-1,Yes,Required,Decidable,Single Translation Unit,Block scope declarations shall not be visually ambiguous,"M3-1-2,DCL53-CPP",Declarations3,Easy, cpp,MISRA-C++-2023,RULE-6-0-2,Yes,Advisory,Decidable,Single Translation Unit,"When an array with external linkage is declared, its size should be explicitly specified",RULE-18-8,Linkage1,Import, cpp,MISRA-C++-2023,RULE-6-0-3,Yes,Advisory,Decidable,Single Translation Unit,"The only declarations in the global namespace should be main, namespace declarations and extern ""C"" declarations",M7-3-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-6-0-4,Yes,Required,Decidable,Single Translation Unit,The identifier main shall not be used for a function other than the global function main,M7-3-2,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-6-2-1,Yes,Required,Decidable,System,The one-definition rule shall not be violated,M3-2-2,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-6-2-2,Yes,Required,Decidable,System,All declarations of a variable or function shall have the same type,"M3-9-1,DCL40-C",Declarations2,Easy, -cpp,MISRA-C++-2023,RULE-6-2-3,Yes,Required,Decidable,System,The source code used to implement an entity shall appear only once,,Declarations2,Medium, +cpp,MISRA-C++-2023,RULE-6-2-3,Yes,Required,Decidable,System,The source code used to implement an entity shall appear only once,,Declarations3,Medium, cpp,MISRA-C++-2023,RULE-6-2-4,Yes,Required,Decidable,Single Translation Unit,A header file shall not contain definitions of functions or objects that are non-inline and have external linkage,A3-1-1,Linkage2,Import, cpp,MISRA-C++-2023,RULE-6-4-1,Yes,Required,Decidable,Single Translation Unit,A variable declared in an inner scope shall not hide a variable declared in an outer scope,A2-10-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-6-4-2,Yes,Required,Decidable,Single Translation Unit,Derived classes shall not conceal functions that are inherited from their bases,A7-3-1,ImportMisra23,Import, @@ -867,8 +867,8 @@ cpp,MISRA-C++-2023,RULE-6-7-2,Yes,Required,Decidable,Single Translation Unit,Glo cpp,MISRA-C++-2023,RULE-6-8-1,Yes,Required,Undecidable,System,An object shall not be accessed outside of its lifetime,A3-8-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-6-8-2,Yes,Mandatory,Decidable,Single Translation Unit,A function must not return a reference or a pointer to a local variable with automatic storage duration,M7-5-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-6-8-3,Yes,Required,Decidable,Single Translation Unit,An assignment operator shall not assign the address of an object with automatic storage duration to an object with a greater lifetime,,Lifetime,Medium, -cpp,MISRA-C++-2023,RULE-6-8-4,Yes,Advisory,Decidable,Single Translation Unit,Member functions returning references to their object should be refqualified appropriately,,Declarations2,Medium, -cpp,MISRA-C++-2023,RULE-6-9-1,Yes,Required,Decidable,Single Translation Unit,The same type aliases shall be used in all declarations of the same entity,,Declarations2,Medium, +cpp,MISRA-C++-2023,RULE-6-8-4,Yes,Advisory,Decidable,Single Translation Unit,Member functions returning references to their object should be refqualified appropriately,,Declarations3,Medium, +cpp,MISRA-C++-2023,RULE-6-9-1,Yes,Required,Decidable,Single Translation Unit,The same type aliases shall be used in all declarations of the same entity,,Declarations3,Medium, cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,A3-9-1,BannedAPIs,Easy, cpp,MISRA-C++-2023,RULE-7-0-1,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion from type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-2,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion to type bool,,Conversions,Easy, @@ -915,16 +915,16 @@ cpp,MISRA-C++-2023,RULE-9-6-3,Yes,Required,Decidable,Single Translation Unit,The cpp,MISRA-C++-2023,RULE-9-6-4,Yes,Required,Undecidable,System,A function declared with the [[noreturn]] attribute shall not return,MSC53-CPP,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-9-6-5,Yes,Required,Decidable,Single Translation Unit,A function with non-void return type shall return a value on all paths,MSC52-CPP,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-10-0-1,Yes,Advisory,Decidable,Single Translation Unit,A declaration should not declare more than one variable or member variable,M8-0-1,ImportMisra23,Import, -cpp,MISRA-C++-2023,RULE-10-1-1,Yes,Advisory,Decidable,Single Translation Unit,The target type of a pointer or lvalue reference parameter should be const-qualified appropriately,RULE-8-13,Declarations2,Hard, -cpp,MISRA-C++-2023,RULE-10-1-2,Yes,Required,Decidable,Single Translation Unit,The volatile qualifier shall be used appropriately,,Declarations2,Easy, +cpp,MISRA-C++-2023,RULE-10-1-1,Yes,Advisory,Decidable,Single Translation Unit,The target type of a pointer or lvalue reference parameter should be const-qualified appropriately,RULE-8-13,Declarations3,Hard, +cpp,MISRA-C++-2023,RULE-10-1-2,Yes,Required,Decidable,Single Translation Unit,The volatile qualifier shall be used appropriately,,Declarations3,Easy, cpp,MISRA-C++-2023,RULE-10-2-1,Yes,Required,Decidable,Single Translation Unit,An enumeration shall be defined with an explicit underlying type,A7-2-2,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-10-2-2,Yes,Advisory,Decidable,Single Translation Unit,Unscoped enumerations should not be declared,A7-2-3,Banned,Easy, cpp,MISRA-C++-2023,RULE-10-2-3,Yes,Required,Decidable,Single Translation Unit,The numeric value of an unscoped enumeration with no fixed underlying type shall not be used,A4-5-1,Banned,Easy, cpp,MISRA-C++-2023,RULE-10-3-1,Yes,Advisory,Decidable,Single Translation Unit,There should be no unnamed namespaces in header files,"DCL59-CPP, M7-3-3",Banned,Easy, cpp,MISRA-C++-2023,RULE-10-4-1,Yes,Required,Decidable,Single Translation Unit,The asm declaration shall not be used,A7-4-1,ImportMisra23,Import, -cpp,MISRA-C++-2023,RULE-11-3-1,Yes,Advisory,Decidable,Single Translation Unit,Variables of array type should not be declared,,Declarations2,Easy, +cpp,MISRA-C++-2023,RULE-11-3-1,Yes,Advisory,Decidable,Single Translation Unit,Variables of array type should not be declared,,Declarations3,Easy, cpp,MISRA-C++-2023,RULE-11-3-2,Yes,Advisory,Decidable,Single Translation Unit,The declaration of an object should contain no more than two levels of pointer indirection,A5-0-3,ImportMisra23,Import, -cpp,MISRA-C++-2023,RULE-11-6-1,Yes,Advisory,Decidable,Single Translation Unit,All variables should be initialized,,Declarations2,Easy, +cpp,MISRA-C++-2023,RULE-11-6-1,Yes,Advisory,Decidable,Single Translation Unit,All variables should be initialized,,Declarations3,Easy, cpp,MISRA-C++-2023,RULE-11-6-2,Yes,Mandatory,Undecidable,System,The value of an object must not be read before it has been set,A8-5-0,Lifetime,Import cpp,MISRA-C++-2023,RULE-11-6-3,Yes,Required,Decidable,Single Translation Unit,"Within an enumerator list, the value of an implicitly-specified enumeration constant shall be unique",RULE-8-12,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-12-2-1,Yes,Advisory,Decidable,Single Translation Unit,Bit-fields should not be declared,A9-6-2,Banned,Easy,