Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f5a2603

Browse files
committed
C++: Add store steps that target the new partial definitions.
1 parent 7a2b69f commit f5a2603

1 file changed

Lines changed: 67 additions & 122 deletions

File tree

cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 67 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -228,69 +228,86 @@ private class ArrayContent extends Content, TArrayContent {
228228
override string toString() { result = "array content" }
229229
}
230230

231-
private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) {
232-
exists(StoreInstruction store, Class c |
233-
store = node2.asInstruction() and
231+
/**
232+
* A store step from the value of a `StoreInstruction` to the "innermost" field of the destination.
233+
* This predicate only holds when there is no `ChiInsturction` that merges the result of the
234+
* `StoreInstruction` into a larger memory.
235+
*/
236+
private predicate instrToFieldNodeStoreStepNoChi(
237+
Node node1, FieldContent f, PartialDefinitionNode node2
238+
) {
239+
exists(StoreInstruction store, PostUpdateFieldNode post |
240+
post = node2.getPartialDefinition() and
241+
not exists(ChiInstruction chi | chi.getPartial() = store) and
242+
post.getPreUpdateNode() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and
234243
store.getSourceValueOperand() = node1.asOperand() and
235-
getWrittenField(store, f.(FieldContent).getAField(), c) and
236-
f.hasOffset(c, _, _)
244+
f.getADirectField() = post.getField()
237245
)
238246
}
239247

240-
private FieldAddressInstruction getFieldInstruction(Instruction instr) {
241-
result = instr or
242-
result = instr.(CopyValueInstruction).getUnary()
243-
}
244-
245-
pragma[noinline]
246-
private predicate getWrittenField(Instruction instr, Field f, Class c) {
247-
exists(FieldAddressInstruction fa |
248-
fa =
249-
getFieldInstruction([
250-
instr.(StoreInstruction).getDestinationAddress(),
251-
instr.(WriteSideEffectInstruction).getDestinationAddress()
252-
]) and
253-
f = fa.getField() and
254-
c = f.getDeclaringType()
248+
/**
249+
* A store step from a `StoreInstruction` to the "innermost" field
250+
* of the destination. This predicate only holds when there exists a `ChiInstruction` that merges the
251+
* result of the `StoreInstruction` into a larger memory.
252+
*/
253+
private predicate instrToFieldNodeStoreStepChi(
254+
Node node1, FieldContent f, PartialDefinitionNode node2
255+
) {
256+
exists(
257+
ChiPartialOperand operand, StoreInstruction store, ChiInstruction chi, PostUpdateFieldNode post
258+
|
259+
post = node2.getPartialDefinition() and
260+
not chi.isResultConflated() and
261+
node1.asOperand() = operand and
262+
chi.getPartialOperand() = operand and
263+
store = operand.getDef() and
264+
post.getPreUpdateNode() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and
265+
f.getADirectField() = post.getField()
255266
)
256267
}
257268

258-
private predicate fieldStoreStepChi(Node node1, FieldContent f, PostUpdateNode node2) {
259-
exists(ChiPartialOperand operand, ChiInstruction chi |
260-
chi.getPartialOperand() = operand and
261-
node1.asOperand() = operand and
262-
node2.asInstruction() = chi and
263-
exists(Class c |
264-
c = chi.getResultType() and
265-
exists(int startBit, int endBit |
266-
chi.getUpdatedInterval(startBit, endBit) and
267-
f.hasOffset(c, startBit, endBit)
268-
)
269-
or
270-
getWrittenField(operand.getDef(), f.getAField(), c) and
271-
f.hasOffset(c, _, _)
272-
)
269+
private predicate callableWithoutDefinitionStoreStep(
270+
Node node1, FieldContent f, PartialDefinitionNode node2
271+
) {
272+
exists(
273+
WriteSideEffectInstruction write, ChiInstruction chi, PostUpdateFieldNode post,
274+
Function callable
275+
|
276+
chi.getPartial() = write and
277+
not chi.isResultConflated() and
278+
post = node2.getPartialDefinition() and
279+
node1.asInstruction() = write and
280+
post.getPreUpdateNode() = getFieldNodeForFieldInstruction(write.getDestinationAddress()) and
281+
f.getADirectField() = post.getField() and
282+
callable = write.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() and
283+
not callable.hasDefinition()
273284
)
274285
}
275286

276-
private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) {
287+
/**
288+
* A store step from a `StoreInstruction` to the `ChiInstruction` generated from assigning
289+
* to a pointer or array indirection
290+
*/
291+
private predicate arrayStoreStepChi(Node node1, ArrayContent a, PartialDefinitionNode node2) {
277292
a = TArrayContent() and
278-
exists(ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store |
293+
exists(
294+
ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store, PartialDefinition pd
295+
|
296+
pd = node2.getPartialDefinition() and
279297
chi.getPartialOperand() = operand and
280298
store = operand.getDef() and
281299
node1.asOperand() = operand and
282300
// This `ChiInstruction` will always have a non-conflated result because both `ArrayStoreNode`
283301
// and `PointerStoreNode` require it in their characteristic predicates.
284-
node2.asInstruction() = chi and
285-
(
286-
// `x[i] = taint()`
287-
// This matches the characteristic predicate in `ArrayStoreNode`.
288-
store.getDestinationAddress() instanceof PointerAddInstruction
289-
or
290-
// `*p = taint()`
291-
// This matches the characteristic predicate in `PointerStoreNode`.
292-
store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction
293-
)
302+
pd.getPreUpdateNode().asOperand() = chi.getTotalOperand()
303+
|
304+
// `x[i] = taint()`
305+
// This matches the characteristic predicate in `ArrayStoreNode`.
306+
store.getDestinationAddress() instanceof PointerAddInstruction
307+
or
308+
// `*p = taint()`
309+
// This matches the characteristic predicate in `PointerStoreNode`.
310+
store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction
294311
)
295312
}
296313

@@ -300,82 +317,10 @@ private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode n
300317
* value of `node1`.
301318
*/
302319
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
303-
fieldStoreStepNoChi(node1, f, node2) or
304-
fieldStoreStepChi(node1, f, node2) or
320+
instrToFieldNodeStoreStepNoChi(node1, f, node2) or
321+
instrToFieldNodeStoreStepChi(node1, f, node2) or
305322
arrayStoreStepChi(node1, f, node2) or
306-
fieldStoreStepAfterArraySuppression(node1, f, node2)
307-
}
308-
309-
// This predicate pushes the correct `FieldContent` onto the access path when the
310-
// `suppressArrayRead` predicate has popped off an `ArrayContent`.
311-
private predicate fieldStoreStepAfterArraySuppression(
312-
Node node1, FieldContent f, PostUpdateNode node2
313-
) {
314-
exists(WriteSideEffectInstruction write, ChiInstruction chi, Class c |
315-
not chi.isResultConflated() and
316-
node1.asInstruction() = chi and
317-
node2.asInstruction() = chi and
318-
chi.getPartial() = write and
319-
getWrittenField(write, f.getAField(), c) and
320-
f.hasOffset(c, _, _)
321-
)
322-
}
323-
324-
bindingset[result, i]
325-
private int unbindInt(int i) { i <= result and i >= result }
326-
327-
pragma[noinline]
328-
private predicate getLoadedField(LoadInstruction load, Field f, Class c) {
329-
exists(FieldAddressInstruction fa |
330-
fa = load.getSourceAddress() and
331-
f = fa.getField() and
332-
c = f.getDeclaringType()
333-
)
334-
}
335-
336-
/**
337-
* Holds if data can flow from `node1` to `node2` via a read of `f`.
338-
* Thus, `node1` references an object with a field `f` whose value ends up in
339-
* `node2`.
340-
*/
341-
private predicate fieldReadStep(Node node1, FieldContent f, Node node2) {
342-
exists(LoadOperand operand |
343-
node2.asOperand() = operand and
344-
node1.asInstruction() = operand.getAnyDef() and
345-
exists(Class c |
346-
c = operand.getAnyDef().getResultType() and
347-
exists(int startBit, int endBit |
348-
operand.getUsedInterval(unbindInt(startBit), unbindInt(endBit)) and
349-
f.hasOffset(c, startBit, endBit)
350-
)
351-
or
352-
getLoadedField(operand.getUse(), f.getAField(), c) and
353-
f.hasOffset(c, _, _)
354-
)
355-
)
356-
}
357-
358-
/**
359-
* When a store step happens in a function that looks like an array write such as:
360-
* ```cpp
361-
* void f(int* pa) {
362-
* pa = source();
363-
* }
364-
* ```
365-
* it can be a write to an array, but it can also happen that `f` is called as `f(&a.x)`. If that is
366-
* the case, the `ArrayContent` that was written by the call to `f` should be popped off the access
367-
* path, and a `FieldContent` containing `x` should be pushed instead.
368-
* So this case pops `ArrayContent` off the access path, and the `fieldStoreStepAfterArraySuppression`
369-
* predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path.
370-
*/
371-
predicate suppressArrayRead(Node node1, ArrayContent a, Node node2) {
372-
a = TArrayContent() and
373-
exists(WriteSideEffectInstruction write, ChiInstruction chi |
374-
node1.asInstruction() = write and
375-
node2.asInstruction() = chi and
376-
chi.getPartial() = write and
377-
getWrittenField(write, _, _)
378-
)
323+
callableWithoutDefinitionStoreStep(node1, f, node2)
379324
}
380325

381326
private class ArrayToPointerConvertInstruction extends ConvertInstruction {

0 commit comments

Comments
 (0)