Skip to content

Commit f590402

Browse files
Implement alignment package for MISRA-C 2012 amendment 3
1 parent 2a805c0 commit f590402

18 files changed

+454
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @id c/misra/redeclaration-of-object-with-unmatched-alignment
3+
* @name RULE-8-15: Alignment should match between all declarations of an object
4+
* @description All declarations of an object with an explicit alignment specification shall specify
5+
* the same alignment.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-8-15
10+
* extern/misra/c/2012/amendment3
11+
* readability
12+
* maintainability
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.c.misra
18+
19+
predicate lexicallyEqualExpr(Expr a, Expr b) {
20+
a.toString() = b.toString() and
21+
a.getNumChild() = b.getNumChild() and
22+
forall(Expr aChild, Expr bChild, int i |
23+
aChild = a.getChild(i) and
24+
bChild = b.getChild(i) and
25+
i < a.getNumChild()
26+
|
27+
lexicallyEqualExpr(aChild, bChild)
28+
)
29+
}
30+
31+
predicate lexicallyEqual(AttributeArgument a, AttributeArgument b) {
32+
lexicallyEqualExpr(a.getValueConstant(), b.getValueConstant()) or
33+
a.getValueType() = b.getValueType()
34+
}
35+
36+
from Attribute alignment, Attribute mismatched, string variable
37+
where
38+
not isExcluded(alignment, AlignmentPackage::redeclarationOfObjectWithUnmatchedAlignmentQuery()) and
39+
alignment.hasName("_Alignas") and
40+
mismatched.hasName("_Alignas") and
41+
exists(Variable v |
42+
v.getAnAttribute() = alignment and v.getAnAttribute() = mismatched and v.getName() = variable
43+
) and
44+
not lexicallyEqual(alignment.getArgument(0), mismatched.getArgument(0))
45+
select alignment,
46+
"Variable " + variable + " declared with lexically different _Alignof() values '$@' and '$@'",
47+
alignment, alignment.getArgument(0).toString(), mismatched, mismatched.getArgument(0).toString()
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
* @id c/misra/redeclaration-of-object-without-alignment
3+
* @name RULE-8-15: Alignment should match between all declarations of an object
4+
* @description An object declared with an explicit alignment shall be explicitly aligned in all
5+
* declarations.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-8-15
10+
* extern/misra/c/2012/amendment3
11+
* readability
12+
* maintainability
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.c.misra
18+
19+
/**
20+
* Performance optimization; start query by joining attributes to declarations
21+
* rather than locations.
22+
*
23+
* Including the entry location also speeds up search.
24+
*/
25+
newtype TAttributeDeclLocation =
26+
TAttributeDeclLocationInfo(
27+
Attribute attribute, DeclarationEntry entry, Location entryLocation
28+
) {
29+
entry.getDeclaration().(Variable).getAnAttribute() = attribute and
30+
entryLocation = entry.getLocation()
31+
}
32+
33+
/**
34+
* Get a DeclarationEntry along with its explicitly declared Attributes.
35+
*
36+
* DeclarationEntry does not have a method for getting Attributes by default,
37+
* because an attribute declared on any DeclarationEntry affects all others,
38+
* and attributes really belong to the declared variable rather than the
39+
* declaration itself.
40+
*
41+
* In order to support this rule, we find for each attribute
42+
* - A declaration entry which
43+
* - corresponds to a variable associated with this attribute
44+
* - is in the same file as this attribute
45+
* - has identifier location after the attribute declaration
46+
* - has no other declaration entry between this one and the attribute.
47+
*
48+
* This should give us a highly reliable means of finding which attributes are
49+
* associated with which `DeclarationEntry`s.
50+
*
51+
* One note of caution: the associated `Variable` must be treated with caution,
52+
* as there are multiple instances of that `Variable` if it is declared
53+
* multiple times, they equal each other, and `getLocation()` on each variable
54+
* returns every location result. This class must act on `DeclarationEntry`s to
55+
* deliver reliable results.
56+
*/
57+
class DeclarationEntryAttribute extends Attribute {
58+
DeclarationEntry declarationEntry;
59+
Location location;
60+
Location declLocation;
61+
File file;
62+
TAttributeDeclLocation locInfo;
63+
64+
DeclarationEntryAttribute() {
65+
locInfo = TAttributeDeclLocationInfo(this, declarationEntry, declLocation) and
66+
file = getFile() and
67+
location = getLocation() and
68+
declLocation = declarationEntry.getLocation() and
69+
declarationEntry.getDeclaration().(Variable).getAnAttribute() = this and
70+
declarationEntry.getFile() = file and
71+
location.isBefore(declLocation, _) and
72+
not exists(TAttributeDeclLocation blocInfo, DeclarationEntry betterFit, Location blocation |
73+
blocInfo = TAttributeDeclLocationInfo(this, betterFit, blocation) and
74+
not betterFit = declarationEntry and
75+
blocation = betterFit.getLocation() and
76+
betterFit.getFile() = file and
77+
betterFit.getDeclaration() = declarationEntry.getDeclaration() and
78+
blocation.isBefore(declLocation, _) and
79+
location.isBefore(blocation, _)
80+
)
81+
}
82+
83+
DeclarationEntry getDeclarationEntry() { result = declarationEntry }
84+
}
85+
86+
from DeclarationEntry unaligned, DeclarationEntry aligned, DeclarationEntryAttribute attribute
87+
where
88+
not isExcluded(unaligned, AlignmentPackage::redeclarationOfObjectWithoutAlignmentQuery()) and
89+
attribute.hasName("_Alignas") and
90+
attribute.getDeclarationEntry() = aligned and
91+
aligned.getDeclaration() = unaligned.getDeclaration() and
92+
not exists(DeclarationEntryAttribute matchingAlignment |
93+
matchingAlignment.hasName("_Alignas") and
94+
matchingAlignment.getDeclarationEntry() = unaligned
95+
)
96+
select unaligned,
97+
"Variable " + unaligned.getName() +
98+
" declared without explicit alignment to match $@ with alignment $@", aligned,
99+
"other definition", attribute, attribute.toString()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @id c/misra/alignment-with-size-zero
3+
* @name RULE-8-16: The alignment specification of zero should not appear in an object declaration
4+
* @description A declaration shall not have an alignment of size zero.
5+
* @kind problem
6+
* @precision very-high
7+
* @problem.severity error
8+
* @tags external/misra/id/rule-8-16
9+
* extern/misra/c/2012/amendment3
10+
* readability
11+
* maintainability
12+
* external/misra/obligation/advisory
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.misra
17+
18+
from Attribute a, Variable v
19+
where
20+
not isExcluded(a, AlignmentPackage::alignmentWithSizeZeroQuery()) and
21+
a.hasName("_Alignas") and
22+
a.getArgument(0).getValueInt() = 0 and
23+
v.getAnAttribute() = a
24+
select a.getArgument(0), "Invalid alignof() size set to zero for variable $@.", v, v.getName()
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* @id c/misra/more-than-one-alignment-specifier-on-declaration
3+
* @name RULE-8-17: At most one explicit alignment specifier should appear in an object declaration
4+
* @description While C permits the usage of multiple alignment specifiers, doing so reduces
5+
* readability and may obscure the intent of the declaration.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-8-17
10+
* extern/misra/c/2012/amendment3
11+
* readability
12+
* external/misra/obligation/advisory
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.misra
17+
18+
from Variable v, Attribute first, Attribute last
19+
where
20+
not isExcluded(v, AlignmentPackage::moreThanOneAlignmentSpecifierOnDeclarationQuery()) and
21+
first = v.getAnAttribute() and
22+
last = v.getAnAttribute() and
23+
first != last and
24+
first.hasName("_Alignas") and
25+
last.hasName("_Alignas") and
26+
not exists(Attribute beforeFirst |
27+
beforeFirst.getLocation().isBefore(first.getLocation(), _) and
28+
v.getAnAttribute() = beforeFirst
29+
) and
30+
not exists(Attribute afterLast |
31+
last.getLocation().isBefore(afterLast.getLocation(), _) and
32+
v.getAnAttribute() = afterLast
33+
)
34+
select v, "Variable " + v.getName() + " contains more than one alignment specifier, $@ and $@",
35+
first, first.toString(), last, last.toString()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| test.c:18:8:18:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@' | test.c:18:8:18:15 | alignas(...) | int | test.c:19:8:19:15 | alignas(...) | 4 |
2+
| test.c:19:8:19:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@' | test.c:19:8:19:15 | alignas(...) | 4 | test.c:18:8:18:15 | alignas(...) | int |
3+
| test.c:22:8:22:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@' | test.c:22:8:22:15 | alignas(...) | ... * ... | test.c:23:8:23:15 | alignas(...) | 32 |
4+
| test.c:23:8:23:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@' | test.c:23:8:23:15 | alignas(...) | 32 | test.c:22:8:22:15 | alignas(...) | ... * ... |
5+
| test.c:28:8:28:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@' | test.c:28:8:28:15 | alignas(...) | ... * ... | test.c:29:8:29:15 | alignas(...) | ... * ... |
6+
| test.c:29:8:29:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@' | test.c:29:8:29:15 | alignas(...) | ... * ... | test.c:28:8:28:15 | alignas(...) | ... * ... |
7+
| test.c:34:8:34:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@' | test.c:34:8:34:15 | alignas(...) | signed int | test.c:35:8:35:15 | alignas(...) | unsigned int |
8+
| test.c:35:8:35:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@' | test.c:35:8:35:15 | alignas(...) | unsigned int | test.c:34:8:34:15 | alignas(...) | signed int |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.c:5:12:5:13 | declaration of g2 | Variable g2 declared without explicit alignment to match $@ with alignment $@ | test.c:4:25:4:26 | declaration of g2 | other definition | test.c:4:8:4:15 | alignas(...) | alignas(...) |
2+
| test.c:7:12:7:13 | declaration of g3 | Variable g3 declared without explicit alignment to match $@ with alignment $@ | test.c:8:25:8:26 | declaration of g3 | other definition | test.c:8:8:8:15 | alignas(...) | alignas(...) |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql

