diff --git a/.vscode/tasks.json b/.vscode/tasks.json index c5b2bbd1b..9dbf66125 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -259,6 +259,7 @@ "Language1", "Language2", "Language3", + "Lifetime", "Linkage1", "Linkage2", "Literals", diff --git a/change_notes/2026-01-26-improve-queries.md b/change_notes/2026-01-26-improve-queries.md index 856f4949e..ca45a56ab 100644 --- a/change_notes/2026-01-26-improve-queries.md +++ b/change_notes/2026-01-26-improve-queries.md @@ -1,4 +1,4 @@ - `A3-1-1` - `ViolationsOfOneDefinitionRule.ql`: - The query previously would incorrectly allow cases where something was defined with `extern` and did not use the defined external linkage library to find external linkage. This change may result in the query finding more results. Additionally a typo has been fixed in the alert message which will cause the old alerts for this query to now show up as new ones. - - `RULE-6-0-2`, `A3-1-4` - `ExternalLinkageArrayWithoutExplicitSizeMisra.ql`, `ExternalLinkageArrayWithoutExplicitSizeAutosar.ql`: +- `RULE-6-0-2`, `A3-1-4` - `ExternalLinkageArrayWithoutExplicitSizeMisra.ql`, `ExternalLinkageArrayWithoutExplicitSizeAutosar.ql`: - The queries listed now find flexible member arrays in structs, as those do not have an explicit size. \ No newline at end of file diff --git a/change_notes/2026-02-03-uninitialized-mem-improve.md b/change_notes/2026-02-03-uninitialized-mem-improve.md new file mode 100644 index 000000000..2fb2fd653 --- /dev/null +++ b/change_notes/2026-02-03-uninitialized-mem-improve.md @@ -0,0 +1,2 @@ +- `A8-5-0`, `EXP53-CPP`, `EXP33-C`, `RULE-9-1` - `MemoryNotInitializedBeforeItIsRead.ql`, `DoNotReadUninitializedMemory.ql`, `DoNotReadUninitializedMemory.ql`, `ObjectWithAutoStorageDurationReadBeforeInit.ql`: + - The queries listed now find uses of the operator 'new' where there is no value initialization provided. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll b/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll index 8d701cb26..1560050d4 100644 --- a/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll +++ b/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll @@ -7,6 +7,7 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import semmle.code.cpp.controlflow.Guards import semmle.code.cpp.controlflow.SubBasicBlocks +import codingstandards.cpp.enhancements.AggregateLiteralEnhancements abstract class ReadOfUninitializedMemorySharedQuery extends Query { } @@ -126,8 +127,18 @@ class InitializationContext extends TInitializationContext { */ class UninitializedVariable extends LocalVariable { UninitializedVariable() { - // Not initialized at declaration - not exists(getInitializer()) and + ( + // Not initialized at declaration + not exists(getInitializer()) + or + //or is a builtin type used with new operator but there is no value initialization as far as we can see + exists(Initializer i, NewExpr n | + i = getInitializer() and + n = i.getExpr() and + this.getUnspecifiedType().stripType() instanceof BuiltInType and + not i.isBraced() + ) + ) and // Not static or thread local, because they are not initialized with indeterminate values not isStatic() and not isThreadLocal() and diff --git a/cpp/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.expected b/cpp/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.expected index 2fb2b79a0..00a81400c 100644 --- a/cpp/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.expected +++ b/cpp/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.expected @@ -3,3 +3,6 @@ | test.cpp:39:7:39:8 | l3 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:38:6:38:7 | l3 | l3 | | test.cpp:86:9:86:16 | arrayPtr | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:79:8:79:15 | arrayPtr | arrayPtr | | test.cpp:93:9:93:10 | l5 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:89:7:89:8 | l5 | l5 | +| test.cpp:134:11:134:11 | i | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:133:7:133:7 | i | i | +| test.cpp:137:13:137:14 | i1 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:136:8:136:9 | i1 | i1 | +| test.cpp:141:12:141:13 | i1 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:136:8:136:9 | i1 | i1 | diff --git a/cpp/common/test/rules/readofuninitializedmemory/test.cpp b/cpp/common/test/rules/readofuninitializedmemory/test.cpp index 6ed07d795..ec5d12fb3 100644 --- a/cpp/common/test/rules/readofuninitializedmemory/test.cpp +++ b/cpp/common/test/rules/readofuninitializedmemory/test.cpp @@ -123,4 +123,75 @@ void test_non_default_init() { use(tlp); // COMPLIANT - thread local variables are zero initialized _Atomic int ai; use(ai); // COMPLIANT - atomics are special and not covered by this rule +} + +namespace { +int i; // COMPLIANT +} + +void extra_test() { + int i; + int j = i + 1; // NON_COMPLIANT + + int *i1 = new int; + int i2 = *i1; // NON_COMPLIANT + + int *i3; + + if (i3 = i1) { // NON_COMPLIANT + } +} + +void extra_conditionals(bool b) { + if (b) { + goto L; + } + int i; + i = 1; +L: + i = i + 1; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +struct S { + int m1; + int m2; +}; + +void struct_test() { + S s1; + S s2 = {1}; + + auto i1 = s1.m1; // NON_COMPLIANT[FALSE_NEGATIVE] - rule currently is not + // field sensitive + auto i2 = s2.m2; // COMPLIANT + + int a1[10] = {1, 1, 1}; + int a2[10]; + + auto a3 = a1[5]; // COMPLIANT + auto a4 = a2[5]; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +class C { +private: + int m1; + int m2; + +public: + C() : m1(1), m2(1) {} + + C(int a) : m1(a) {} + + int getm2() { return m2; } +}; + +void test_class() { + C c1; + if (c1.getm2() > 0) { // COMPLIANT + } + + C c2(5); + if (c2.getm2() > 0) { // NON_COMPLIANT[FALSE_NEGATIVE] - rule currently is not + // field sensitive + } } \ No newline at end of file diff --git a/cpp/misra/src/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.ql b/cpp/misra/src/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.ql new file mode 100644 index 000000000..77b45a5a1 --- /dev/null +++ b/cpp/misra/src/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/value-of-an-object-must-not-be-read-before-it-has-been-set + * @name RULE-11-6-2: The value of an object must not be read before it has been set + * @description Reading from uninitialized indeterminate values may produce undefined behavior. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/rule-11-6-2 + * correctness + * security + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.readofuninitializedmemory.ReadOfUninitializedMemory + +class ValueOfAnObjectMustNotBeReadBeforeItHasBeenSetQuery extends ReadOfUninitializedMemorySharedQuery { + ValueOfAnObjectMustNotBeReadBeforeItHasBeenSetQuery() { + this = LifetimePackage::valueOfAnObjectMustNotBeReadBeforeItHasBeenSetQuery() + } +} diff --git a/cpp/misra/test/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.testref b/cpp/misra/test/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.testref new file mode 100644 index 000000000..e2ec5838e --- /dev/null +++ b/cpp/misra/test/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.testref @@ -0,0 +1 @@ +cpp/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.ql \ No newline at end of file diff --git a/rule_packages/cpp/Lifetime.json b/rule_packages/cpp/Lifetime.json new file mode 100644 index 000000000..30a22a8d2 --- /dev/null +++ b/rule_packages/cpp/Lifetime.json @@ -0,0 +1,47 @@ +{ + "MISRA-C++-2023": { + "RULE-11-6-2": { + "properties": { + "enforcement": "undecidable", + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Reading from uninitialized indeterminate values may produce undefined behavior.", + "kind": "problem", + "name": "The value of an object must not be read before it has been set", + "precision": "medium", + "severity": "error", + "short_name": "ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet", + "shared_implementation_short_name": "ReadOfUninitializedMemory", + "tags": [ + "correctness", + "security", + "scope/system" + ] + } + ], + "title": "The value of an object must not be read before it has been set" + }, + "RULE-6-8-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "An assignment operator shall not assign the address of an object with automatic storage duration to an object with a greater lifetime", + "kind": "problem", + "name": "An assignment operator shall not assign the address of an object with automatic storage duration to", + "precision": "very-high", + "severity": "error", + "short_name": "AssignmentOperatorAssignTheAddressOfAnObjectWithAutomaticStorageDurationToAnObjectWithAGreaterLifetime", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "An assignment operator shall not assign the address of an object with automatic storage duration to an object with a greater lifetime" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index cca308583..1a023e85e 100644 --- a/rules.csv +++ b/rules.csv @@ -925,7 +925,7 @@ cpp,MISRA-C++-2023,RULE-10-4-1,Yes,Required,Decidable,Single Translation Unit,Th 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-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-2,Yes,Mandatory,Undecidable,System,The value of an object must not be read before it has been set,A8-5-0,Lifetime,Very Hard, +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, cpp,MISRA-C++-2023,RULE-12-2-2,Yes,Required,Decidable,Single Translation Unit,A bit-field shall have an appropriate type,RULE-6-1,ImportMisra23,Import,