From e30b3c34dcd9defdba2adc5dea814be68e2c585e Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 11 Mar 2025 22:12:53 -0700 Subject: [PATCH 1/5] Implement final MISRA 2023 rule amendments --- amendments.csv | 9 +- ...dLocalObjectAddressCopiedToGlobalObject.ql | 39 ++++ .../ExceptionHandlingFeaturesOfFenvhUsed.ql | 26 ++- c/misra/test/rules/DIR-4-9/test.c | 1 + .../EmergentLanguageFeaturesUsed.expected | 1 - ...ObjectAddressCopiedToGlobalObject.expected | 4 + ...calObjectAddressCopiedToGlobalObject.qlref | 1 + c/misra/test/rules/RULE-18-6/test.c | 169 ++++++++++++++++++ ...eptionHandlingFeaturesOfFenvhUsed.expected | 28 +-- c/misra/test/rules/RULE-21-12/test.c | 9 +- .../2025-03-11-various-misra-amendments.md | 8 + .../src/codingstandards/cpp/Emergent.qll | 4 - .../cpp/IrreplaceableFunctionLikeMacro.qll | 6 + .../cpp/exclusions/c/Pointers1.qll | 17 ++ ...ddressOfAutoStorageObjectToOtherObject.qll | 2 +- rule_packages/c/Pointers1.json | 12 ++ 16 files changed, 303 insertions(+), 33 deletions(-) create mode 100644 c/misra/src/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql create mode 100644 c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.expected create mode 100644 c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.qlref create mode 100644 c/misra/test/rules/RULE-18-6/test.c create mode 100644 change_notes/2025-03-11-various-misra-amendments.md diff --git a/amendments.csv b/amendments.csv index 6049525515..b496790f07 100644 --- a/amendments.csv +++ b/amendments.csv @@ -1,8 +1,8 @@ language,standard,amendment,rule_id,supportable,implementation_category,implemented,difficulty c,MISRA-C-2012,Amendment3,DIR-4-6,Yes,Expand,Yes,Easy -c,MISRA-C-2012,Amendment3,DIR-4-9,Yes,Refine,No,Easy +c,MISRA-C-2012,Amendment3,DIR-4-9,Yes,Refine,Yes,Easy c,MISRA-C-2012,Amendment3,DIR-4-11,Yes,Refine,No,Import -c,MISRA-C-2012,Amendment3,RULE-1-4,Yes,Replace,No,Easy +c,MISRA-C-2012,Amendment3,RULE-1-4,Yes,Replace,Yes,Easy c,MISRA-C-2012,Amendment3,RULE-10-1,Yes,Replace,Yes,Easy c,MISRA-C-2012,Amendment3,RULE-10-3,Yes,Refine,Yes,Easy c,MISRA-C-2012,Amendment3,RULE-10-4,Yes,Refine,Yes,Import @@ -10,11 +10,11 @@ c,MISRA-C-2012,Amendment3,RULE-10-5,Yes,Expand,Yes,Easy c,MISRA-C-2012,Amendment3,RULE-10-7,Yes,Refine,Yes,Import c,MISRA-C-2012,Amendment3,RULE-10-8,Yes,Refine,Yes,Import c,MISRA-C-2012,Amendment3,RULE-21-11,Yes,Clarification,Yes,Import -c,MISRA-C-2012,Amendment3,RULE-21-12,Yes,Replace,No,Easy +c,MISRA-C-2012,Amendment3,RULE-21-12,Yes,Replace,Yes,Easy c,MISRA-C-2012,Amendment4,RULE-11-3,Yes,Expand,No,Easy c,MISRA-C-2012,Amendment4,RULE-11-8,Yes,Expand,No,Easy c,MISRA-C-2012,Amendment4,RULE-13-2,Yes,Expand,No,Very Hard -c,MISRA-C-2012,Amendment4,RULE-18-6,Yes,Expand,No,Medium +c,MISRA-C-2012,Amendment4,RULE-18-6,Yes,Expand,Yes,Medium c,MISRA-C-2012,Amendment4,RULE-18-8,Yes,Split,Yes,Easy c,MISRA-C-2012,Amendment4,RULE-2-2,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-2-7,Yes,Clarification,Yes,Import @@ -26,7 +26,6 @@ c,MISRA-C-2012,Amendment4,RULE-10-1,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-18-3,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-1-4,Yes,Replace,No,Easy c,MISRA-C-2012,Amendment4,RULE-9-1,Yes,Refine,No,Easy -c,MISRA-C-2012,Amendment4,RULE-9-2,Yes,Refine,No,Import c,MISRA-C-2012,Corrigendum2,DIR-4-10,Yes,Clarification,Yes,Import c,MISRA-C-2012,Corrigendum2,RULE-7-4,Yes,Refine,No,Easy c,MISRA-C-2012,Corrigendum2,RULE-8-2,Yes,Clarification,Yes,Import diff --git a/c/misra/src/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql b/c/misra/src/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql new file mode 100644 index 0000000000..6a520447d1 --- /dev/null +++ b/c/misra/src/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql @@ -0,0 +1,39 @@ +/** + * @id c/misra/thread-local-object-address-copied-to-global-object + * @name RULE-18-6: The address of an object with thread-local storage shall not be copied to a global object + * @description Storing the address of a thread-local object in a global object will result in + * undefined behavior if the address is accessed after the relevant thread is + * terminated. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-6 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codingstandards.cpp.Concurrency + +from AssignExpr assignment, Element threadLocal, ObjectIdentity static +where + not isExcluded(assignment, Pointers1Package::threadLocalObjectAddressCopiedToGlobalObjectQuery()) and + assignment.getLValue() = static.getASubobjectAccess() and + static.getStorageDuration().isStatic() and + ( + exists(ObjectIdentity threadLocalObj | + threadLocal = threadLocalObj and + assignment.getRValue() = threadLocalObj.getASubobjectAddressExpr() and + threadLocalObj.getStorageDuration().isThread() + ) + or + exists(TSSGetFunctionCall getCall | + threadLocal = getCall.getKey() and + assignment.getRValue() = getCall + ) + ) +select assignment, "Thread local object $@ address copied to static object $@.", + threadLocal.getLocation(), threadLocal.toString(), static.getLocation(), static.toString() diff --git a/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql b/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql index 33da2f5d03..c70e71ea1a 100644 --- a/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql +++ b/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql @@ -18,7 +18,8 @@ import codingstandards.c.misra class FPExceptionHandlingFunction extends Function { FPExceptionHandlingFunction() { this.hasName([ - "feclearexcept", "fegetexceptflag", "feraiseexcept", "fesetexceptflag", "fetestexcept" + "feclearexcept", "fegetexceptflag", "feraiseexcept", "fesetexceptflag", "fetestexcept", + "fesetenv", "feupdateenv", "fesetround" ]) and this.getFile().getBaseName() = "fenv.h" } @@ -33,22 +34,29 @@ class FPExceptionHandlingMacro extends Macro { } } -from Locatable call, string name, string kind +from Locatable element, string name, string message where - not isExcluded(call, BannedPackage::exceptionHandlingFeaturesOfFenvhUsedQuery()) and + not isExcluded(element, BannedPackage::exceptionHandlingFeaturesOfFenvhUsedQuery()) and ( + exists(Include include | + include.getIncludedFile().getBaseName() = "fenv.h" and + message = "Include of banned header" and + name = "fenv.h" and + element = include + ) + or exists(FPExceptionHandlingFunction f | - call = f.getACallToThisFunction() and + element = f.getACallToThisFunction() and name = f.getName() and - kind = "function" + message = "Call to banned function" ) or exists(FPExceptionHandlingMacro m | - call = m.getAnInvocation() and + element = m.getAnInvocation() and name = m.getName() and - kind = "macro" and + message = "Expansion of banned macro" and // Exclude macro invocations expanded from other macro invocations from macros in fenv.h. - not call.(MacroInvocation).getParentInvocation().getMacro().getFile().getBaseName() = "fenv.h" + not element.(MacroInvocation).getParentInvocation().getMacro().getFile().getBaseName() = "fenv.h" ) ) -select call, "Call to banned " + kind + " " + name + "." +select element, message + " '" + name + "'." diff --git a/c/misra/test/rules/DIR-4-9/test.c b/c/misra/test/rules/DIR-4-9/test.c index 50e6bdb042..c91e1a15a2 100644 --- a/c/misra/test/rules/DIR-4-9/test.c +++ b/c/misra/test/rules/DIR-4-9/test.c @@ -10,6 +10,7 @@ #define MACRO8(x) "NOP" // COMPLIANT #define MACRO9() printf_custom("output = %d", 7) // NON_COMPLIANT #define MACRO10(x) // COMPLIANT +#define MACRO11(x) _Generic((x), int: 1, default: 0) // COMPLIANT #define MY_ASSERT(X) assert(X) // NON_COMPLIANT[FALSE_NEGATIVE] const char a1[MACRO2(1, 1) + 6]; diff --git a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected index 04c0e1bbd6..b0bbc467aa 100644 --- a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected +++ b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected @@ -1,6 +1,5 @@ | test.c:2:1:2:22 | #include | Usage of emergent language feature. | | test.c:4:1:4:20 | #include | Usage of emergent language feature. | -| test.c:6:1:6:49 | #define MACRO(x) _Generic((x), int : 0, long : 1) | Usage of emergent language feature. | | test.c:7:1:7:32 | #define __STDC_WANT_LIB_EXT1__ 1 | Usage of emergent language feature. | | test.c:12:26:12:40 | atomic_new_type | Usage of emergent language feature. | | test.c:17:15:17:15 | i | Usage of emergent language feature. | diff --git a/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.expected b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.expected new file mode 100644 index 0000000000..99c5a91645 --- /dev/null +++ b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.expected @@ -0,0 +1,4 @@ +| test.c:29:3:29:10 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:8:19:8:20 | test.c:8:19:8:20 | t1 | test.c:12:6:12:7 | test.c:12:6:12:7 | g2 | +| test.c:55:3:55:14 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:10:17:10:18 | test.c:10:17:10:18 | t3 | test.c:13:3:13:4 | test.c:13:3:13:4 | g3 | +| test.c:152:3:152:21 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:152:16:152:20 | test.c:152:16:152:20 | & ... | test.c:12:6:12:7 | test.c:12:6:12:7 | g2 | +| test.c:155:3:155:23 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:155:18:155:22 | test.c:155:18:155:22 | & ... | test.c:13:3:13:4 | test.c:13:3:13:4 | g3 | diff --git a/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.qlref b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.qlref new file mode 100644 index 0000000000..90cdd7a43f --- /dev/null +++ b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.qlref @@ -0,0 +1 @@ +rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-6/test.c b/c/misra/test/rules/RULE-18-6/test.c new file mode 100644 index 0000000000..13b1070397 --- /dev/null +++ b/c/misra/test/rules/RULE-18-6/test.c @@ -0,0 +1,169 @@ +#include + +typedef struct { + int *p; + int m +} s; + +_Thread_local int t1; +_Thread_local int *t2; +_Thread_local s t3; +int g1; +int *g2; +s g3; + +void f1() { + // Regular object accesses + t1 = t1; // COMPLIANT + t1 = *t2; // COMPLIANT + t1 = g1; // COMPLIANT + t1 = *g2; // COMPLIANT + g1 = t1; // COMPLIANT + g1 = *t2; // COMPLIANT + g1 = g1; // COMPLIANT + g1 = *g2; // COMPLIANT + t2 = &t1; // COMPLIANT + t2 = t2; // COMPLIANT + t2 = &g1; // COMPLIANT + t2 = g2; // COMPLIANT + g2 = &t1; // NON-COMPLIANT + g2 = t2; // COMPLIANT + g2 = &g1; // COMPLIANT + g2 = g2; // COMPLIANT + *t2 = t1; // COMPLIANT + *t2 = *t2; // COMPLIANT + *t2 = g1; // COMPLIANT + *t2 = *g2; // COMPLIANT + *g2 = t1; // COMPLIANT + *g2 = *t2; // COMPLIANT + *g2 = g1; // COMPLIANT + *g2 = *g2; // COMPLIANT + + // Subobject accesses + t3.m = t3.m; // COMPLIANT + t3.m = *t3.p; // COMPLIANT + t3.m = g3.m; // COMPLIANT + t3.m = *g3.p; // COMPLIANT + g3.m = t3.m; // COMPLIANT + g3.m = *t3.p; // COMPLIANT + g3.m = g3.m; // COMPLIANT + g3.m = *g3.p; // COMPLIANT + t3.p = &t3.m; // COMPLIANT + t3.p = t3.p; // COMPLIANT + t3.p = &g3.m; // COMPLIANT + t3.p = g3.p; // COMPLIANT + g3.p = &t3.m; // NON-COMPLIANT + g3.p = t3.p; // COMPLIANT + g3.p = &g3.m; // COMPLIANT + g3.p = g3.p; // COMPLIANT + *t3.p = t3.m; // COMPLIANT + *t3.p = *t3.p; // COMPLIANT + *t3.p = g3.m; // COMPLIANT + *t3.p = *g3.p; // COMPLIANT + *g3.p = t3.m; // COMPLIANT + *g3.p = *t3.p; // COMPLIANT + *g3.p = g3.m; // COMPLIANT + *g3.p = *g3.p; // COMPLIANT + + // Storing values in locals (automatic storage duration) + int l1; + int *l2; + s l3; + + l1 = l1; // COMPLIANT + l1 = *l2; // COMPLIANT + l1 = l3.m; // COMPLIANT + l1 = *l3.p; // COMPLIANT + l1 = t1; // COMPLIANT + l1 = *t2; // COMPLIANT + l1 = t3.m; // COMPLIANT + l1 = *t3.p; // COMPLIANT + l1 = g1; // COMPLIANT + l1 = *g2; // COMPLIANT + l1 = g3.m; // COMPLIANT + l1 = *g3.p; // COMPLIANT + l2 = &l1; // COMPLIANT + l2 = l2; // COMPLIANT + l2 = &l3.m; // COMPLIANT + l2 = l3.p; // COMPLIANT + l2 = &t1; // COMPLIANT + l2 = t2; // COMPLIANT + l2 = &t3.m; // COMPLIANT + l2 = t3.p; // COMPLIANT + l2 = &g1; // COMPLIANT + l2 = g2; // COMPLIANT + l2 = &g3.m; // COMPLIANT + l2 = g3.p; // COMPLIANT + *l2 = l1; // COMPLIANT + *l2 = *l2; // COMPLIANT + *l2 = l3.m; // COMPLIANT + *l2 = *l3.p; // COMPLIANT + *l2 = t1; // COMPLIANT + *l2 = *t2; // COMPLIANT + *l2 = t3.m; // COMPLIANT + *l2 = *t3.p; // COMPLIANT + *l2 = g1; // COMPLIANT + *l2 = *g2; // COMPLIANT + *l2 = g3.m; // COMPLIANT + *l2 = *g3.p; // COMPLIANT + l3.m = l1; // COMPLIANT + l3.m = *l2; // COMPLIANT + l3.m = l3.m; // COMPLIANT + l3.m = *l3.p; // COMPLIANT + l3.m = t1; // COMPLIANT + l3.m = *t2; // COMPLIANT + l3.m = t3.m; // COMPLIANT + l3.m = *t3.p; // COMPLIANT + l3.m = g1; // COMPLIANT + l3.m = *g2; // COMPLIANT + l3.m = g3.m; // COMPLIANT + l3.m = *g3.p; // COMPLIANT + l3.p = &l1; // COMPLIANT + l3.p = l2; // COMPLIANT + l3.p = &l3.m; // COMPLIANT + l3.p = l3.p; // COMPLIANT + l3.p = &t1; // COMPLIANT + l3.p = t2; // COMPLIANT + l3.p = &t3.m; // COMPLIANT + l3.p = t3.p; // COMPLIANT + l3.p = &g1; // COMPLIANT + l3.p = g2; // COMPLIANT + l3.p = &g3.m; // COMPLIANT + l3.p = g3.p; // COMPLIANT + *l3.p = l1; // COMPLIANT + *l3.p = *l2; // COMPLIANT + *l3.p = l3.m; // COMPLIANT + *l3.p = *l3.p; // COMPLIANT + *l3.p = t1; // COMPLIANT + *l3.p = *t2; // COMPLIANT + *l3.p = t3.m; // COMPLIANT + *l3.p = *t3.p; // COMPLIANT + *l3.p = g1; // COMPLIANT + *l3.p = *g2; // COMPLIANT + *l3.p = g3.m; // COMPLIANT + *l3.p = *g3.p; // COMPLIANT + + // Storing local values in globals is covered by the shared query. +} + +tss_t tss1; +void f2() { + g1 = *(int *)tss_get(&tss1); // COMPLIANT + g2 = tss_get(&tss1); // NON-COMPLIANT + *g2 = *(int *)tss_get(&tss1); // COMPLIANT + g3.m = *(int *)tss_get(&tss1); // COMPLIANT + g3.p = tss_get(&tss1); // NON-COMPLIANT + *g3.p = *(int *)tss_get(&tss1); // COMPLIANT + g1 = ((s *)tss_get(&tss1))->m; // COMPLIANT + g1 = *((s *)tss_get(&tss1))->p; // COMPLIANT + g2 = &((s *)tss_get(&tss1))->m; // NON-COMPLIANT[false negative] + g2 = *((s *)tss_get(&tss1))->p; // COMPLIANT + *g2 = ((s *)tss_get(&tss1))->m; // COMPLIANT + *g2 = *((s *)tss_get(&tss1))->p; // COMPLIANT + g3.m = ((s *)tss_get(&tss1))->m; // COMPLIANT + g3.m = *((s *)tss_get(&tss1))->p; // COMPLIANT + g3.p = &((s *)tss_get(&tss1))->m; // NON-COMPLIANT[false negative] + g3.p = *((s *)tss_get(&tss1))->p; // COMPLIANT + *g3.p = ((s *)tss_get(&tss1))->m; // COMPLIANT + *g3.p = *((s *)tss_get(&tss1))->p; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected b/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected index 747b25a2c1..8032bf38cc 100644 --- a/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected +++ b/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected @@ -1,12 +1,16 @@ -| test.c:4:11:4:23 | call to feclearexcept | Call to banned function feclearexcept. | -| test.c:4:25:4:34 | FE_INVALID | Call to banned macro FE_INVALID. | -| test.c:6:3:6:17 | call to fegetexceptflag | Call to banned function fegetexceptflag. | -| test.c:6:24:6:36 | FE_ALL_EXCEPT | Call to banned macro FE_ALL_EXCEPT. | -| test.c:7:3:7:15 | call to feraiseexcept | Call to banned function feraiseexcept. | -| test.c:7:17:7:28 | FE_DIVBYZERO | Call to banned macro FE_DIVBYZERO. | -| test.c:8:3:8:15 | call to feraiseexcept | Call to banned function feraiseexcept. | -| test.c:8:17:8:27 | FE_OVERFLOW | Call to banned macro FE_OVERFLOW. | -| test.c:9:3:9:17 | call to fesetexceptflag | Call to banned function fesetexceptflag. | -| test.c:9:24:9:36 | FE_ALL_EXCEPT | Call to banned macro FE_ALL_EXCEPT. | -| test.c:10:3:10:14 | call to fetestexcept | Call to banned function fetestexcept. | -| test.c:10:16:10:27 | FE_UNDERFLOW | Call to banned macro FE_UNDERFLOW. | +| test.c:2:1:2:17 | #include | Include of banned header 'fenv.h'. | +| test.c:6:11:6:23 | call to feclearexcept | Call to banned function 'feclearexcept'. | +| test.c:6:25:6:34 | FE_INVALID | Expansion of banned macro 'FE_INVALID'. | +| test.c:8:3:8:17 | call to fegetexceptflag | Call to banned function 'fegetexceptflag'. | +| test.c:8:24:8:36 | FE_ALL_EXCEPT | Expansion of banned macro 'FE_ALL_EXCEPT'. | +| test.c:9:3:9:15 | call to feraiseexcept | Call to banned function 'feraiseexcept'. | +| test.c:9:17:9:28 | FE_DIVBYZERO | Expansion of banned macro 'FE_DIVBYZERO'. | +| test.c:10:3:10:15 | call to feraiseexcept | Call to banned function 'feraiseexcept'. | +| test.c:10:17:10:27 | FE_OVERFLOW | Expansion of banned macro 'FE_OVERFLOW'. | +| test.c:11:3:11:17 | call to fesetexceptflag | Call to banned function 'fesetexceptflag'. | +| test.c:11:24:11:36 | FE_ALL_EXCEPT | Expansion of banned macro 'FE_ALL_EXCEPT'. | +| test.c:12:3:12:14 | call to fetestexcept | Call to banned function 'fetestexcept'. | +| test.c:12:16:12:27 | FE_UNDERFLOW | Expansion of banned macro 'FE_UNDERFLOW'. | +| test.c:15:3:15:10 | call to fesetenv | Call to banned function 'fesetenv'. | +| test.c:16:3:16:13 | call to feupdateenv | Call to banned function 'feupdateenv'. | +| test.c:17:3:17:12 | call to fesetround | Call to banned function 'fesetround'. | diff --git a/c/misra/test/rules/RULE-21-12/test.c b/c/misra/test/rules/RULE-21-12/test.c index ae4d90a402..9a049c9ed8 100644 --- a/c/misra/test/rules/RULE-21-12/test.c +++ b/c/misra/test/rules/RULE-21-12/test.c @@ -1,4 +1,6 @@ +// NON_COMPLIANT: Cannot #include fenv.h. #include + void f2(); void f1() { int i = feclearexcept(FE_INVALID); // NON_COMPLIANT @@ -8,5 +10,10 @@ void f1() { feraiseexcept(FE_OVERFLOW); // NON_COMPLIANT fesetexceptflag(&i2, FE_ALL_EXCEPT); // NON_COMPLIANT fetestexcept(FE_UNDERFLOW); // NON_COMPLIANT - f2(); // COMPLIANT + fenv_t env; + fegetenv(&env); + fesetenv(&env); // NON_COMPLIANT + feupdateenv(&env); // NON_COMPLIANT + fesetround(0); // NON_COMPLIANT + f2(); // COMPLIANT } diff --git a/change_notes/2025-03-11-various-misra-amendments.md b/change_notes/2025-03-11-various-misra-amendments.md new file mode 100644 index 0000000000..99acdcc63a --- /dev/null +++ b/change_notes/2025-03-11-various-misra-amendments.md @@ -0,0 +1,8 @@ + - `DIR-4-9` - `FunctionOverFunctionLikeMacro.ql`: + - Macros with `_Generic` now no longer reported. + - `RULE-1-4` - `EmergentLanguageFeaturesUsed.ql`: + - Ban on usage of `_Generics` removed. + - `RULE-18-6` - `ThreadLocalObjectAddressCopiedToGlobalObject.ql`: + - New query added to detect thread local objects assigned to static storage duration objects. + - `RULE-21-12` - `ExceptionHandlingFeaturesOfFenvhUsed.ql`: + - Added reports for `#include`ing "fenv.h", and for using `fesetenv`, `feupdatenv`, and `fesetround`. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Emergent.qll b/cpp/common/src/codingstandards/cpp/Emergent.qll index 506d024bc9..3b3fbbaebd 100644 --- a/cpp/common/src/codingstandards/cpp/Emergent.qll +++ b/cpp/common/src/codingstandards/cpp/Emergent.qll @@ -30,8 +30,4 @@ module C11 { getBody() = "1" } } - - class GenericMacro extends EmergentLanguageFeature, Macro { - GenericMacro() { getBody().indexOf("_Generic") = 0 } - } } diff --git a/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll b/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll index af62cacfd3..e3d6df7e50 100644 --- a/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll +++ b/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll @@ -56,3 +56,9 @@ private class FunctionLikeMacroWithOperatorArgument extends IrreplaceableFunctio ) } } + +private class GenericMacro extends IrreplaceableFunctionLikeMacro { + GenericMacro() { + getBody().matches("%_Generic%") + } +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll index e35f0f3a88..725fe46904 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll @@ -19,6 +19,7 @@ newtype Pointers1Query = TDoNotUseAdditionOrSubtractionOperatorsOnPointersQuery() or TNoMoreThanTwoLevelsOfPointerNestingInDeclarationsQuery() or TAutomaticStorageObjectAddressCopiedToOtherObjectQuery() or + TThreadLocalObjectAddressCopiedToGlobalObjectQuery() or TObjectWithNoPointerDereferenceShouldBeOpaqueQuery() or TPointerShouldPointToConstTypeWhenPossibleQuery() @@ -158,6 +159,15 @@ predicate isPointers1QueryMetadata(Query query, string queryId, string ruleId, s ruleId = "RULE-18-6" and category = "required" or + query = + // `Query` instance for the `threadLocalObjectAddressCopiedToGlobalObject` query + Pointers1Package::threadLocalObjectAddressCopiedToGlobalObjectQuery() and + queryId = + // `@id` for the `threadLocalObjectAddressCopiedToGlobalObject` query + "c/misra/thread-local-object-address-copied-to-global-object" and + ruleId = "RULE-18-6" and + category = "required" + or query = // `Query` instance for the `objectWithNoPointerDereferenceShouldBeOpaque` query Pointers1Package::objectWithNoPointerDereferenceShouldBeOpaqueQuery() and @@ -283,6 +293,13 @@ module Pointers1Package { TQueryC(TPointers1PackageQuery(TAutomaticStorageObjectAddressCopiedToOtherObjectQuery())) } + Query threadLocalObjectAddressCopiedToGlobalObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadLocalObjectAddressCopiedToGlobalObject` query + TQueryC(TPointers1PackageQuery(TThreadLocalObjectAddressCopiedToGlobalObjectQuery())) + } + Query objectWithNoPointerDereferenceShouldBeOpaqueQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll b/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll index 1b22fd5c3b..214f8e9aba 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll @@ -54,4 +54,4 @@ query predicate problems(Expr use, string message, Expr source, string srcStr) { srcStr = "parameter" ) ) -} +} \ No newline at end of file diff --git a/rule_packages/c/Pointers1.json b/rule_packages/c/Pointers1.json index 5f53d15702..1b54fc1fb6 100644 --- a/rule_packages/c/Pointers1.json +++ b/rule_packages/c/Pointers1.json @@ -305,6 +305,18 @@ "correctness", "external/misra/c/2012/third-edition-first-revision" ] + }, + { + "description": "Storing the address of a thread-local object in a global object will result in undefined behavior if the address is accessed after the relevant thread is terminated.", + "kind": "problem", + "name": "The address of an object with thread-local storage shall not be copied to a global object", + "precision": "very-high", + "severity": "error", + "short_name": "ThreadLocalObjectAddressCopiedToGlobalObject", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] } ], "title": "The address of an object with automatic storage shall not be copied to another object that persists after the first object has ceased to exist" From a1142f3b4ef9e4768f5ffa5ea13025c92dcf2bf2 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 12 Mar 2025 11:38:15 -0700 Subject: [PATCH 2/5] reformat (and reformat generic with clang-format 11) --- .../rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql | 3 ++- c/misra/test/rules/DIR-4-9/test.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql b/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql index c70e71ea1a..b8d17de8aa 100644 --- a/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql +++ b/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql @@ -56,7 +56,8 @@ where name = m.getName() and message = "Expansion of banned macro" and // Exclude macro invocations expanded from other macro invocations from macros in fenv.h. - not element.(MacroInvocation).getParentInvocation().getMacro().getFile().getBaseName() = "fenv.h" + not element.(MacroInvocation).getParentInvocation().getMacro().getFile().getBaseName() = + "fenv.h" ) ) select element, message + " '" + name + "'." diff --git a/c/misra/test/rules/DIR-4-9/test.c b/c/misra/test/rules/DIR-4-9/test.c index c91e1a15a2..304c4bd004 100644 --- a/c/misra/test/rules/DIR-4-9/test.c +++ b/c/misra/test/rules/DIR-4-9/test.c @@ -10,7 +10,7 @@ #define MACRO8(x) "NOP" // COMPLIANT #define MACRO9() printf_custom("output = %d", 7) // NON_COMPLIANT #define MACRO10(x) // COMPLIANT -#define MACRO11(x) _Generic((x), int: 1, default: 0) // COMPLIANT +#define MACRO11(x) _Generic((x), int : 1, default : 0) // COMPLIANT #define MY_ASSERT(X) assert(X) // NON_COMPLIANT[FALSE_NEGATIVE] const char a1[MACRO2(1, 1) + 6]; From fd9fc0daf28ef5d8ecae6e065f25729ce2bbb2b5 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 12 Mar 2025 11:41:17 -0700 Subject: [PATCH 3/5] format IrreplaceableFunctionLikeMacro.qll --- .../codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll b/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll index e3d6df7e50..8daf129622 100644 --- a/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll +++ b/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll @@ -58,7 +58,5 @@ private class FunctionLikeMacroWithOperatorArgument extends IrreplaceableFunctio } private class GenericMacro extends IrreplaceableFunctionLikeMacro { - GenericMacro() { - getBody().matches("%_Generic%") - } -} \ No newline at end of file + GenericMacro() { getBody().matches("%_Generic%") } +} From fbbb19d74d534f680989888ac887f13b295b46f4 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 12 Mar 2025 11:44:17 -0700 Subject: [PATCH 4/5] Readd removed newline --- .../DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll b/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll index 214f8e9aba..1b22fd5c3b 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll @@ -54,4 +54,4 @@ query predicate problems(Expr use, string message, Expr source, string srcStr) { srcStr = "parameter" ) ) -} \ No newline at end of file +} From 6b9dc41a53e8840cd0c8aaa07dfe6b0cb9600d08 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 26 Mar 2025 23:40:27 -0700 Subject: [PATCH 5/5] Feedback --- change_notes/2025-03-11-various-misra-amendments.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/change_notes/2025-03-11-various-misra-amendments.md b/change_notes/2025-03-11-various-misra-amendments.md index 99acdcc63a..19783fe803 100644 --- a/change_notes/2025-03-11-various-misra-amendments.md +++ b/change_notes/2025-03-11-various-misra-amendments.md @@ -5,4 +5,5 @@ - `RULE-18-6` - `ThreadLocalObjectAddressCopiedToGlobalObject.ql`: - New query added to detect thread local objects assigned to static storage duration objects. - `RULE-21-12` - `ExceptionHandlingFeaturesOfFenvhUsed.ql`: - - Added reports for `#include`ing "fenv.h", and for using `fesetenv`, `feupdatenv`, and `fesetround`. \ No newline at end of file + - Added reports for `#include`ing "fenv.h", and for using `fesetenv`, `feupdatenv`, and `fesetround`. + - Report message altered to handle new cases. \ No newline at end of file