Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions amendments.csv
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
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
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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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()
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand All @@ -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 + "'."
1 change: 1 addition & 0 deletions c/misra/test/rules/DIR-4-9/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
| test.c:2:1:2:22 | #include <stdatomic.h> | Usage of emergent language feature. |
| test.c:4:1:4:20 | #include <threads.h> | 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. |
Expand Down
Original file line number Diff line number Diff line change
@@ -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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql
169 changes: 169 additions & 0 deletions c/misra/test/rules/RULE-18-6/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#include <threads.h>

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
}
Original file line number Diff line number Diff line change
@@ -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 <fenv.h> | 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'. |
9 changes: 8 additions & 1 deletion c/misra/test/rules/RULE-21-12/test.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// NON_COMPLIANT: Cannot #include fenv.h.
#include <fenv.h>

void f2();
void f1() {
int i = feclearexcept(FE_INVALID); // NON_COMPLIANT
Expand All @@ -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
}
8 changes: 8 additions & 0 deletions change_notes/2025-03-11-various-misra-amendments.md
Original file line number Diff line number Diff line change
@@ -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`.
4 changes: 0 additions & 4 deletions cpp/common/src/codingstandards/cpp/Emergent.qll
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,4 @@ module C11 {
getBody() = "1"
}
}

class GenericMacro extends EmergentLanguageFeature, Macro {
GenericMacro() { getBody().indexOf("_Generic") = 0 }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,7 @@ private class FunctionLikeMacroWithOperatorArgument extends IrreplaceableFunctio
)
}
}

private class GenericMacro extends IrreplaceableFunctionLikeMacro {
GenericMacro() { getBody().matches("%_Generic%") }
}
Loading
Loading