c/misra/test/rules/RULE-8-15/test.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
extern _Alignas(16) int g1; // COMPLIANT
2+
extern _Alignas(16) int g1; // COMPLIANT
3+
4+
extern _Alignas(16) int g2;
5+
extern int g2; // NON_COMPLIANT
6+
7+
extern int g3; // NON_COMPLIANT
8+
extern _Alignas(16) int g3;
9+
10+
// Does not compile on clang:
11+
// extern _Alignas(16) int g4; // COMPLIANT
12+
// extern _Alignas(32) int g4; // COMPLIANT
13+
14+
extern int g5; // COMPLIANT
15+
extern int g5; // COMPLIANT
16+
17+
// Spec says elements must be lexically identical after macro expansion
18+
extern _Alignas(int) int g6; // NON_COMPLIANT
19+
extern _Alignas(4) int g6; // NON_COMPLIANT
20+
21+
#define THIRTY_TWO 32
22+
extern _Alignas(16 * 2) int g7; // NON_COMPLIANT
23+
extern _Alignas(32) int g7; // NON_COMPLIANT
24+
25+
extern _Alignas(THIRTY_TWO) int g8; // COMPLIANT
26+
extern _Alignas(32) int g8; // COMPLIANT
27+
28+
extern _Alignas(16 * 2) int g9; // NON_COMPLIANT
29+
extern _Alignas(2 * 16) int g9; // NON_COMPLIANT
30+
31+
extern _Alignas(int) int g10; // COMPLIANT
32+
extern _Alignas(int) int g10; // COMPLIANT
33+
34+
extern _Alignas(signed int) int g11; // NON_COMPLIANT
35+
extern _Alignas(unsigned int) int g11; // NON_COMPLIANT
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| test.c:2:10:2:10 | 0 | Invalid alignof() size set to zero for variable $@. | test.c:2:17:2:18 | g2 | g2 |
2+
| test.c:3:10:3:14 | ... - ... | Invalid alignof() size set to zero for variable $@. | test.c:3:21:3:22 | g3 | g3 |
3+
| test.c:8:12:8:12 | 0 | Invalid alignof() size set to zero for variable $@. | test.c:8:19:8:20 | m2 | m2 |
4+
| test.c:13:12:13:12 | 0 | Invalid alignof() size set to zero for variable $@. | test.c:13:19:13:20 | l2 | l2 |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-8-16/AlignmentWithSizeZero.ql

