Skip to content

Commit dd475be

Browse files
Implement InvalidMemory, Rule 18-8 amendment.
1 parent 7736c34 commit dd475be

23 files changed

+958
-51
lines changed

amendments.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ c,MISRA-C-2012,Amendment4,RULE-11-3,Yes,Expand,No,Easy
1515
c,MISRA-C-2012,Amendment4,RULE-11-8,Yes,Expand,No,Easy
1616
c,MISRA-C-2012,Amendment4,RULE-13-2,Yes,Expand,No,Very Hard
1717
c,MISRA-C-2012,Amendment4,RULE-18-6,Yes,Expand,No,Medium
18-
c,MISRA-C-2012,Amendment4,RULE-18-8,Yes,Split,No,Easy
18+
c,MISRA-C-2012,Amendment4,RULE-18-8,Yes,Split,Yes,Easy
1919
c,MISRA-C-2012,Corrigendum2,RULE-2-2,Yes,Clarification,No,Import
2020
c,MISRA-C-2012,Corrigendum2,RULE-2-7,Yes,Clarification,No,Import
2121
c,MISRA-C-2012,Corrigendum2,RULE-3-1,Yes,Refine,No,Easy

c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,7 @@
1313

1414
import cpp
1515
import codingstandards.c.cert
16-
17-
/**
18-
* A struct or union type that contains an array type
19-
*/
20-
class StructOrUnionTypeWithArrayField extends Struct {
21-
StructOrUnionTypeWithArrayField() {
22-
this.getAField().getUnspecifiedType() instanceof ArrayType
23-
or
24-
// nested struct or union containing an array type
25-
this.getAField().getUnspecifiedType().(Struct) instanceof StructOrUnionTypeWithArrayField
26-
}
27-
}
16+
import codingstandards.cpp.lifetimes.CLifetimes
2817

2918
// Note: Undefined behavior is possible regardless of whether the accessed field from the returned
3019
// struct is an array or a scalar (i.e. arithmetic and pointer types) member, according to the standard.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/**
2+
* @id c/misra/pointers-to-variably-modified-array-types-used
3+
* @name RULE-18-10: Pointers to variably-modified array types shall not be used
4+
* @description Pointers to variably-modified array types shall not be used, as these pointer types
5+
* are frequently incompatible with other fixed or variably sized arrays, resulting in
6+
* undefined behavior.
7+
* @kind problem
8+
* @precision high
9+
* @problem.severity error
10+
* @tags external/misra/id/rule-18-10
11+
* external/misra/c/2012/amendment4
12+
* correctness
13+
* security
14+
* external/misra/obligation/mandatory
15+
*/
16+
17+
import cpp
18+
import codingstandards.c.misra
19+
import codingstandards.cpp.VariablyModifiedTypes
20+
21+
/**
22+
* Check that the declaration entry, which may be a parameter or a variable
23+
* etc., seems to subsume the location of `inner`, including the declaration
24+
* type text.
25+
*
26+
* The location of the `DeclarationEntry` itself points to the _identifier_
27+
* that is declared. This range will not include the type of the declaration.
28+
*
29+
* For parameters, the `before` and `end` `Location` objects will be
30+
* constrained to the closest earlier element (parameter or function body),
31+
* these values can therefore be captured and inspected for debugging.
32+
*
33+
* For declarations which occur in statements, the `before` and `end`
34+
* `Location` objects will be both constrained to be equal, and equal to,
35+
* the `Location` of the containing `DeclStmt`.
36+
*/
37+
predicate declarationSubsumes(
38+
DeclarationEntry entry, Location inner, Location before, Location after
39+
) {
40+
inner.getFile() = entry.getLocation().getFile() and
41+
(
42+
exists(ParameterDeclarationEntry param, FunctionDeclarationEntry func, int i |
43+
param = entry and
44+
func = param.getFunctionDeclarationEntry() and
45+
func.getParameterDeclarationEntry(i) = param and
46+
before = entry.getLocation() and
47+
(
48+
after = func.getParameterDeclarationEntry(i + 1).getLocation()
49+
or
50+
not exists(ParameterDeclarationEntry afterParam |
51+
afterParam = func.getParameterDeclarationEntry(i + 1)
52+
) and
53+
after = func.getBlock().getLocation()
54+
)
55+
) and
56+
before.isBefore(inner, _) and
57+
inner.isBefore(after, _)
58+
or
59+
exists(DeclStmt s |
60+
s.getADeclaration() = entry.getDeclaration() and
61+
before = s.getLocation() and
62+
after = before and
63+
before.subsumes(inner)
64+
)
65+
)
66+
}
67+
68+
/**
69+
* A declaration involving a pointer to a variably-modified type.
70+
*/
71+
class InvalidDeclaration extends DeclarationEntry {
72+
Expr sizeExpr;
73+
CandidateVlaType vlaType;
74+
75+
// `before` and `after` are captured for debugging, see doc comment for
76+
// `declarationSubsumes`.
77+
Location before;
78+
Location after;
79+
80+
InvalidDeclaration() {
81+
sizeExpr = any(VlaDimensionStmt vla).getDimensionExpr() and
82+
declarationSubsumes(this, sizeExpr.getLocation(), before, after) and
83+
(
84+
if this instanceof ParameterDeclarationEntry
85+
then vlaType = this.getType().(VariablyModifiedTypeIfAdjusted).getInnerVlaType()
86+
else vlaType = this.getType().(VariablyModifiedTypeIfUnadjusted).getInnerVlaType()
87+
)
88+
// Capture only pointers to VLA types, not raw VLA types.
89+
and not vlaType = this.getType()
90+
}
91+
92+
Expr getSizeExpr() { result = sizeExpr }
93+
94+
CandidateVlaType getVlaType() { result = vlaType }
95+
}
96+
97+
from InvalidDeclaration v, string declstr, string adjuststr, string relationstr
98+
where
99+
not isExcluded(v, InvalidMemory3Package::pointersToVariablyModifiedArrayTypesUsedQuery()) and
100+
(
101+
if v instanceof ParameterDeclarationEntry
102+
then declstr = "Parameter "
103+
else
104+
if v instanceof VariableDeclarationEntry
105+
then declstr = "Variable "
106+
else declstr = "Declaration "
107+
) and
108+
(
109+
if
110+
v instanceof ParameterDeclarationEntry and
111+
v.getType() instanceof ParameterAdjustedVariablyModifiedType
112+
then adjuststr = "adjusted to"
113+
else adjuststr = "declared with"
114+
) and
115+
(
116+
if v.getType().(PointerType).getBaseType() instanceof CandidateVlaType
117+
then relationstr = "pointer to"
118+
else relationstr = "with inner"
119+
)
120+
select v,
121+
declstr + v.getName() + " is " + adjuststr + " variably-modified type, " + relationstr +
122+
" variable length array of non constant size $@ and element type '" +
123+
v.getVlaType().getVariableBaseType() + "'", v.getSizeExpr(), v.getSizeExpr().toString()

