Skip to content

Commit a00bd7a

Browse files
committed
C++: Respond to review comments.
1 parent 7b00367 commit a00bd7a

File tree

3 files changed

+92
-82
lines changed

3 files changed

+92
-82
lines changed

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

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -350,20 +350,25 @@ private class InexactLoadOperand extends LoadOperand {
350350
InexactLoadOperand() { this.isDefinitionInexact() }
351351
}
352352

353+
/** Get the result type of an `Instruction` i, if it is a `PointerType`. */
354+
private PointerType getPointerType(Instruction i) {
355+
// We are done if the type is a pointer type that is not a glvalue
356+
i.getResultLanguageType().hasType(result, false)
357+
or
358+
// Some instructions produce a glvalue. Recurse past those to get the actual `PointerType`.
359+
result = getPointerType(i.(PointerOffsetInstruction).getLeft())
360+
}
361+
353362
private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) {
354363
a = TArrayContent() and
355364
// Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array.
356-
exists(InexactLoadOperand operand, Instruction address |
365+
exists(InexactLoadOperand operand, LoadInstruction load |
366+
load.getSourceValueOperand() = operand and
357367
node1.asInstruction() = operand.getAnyDef() and
358368
not node1.asInstruction().isResultConflated() and
359369
operand = node2.asOperand() and
360-
instructionOperandLocalFlowStep+(instructionNode(address),
361-
operandNode(operand.getAddressOperand())) and
362-
(
363-
address instanceof LoadInstruction or
364-
address instanceof ArrayToPointerConvertInstruction or
365-
address instanceof PointerOffsetInstruction
366-
)
370+
// Ensure that the load is actually loading from an array or a pointer.
371+
getPointerType(load.getSourceAddress()).getBaseType() = load.getResultType()
367372
)
368373
}
369374

@@ -392,19 +397,18 @@ bindingset[result, i]
392397
private int unbindInt(int i) { i <= result and i >= result }
393398

394399
pragma[noinline]
395-
private predicate getFieldNodeFromLoadOperand(FieldNode fieldNode, LoadOperand loadOperand) {
396-
fieldNode = getFieldNodeForFieldInstruction(loadOperand.getAddressOperand().getDef())
400+
private FieldNode getFieldNodeFromLoadOperand(LoadOperand loadOperand) {
401+
result = getFieldNodeForFieldInstruction(loadOperand.getAddressOperand().getDef())
397402
}
398403

399-
// Sometimes there's no explicit field dereference. In such cases we use the IR alias analysis to
400-
// determine the offset being, and deduce the field from this information.
404+
/**
405+
* Sometimes there's no explicit field dereference. In such cases we use the IR alias analysis to
406+
* determine the offset being, and deduce the field from this information.
407+
*/
401408
private predicate aliasedReadStep(Node node1, FieldContent f, Node node2) {
402409
exists(LoadOperand operand, Class c, int startBit, int endBit |
403410
// Ensure that we don't already catch this store step using a `FieldNode`.
404-
not exists(FieldNode node |
405-
getFieldNodeFromLoadOperand(node, operand) and
406-
instrToFieldNodeReadStep(node, f, _)
407-
) and
411+
not instrToFieldNodeReadStep(getFieldNodeFromLoadOperand(operand), f, _) and
408412
node1.asInstruction() = operand.getAnyDef() and
409413
node2.asOperand() = operand and
410414
not node1.asInstruction().isResultConflated() and
@@ -414,6 +418,11 @@ private predicate aliasedReadStep(Node node1, FieldContent f, Node node2) {
414418
)
415419
}
416420

421+
/** Get the result type of an `Instruction` i, if it is a `ReferenceType`. */
422+
private ReferenceType getReferenceType(Instruction i) {
423+
i.getResultLanguageType().hasType(result, false)
424+
}
425+
417426
/**
418427
* In cases such as:
419428
* ```cpp
@@ -431,7 +440,7 @@ private predicate aliasedReadStep(Node node1, FieldContent f, Node node2) {
431440
*/
432441
private predicate innerReadSteap(Node node1, Content a, Node node2) {
433442
a = TArrayContent() and
434-
exists(WriteSideEffectInstruction write, CallInstruction call, Expr arg |
443+
exists(WriteSideEffectInstruction write, CallInstruction call, CopyValueInstruction copyValue |
435444
write.getPrimaryInstruction() = call and
436445
node1.asInstruction() = write and
437446
(
@@ -440,8 +449,9 @@ private predicate innerReadSteap(Node node1, Content a, Node node2) {
440449
exists(ChiInstruction chi | chi.getPartial() = write and not chi.isResultConflated())
441450
) and
442451
node2.asInstruction() = write and
443-
arg = call.getArgument(write.getIndex()).getUnconvertedResultExpression() and
444-
(arg instanceof AddressOfExpr or arg.getConversion() instanceof ReferenceToExpr)
452+
copyValue = call.getArgument(write.getIndex()) and
453+
[getPointerType(copyValue).getBaseType(), getReferenceType(copyValue).getBaseType()] =
454+
copyValue.getSourceValue().getResultType()
445455
)
446456
}
447457

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

Lines changed: 60 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ class OperandNode extends Node, TOperandNode {
192192
FieldNode getFieldNodeForFieldInstruction(Instruction instr) {
193193
result.getFieldInstruction() =
194194
any(FieldAddressInstruction fai |
195-
instructionOperandLocalFlowStep*(instructionNode(fai), instructionNode(instr))
195+
longestRegisterInstructionOperandLocalFlowStep(instructionNode(fai), instructionNode(instr))
196196
)
197197
}
198198

@@ -251,13 +251,19 @@ class FieldNode extends Node, TFieldNode {
251251
/**
252252
* INTERNAL: do not use. A partial definition of a `FieldNode`.
253253
*/
254-
class PartialFieldDefinition extends PartialDefinition {
255-
override FieldNode node;
256-
257-
override FieldNode getPreUpdateNode() { result = node }
254+
class PartialFieldDefinition extends FieldNode, PartialDefinition {
255+
/**
256+
* The pre-update node of a partial definition of a `FieldNode` is the `FieldNode` itself. This ensures
257+
* that the data flow library's reverse read mechanism builds up the correct access path for nested
258+
* fields.
259+
* For instance, in `a.b.c = x` there is a partial definition for `c` (let's call it `post[c]`) and a
260+
* partial definition for `b` (let's call it `post[b]`), and there is a read step from `b` to `c`
261+
* (using `instrToFieldNodeReadStep`), so there is a store step from `post[c]` to `post[b]`.
262+
*/
263+
override FieldNode getPreUpdateNode() { result = this }
258264

259265
override Expr getDefinedExpr() {
260-
result = node.getFieldInstruction().getObjectAddress().getUnconvertedResultExpression()
266+
result = this.getFieldInstruction().getObjectAddress().getUnconvertedResultExpression()
261267
}
262268
}
263269

@@ -411,39 +417,13 @@ abstract class PostUpdateNode extends Node {
411417
override Location getLocation() { result = getPreUpdateNode().getLocation() }
412418
}
413419

414-
/**
415-
* A partial definition of a node. A partial definition that targets arrays or pointers is attached to
416-
* an `InstructionNode` (specifially, to the `ChiInstruction` that follows the `StoreInstruction`), and
417-
* a partial definition that targets a `FieldNode` is attached to the `FieldNode`.
418-
*
419-
* The pre-update node of a partial definition of a `FieldNode` is the `FieldNode` itself. This ensures
420-
* that the data flow library's reverse read mechanism builds up the correct access path for nested
421-
* fields.
422-
* For instance, in `a.b.c = x` there is a partial definition for `c` (let's call it `post[c]`) and a
423-
* partial definition for `b` (let's call it `post[b]`), and there is a read step from `b` to `c`
424-
* (using `instrToFieldNodeReadStep`), so there is a store step from `post[c]` to `post[b]`.
425-
*/
426-
private newtype TPartialDefinition =
427-
MkPartialDefinition(Node node) {
428-
isPointerStoreNode(node, _, _) or
429-
isArrayStoreNode(node, _, _) or
430-
node instanceof FieldNode
431-
}
432-
433420
/** INTERNAL: do not use. A partial definition of a node. */
434-
abstract class PartialDefinition extends TPartialDefinition {
435-
Node node;
436-
437-
PartialDefinition() { this = MkPartialDefinition(node) }
438-
421+
abstract class PartialDefinition extends Node {
439422
/** Gets the node before the state update. */
440423
abstract Node getPreUpdateNode();
441424

442425
/** Gets the expression that is partially defined by this node. */
443426
abstract Expr getDefinedExpr();
444-
445-
/** Gets a string representation of this partial definition. */
446-
string toString() { result = node.toString() + " [partial definition]" }
447427
}
448428

449429
/**
@@ -475,52 +455,44 @@ class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode {
475455
override string toString() { result = getPreUpdateNode().toString() + " [post update]" }
476456
}
477457

478-
private predicate isArrayStoreNode(
479-
InstructionNode node, ChiInstruction chi, PointerAddInstruction add
480-
) {
481-
chi = node.getInstruction() and
482-
not chi.isResultConflated() and
483-
exists(StoreInstruction store |
484-
chi.getPartial() = store and
485-
add = store.getDestinationAddress()
486-
)
487-
}
488-
489458
/**
490459
* The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden
491460
* `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`.
492461
*/
493-
private class ArrayStoreNode extends PartialDefinition {
494-
override InstructionNode node;
462+
private class ArrayStoreNode extends InstructionNode, PartialDefinition {
495463
ChiInstruction chi;
496464
PointerAddInstruction add;
497465

498-
ArrayStoreNode() { isArrayStoreNode(node, chi, add) }
466+
ArrayStoreNode() {
467+
chi = this.getInstruction() and
468+
not chi.isResultConflated() and
469+
exists(StoreInstruction store |
470+
chi.getPartial() = store and
471+
add = store.getDestinationAddress()
472+
)
473+
}
499474

500475
override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() }
501476

502477
override Expr getDefinedExpr() { result = add.getLeft().getUnconvertedResultExpression() }
503478
}
504479

505-
private predicate isPointerStoreNode(InstructionNode node, ChiInstruction chi, LoadInstruction load) {
506-
chi = node.getInstruction() and
507-
not chi.isResultConflated() and
508-
exists(StoreInstruction store |
509-
chi.getPartial() = store and
510-
load = store.getDestinationAddress().(CopyValueInstruction).getUnary()
511-
)
512-
}
513-
514480
/**
515481
* The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden
516482
* `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`.
517483
*/
518-
private class PointerStoreNode extends PartialDefinition {
519-
override InstructionNode node;
484+
private class PointerStoreNode extends InstructionNode, PartialDefinition {
520485
ChiInstruction chi;
521486
LoadInstruction load;
522487

523-
PointerStoreNode() { isPointerStoreNode(node, chi, load) }
488+
PointerStoreNode() {
489+
chi = this.getInstruction() and
490+
not chi.isResultConflated() and
491+
exists(StoreInstruction store |
492+
chi.getPartial() = store and
493+
load = store.getDestinationAddress().(CopyValueInstruction).getUnary()
494+
)
495+
}
524496

525497
override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() }
526498

@@ -734,12 +706,40 @@ private predicate flowIntoReadNode(Node nodeFrom, FieldNode nodeTo) {
734706
)
735707
}
736708

709+
/** Holds if `node` holds an `Instruction` or `Operand` that has a register result. */
710+
private predicate hasRegisterResult(Node node) {
711+
node.asOperand() instanceof RegisterOperand
712+
or
713+
exists(Instruction i | i = node.asInstruction() and not i.hasMemoryResult())
714+
}
715+
716+
/**
717+
* Holds if there is a `Instruction` or `Operand` flow step from `nodeFrom` to `nodeTo` and both
718+
* `nodeFrom` and `nodeTo` wraps register results.
719+
*/
720+
private predicate registerInstructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) {
721+
hasRegisterResult(nodeFrom) and
722+
hasRegisterResult(nodeTo) and
723+
instructionOperandLocalFlowStep(nodeFrom, nodeTo)
724+
}
725+
726+
/**
727+
* INTERNAL: do not use.
728+
* Holds if `nodeFrom` has no incoming local `Operand` or `Instruction` register flow and `nodeFrom` can
729+
* reach `nodeTo` using only local `Instruction` or `Operand` register flow steps.
730+
*/
731+
bindingset[nodeTo]
732+
private predicate longestRegisterInstructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) {
733+
registerInstructionOperandLocalFlowStep*(nodeFrom, nodeTo) and
734+
not registerInstructionOperandLocalFlowStep(_, nodeFrom)
735+
}
736+
737737
/**
738738
* INTERNAL: do not use.
739739
* Holds if `nodeFrom` is an operand and `nodeTo` is an instruction node that uses this operand, or
740740
* if `nodeFrom` is an instruction and `nodeTo` is an operand that refers to this instruction.
741741
*/
742-
predicate instructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) {
742+
private predicate instructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) {
743743
// Operand -> Instruction flow
744744
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
745745
or

cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ edges
5858
| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 |
5959
| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 |
6060
| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 |
61-
| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | aliasing.cpp:101:21:101:22 | m1 [m1] |
61+
| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | aliasing.cpp:100:14:100:14 | Store [m1] |
6262
| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:5:98:6 | m1 [post update] [m1] |
63-
| aliasing.cpp:101:21:101:22 | m1 [m1] | aliasing.cpp:102:8:102:10 | * ... |
63+
| aliasing.cpp:100:14:100:14 | Store [m1] | aliasing.cpp:102:8:102:10 | * ... |
6464
| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] |
6565
| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:126:15:126:20 | taint_a_ptr output argument [array content] |
6666
| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] |
@@ -373,7 +373,7 @@ nodes
373373
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
374374
| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] |
375375
| aliasing.cpp:98:10:98:19 | call to user_input | semmle.label | call to user_input |
376-
| aliasing.cpp:101:21:101:22 | m1 [m1] | semmle.label | m1 [m1] |
376+
| aliasing.cpp:100:14:100:14 | Store [m1] | semmle.label | Store [m1] |
377377
| aliasing.cpp:102:8:102:10 | * ... | semmle.label | * ... |
378378
| aliasing.cpp:106:3:106:20 | Chi [array content] | semmle.label | Chi [array content] |
379379
| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] |

0 commit comments

Comments
 (0)