Skip to content

Commit db1a631

Browse files
committed
Address review comments
1 parent 1649c21 commit db1a631

File tree

7 files changed

+87
-37
lines changed

7 files changed

+87
-37
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
- `A8-5-0`, `EXP53-CPP`, `EXP33-C`, `RULE-9-1` - `MemoryNotInitializedBeforeItIsRead.ql`, `DoNotReadUninitializedMemory.ql`, `DoNotReadUninitializedMemory.ql`, `ObjectWithAutoStorageDurationReadBeforeInit.ql`:
2-
- The queries listed now find uses of the operator 'new' where there is no value initialization provided.
2+
- The queries listed now find uses of the operator 'new' where there is no value initialization provided. The queries listed now also uses an out of the box library to consider initialization within another function as valid initialization (`InitializationFunctions.qll`). We do not yet track finely track the initialization/use of `p` vs `*p`.

cpp/common/src/codingstandards/cpp/lifetimes/CppObjects.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ class AggregateLiteralObjectIdentity extends AggregateLiteral, ObjectIdentityBas
246246
}
247247

248248
/**
249-
* An object identified by a call to `malloc`.
249+
* An object identified by a call to `malloc` or allcoated with a `new` or `new[]` expression.
250250
*
251251
* Note: the malloc expression returns an address to this object, not the object itself. Therefore,
252252
* `getAnAccess()` returns cases where this malloc result is dereferenced, and not the malloc call

cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ class InitializationContext extends TInitializationContext {
122122
}
123123
}
124124

125+
/**
126+
* Catches `new int;` as an expression that doesn't initialize its value. Note that the pointer returned has been initialized (ie it is a valid pointer),
127+
* but the pointee/value has not. In our analysis, we simply count `x` as uninitialized in `x = new int` for now, though a more thorough analysis might track the initialization of `x` and `*x` separately.
128+
*/
125129
class NewNotInit extends NewExpr {
126130
NewNotInit() {
127131
this.getAllocatedType() instanceof BuiltInType and
@@ -133,10 +137,6 @@ class NonInitAssignment extends Assignment {
133137
NonInitAssignment() { this.getRValue() instanceof NewNotInit }
134138
}
135139

136-
class VariableAccessOnLHSOfNonInitAssignment extends VariableAccess {
137-
VariableAccessOnLHSOfNonInitAssignment() { exists(NonInitAssignment a | this = a.getLValue()) }
138-
}
139-
140140
/**
141141
* A local variable without an initializer which is amenable to initialization analysis.
142142
*/
@@ -146,14 +146,7 @@ class UninitializedVariable extends LocalVariable {
146146
(
147147
not exists(getInitializer().getExpr())
148148
or
149-
//or is a builtin type used with new operator but there is no value initialization as far as we can see
150-
exists(Initializer i, NewExpr n |
151-
i = getInitializer() and
152-
n = i.getExpr() and
153-
this.getUnspecifiedType().stripType() instanceof BuiltInType and
154-
//ignore value init
155-
not exists(n.getAChild())
156-
)
149+
getInitializer().getExpr() instanceof NewNotInit
157150
) and
158151
// Not static or thread local, because they are not initialized with indeterminate values
159152
not isStatic() and
@@ -213,17 +206,32 @@ class UninitializedVariable extends LocalVariable {
213206
// Not a pointless read
214207
not result = any(ExprStmt es).getExpr() and
215208
// not involved in a new expr assignment since that does not define
216-
not result instanceof VariableAccessOnLHSOfNonInitAssignment
209+
not result = any(NonInitAssignment a).getLValue()
217210
}
218211

219212
/**
220-
* Gets an access of the variable `v` which is not used as an lvalue, and not used as an argument
213+
* Gets an access of the this variable which is not used as an lvalue, and not used as an argument
221214
* to an initialization function.
222215
*/
223216
VariableAccess getAUse() {
224217
result = this.getAnAccess() and
225-
// Not used as an lvalue
226-
not result = any(AssignExpr a).getLValue() and
218+
(
219+
//count rvalue x as a use if not new int
220+
result.isRValue() and
221+
not exists(PointerDereferenceExpr e | result = e.getAChild()) and
222+
not this.getInitializer().getExpr() instanceof NewNotInit
223+
or
224+
//count lvalue x as a use if used in *x and not new int
225+
result.isLValue() and
226+
exists(PointerDereferenceExpr e | result = e.getAChild()) and
227+
exists(this.getInitializer()) and
228+
not this.getInitializer().getExpr() instanceof NewNotInit
229+
or
230+
//count rvalue *x as a use if has new int
231+
result.isRValue() and
232+
this.getInitializer().getExpr() instanceof NewNotInit and
233+
exists(PointerDereferenceExpr e | result = e.getAChild())
234+
) and
227235
// Not passed to another initialization function
228236
not exists(Call c, int j | j = c.getTarget().(InitializationFunction).initializedParameter() |
229237
result = c.getArgument(j).(AddressOfExpr).getOperand()
@@ -234,6 +242,26 @@ class UninitializedVariable extends LocalVariable {
234242
not result.getParent+() instanceof SizeofOperator
235243
}
236244

245+
// /**
246+
// * Gets an access of the this variable which is not used as an lvalue, and not used as an argument
247+
// * to an initialization function.
248+
// */
249+
// VariableAccess getAUse() {
250+
// result = this.getAnAccess() and
251+
// // Not used as an lvalue
252+
// not result = any(AssignExpr a).getLValue() and
253+
// //(result.isRValue() and not result.getType() instanceof PointerType and not this.getInitializer().getExpr() instanceof NewNotInit) and
254+
// // Not passed to another initialization function
255+
// not exists(Call c, int j | j = c.getTarget().(InitializationFunction).initializedParameter() |
256+
// result = c.getArgument(j).(AddressOfExpr).getOperand()
257+
// or
258+
// result.isRValue() and result = c.getArgument(j)
259+
// ) and
260+
// // Not a pointless read
261+
// not result = any(ExprStmt es).getExpr() and
262+
// // sizeof operators are not real uses
263+
// not result.getParent+() instanceof SizeofOperator
264+
// }
237265
/** Get a read of the variable that may occur while the variable is uninitialized. */
238266
VariableAccess getAnUnitializedUse() {
239267
exists(SubBasicBlock useSbb |

cpp/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.expected

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
| test.cpp:134:11:134:11 | i | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:133:7:133:7 | i | i |
77
| test.cpp:137:13:137:14 | i1 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:136:8:136:9 | i1 | i1 |
88
| test.cpp:141:7:141:8 | i3 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:139:8:139:9 | i3 | i3 |
9-
| test.cpp:141:13:141:14 | i1 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:136:8:136:9 | i1 | i1 |
10-
| test.cpp:201:7:201:8 | p0 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:200:8:200:9 | p0 | p0 |
11-
| test.cpp:204:4:204:5 | p1 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:203:8:203:9 | p1 | p1 |
12-
| test.cpp:206:7:206:8 | p1 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:203:8:203:9 | p1 | p1 |
13-
| test.cpp:211:7:211:8 | p2 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:209:8:209:9 | p2 | p2 |
14-
| test.cpp:214:10:214:11 | p2 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:209:8:209:9 | p2 | p2 |
15-
| test.cpp:221:7:221:8 | p4 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:219:8:219:9 | p4 | p4 |
9+
| test.cpp:204:8:204:9 | p0 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:202:8:202:9 | p0 | p0 |
10+
| test.cpp:207:4:207:5 | p1 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:206:8:206:9 | p1 | p1 |
11+
| test.cpp:211:8:211:9 | p1 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:206:8:206:9 | p1 | p1 |
12+
| test.cpp:217:8:217:9 | p2 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:214:8:214:9 | p2 | p2 |
13+
| test.cpp:220:10:220:11 | p2 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:214:8:214:9 | p2 | p2 |
14+
| test.cpp:229:7:229:8 | p4 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:227:8:227:9 | p4 | p4 |
15+
| test.cpp:233:14:233:15 | p5 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:232:8:232:9 | p5 | p5 |
16+
| test.cpp:237:8:237:9 | p6 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:235:8:235:9 | p6 | p6 |

cpp/common/test/rules/readofuninitializedmemory/test.cpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -196,28 +196,46 @@ void test_class() {
196196
}
197197
}
198198

199+
void initialize(int *p) { *p = 0; }
200+
199201
void extra_extra_test() {
200202
int *p0 = new int;
201-
use(p0); // NON_COMPLIANT
203+
use(p0); // COMPLIANT -- the pointer is valid
204+
use(*p0); // COMPLIANT[FALSE_POSITIVE] -- the pointer is valid
202205

203206
int *p1 = new int;
204-
*p1 = 0; // COMPLIANT[FALSE_POSITIVE] -- this is not found bc this is not an
205-
// lvalue access
206-
use(p1); // COMPLIANT[FALSE_POSITIVE] -- the pointee of p1 has been
207-
// initialized
207+
*p1 = 0; // COMPLIANT[FALSE_POSITIVE] -- this is not found bc this is not an
208+
// lvalue access
209+
use(p1); // COMPLIANT -- the pointee of p1 has been
210+
// initialized
211+
use(*p1); // COMPLIANT[FALSE_POSITIVE] -- the pointee of p1 has been
212+
// initialized
208213

209214
int *p2 = new int;
210215
p2 = new int;
211-
use(p2); // NON_COMPLIANT
216+
use(p2); // COMPLIANT -- the pointer is valid
217+
use(*p2); // NON_COMPLIANT -- the value may be read
212218

213219
int *p3 = new int(1);
214220
*p3 = *p2; // NON_COMPLIANT -- the pointee of p2 has not been
215221
// initialized
216-
use(p3); // NON_COMPLIANT[FALSE_NEGATIVE] -- the pointee of p3 has be
222+
use(p3); // NON_COMPLIANT[FALSE_NEGATIVE] -- the pointee of p3 has been
223+
// overridden
224+
use(*p3); // NON_COMPLIANT[FALSE_NEGATIVE] -- the pointee of p3 has been
217225
// overridden
218226

219227
int *p4;
220228
p4 = new int;
221-
use(p4); // NON_COMPLIANT -- the pointee of p4 has not been
222-
// initialized
229+
use(p4); // COMPLIANT[FALSE_POSITIVE] -- the pointer is valid but new int isnt seen
230+
use(*p4); // COMPLIANT -- the value is not read and the pointer is valid
231+
232+
int *p5;
233+
initialize(p5); // NON_COMPLIANT
234+
235+
int *p6 = new int;
236+
initialize(p6); // COMPLIANT
237+
use(*p6); // COMPLIANT[FALSE_POSITIVE]
238+
239+
int p7;
240+
initialize(&p7); // COMPLIANT
223241
}

cpp/misra/src/rules/RULE-6-8-3/AutomaticStorageAssignedToObjectGreaterLifetime.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @id cpp/misra/automatic-storage-assigned-to-object-greater-lifetime
3-
* @name RULE-6-8-3: Declare objects with appropriate storage durations
3+
* @name RULE-6-8-3: Do not assign the address of an object with automatic storage to an object that may persist after it's lifetime
44
* @description When storage durations are not compatible between assigned pointers it can lead to
55
* referring to objects outside of their lifetime, which is undefined behaviour.
66
* @kind problem

rule_packages/cpp/Lifetime.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
"correctness",
1919
"security",
2020
"scope/system"
21-
]
21+
],
22+
"implementation_scope": {
23+
"description": "The rule currently does not track member initialization or arrays at all (that have been declared with array types when they have not been assigned via pointers)."
24+
}
2225
}
2326
],
2427
"title": "The value of an object must not be read before it has been set"
@@ -32,7 +35,7 @@
3235
{
3336
"description": "When storage durations are not compatible between assigned pointers it can lead to referring to objects outside of their lifetime, which is undefined behaviour.",
3437
"kind": "problem",
35-
"name": "Declare objects with appropriate storage durations",
38+
"name": "Do not assign the address of an object with automatic storage to an object that may persist after it's lifetime",
3639
"precision": "very-high",
3740
"severity": "error",
3841
"short_name": "AutomaticStorageAssignedToObjectGreaterLifetime",

0 commit comments

Comments
 (0)