Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 1 addition & 1 deletion amendments.csv
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ 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-8,Yes,Split,No,Easy
c,MISRA-C-2012,Amendment4,RULE-18-8,Yes,Split,Yes,Easy
c,MISRA-C-2012,Corrigendum2,RULE-2-2,Yes,Clarification,No,Import
c,MISRA-C-2012,Corrigendum2,RULE-2-7,Yes,Clarification,No,Import
c,MISRA-C-2012,Corrigendum2,RULE-3-1,Yes,Refine,No,Easy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,7 @@

import cpp
import codingstandards.c.cert

/**
* A struct or union type that contains an array type
*/
class StructOrUnionTypeWithArrayField extends Struct {
StructOrUnionTypeWithArrayField() {
this.getAField().getUnspecifiedType() instanceof ArrayType
or
// nested struct or union containing an array type
this.getAField().getUnspecifiedType().(Struct) instanceof StructOrUnionTypeWithArrayField
}
}
import codingstandards.cpp.lifetimes.CLifetimes

// Note: Undefined behavior is possible regardless of whether the accessed field from the returned
// struct is an array or a scalar (i.e. arithmetic and pointer types) member, according to the standard.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @id c/misra/pointers-to-variably-modified-array-types-used
* @name RULE-18-10: Pointers to variably-modified array types shall not be used
* @description Pointers to variably-modified array types shall not be used, as these pointer types
* are frequently incompatible with other fixed or variably sized arrays, resulting in
* undefined behavior.
* @kind problem
* @precision high
* @problem.severity error
* @tags external/misra/id/rule-18-10
* external/misra/c/2012/amendment4
* correctness
* security
* external/misra/obligation/mandatory
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.VariablyModifiedTypes

from VmtDeclarationEntry v, string declstr, string adjuststr, string relationstr
where
not isExcluded(v, InvalidMemory3Package::pointersToVariablyModifiedArrayTypesUsedQuery()) and
// Capture only pointers to VLA types, not raw VLA types.
not v.getVlaType() = v.getType() and
(
if v instanceof ParameterDeclarationEntry
then declstr = "Parameter "
else
if v instanceof VariableDeclarationEntry
then declstr = "Variable "
else declstr = "Declaration "
) and
(
if
v instanceof ParameterDeclarationEntry and
v.getType() instanceof ParameterAdjustedVariablyModifiedType
then adjuststr = "adjusted to"
else adjuststr = "declared with"
) and
(
if v.getType().(PointerType).getBaseType() instanceof CandidateVlaType
then relationstr = "pointer to"
else relationstr = "with inner"
)
select v,
declstr + v.getName() + " is " + adjuststr + " variably-modified type, " + relationstr +
" variable length array of non constant size $@ and element type '" +
v.getVlaType().getVariableBaseType() + "'", v.getSizeExpr(), v.getSizeExpr().toString()
41 changes: 12 additions & 29 deletions c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,17 @@
import cpp
import codingstandards.c.misra

/**
* A variable length array (VLA)
* ie an array where the size
* is not an integer constant expression
*/
class VariableLengthArray extends VariableDeclarationEntry {
VariableLengthArray() {
//VLAs will not have: static/extern specifiers (compilation error)
not this.hasSpecifier("static") and
not this.hasSpecifier("extern") and
//VLAs are not allowed to be initialized
not this.getDeclaration().hasInitializer() and
exists(ArrayType a |
//a.hasArraySize() does not catch multidimensional VLAs like a[1][]
a.toString().matches("%[]%") and
this.getUnspecifiedType() = a and
//variable length array is one declared in block or function prototype
(
this.getDeclaration().getParentScope() instanceof Function or
this.getDeclaration().getParentScope() instanceof BlockStmt
)
)
}
}

