forked from github/codeql-coding-standards
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSingleUsePODVariable.qll
More file actions
98 lines (91 loc) · 3.84 KB
/
SingleUsePODVariable.qll
File metadata and controls
98 lines (91 loc) · 3.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/** A module providing predicates that support identifying single use non volatile POD variables. */
import cpp
import codingstandards.cpp.TrivialType
import codingstandards.cpp.deadcode.UnusedVariables
/** Gets the constant value of a constexpr variable. */
private string getConstExprValue(Variable v) {
result = v.getInitializer().getExpr().getValue() and
v.isConstexpr()
}
/**
* Gets the number of uses of variable `v` in an opaque assignment, where an opaque assignment is a cast from one type to the other, and `v` is assumed to be a member of the resulting type.
* e.g.,
* struct foo {
* int bar;
* }
*
* struct foo * v = (struct foo*)buffer;
*/
Expr getIndirectSubObjectAssignedValue(MemberVariable subobject) {
// struct foo * ptr = (struct foo*)buffer;
exists(Struct someStruct, Variable instanceOfSomeStruct | someStruct.getAMember() = subobject |
instanceOfSomeStruct.getType().(PointerType).getBaseType() = someStruct and
exists(Cast assignedValue |
// Exclude cases like struct foo * v = nullptr;
not assignedValue.isImplicit() and
// `v` is a subobject of another type that reinterprets another object. We count that as a use of `v`.
assignedValue.getExpr() = instanceOfSomeStruct.getAnAssignedValue() and
result = assignedValue
)
or
// struct foo; read(..., (char *)&foo);
instanceOfSomeStruct.getType() = someStruct and
exists(Call externalInitializerCall, Cast castToCharPointer, int n |
externalInitializerCall.getArgument(n).(AddressOfExpr).getOperand() =
instanceOfSomeStruct.getAnAccess() and
externalInitializerCall.getArgument(n) = castToCharPointer.getExpr() and
castToCharPointer.getType().(PointerType).getBaseType().getUnspecifiedType() instanceof
CharType and
result = externalInitializerCall
)
or
// the object this subject is part of is initialized and we assume this initializes the subobject.
instanceOfSomeStruct.getType() = someStruct and
result = instanceOfSomeStruct.getInitializer().getExpr()
)
}
/** Gets a "use" count according to rule M0-1-4. */
int getUseCount(Variable v) {
// We enforce that it's a POD type variable, so if it has an initializer it is explicit
result =
count(getAUserInitializedValue(v)) +
count(VariableAccess access | access = v.getAnAccess() and not access.isCompilerGenerated()) +
// For constexpr variables used as template arguments, we don't see accesses (just the
// appropriate literals). We therefore take a conservative approach and count the number of
// template instantiations that use the given constant, and consider each one to be a use
// of the variable
count(ClassTemplateInstantiation cti |
cti.getTemplateArgument(_).(Expr).getValue() = getConstExprValue(v)
) + count(getIndirectSubObjectAssignedValue(v))
}
Expr getAUserInitializedValue(Variable v) {
(
result = v.getInitializer().getExpr()
or
exists(UserProvidedConstructorFieldInit cfi | cfi.getTarget() = v and result = cfi.getExpr())
or
exists(ClassAggregateLiteral l | not l.isCompilerGenerated() | result = l.getAFieldExpr(v))
) and
not result.isCompilerGenerated()
}
/** Gets a single use of `v`, if `isSingleUseNonVolatilePODVariable` holds. */
Element getSingleUse(Variable v) {
isSingleUseNonVolatilePODVariable(v) and
(
result = v.getInitializer()
or
result = any(UserProvidedConstructorFieldInit cfi | cfi.getTarget() = v)
or
exists(VariableAccess access |
access = v.getAnAccess() and not access.isCompilerGenerated() and result = access
)
)
}
/** Holds if the given variable is non-volatile POD type variable with a single use. */
predicate isSingleUseNonVolatilePODVariable(Variable v) {
// Not volatile
not v.isVolatile() and
// This is a POD type
v.getType() instanceof PODType and
getUseCount(v) = 1
}