diff --git a/amendments.csv b/amendments.csv index 64d2e2e858..abe31e7815 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,Yes,Easy c,MISRA-C-2012,Amendment4,RULE-11-8,Yes,Expand,Yes,Easy c,MISRA-C-2012,Amendment4,RULE-13-2,Yes,Expand,Yes,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,Yes,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,Yes,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..b8d17de8aa 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,30 @@ 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..304c4bd004 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..19783fe803 --- /dev/null +++ b/change_notes/2025-03-11-various-misra-amendments.md @@ -0,0 +1,9 @@ + - `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`. + - Report message altered to handle new cases. \ 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..8daf129622 100644 --- a/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll +++ b/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll @@ -56,3 +56,7 @@ private class FunctionLikeMacroWithOperatorArgument extends IrreplaceableFunctio ) } } + +private class GenericMacro extends IrreplaceableFunctionLikeMacro { + GenericMacro() { getBody().matches("%_Generic%") } +} 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/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"