from VariableLengthArray v
from VlaDeclStmt v, Expr size, ArrayType arrayType, string typeStr
where
not isExcluded(v, Declarations7Package::variableLengthArrayTypesUsedQuery()) and
//an exception, argv in : int main(int argc, char *argv[])
not v.getDeclaration().getParentScope().(Function).hasName("main")
select v, "Variable length array declared."
size = v.getVlaDimensionStmt(0).getDimensionExpr() and
(
// Holds is if v is a variable declaration:
arrayType = v.getVariable().getType().stripTopLevelSpecifiers()
or
// Holds is if v is a typedef declaration:
arrayType = v.getType().stripTopLevelSpecifiers()
) and
typeStr = arrayType.getBaseType().toString()
select v, "Variable length array of element type '" + typeStr + "' with non-constant size $@.",
size, size.toString()
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* @id c/misra/array-to-pointer-conversion-of-temporary-object
* @name RULE-18-9: An object with temporary lifetime shall not undergo array to pointer conversion
* @description Modifying or accessing elements of an array with temporary lifetime that has been
* converted to a pointer will result in undefined behavior.
* @kind problem
* @precision high
* @problem.severity error
* @tags external/misra/id/rule-18-9
* external/misra/c/2012/amendment3
* correctness
* security
* external/misra/obligation/required
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.lifetimes.CLifetimes

/**
* Holds if the value of an expression is used or stored.
*
* For instance, `(x)` does not use any values, but `x + y` uses `x` and `y`.
*
* A pointer-to-array conversion does not need to be flagged if the result of
* that conversion is not used or stored.
*/
predicate isUsedOrStored(Expr e) {
e = any(Operation o).getAnOperand()
or
e = any(ConditionalExpr c).getCondition()
or
e = any(Call c).getAnArgument()
or
e = any(VariableDeclarationEntry d).getDeclaration().getInitializer().getExpr()
or
e = any(ClassAggregateLiteral l).getAFieldExpr(_)
}

/**
* Find expressions that defer their value directly to an inner expression
* value.
*
* When an array is on the rhs of a comma expr, or in the then/else branch of a
* ternary expr, and the result us used as a pointer, then the ArrayToPointer
* conversion is marked inside comma expr/ternary expr, on the operands. These
* conversions are only non-compliant if they flow into an operation or store.
*
* Full flow analysis with localFlowStep should not be necessary, and may cast a
* wider net than needed for some queries, potentially resulting in false
* positives.
*/
Expr temporaryObjectFlowStep(Expr e) {
e = result.(CommaExpr).getRightOperand()
or
e = result.(ConditionalExpr).getThen()
or
e = result.(ConditionalExpr).getElse()
}

from
TemporaryLifetimeArrayAccess fa, TemporaryLifetimeExpr temporary,
ArrayToPointerConversion conversion
where
not isExcluded(conversion, InvalidMemory3Package::arrayToPointerConversionOfTemporaryObjectQuery()) and
fa.getTemporary() = temporary and
conversion.getExpr() = fa and
isUsedOrStored(temporaryObjectFlowStep*(conversion.getExpr()))
select conversion, "Array to pointer conversion of array $@ from temporary object $@",
fa.getTarget(), fa.getTarget().getName(), temporary, temporary.toString()
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* @id c/misra/modifiable-l-value-subscripted-with-temporary-lifetime
* @name RULE-18-9: Usage of the subscript operator on an object with temporary lifetime shall not return a modifiable value
* @description Modifying elements of an array with temporary lifetime will result in undefined
* behavior.
* @kind problem
* @precision high
* @problem.severity error
* @tags external/misra/id/rule-18-9
* external/misra/c/2012/amendment3
* correctness
* security
* external/misra/obligation/required
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.lifetimes.CLifetimes

class TemporaryLifetimeArrayExpr extends ArrayExpr {
TemporaryLifetimeArrayAccess member;
Type elementType;

TemporaryLifetimeArrayExpr() {
member = getArrayBase() and
elementType = member.getType().(ArrayType).getBaseType()
or
exists(TemporaryLifetimeArrayExpr inner |
inner = getArrayBase() and
member = inner.getMember() and
elementType = inner.getElementType().(ArrayType).getBaseType()
)
}

TemporaryLifetimeArrayAccess getMember() { result = member }

Type getElementType() { result = elementType }
}

