Skip to content

Implement C Memory1 package #224

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

Merged
merged 5 commits into from
Mar 8, 2023
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
| 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] |
| 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] |
| 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] |
| 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] |
| 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] |
| 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 |
| 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 number Diff line number Diff line change
@@ -0,0 +1,2 @@
// GENERATED FILE - DO NOT MODIFY
import codingstandards.cpp.rules.useinitializerbracestomatchaggregatetypestructure.UseInitializerBracesToMatchAggregateTypeStructure
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
struct Foo {
int m_i1;
int m_i2;
struct {
int m_s1_i1;
int m_s1_i2;
} m_s1;
};

struct Bar {
struct {
int m_s1_i1;
int m_s1_i2;
} m_s1;
int m_i1;
int m_i2;
};

struct Baz {
int m_baz_i1;
int m_baz_i2;
struct Foo f;
};

struct StructNested {
int m_nested_i1;
int *m_nested_i2;
struct Baz m_baz;
int m_array[10];
};

void test() {
int l01[4] = {1, 2, 3, 4}; // COMPLIANT
int l02[4][2] = {{1, 2}, {3, 4}, {3, 4}, {3, 4}}; // COMPLIANT
int l03[4][2] = {1, 2, 3, 4, 3, 4, 3, 4}; // NON_COMPLIANT - implied braces
int l04[4][2] = {0}; // COMPLIANT
int l06[4][2] = {{0}, {0}, {0}, {0}}; // COMPLIANT, nested zero initializer
int l08[4] = {1, 2}; // COMPLIANT, but missing explicit init
int l09[2][2] = {{1, 2}}; // COMPLIANT, but missing explicit init
int l10[2][2] = {{1, 2}, [1] = {0}}; // COMPLIANT
int l11[2][2] = {{1, 2}, [1] = 0}; // NON_COMPLIANT - implied braces
int l12[2][2] = {{1, 2}, [1][0] = 0, [1][1] = 0}; // COMPLIANT
int l13[2][2] = {{0}, [1][0] = 0}; // COMPLIANT
int l14[2][2] = {
{0}, [1][0] = 0, 0}; // NON_COMPLIANT[FALSE_NEGATIVE] - not all elements
// initialized with designated initializer
struct Foo f1 = {1, 2, 3, 4}; // NON_COMPLIANT - implied braces
struct Foo f2 = {1, 2, {3, 4}}; // COMPLIANT
struct Foo f3 = {0}; // COMPLIANT
struct Foo f4 = {0, 2}; // COMPLIANT, but missing explicit init
struct Foo f5 = {0, 2, {0}}; // COMPLIANT
struct Bar b1 = {0}; // COMPLIANT
struct Bar b2 = {{0}}; // COMPLIANT, but missing explicit init
struct StructNested n = {0}; // COMPLIANT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @id c/misra/initializer-for-aggregate-or-union-not-enclosed-in-braces
* @name RULE-9-2: The initializer for an aggregate or union shall be enclosed in braces
* @description Using braces in initializers of objects and subobjects improves code readability and
* clarifies intent.
* @kind problem
* @precision high
* @problem.severity recommendation
* @tags external/misra/id/rule-9-2
* maintainability
* readability
* external/misra/obligation/required
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.rules.useinitializerbracestomatchaggregatetypestructure.UseInitializerBracesToMatchAggregateTypeStructure

class InitializerForAggregateOrUnionNotEnclosedInBracesQuery extends UseInitializerBracesToMatchAggregateTypeStructureSharedQuery {
InitializerForAggregateOrUnionNotEnclosedInBracesQuery() {
this = Memory1Package::initializerForAggregateOrUnionNotEnclosedInBracesQuery()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* @id c/misra/partially-initialized-array-with-explicit-initializers
* @name RULE-9-3: Arrays shall not be partially initialized
* @description An array object or a subobject of an array shall be explicitly initialized if any
* other object in that array is explicitly initialized.
* @kind problem
* @precision high
* @problem.severity warning
* @tags external/misra/id/rule-9-3
* maintainability
* readability
* external/misra/obligation/required
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.enhancements.AggregateLiteralEnhancements

/**
* Holds if the aggregate literal has at least one explicit initializer, and at least one
* _missing_ explicit initializer, and not _only_ designated initializers.
*/
predicate isMissingExplicitInitializers(AggregateLiteral al) {
not al.isCompilerGenerated() and
not al.isAffectedByMacro() and
// Partially initialized, but not initialized with a leading zero (which is permitted)
isPartiallyValueInitialized(al) and
not isLeadingZeroInitialized(al)
}

// note: this query is similar to M8-5-2: MissingExplicitInitializers.ql
// but, pursuant to Rule 9.3, only covers array initializers rather than all aggregates
from AggregateLiteral al, Type aggType, Element explanationElement, string explanationDescription
where
not isExcluded(al, Memory1Package::partiallyInitializedArrayWithExplicitInitializersQuery()) and
// The aggregate literal is missing at least one explicit initializer
isMissingExplicitInitializers(al) and
// Missing array initializer
exists(int arraySize, int minIndex, int maxIndex |
// Identify the size of the array with a missing initializer
arraySize = al.getType().getUnspecifiedType().(ArrayType).getArraySize() and
// Identify the smallest index missing an initialzer
minIndex =
min(int index |
index = [0 .. arraySize - 1] and ArrayAggregateLiterals::isValueInitialized(al, index)
|
index
) and
// Identify the largest index missing an initialzer
maxIndex =
max(int index |
index = [0 .. arraySize - 1] and ArrayAggregateLiterals::isValueInitialized(al, index)
|
index
) and
// Ensure that the maxIndex is the last array entry. If it's not, something is up with this
// database, and so we shouldn't report it (because you can only initialize trailing array
// values)
maxIndex = (arraySize - 1) and
// Nothing useful to point to as the explanation element, so let's just set it to the parent
// array
explanationElement = al and
(
if minIndex = maxIndex
then
// Only one element missing
explanationDescription = "the element at index " + minIndex
else
// Multiple elements missing
explanationDescription = "the elements in the index range " + minIndex + " to " + maxIndex
)
)
select al,
"Aggregate literal for " + getAggregateTypeDescription(al, aggType) +
" is missing an explicit initializer for $@.", aggType, aggType.getName(), explanationElement,
explanationDescription
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/**
* @id c/misra/repeated-initialization-of-aggregate-object-element
* @name RULE-9-4: An element of an object shall not be initialized more than once
* @description Repeated initialization of an element in an object can lead to side-effects or may
* signal a logic error.
* @kind problem
* @precision high
* @problem.severity error
* @tags external/misra/id/rule-9-4
* correctness
* maintainability
* readability
* external/misra/obligation/required
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.enhancements.AggregateLiteralEnhancements

/**
* Gets the `n`th parent of `e`.
* If `n` is zero, the result is `e`.
*/
Expr getNthParent(Expr e, int n) {
if n = 0 then result = e else result = getNthParent(e.getParent(), n - 1)
}

/**
* Returns a string representation of the index of `e` relative
* to the nested array aggregate literal structure it is contained in.
*/
string getNestedArrayIndexString(Expr e) {
result =
concat(int depth |
depth = [0 .. getMaxDepth(getRootAggregate(e.getParent()))]
|
"[" +
any(int elementIndex |
exists(ArrayAggregateLiteral parent |
parent = getNthParent(e, pragma[only_bind_into](depth + 1)) and
parent.getElementExpr(elementIndex) = getNthParent(e, pragma[only_bind_into](depth))
)
|
elementIndex
).toString() + "]"
order by
depth desc
)
}

/**
* Returns the number of levels of nested `ArrayAggregateLiteral`s in `al`.
* If there are no nested array aggregate literals, the max depth of the `ArrayAggregateLiteral` is `0`.
*/
language[monotonicAggregates]
int getMaxDepth(ArrayAggregateLiteral al) {
if not exists(al.getElementExpr(_).(ArrayAggregateLiteral))
then result = 0
else result = 1 + max(Expr child | child = al.getElementExpr(_) | getMaxDepth(child))
}

// internal recursive predicate for `hasMultipleInitializerExprsForSameIndex`
predicate hasMultipleInitializerExprsForSameIndexInternal(
ArrayAggregateLiteral al1, ArrayAggregateLiteral al2, Expr out_al1_expr, Expr out_al2_expr
) {
exists(int shared_index, Expr al1_expr, Expr al2_expr |
// an `Expr` initializing an element of the same index in both `al1` and `al2`
shared_index = [0 .. al1.getArraySize() - 1] and
al1_expr = al1.getElementExpr(shared_index) and
al2_expr = al2.getElementExpr(shared_index) and
// but not the same `Expr`
not al1_expr = al2_expr and
(
// case A - the children are not aggregate literals
// holds if `al1` and `al2` both hold for .getElement[sharedIndex]
not al1_expr instanceof ArrayAggregateLiteral and
out_al1_expr = al1_expr and
out_al2_expr = al2_expr
or
// case B - `al1` and `al2` both have an aggregate literal child at the same index, so recurse
hasMultipleInitializerExprsForSameIndexInternal(al1_expr, al2_expr, out_al1_expr, out_al2_expr)
)
)
}

/**
* Holds if `expr1` and `expr2` both initialize the same array element of `root`.
*/
predicate hasMultipleInitializerExprsForSameIndex(ArrayAggregateLiteral root, Expr expr1, Expr expr2) {
hasMultipleInitializerExprsForSameIndexInternal(root, root, expr1, expr2)
}

/**
* Holds if `expr1` and `expr2` both initialize the same field of `root`.
*
* The dbschema keyset for `aggregate_field_init` prevents referencing multiple `Expr`
* that initialize the same Field and are part of the same `ClassAggregateLiteral`.
* This predicate is therefore unable to distinguish the individual duplicate expressions.
*/
predicate hasMultipleInitializerExprsForSameField(ClassAggregateLiteral root, Field f) {
count(root.getFieldExpr(f)) > 1
}

from
AggregateLiteral root, Expr e1, Expr e2, string elementDescription, string rootType,
string clarification
where
not isExcluded(e1, Memory1Package::repeatedInitializationOfAggregateObjectElementQuery()) and
exists(Initializer init | init.getExpr() = root) and
(
hasMultipleInitializerExprsForSameIndex(root, e1, e2) and
elementDescription = getNestedArrayIndexString(e1) and
rootType = "Array aggregate literal" and
clarification = ", which is already initialized $@."
or
exists(Field f |
// we cannot distinguish between different aggregate field init expressions.
// therefore, we only report the root aggregate rather than any child init expr.
// see `hasMultipleInitializerExprsForSameField` documentation.
hasMultipleInitializerExprsForSameField(root, f) and
e1 = root and
e2 = root and
elementDescription = f.getQualifiedName() and
rootType = "Structure aggregate literal" and
clarification = "."
)
) and
// de-duplicate the results by excluding permutations of `e1` and `e2`
e1.getLocation().toString() <= e2.getLocation().toString()
select e1, "$@ repeats initialization of element " + elementDescription + clarification, root,
rootType, e2, "here"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c/common/test/rules/useinitializerbracestomatchaggregatetypestructure/UseInitializerBracesToMatchAggregateTypeStructure.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-9-3/PartiallyInitializedArrayWithExplicitInitializers.ql
37 changes: 37 additions & 0 deletions c/misra/test/rules/RULE-9-3/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
void test() {
int l01[4] = {1, 2, 3, 4}; // COMPLIANT
int l02[4][2] = {{1, 2}, {3, 4}, {3, 4}, {3, 4}}; // COMPLIANT
int l03[4][2] = {1, 2, 3, 4, 3, 4, 3, 4}; // COMPLIANT
int l04[4][2] = {0}; // COMPLIANT
int l06[4][2] = {{0}, {0}, {0}, {0}}; // COMPLIANT
int l08[4] = {1, 2}; // NON_COMPLIANT
int l09[2][2] = {{1, 2}}; // NON_COMPLIANT
int l10[2][2] = {{1, 2}, [1] = {0}}; // COMPLIANT
int l11[2][2] = {{1, 2}, [1] = 0}; // COMPLIANT
int l12[2][2] = {{1, 2}, [1][0] = 0, [1][1] = 0}; // COMPLIANT
int l13[2][2] = {{0}, [1][0] = 0}; // NON_COMPLIANT - not all elements
// initialized with designated initializer
int l14[2][2] = {
{0}, [1][0] = 0, 0}; // NON_COMPLIANT - not all elements
// initialized with designated initializer

int l15[2] = {[1] = 0}; // COMPILANT - sparse matrix initialized with
// designated initializer
int l16[2][2] = {[0] = {0, 1}}; // NON_COMPLIANT - sub-elements not
// initialized with designated initializer

int l17[4][4] = {
[0][0] = 0, [0][1] = 0, [0][2] = 0, [0][3] = 0, [2][0] = 0,
[2][1] = 0, [2][2] = 0, [2][3] = 0}; // COMPLIANT - sparse matrix
// initialized with designated
// initializer

int l18[4][4] = {
[0][0] = 0, [0][1] = 0, [0][2] = 0, [0][3] = 0, [2][0] = 0,
[2][1] = 0, [2][2] = 0, [2][3] = 0, 2}; // NON_COMPLIANT - not all
// elements initialized with
// designated initializer

char str1[4] = "abc"; // COMPLIANT
char str2[5] = "abc"; // COMPLIANT - array initialized by string literal
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
| 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 |
| 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 |
| 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 |
| 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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-9-4/RepeatedInitializationOfAggregateObjectElement.ql
Loading