c/misra/test/rules/RULE-8-16/test.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
_Alignas(8) int g1; // COMPLIANT
2+
_Alignas(0) int g2; // NON-COMPLIANT
3+
_Alignas(8 - 8) int g3; // NON-COMPLIANT
4+
_Alignas(float) int g4; // COMPLIANT
5+
6+
struct s {
7+
_Alignas(64) int m1; // COMPLIANT
8+
_Alignas(0) int m2; // NON_COMPLIANT
9+
};
10+
11+
void f() {
12+
_Alignas(8) int l1; // COMPLIANT
13+
_Alignas(0) int l2; // NON-COMPLIANT
14+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| test.c:2:30:2:31 | g2 | Variable g2 contains more than one alignment specifier, $@ and $@ | test.c:2:1:2:8 | alignas(...) | alignas(...) | test.c:2:13:2:20 | alignas(...) | alignas(...) |
2+
| test.c:3:29:3:30 | g3 | Variable g3 contains more than one alignment specifier, $@ and $@ | test.c:3:1:3:8 | alignas(...) | alignas(...) | test.c:3:13:3:20 | alignas(...) | alignas(...) |
3+
| test.c:4:35:4:36 | g4 | Variable g4 contains more than one alignment specifier, $@ and $@ | test.c:4:1:4:8 | alignas(...) | alignas(...) | test.c:4:17:4:24 | alignas(...) | alignas(...) |
4+
| test.c:6:53:6:54 | g5 | Variable g5 contains more than one alignment specifier, $@ and $@ | test.c:5:1:5:8 | alignas(...) | alignas(...) | test.c:6:33:6:40 | alignas(...) | alignas(...) |
5+
| test.c:10:35:10:36 | m2 | Variable m2 contains more than one alignment specifier, $@ and $@ | test.c:10:3:10:10 | alignas(...) | alignas(...) | test.c:10:18:10:25 | alignas(...) | alignas(...) |
6+
| test.c:15:35:15:36 | l2 | Variable l2 contains more than one alignment specifier, $@ and $@ | test.c:15:3:15:10 | alignas(...) | alignas(...) | test.c:15:18:15:25 | alignas(...) | alignas(...) |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql

c/misra/test/rules/RULE-8-17/test.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
_Alignas(8) int g1; // COMPLIANT
2+
_Alignas(8) _Alignas(16) int g2; // NON-COMPLIANT
3+
_Alignas(8) _Alignas(8) int g3; // NON-COMPLIANT
4+
_Alignas(float) _Alignas(int) int g4; // NON-COMPLIANT
5+
_Alignas(float) _Alignas(float) int g5; // NON-COMPLIANT
6+
_Alignas(float) _Alignas(float) _Alignas(float) int g5; // NON-COMPLIANT
7+
8+
struct s {
9+
_Alignas(64) int m1; // COMPLIANT
10+
_Alignas(long) _Alignas(16) int m2; // NON_COMPLIANT
11+
};
12+
13+
void f() {
14+
_Alignas(8) int l1; // COMPLIANT
15+
_Alignas(long) _Alignas(16) int l2; // NON_COMPLIANT
16+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
2+
import cpp
3+
import RuleMetadata
4+
import codingstandards.cpp.exclusions.RuleMetadata
5+
6+
newtype AlignmentQuery =
7+
TRedeclarationOfObjectWithoutAlignmentQuery() or
8+
TRedeclarationOfObjectWithUnmatchedAlignmentQuery() or
9+
TAlignmentWithSizeZeroQuery() or
10+
TMoreThanOneAlignmentSpecifierOnDeclarationQuery()
11+
12+
predicate isAlignmentQueryMetadata(Query query, string queryId, string ruleId, string category) {
13+
query =
14+
// `Query` instance for the `redeclarationOfObjectWithoutAlignment` query
15+
AlignmentPackage::redeclarationOfObjectWithoutAlignmentQuery() and
16+
queryId =
17+
// `@id` for the `redeclarationOfObjectWithoutAlignment` query
18+
"c/misra/redeclaration-of-object-without-alignment" and
19+
ruleId = "RULE-8-15" and
20+
category = "required"
21+
or
22+
query =
23+
// `Query` instance for the `redeclarationOfObjectWithUnmatchedAlignment` query
24+
AlignmentPackage::redeclarationOfObjectWithUnmatchedAlignmentQuery() and
25+
queryId =
26+
// `@id` for the `redeclarationOfObjectWithUnmatchedAlignment` query
27+
"c/misra/redeclaration-of-object-with-unmatched-alignment" and
28+
ruleId = "RULE-8-15" and
29+
category = "required"
30+
or
31+
query =
32+
// `Query` instance for the `alignmentWithSizeZero` query
33+
AlignmentPackage::alignmentWithSizeZeroQuery() and
34+
queryId =
35+
// `@id` for the `alignmentWithSizeZero` query
36+
"c/misra/alignment-with-size-zero" and
37+
ruleId = "RULE-8-16" and
38+
category = "advisory"
39+
or
40+
query =
41+
// `Query` instance for the `moreThanOneAlignmentSpecifierOnDeclaration` query
42+
AlignmentPackage::moreThanOneAlignmentSpecifierOnDeclarationQuery() and
43+
queryId =
44+
// `@id` for the `moreThanOneAlignmentSpecifierOnDeclaration` query
45+
"c/misra/more-than-one-alignment-specifier-on-declaration" and
46+
ruleId = "RULE-8-17" and
47+
category = "advisory"
48+
}
49+
50+
module AlignmentPackage {
51+
Query redeclarationOfObjectWithoutAlignmentQuery() {
52+
//autogenerate `Query` type
53+
result =
54+
// `Query` type for `redeclarationOfObjectWithoutAlignment` query
55+
TQueryC(TAlignmentPackageQuery(TRedeclarationOfObjectWithoutAlignmentQuery()))
56+
}
57+
58+
Query redeclarationOfObjectWithUnmatchedAlignmentQuery() {
59+
//autogenerate `Query` type
60+
result =
61+
// `Query` type for `redeclarationOfObjectWithUnmatchedAlignment` query
62+
TQueryC(TAlignmentPackageQuery(TRedeclarationOfObjectWithUnmatchedAlignmentQuery()))
63+
}
64+
65+
Query alignmentWithSizeZeroQuery() {
66+
//autogenerate `Query` type
67+
result =
68+
// `Query` type for `alignmentWithSizeZero` query
69+
TQueryC(TAlignmentPackageQuery(TAlignmentWithSizeZeroQuery()))
70+
}
71+
72+
Query moreThanOneAlignmentSpecifierOnDeclarationQuery() {
73+
//autogenerate `Query` type
74+
result =
75+
// `Query` type for `moreThanOneAlignmentSpecifierOnDeclaration` query
76+
TQueryC(TAlignmentPackageQuery(TMoreThanOneAlignmentSpecifierOnDeclarationQuery()))
77+
}
78+
}

0 commit comments

Comments
 (0)