predicate usedAsModifiableLvalue(Expr expr) {
exists(Assignment parent | parent.getLValue() = expr)
or
exists(CrementOperation parent | parent.getOperand() = expr)
or
exists(AddressOfExpr parent | parent.getOperand() = expr)
or
exists(FieldAccess parent | parent.getQualifier() = expr and usedAsModifiableLvalue(parent))
}

from TemporaryLifetimeArrayExpr expr, TemporaryLifetimeArrayAccess member
where
not isExcluded(expr,
InvalidMemory3Package::modifiableLValueSubscriptedWithTemporaryLifetimeQuery()) and
member = expr.getMember() and
not expr.isUnevaluated() and
usedAsModifiableLvalue(expr)
select expr,
"Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ ",
member, member.getTarget().getName(), member.getTemporary(), member.getTemporary().toString()
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
| test.c:17:11:17:12 | definition of p5 | Parameter p5 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int' | test.c:17:15:17:16 | p0 | p0 |
| test.c:18:11:18:12 | definition of p6 | Parameter p6 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:18:18:18:19 | p0 | p0 |
| test.c:19:11:19:12 | definition of p7 | Parameter p7 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int[2]' | test.c:19:15:19:16 | p0 | p0 |
| test.c:20:11:20:12 | definition of p8 | Parameter p8 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int[]' | test.c:20:15:20:16 | p0 | p0 |
| test.c:20:11:20:12 | definition of p8 | Parameter p8 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int[]' | test.c:20:19:20:20 | p0 | p0 |
| test.c:24:12:24:13 | definition of p9 | Parameter p9 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int *' | test.c:24:16:24:17 | p0 | p0 |
| test.c:25:13:25:15 | definition of p10 | Parameter p10 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int *' | test.c:25:18:25:19 | p0 | p0 |
| test.c:28:12:28:14 | definition of p11 | Parameter p11 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:28:21:28:22 | p0 | p0 |
| test.c:32:17:32:19 | definition of p13 | Parameter p13 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'const int' | test.c:32:22:32:23 | p0 | p0 |
| test.c:33:17:33:19 | definition of p14 | Parameter p14 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:33:22:33:23 | p0 | p0 |
| test.c:40:12:40:14 | definition of p17 | Parameter p17 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:40:24:40:25 | p0 | p0 |
| test.c:41:14:41:16 | definition of p18 | Parameter p18 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:41:27:41:28 | p0 | p0 |
| test.c:68:9:68:11 | definition of p27 | Parameter p27 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:68:13:68:14 | p0 | p0 |
| test.c:68:9:68:11 | definition of p27 | Parameter p27 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:68:17:68:18 | p0 | p0 |
| test.c:74:8:74:9 | definition of l3 | Variable l3 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int' | test.c:74:12:74:13 | p0 | p0 |
| test.c:79:15:79:16 | definition of l4 | Variable l4 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int' | test.c:79:19:79:20 | p0 | p0 |
| test.c:84:16:84:18 | declaration of td3 | Declaration td3 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:84:21:84:22 | p0 | p0 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql
95 changes: 95 additions & 0 deletions c/misra/test/rules/RULE-18-10/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#define CONSTANT 1

int g1[3]; // COMPLIANT
int (*g2)[3]; // COMPLIANT
int (*g3)[CONSTANT]; // COMPLIANT

