Skip to content

Commit 5facdd5

Browse files
First draft that seems potentially complete.
1 parent ef6492b commit 5facdd5

File tree

3 files changed

+146
-124
lines changed

3 files changed

+146
-124
lines changed

cpp/misra/src/rules/RULE-10-1-1/PointerOrRefParamNotConst.ql

Lines changed: 80 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,9 @@ import codingstandards.cpp.alertreporting.HoldsForAllCopies
2525
* Holds if the function is in a template scope and should be excluded.
2626
*/
2727
predicate isInTemplateScope(Function f) {
28-
// Function templates
2928
f.isFromTemplateInstantiation(_)
3029
or
31-
f instanceof TemplateFunction
32-
or
33-
// Functions declared within the scope of a template class
34-
exists(TemplateClass tc | f.getDeclaringType() = tc)
35-
or
36-
f.getDeclaringType().isFromTemplateInstantiation(_)
37-
or
38-
// Lambdas within template scope
39-
exists(LambdaExpression le |
40-
le.getLambdaFunction() = f and
41-
isInTemplateScope(le.getEnclosingFunction())
42-
)
30+
f.isFromUninstantiatedTemplate(_)
4331
}
4432

4533
/**
@@ -96,6 +84,9 @@ class PointerLikeType extends Type {
9684
predicate pointsToNonConst() { not innerType.isConst() }
9785
}
9886

87+
/**
88+
* A `Parameter` whose type is a `PointerLikeType` such as a pointer or reference.
89+
*/
9990
class PointerLikeParam extends Parameter {
10091
PointerLikeType pointerLikeType;
10192

@@ -107,6 +98,28 @@ class PointerLikeParam extends Parameter {
10798
not pointerLikeType.getInnerType() instanceof VoidType
10899
}
109100

101+
/**
102+
* Get the pointer like type of this parameter.
103+
*/
104+
PointerLikeType getPointerLikeType() { result = pointerLikeType }
105+
106+
/**
107+
* Get usages of this parameter that maintain pointer-like semantics -- typically this means
108+
* either a normal access, or switching between pointers and reference semantics.
109+
*
110+
* Examples of accesses with pointer-like semantics include:
111+
* - `ref` in `int &x = ref`, or `&ref` in `int *x = &ref`;
112+
* - `ptr` in `int *x = ptr`, or `*ptr` in `int &x = *ptr`;
113+
*
114+
* In the above examples, we can still access the value pointed to by `ref` or `ptr` through the
115+
* expression.
116+
*
117+
* Examples of non-pointer-like semantics include:
118+
* - `ref` in `int x = ref` and `*ptr` in `int x = *ptr`;
119+
*
120+
* In the above examples, the value pointed to by `ref` or `ptr` is copied and the expression
121+
* refers to a new/different object.
122+
*/
110123
Expr getAPointerLikeAccess() {
111124
result = this.getAnAccess()
112125
or
@@ -121,17 +134,40 @@ class PointerLikeParam extends Parameter {
121134
}
122135
}
123136

124-
query predicate test(
125-
PointerLikeParam param, Expr ptrLikeAccess, Type argtype, Type innerType, string explain
126-
) {
127-
ptrLikeAccess = param.getAPointerLikeAccess() and
128-
exists(FunctionCall fc |
129-
fc.getArgument(0) = ptrLikeAccess and
130-
argtype = fc.getTarget().getParameter(0).getType() and
131-
argtype.(PointerLikeType).pointsToNonConst() and
132-
innerType = argtype.(PointerLikeType).getInnerType()
133-
) and
134-
explain = argtype.explain()
137+
/**
138+
* A `VariableEffect` whose target variable is a `PointerLikeParam`.
139+
*
140+
* Examples of pointer-like effects on a pointer-like parameter `p` would include `p = ...`, `++p`,
141+
* `*p = ...`, and `++*p`, etc.
142+
*/
143+
class PointerLikeEffect extends VariableEffect {
144+
PointerLikeParam param;
145+
146+
PointerLikeEffect() { param = this.getTarget() }
147+
148+
/**
149+
* Holds if this effect modifies the pointed-to or referred-to object.
150+
*
151+
* For example, `*p = 0` modifies the inner type if `p` is a pointer, and `p = 0` affects the
152+
* inner type if `p` is a reference.
153+
*/
154+
predicate affectsInnerType() {
155+
if param.getPointerLikeType() instanceof ReferenceType
156+
then affectsOuterType()
157+
else not affectsOuterType()
158+
}
159+
160+
/**
161+
* Holds if this effect modifies the pointer or reference itself.
162+
*
163+
* For example, `p = ...` and `++p` modify the outer type, whether that type is a pointer or
164+
* reference, while `*p = 0` does not modify the outer type.
165+
*/
166+
predicate affectsOuterType() {
167+
this.(Assignment).getLValue() = param.getAnAccess()
168+
or
169+
this.(CrementOperation).getOperand() = param.getAnAccess()
170+
}
135171
}
136172

137173
/**
@@ -158,17 +194,10 @@ class NonConstParam extends PointerLikeParam {
158194
not this.getFunction().hasGlobalName("main") and
159195
// Exclude deleted functions
160196
not this.getFunction().isDeleted() and
161-
// Exclude any parameter whose underlying data is modified (VariableEffect)
162-
not exists(VariableEffect effect |
197+
// Exclude any parameter whose underlying data is modified
198+
not exists(PointerLikeEffect effect |
163199
effect.getTarget() = this and
164-
(
165-
// For reference types, any effect is a target modification
166-
pointerLikeType.getOuterType() instanceof ReferenceType
167-
or
168-
// For pointer types, exclude effects that only modify the pointer itself
169-
not effect.(AssignExpr).getLValue() = this.getAnAccess() and
170-
not effect.(CrementOperation).getOperand() = this.getAnAccess()
171-
)
200+
effect.affectsInnerType()
172201
) and
173202
// Exclude parameters passed as arguments to functions taking non-const pointer/ref params
174203
not exists(FunctionCall fc, int i |
@@ -183,19 +212,30 @@ class NonConstParam extends PointerLikeParam {
183212
) and
184213
// Exclude parameters assigned to a non-const pointer/reference alias
185214
not exists(Variable v |
186-
v.getAnAssignedValue() = this.getAnAccess() and
215+
v.getAnAssignedValue() = this.getAPointerLikeAccess() and
187216
v.getType().(PointerLikeType).pointsToNonConst()
188217
) and
189218
// Exclude parameters returned as non-const pointer/reference
190219
not exists(ReturnStmt ret |
191-
ret.getExpr() = this.getAnAccess() and
220+
ret.getExpr() = this.getAPointerLikeAccess() and
192221
ret.getEnclosingFunction().getType().(PointerLikeType).pointsToNonConst()
222+
) and
223+
not exists(FieldAccess fa |
224+
fa.getQualifier() = [this.getAPointerLikeAccess(), this.getAnAccess()] and
225+
fa.isLValueCategory()
226+
) and
227+
not exists(AddressOfExpr addrOf |
228+
// exclude pointer to pointer and reference to pointer cases.
229+
addrOf.getOperand() = this.getAPointerLikeAccess() and
230+
addrOf.getType().(PointerLikeType).getInnerType() instanceof PointerLikeType
193231
)
194232
}
195233
}
196234

197-
from NonConstParam param
198-
where not isExcluded(param, Declarations3Package::pointerOrRefParamNotConstQuery())
235+
from NonConstParam param, Type innerType
236+
where
237+
not isExcluded(param, Declarations3Package::pointerOrRefParamNotConstQuery()) and
238+
innerType = param.getPointerLikeType().getInnerType()
199239
select param,
200-
"Parameter '" + param.getName() +
201-
"' points/refers to a non-const-qualified type but does not modify the target object."
240+
"Parameter '" + param.getName() + "' points/refers to a non-const type '" + innerType.toString() +
241+
"' but does not modify the target object."

0 commit comments

Comments
 (0)