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 |

0 commit comments

Comments
 (0)