c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,15 @@
1515
import cpp
1616
import codingstandards.c.misra
1717

18-
/**
19-
* A variable length array (VLA)
20-
* ie an array where the size
21-
* is not an integer constant expression
22-
*/
23-
class VariableLengthArray extends VariableDeclarationEntry {
24-
VariableLengthArray() {
25-
//VLAs will not have: static/extern specifiers (compilation error)
26-
not this.hasSpecifier("static") and
27-
not this.hasSpecifier("extern") and
28-
//VLAs are not allowed to be initialized
29-
not this.getDeclaration().hasInitializer() and
30-
exists(ArrayType a |
31-
//a.hasArraySize() does not catch multidimensional VLAs like a[1][]
32-
a.toString().matches("%[]%") and
33-
this.getUnspecifiedType() = a and
34-
//variable length array is one declared in block or function prototype
35-
(
36-
this.getDeclaration().getParentScope() instanceof Function or
37-
this.getDeclaration().getParentScope() instanceof BlockStmt
38-
)
39-
)
40-
}
41-
}
42-
43-
from VariableLengthArray v
18+
from VlaDeclStmt v, Expr size, ArrayType arrayType, string typeStr
4419
where
4520
not isExcluded(v, Declarations7Package::variableLengthArrayTypesUsedQuery()) and
46-
//an exception, argv in : int main(int argc, char *argv[])
47-
not v.getDeclaration().getParentScope().(Function).hasName("main")
48-
select v, "Variable length array declared."
21+
size = v.getVlaDimensionStmt(0).getDimensionExpr() and
22+
(
23+
arrayType = v.getVariable().getType()
24+
or
25+
arrayType = v.getType().getUnspecifiedType()
26+
) and
27+
typeStr = arrayType.getBaseType().toString()
28+
select v, "Variable length array of element type '" + typeStr + "' with non-constant size $@.",
29+
size, size.toString()
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/**
2+
* @id c/misra/array-to-pointer-conversion-of-temporary-object
3+
* @name RULE-18-9: An object with temporary lifetime shall not undergo array to pointer conversion
4+
* @description Modifying or accessing elements of an array with temporary lifetime that has been
5+
* converted to a pointer will result in undefined behavior.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-18-9
10+
* external/misra/c/2012/amendment3
11+
* correctness
12+
* security
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.c.misra
18+
import codingstandards.cpp.lifetimes.CLifetimes
19+
20+
/**
21+
* Get the expression(s) whose value is "used" by this expression.
22+
*
23+
* For instance, `(x)` does not use any values, but `x + y` uses `x` and `y`.
24+
*
25+
* A pointer-to-array conversion does not need to be flagged if the result of
26+
* that conversion is not used or stored.
27+
*/
28+
Expr usedValuesOf(Expr expr) {
29+
result = expr.(BinaryOperation).getLeftOperand()
30+
or
31+
result = expr.(BinaryOperation).getRightOperand()
32+
or
33+
result = expr.(UnaryOperation).getOperand()
34+
or
35+
result = expr.(ConditionalExpr).getCondition()
36+
or
37+
result = expr.(Call).getAnArgument()
38+
}
39+
40+
/**
41+
* Get the expression(s) whose value is stored by this declaration.
42+
*
43+
* A pointer-to-array conversion does not need to be flagged if the result of
44+
* that conversion is not used or stored.
45+
*/
46+
predicate isStored(Expr e) {
47+
e = any(VariableDeclarationEntry d).getDeclaration().getInitializer().getExpr()
48+
or
49+
e = any(ClassAggregateLiteral l).getAFieldExpr(_)
50+
}
51+
52+
/**
53+
* Find expressions that defer their value directly to an inner expression
54+
* value.
55+
*
56+
* When an array is on the rhs of a comma expr, or in the then/else branch of a
57+
* ternary expr, and the result us used as a pointer, then the ArrayToPointer
58+
* conversion is marked inside comma expr/ternary expr, on the operands. These
59+
* conversions are only non-compliant if they flow into an operation or store.
60+
*
61+
* Full flow analysis with localFlowStep should not be necessary, and may cast a
62+
* wider net than needed for some queries, potentially resulting in false
63+
* positives.
64+
*/
65+
Expr temporaryObjectFlowStep(Expr e) {
66+
e = result.(CommaExpr).getRightOperand()
67+
or
68+
e = result.(ConditionalExpr).getThen()
69+
or
70+
e = result.(ConditionalExpr).getElse()
71+
}
72+
73+
from
74+
TemporaryLifetimeArrayAccess fa, TemporaryLifetimeExpr temporary,
75+
ArrayToPointerConversion conversion
76+
where
77+
not isExcluded(conversion, InvalidMemory3Package::arrayToPointerConversionOfTemporaryObjectQuery()) and
78+
fa.getTemporary() = temporary and
79+
conversion.getExpr() = fa and
80+
(
81+
temporaryObjectFlowStep*(conversion.getExpr()) = usedValuesOf(any(Expr e))
82+
or
83+
isStored(temporaryObjectFlowStep*(conversion.getExpr()))
84+
)
85+
select conversion, "Array to pointer conversion of array $@ from temporary object $@",
86+
fa.getTarget(), fa.getTarget().getName(), temporary, temporary.toString()
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* @id c/misra/modifiable-l-value-subscripted-with-temporary-lifetime
3+
* @name RULE-18-9: Usage of the subscript operator on an object with temporary lifetime shall not return a modifiable value
4+
* @description Modifying elements of an array with temporary lifetime will result in undefined
5+
* behavior.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-18-9
10+
* external/misra/c/2012/amendment3
11+
* correctness
12+
* security
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.c.misra
18+
import codingstandards.cpp.lifetimes.CLifetimes
19+
20+
class TemporaryLifetimeArrayExpr extends ArrayExpr {
21+
TemporaryLifetimeArrayAccess member;
22+
Type elementType;
23+
24+
TemporaryLifetimeArrayExpr() {
25+
member = getArrayBase() and
26+
elementType = member.getType().(ArrayType).getBaseType()
27+
or
28+
exists(TemporaryLifetimeArrayExpr inner |
29+
inner = getArrayBase() and
30+
member = inner.getMember() and
31+
elementType = inner.getElementType().(ArrayType).getBaseType()
32+
)
33+
}
34+
35+
TemporaryLifetimeArrayAccess getMember() { result = member }
36+
37+
Type getElementType() { result = elementType }
38+
}
39+
40+
predicate usedAsModifiableLvalue(Expr expr) {
41+
exists(Assignment parent | parent.getLValue() = expr)
42+
or
43+
exists(CrementOperation parent | parent.getOperand() = expr)
44+
or
45+
exists(AddressOfExpr parent | parent.getOperand() = expr)
46+
or
47+
exists(FieldAccess parent | parent.getQualifier() = expr and usedAsModifiableLvalue(parent))
48+
49+
}
50+
51+
from TemporaryLifetimeArrayExpr expr, TemporaryLifetimeArrayAccess member
52+
where
53+
not isExcluded(expr,
54+
InvalidMemory3Package::modifiableLValueSubscriptedWithTemporaryLifetimeQuery()) and
55+
member = expr.getMember() and
56+
not expr.isUnevaluated() and
57+
usedAsModifiableLvalue(expr)
58+
select expr,
59+
"Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ ",
60+
member, member.getTarget().getName(), member.getTemporary(), member.getTemporary().toString()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
| 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 |
2+
| 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 |
3+
| 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 |
4+
| 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 |
5+
| 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 |
6+
| 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 |
7+
| 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 |
8+
| 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 |
9+
| 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 |
10+
| test.c:33:18:33:20 | 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:23:33:24 | p0 | p0 |
11+
| 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 |
12+
| 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 |
13+
| 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 |
14+
| 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 |
15+
| 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 |
16+
| 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 |
17+
| test.c:84:17:84:19 | 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:22:84:23 | p0 | p0 |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql

0 commit comments

Comments
 (0)