Skip to content

Commit e51019d

Browse files
committed
Address FPs on subojects
Members of a struct can be initialized indirectly in various ways. We account for those when counting uses.
1 parent d3baeb9 commit e51019d

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

cpp/autosar/src/rules/M0-1-4/SingleUsePODVariable.qll

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,44 @@ private string getConstExprValue(Variable v) {
1010
v.isConstexpr()
1111
}
1212

13+
/**
14+
* Gets the number of uses of variable `v` in an opaque assignment, where an opaqua assignment for example a cast from one type to the other and `v` is assumed to be a member of the resulting type.
15+
* e.g.,
16+
* struct foo {
17+
* int bar;
18+
* }
19+
*
20+
* struct foo * v = (struct foo*)buffer;
21+
*/
22+
Expr getIndirectSubObjectAssignedValue(MemberVariable subobject) {
23+
// struct foo * ptr = (struct foo*)buffer;
24+
exists(Struct someStruct, Variable instanceOfSomeStruct | someStruct.getAMember() = subobject |
25+
instanceOfSomeStruct.getType().(PointerType).getBaseType() = someStruct and
26+
exists(Cast assignedValue |
27+
// Exclude cases like struct foo * v = nullptr;
28+
not assignedValue.isImplicit() and
29+
// `v` is a subobject of another type that reinterprets another object. We count that as a use of `v`.
30+
assignedValue.getExpr() = instanceOfSomeStruct.getAnAssignedValue() and
31+
result = assignedValue
32+
)
33+
or
34+
// struct foo; read(..., (char *)&foo);
35+
instanceOfSomeStruct.getType() = someStruct and
36+
exists(Call externalInitializerCall, Cast castToCharPointer, int n |
37+
externalInitializerCall.getArgument(n).(AddressOfExpr).getOperand() =
38+
instanceOfSomeStruct.getAnAccess() and
39+
externalInitializerCall.getArgument(n) = castToCharPointer.getExpr() and
40+
castToCharPointer.getType().(PointerType).getBaseType().getUnspecifiedType() instanceof
41+
CharType and
42+
result = externalInitializerCall
43+
)
44+
or
45+
// the object this subject is part of is initialized and we assumes this initializes the subobject.
46+
instanceOfSomeStruct.getType() = someStruct and
47+
result = instanceOfSomeStruct.getInitializer().getExpr()
48+
)
49+
}
50+
1351
/** Gets a "use" count according to rule M0-1-4. */
1452
int getUseCount(Variable v) {
1553
// We enforce that it's a POD type variable, so if it has an initializer it is explicit
@@ -23,7 +61,7 @@ int getUseCount(Variable v) {
2361
// of the variable
2462
count(ClassTemplateInstantiation cti |
2563
cti.getTemplateArgument(_).(Expr).getValue() = getConstExprValue(v)
26-
)
64+
) + count(getIndirectSubObjectAssignedValue(v))
2765
}
2866

2967
Expr getAUserInitializedValue(Variable v) {

cpp/autosar/test/rules/M0-1-4/test_member.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,41 @@ void test_array_initialized_members() {
9393

9494
l1[0].m1;
9595
}
96+
97+
void test_indirect_assigned_members(void *opaque) {
98+
struct s1 {
99+
int m1; // COMPLIANT
100+
};
101+
102+
struct s1 *p = (struct s1 *)opaque;
103+
p->m1;
104+
105+
struct s2 {
106+
int m1; // COMPLIANT
107+
};
108+
109+
char buffer[sizeof(struct s2) + 8] = {0};
110+
struct s2 *l2 = (struct s2 *)&buffer[8];
111+
l2->m1;
112+
}
113+
114+
void test_external_assigned_members(void (*fp)(unsigned char *)) {
115+
116+
struct s1 {
117+
int m1; // COMPLIANT
118+
};
119+
120+
struct s1 l1;
121+
fp((unsigned char *)&l1);
122+
l1.m1;
123+
124+
struct s2 {
125+
int m1; // COMPLIANT
126+
};
127+
128+
struct s2 (*copy_init)();
129+
struct s2 l2 = copy_init();
130+
l2.m1;
131+
}
132+
96133
} // namespace test

0 commit comments

Comments
 (0)