Skip to content

Commit 46f16cc

Browse files
authored
Merge pull request #224 from kraiouchkine/Memory1
Implement C Memory1 package
2 parents 0e9bcdd + ca169de commit 46f16cc

25 files changed

+640
-46
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
| test.c:35:20:35:23 | {...} | Missing braces on aggregate literal of type int[2]$@ which is assigned to index 0 in $@. | file://:0:0:0:0 | int[2] | int[2] | test.c:35:18:35:42 | {...} | array of type int[4][2] |
2+
| test.c:35:26:35:29 | {...} | Missing braces on aggregate literal of type int[2]$@ which is assigned to index 1 in $@. | file://:0:0:0:0 | int[2] | int[2] | test.c:35:18:35:42 | {...} | array of type int[4][2] |
3+
| test.c:35:32:35:35 | {...} | Missing braces on aggregate literal of type int[2]$@ which is assigned to index 2 in $@. | file://:0:0:0:0 | int[2] | int[2] | test.c:35:18:35:42 | {...} | array of type int[4][2] |
4+
| test.c:35:38:35:41 | {...} | Missing braces on aggregate literal of type int[2]$@ which is assigned to index 3 in $@. | file://:0:0:0:0 | int[2] | int[2] | test.c:35:18:35:42 | {...} | array of type int[4][2] |
5+
| test.c:41:34:41:34 | {...} | Missing braces on aggregate literal of type int[2]$@ which is assigned to index 1 in $@. | file://:0:0:0:0 | int[2] | int[2] | test.c:41:18:41:35 | {...} | array of type int[2][2] |
6+
| test.c:47:26:47:29 | {...} | Missing braces on aggregate literal of type $@ which is assigned to field $@. | test.c:4:10:4:10 | struct <unnamed> | struct <unnamed> | test.c:7:5:7:8 | m_s1 | m_s1 |
7+
| test.c:47:26:47:29 | {...} | Missing braces on aggregate literal of type $@ which is assigned to field $@. | test.c:11:10:11:10 | struct <unnamed> | struct <unnamed> | test.c:7:5:7:8 | m_s1 | m_s1 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// GENERATED FILE - DO NOT MODIFY
2+
import codingstandards.cpp.rules.useinitializerbracestomatchaggregatetypestructure.UseInitializerBracesToMatchAggregateTypeStructure
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
struct Foo {
2+
int m_i1;
3+
int m_i2;
4+
struct {
5+
int m_s1_i1;
6+
int m_s1_i2;
7+
} m_s1;
8+
};
9+
10+
struct Bar {
11+
struct {
12+
int m_s1_i1;
13+
int m_s1_i2;
14+
} m_s1;
15+
int m_i1;
16+
int m_i2;
17+
};
18+
19+
struct Baz {
20+
int m_baz_i1;
21+
int m_baz_i2;
22+
struct Foo f;
23+
};
24+
25+
struct StructNested {
26+
int m_nested_i1;
27+
int *m_nested_i2;
28+
struct Baz m_baz;
29+
int m_array[10];
30+
};
31+
32+
void test() {
33+
int l01[4] = {1, 2, 3, 4}; // COMPLIANT
34+
int l02[4][2] = {{1, 2}, {3, 4}, {3, 4}, {3, 4}}; // COMPLIANT
35+
int l03[4][2] = {1, 2, 3, 4, 3, 4, 3, 4}; // NON_COMPLIANT - implied braces
36+
int l04[4][2] = {0}; // COMPLIANT
37+
int l06[4][2] = {{0}, {0}, {0}, {0}}; // COMPLIANT, nested zero initializer
38+
int l08[4] = {1, 2}; // COMPLIANT, but missing explicit init
39+
int l09[2][2] = {{1, 2}}; // COMPLIANT, but missing explicit init
40+
int l10[2][2] = {{1, 2}, [1] = {0}}; // COMPLIANT
41+
int l11[2][2] = {{1, 2}, [1] = 0}; // NON_COMPLIANT - implied braces
42+
int l12[2][2] = {{1, 2}, [1][0] = 0, [1][1] = 0}; // COMPLIANT
43+
int l13[2][2] = {{0}, [1][0] = 0}; // COMPLIANT
44+
int l14[2][2] = {
45+
{0}, [1][0] = 0, 0}; // NON_COMPLIANT[FALSE_NEGATIVE] - not all elements
46+
// initialized with designated initializer
47+
struct Foo f1 = {1, 2, 3, 4}; // NON_COMPLIANT - implied braces
48+
struct Foo f2 = {1, 2, {3, 4}}; // COMPLIANT
49+
struct Foo f3 = {0}; // COMPLIANT
50+
struct Foo f4 = {0, 2}; // COMPLIANT, but missing explicit init
51+
struct Foo f5 = {0, 2, {0}}; // COMPLIANT
52+
struct Bar b1 = {0}; // COMPLIANT
53+
struct Bar b2 = {{0}}; // COMPLIANT, but missing explicit init
54+
struct StructNested n = {0}; // COMPLIANT
55+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @id c/misra/initializer-for-aggregate-or-union-not-enclosed-in-braces
3+
* @name RULE-9-2: The initializer for an aggregate or union shall be enclosed in braces
4+
* @description Using braces in initializers of objects and subobjects improves code readability and
5+
* clarifies intent.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity recommendation
9+
* @tags external/misra/id/rule-9-2
10+
* maintainability
11+
* readability
12+
* external/misra/obligation/required
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.misra
17+
import codingstandards.cpp.rules.useinitializerbracestomatchaggregatetypestructure.UseInitializerBracesToMatchAggregateTypeStructure
18+
19+
class InitializerForAggregateOrUnionNotEnclosedInBracesQuery extends UseInitializerBracesToMatchAggregateTypeStructureSharedQuery {
20+
InitializerForAggregateOrUnionNotEnclosedInBracesQuery() {
21+
this = Memory1Package::initializerForAggregateOrUnionNotEnclosedInBracesQuery()
22+
}
23+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* @id c/misra/partially-initialized-array-with-explicit-initializers
3+
* @name RULE-9-3: Arrays shall not be partially initialized
4+
* @description An array object or a subobject of an array shall be explicitly initialized if any
5+
* other object in that array is explicitly initialized.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity warning
9+
* @tags external/misra/id/rule-9-3
10+
* maintainability
11+
* readability
12+
* external/misra/obligation/required
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.misra
17+
import codingstandards.cpp.enhancements.AggregateLiteralEnhancements
18+
19+
/**
20+
* Holds if the aggregate literal has at least one explicit initializer, and at least one
21+
* _missing_ explicit initializer, and not _only_ designated initializers.
22+
*/
23+
predicate isMissingExplicitInitializers(AggregateLiteral al) {
24+
not al.isCompilerGenerated() and
25+
not al.isAffectedByMacro() and
26+
// Partially initialized, but not initialized with a leading zero (which is permitted)
27+
isPartiallyValueInitialized(al) and
28+
not isLeadingZeroInitialized(al)
29+
}
30+
31+
// note: this query is similar to M8-5-2: MissingExplicitInitializers.ql
32+
// but, pursuant to Rule 9.3, only covers array initializers rather than all aggregates
33+
from AggregateLiteral al, Type aggType, Element explanationElement, string explanationDescription
34+
where
35+
not isExcluded(al, Memory1Package::partiallyInitializedArrayWithExplicitInitializersQuery()) and
36+
// The aggregate literal is missing at least one explicit initializer
37+
isMissingExplicitInitializers(al) and
38+
// Missing array initializer
39+
exists(int arraySize, int minIndex, int maxIndex |
40+
// Identify the size of the array with a missing initializer
41+
arraySize = al.getType().getUnspecifiedType().(ArrayType).getArraySize() and
42+
// Identify the smallest index missing an initialzer
43+
minIndex =
44+
min(int index |
45+
index = [0 .. arraySize - 1] and ArrayAggregateLiterals::isValueInitialized(al, index)
46+
|
47+
index
48+
) and
49+
// Identify the largest index missing an initialzer
50+
maxIndex =
51+
max(int index |
52+
index = [0 .. arraySize - 1] and ArrayAggregateLiterals::isValueInitialized(al, index)
53+
|
54+
index
55+
) and
56+
// Ensure that the maxIndex is the last array entry. If it's not, something is up with this
57+
// database, and so we shouldn't report it (because you can only initialize trailing array
58+
// values)
59+
maxIndex = (arraySize - 1) and
60+
// Nothing useful to point to as the explanation element, so let's just set it to the parent
61+
// array
62+
explanationElement = al and
63+
(
64+
if minIndex = maxIndex
65+
then
66+
// Only one element missing
67+
explanationDescription = "the element at index " + minIndex
68+
else
69+
// Multiple elements missing
70+
explanationDescription = "the elements in the index range " + minIndex + " to " + maxIndex
71+
)
72+
)
73+
select al,
74+
"Aggregate literal for " + getAggregateTypeDescription(al, aggType) +
75+
" is missing an explicit initializer for $@.", aggType, aggType.getName(), explanationElement,
76+
explanationDescription
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/**
2+
* @id c/misra/repeated-initialization-of-aggregate-object-element
3+
* @name RULE-9-4: An element of an object shall not be initialized more than once
4+
* @description Repeated initialization of an element in an object can lead to side-effects or may
5+
* signal a logic error.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-9-4
10+
* correctness
11+
* maintainability
12+
* readability
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.c.misra
18+
import codingstandards.cpp.enhancements.AggregateLiteralEnhancements
19+
20+
/**
21+
* Gets the `n`th parent of `e`.
22+
* If `n` is zero, the result is `e`.
23+
*/
24+
Expr getNthParent(Expr e, int n) {
25+
if n = 0 then result = e else result = getNthParent(e.getParent(), n - 1)
26+
}
27+
28+
/**
29+
* Returns a string representation of the index of `e` relative
30+
* to the nested array aggregate literal structure it is contained in.
31+
*/
32+
string getNestedArrayIndexString(Expr e) {
33+
result =
34+
concat(int depth |
35+
depth = [0 .. getMaxDepth(getRootAggregate(e.getParent()))]
36+
|
37+
"[" +
38+
any(int elementIndex |
39+
exists(ArrayAggregateLiteral parent |
40+
parent = getNthParent(e, pragma[only_bind_into](depth + 1)) and
41+
parent.getElementExpr(elementIndex) = getNthParent(e, pragma[only_bind_into](depth))
42+
)
43+
|
44+
elementIndex
45+
).toString() + "]"
46+
order by
47+
depth desc
48+
)
49+
}
50+
51+
/**
52+
* Returns the number of levels of nested `ArrayAggregateLiteral`s in `al`.
53+
* If there are no nested array aggregate literals, the max depth of the `ArrayAggregateLiteral` is `0`.
54+
*/
55+
language[monotonicAggregates]
56+
int getMaxDepth(ArrayAggregateLiteral al) {
57+
if not exists(al.getElementExpr(_).(ArrayAggregateLiteral))
58+
then result = 0
59+
else result = 1 + max(Expr child | child = al.getElementExpr(_) | getMaxDepth(child))
60+
}
61+
62+
// internal recursive predicate for `hasMultipleInitializerExprsForSameIndex`
63+
predicate hasMultipleInitializerExprsForSameIndexInternal(
64+
ArrayAggregateLiteral al1, ArrayAggregateLiteral al2, Expr out_al1_expr, Expr out_al2_expr
65+
) {
66+
exists(int shared_index, Expr al1_expr, Expr al2_expr |
67+
// an `Expr` initializing an element of the same index in both `al1` and `al2`
68+
shared_index = [0 .. al1.getArraySize() - 1] and
69+
al1_expr = al1.getElementExpr(shared_index) and
70+
al2_expr = al2.getElementExpr(shared_index) and
71+
// but not the same `Expr`
72+
not al1_expr = al2_expr and
73+
(
74+
// case A - the children are not aggregate literals
75+
// holds if `al1` and `al2` both hold for .getElement[sharedIndex]
76+
not al1_expr instanceof ArrayAggregateLiteral and
77+
out_al1_expr = al1_expr and
78+
out_al2_expr = al2_expr
79+
or
80+
// case B - `al1` and `al2` both have an aggregate literal child at the same index, so recurse
81+
hasMultipleInitializerExprsForSameIndexInternal(al1_expr, al2_expr, out_al1_expr, out_al2_expr)
82+
)
83+
)
84+
}
85+
86+
/**
87+
* Holds if `expr1` and `expr2` both initialize the same array element of `root`.
88+
*/
89+
predicate hasMultipleInitializerExprsForSameIndex(ArrayAggregateLiteral root, Expr expr1, Expr expr2) {
90+
hasMultipleInitializerExprsForSameIndexInternal(root, root, expr1, expr2)
91+
}
92+
93+
/**
94+
* Holds if `expr1` and `expr2` both initialize the same field of `root`.
95+
*
96+
* The dbschema keyset for `aggregate_field_init` prevents referencing multiple `Expr`
97+
* that initialize the same Field and are part of the same `ClassAggregateLiteral`.
98+
* This predicate is therefore unable to distinguish the individual duplicate expressions.
99+
*/
100+
predicate hasMultipleInitializerExprsForSameField(ClassAggregateLiteral root, Field f) {
101+
count(root.getFieldExpr(f)) > 1
102+
}
103+
104+
from
105+
AggregateLiteral root, Expr e1, Expr e2, string elementDescription, string rootType,
106+
string clarification
107+
where
108+
not isExcluded(e1, Memory1Package::repeatedInitializationOfAggregateObjectElementQuery()) and
109+
exists(Initializer init | init.getExpr() = root) and
110+
(
111+
hasMultipleInitializerExprsForSameIndex(root, e1, e2) and
112+
elementDescription = getNestedArrayIndexString(e1) and
113+
rootType = "Array aggregate literal" and
114+
clarification = ", which is already initialized $@."
115+
or
116+
exists(Field f |
117+
// we cannot distinguish between different aggregate field init expressions.
118+
// therefore, we only report the root aggregate rather than any child init expr.
119+
// see `hasMultipleInitializerExprsForSameField` documentation.
120+
hasMultipleInitializerExprsForSameField(root, f) and
121+
e1 = root and
122+
e2 = root and
123+
elementDescription = f.getQualifiedName() and
124+
rootType = "Structure aggregate literal" and
125+
clarification = "."
126+
)
127+
) and
128+
// de-duplicate the results by excluding permutations of `e1` and `e2`
129+
e1.getLocation().toString() <= e2.getLocation().toString()
130+
select e1, "$@ repeats initialization of element " + elementDescription + clarification, root,
131+
rootType, e2, "here"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
c/common/test/rules/useinitializerbracestomatchaggregatetypestructure/UseInitializerBracesToMatchAggregateTypeStructure.ql
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| test.c:7:15:7:21 | {...} | Aggregate literal for type int[4]$@ is missing an explicit initializer for $@. | file://:0:0:0:0 | int[4] | int[4] | test.c:7:15:7:21 | {...} | the elements in the index range 2 to 3 |
2+
| test.c:8:18:8:26 | {...} | Aggregate literal for type int[2][2]$@ is missing an explicit initializer for $@. | file://:0:0:0:0 | int[2][2] | int[2][2] | test.c:8:18:8:26 | {...} | the element at index 1 |
3+
| test.c:12:18:12:35 | {...} | Aggregate literal for type int[2][2]$@ is missing an explicit initializer for $@. | file://:0:0:0:0 | int[2][2] | int[2][2] | test.c:12:18:12:35 | {...} | the element at index 1 |
4+
| test.c:14:18:15:25 | {...} | Aggregate literal for type int[2][2]$@ is missing an explicit initializer for $@. | file://:0:0:0:0 | int[2][2] | int[2][2] | test.c:14:18:15:25 | {...} | the element at index 1 |
5+
| test.c:20:18:20:32 | {...} | Aggregate literal for type int[2][2]$@ is missing an explicit initializer for $@. | file://:0:0:0:0 | int[2][2] | int[2][2] | test.c:20:18:20:32 | {...} | the element at index 1 |
6+
| test.c:31:43:31:43 | {...} | Aggregate literal for type int[4]$@ is missing an explicit initializer for $@. | file://:0:0:0:0 | int[4] | int[4] | test.c:31:43:31:43 | {...} | the elements in the index range 1 to 3 |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-9-3/PartiallyInitializedArrayWithExplicitInitializers.ql

c/misra/test/rules/RULE-9-3/test.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
void test() {
2+
int l01[4] = {1, 2, 3, 4}; // COMPLIANT
3+
int l02[4][2] = {{1, 2}, {3, 4}, {3, 4}, {3, 4}}; // COMPLIANT
4+
int l03[4][2] = {1, 2, 3, 4, 3, 4, 3, 4}; // COMPLIANT
5+
int l04[4][2] = {0}; // COMPLIANT
6+
int l06[4][2] = {{0}, {0}, {0}, {0}}; // COMPLIANT
7+
int l08[4] = {1, 2}; // NON_COMPLIANT
8+
int l09[2][2] = {{1, 2}}; // NON_COMPLIANT
9+
int l10[2][2] = {{1, 2}, [1] = {0}}; // COMPLIANT
10+
int l11[2][2] = {{1, 2}, [1] = 0}; // COMPLIANT
11+
int l12[2][2] = {{1, 2}, [1][0] = 0, [1][1] = 0}; // COMPLIANT
12+
int l13[2][2] = {{0}, [1][0] = 0}; // NON_COMPLIANT - not all elements
13+
// initialized with designated initializer
14+
int l14[2][2] = {
15+
{0}, [1][0] = 0, 0}; // NON_COMPLIANT - not all elements
16+
// initialized with designated initializer
17+
18+
int l15[2] = {[1] = 0}; // COMPILANT - sparse matrix initialized with
19+
// designated initializer
20+
int l16[2][2] = {[0] = {0, 1}}; // NON_COMPLIANT - sub-elements not
21+
// initialized with designated initializer
22+
23+
int l17[4][4] = {
24+
[0][0] = 0, [0][1] = 0, [0][2] = 0, [0][3] = 0, [2][0] = 0,
25+
[2][1] = 0, [2][2] = 0, [2][3] = 0}; // COMPLIANT - sparse matrix
26+
// initialized with designated
27+
// initializer
28+
29+
int l18[4][4] = {
30+
[0][0] = 0, [0][1] = 0, [0][2] = 0, [0][3] = 0, [2][0] = 0,
31+
[2][1] = 0, [2][2] = 0, [2][3] = 0, 2}; // NON_COMPLIANT - not all
32+
// elements initialized with
33+
// designated initializer
34+
35+
char str1[4] = "abc"; // COMPLIANT
36+
char str2[5] = "abc"; // COMPLIANT - array initialized by string literal
37+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| test.c:10:16:10:16 | 1 | $@ repeats initialization of element [0], which is already initialized $@. | test.c:9:14:10:26 | {...} | Array aggregate literal | test.c:10:7:10:7 | 0 | here |
2+
| test.c:12:28:12:28 | 1 | $@ repeats initialization of element [0][0], which is already initialized $@. | test.c:12:17:16:29 | {...} | Array aggregate literal | test.c:16:28:16:28 | 1 | here |
3+
| test.c:25:64:25:64 | 7 | $@ repeats initialization of element [1][1][0], which is already initialized $@. | test.c:24:20:26:35 | {...} | Array aggregate literal | test.c:26:34:26:34 | 1 | here |
4+
| test.c:36:17:37:25 | {...} | $@ repeats initialization of element s1::a. | test.c:36:17:37:25 | {...} | Structure aggregate literal | test.c:36:17:37:25 | {...} | here |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-9-4/RepeatedInitializationOfAggregateObjectElement.ql

0 commit comments

Comments
 (0)