void f1(
int p0,

// Basic fixed length array types:
int p1[3], // COMPLIANT
int (*p2)[3], // COMPLIANT
int (*p3)[2][3], // COMPLIANT
int (*p4)[CONSTANT], // COMPLIANT

// Basic pointers to VMTs:
int (*p5)[p0], // NON-COMPLIANT
int (*p6)[2][p0], // NON-COMPLIANT
int (*p7)[p0][2], // NON-COMPLIANT
int (*p8)[p0][p0], // NON-COMPLIANT

// Types referring to pointers to VMTs:
// - pointer to pointer to VMT
int(*(*p9)[p0]), // NON-COMPLIANT
int(*(**p10)[p0]), // NON-COMPLIANT

// - array of pointers to VMT
int (*(p11[3]))[p0], // NON-COMPLIANT

// - const VMTs, const array-to-pointer adjustment
const int p12[p0], // COMPLIANT
const int (*p13)[p0], // NON-COMPLIANT
int (*const p14)[p0], // NON-COMPLIANT

// - function types with argument that is a pointer to a VMT
int p15(int (*inner)[p0]), // NON-COMPLIANT[FALSE_NEGATIVE]
int (*p16)(int (*inner)[p0]), // NON-COMPLIANT[FALSE_NEGATIVE]

// - function types that returns a pointer to a VMT
int (*(p17(void)))[p0], // NON-COMPLIANT
int (*((*p18)(void)))[p0], // NON-COMPLIANT

// - structs cannot contain a VMT as a member.
struct {
int g1[3]; // COMPLIANT
int(*g2)[3]; // COMPLIANT
int(*g3)[CONSTANT]; // COMPLIANT
// Pointer to VMT (`int (*g4)[p0]`) is not allowed.
} p19,

// - unions cannot contain a VMT as a member.
union {
int g1[3]; // COMPLIANT
int(*g2)[3]; // COMPLIANT
int(*g3)[CONSTANT]; // COMPLIANT
// Pointer to VMT (`int (*g4)[p0]`) is not allowed.
} p20,

// Unknown array length types:
int p21[], // COMPLIANT
int p22[][], // COMPLIANT
int (*p23)[], // COMPLIANT
int (*p24)[2][], // COMPLIANT
int (*p25)[][2], // COMPLIANT

// VLA types that are rewritten as pointers:
int p26[p0], // COMPLIANT
int p27[p0][p0] // NON-COMPLIANT
) {
// Local variables may contain pointers to VMTs:
int l0[p0]; // COMPLIANT
int(*l1)[]; // COMPLIANT
int(*l2)[3]; // COMPLIANT
int(*l3)[p0]; // NON-COMPLIANT

int l6[10] = p23;

// A pointer to a VMT may be declared `static`.
static int(*l4)[p0]; // NON-COMPLIANT

// Block scope typedefs may refer to VMTs
typedef int(*td1)[3]; // COMPLIANT
typedef int(*td2)[]; // COMPLIANT
typedef int(*td3)[p0]; // NON-COMPLIANT

td3 l5; // NON-COMPLIANT
}

// Function prototypes may contain VMTs using '*' syntax:
void f2(int (*p1)[3], // COMPLIANT
int (*p2)[*], // NON-COMPLIANT[FALSE_NEGATIVE]
int (*p3)[2][*], // NON-COMPLIANT[FALSE_NEGATIVE]
int (*p4)[*][2], // NON-COMPLIANT[FALSE_NEGATIVE]
int (*p5)[*][*] // NON-COMPLIANT[FALSE_NEGATIVE]
);
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
| test.c:3:19:3:20 | definition of pa | Variable length array declared. |
| test.c:6:7:6:8 | definition of a1 | Variable length array declared. |
| test.c:7:7:7:8 | definition of a2 | Variable length array declared. |
| test.c:8:7:8:8 | definition of a3 | Variable length array declared. |
| test.c:14:20:14:21 | definition of pa | Variable length array declared. |
| test.c:6:7:6:7 | VLA declaration | Variable length array of element type 'int' with non-constant size $@. | test.c:6:10:6:14 | ... + ... | ... + ... |
| test.c:7:7:7:7 | VLA declaration | Variable length array of element type 'int' with non-constant size $@. | test.c:7:10:7:10 | n | n |
| test.c:8:7:8:7 | VLA declaration | Variable length array of element type 'int[]' with non-constant size $@. | test.c:8:13:8:13 | n | n |
| test.c:12:7:12:7 | VLA declaration | Variable length array of element type 'int[1]' with non-constant size $@. | test.c:12:10:12:10 | n | n |
| test.c:18:15:18:15 | VLA declaration | Variable length array of element type 'int' with non-constant size $@. | test.c:18:26:18:26 | n | n |
Loading
Loading