Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement final MISRA C 2023 rule amendments #872

Merged
merged 6 commits into from
Mar 28, 2025
Merged
Show file tree
Hide file tree
Changes from all 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,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
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,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
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
}
9 changes: 9 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,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.
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