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

Skip to content

Commit 7a2b69f

Browse files
committed
C++: Add partial definition class backed by an IPA.
1 parent 2930128 commit 7a2b69f

1 file changed

Lines changed: 136 additions & 104 deletions

File tree

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

Lines changed: 136 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ private newtype TIRDataFlowNode =
1818
TVariableNode(Variable var) or
1919
// `FieldNodes` are used as targets of certain `storeStep`s to implement handling of stores to
2020
// nested structs.
21-
TFieldNode(FieldAddressInstruction field)
21+
TFieldNode(FieldAddressInstruction field) or
22+
TPartialDefinitionNode(PartialDefinition pd)
2223

2324
/**
2425
* A node in a data flow graph.
@@ -258,6 +259,23 @@ class FieldNode extends Node, TFieldNode {
258259

259260
override string toString() { result = this.getField().toString() }
260261
}
262+
263+
/**
264+
* INTERNAL: do not use. A `FieldNode` represents the state of an object after modifying one
265+
* of its fields.
266+
*/
267+
class PostUpdateFieldNode extends PartialDefinition {
268+
override FieldNode node;
269+
270+
override FieldNode getPreUpdateNode() { result = node }
271+
272+
override Expr getDefinedExpr() {
273+
result = node.getFieldInstruction().getObjectAddress().getUnconvertedResultExpression()
274+
}
275+
276+
Field getField() { result = node.getField() }
277+
}
278+
261279
/**
262280
* An expression, viewed as a node in a data flow graph.
263281
*/
@@ -395,11 +413,37 @@ deprecated class UninitializedNode extends Node {
395413
* This class exists to match the interface used by Java. There are currently no non-abstract
396414
* classes that extend it. When we implement field flow, we can revisit this.
397415
*/
398-
abstract class PostUpdateNode extends InstructionNode {
416+
abstract class PostUpdateNode extends Node {
399417
/**
400418
* Gets the node before the state update.
401419
*/
402420
abstract Node getPreUpdateNode();
421+
422+
override Function getFunction() { result = getPreUpdateNode().getFunction() }
423+
424+
override IRType getType() { result = getPreUpdateNode().getType() }
425+
426+
override Location getLocation() { result = getPreUpdateNode().getLocation() }
427+
}
428+
429+
private newtype TPartialDefinition =
430+
MkPartialDefinition(Node node) {
431+
isPointerStoreNode(node, _, _) or
432+
isArrayStoreNode(node, _, _) or
433+
node instanceof FieldNode
434+
}
435+
436+
/** INTERNAL: do not use. A partial definition of a node. */
437+
abstract class PartialDefinition extends TPartialDefinition {
438+
Node node;
439+
440+
PartialDefinition() { this = MkPartialDefinition(node) }
441+
442+
abstract Node getPreUpdateNode();
443+
444+
abstract Expr getDefinedExpr();
445+
446+
string toString() { result = node.toString() + " [partial definition]" }
403447
}
404448

405449
/**
@@ -415,132 +459,73 @@ abstract class PostUpdateNode extends InstructionNode {
415459
* setY(&x); // a partial definition of the object `x`.
416460
* ```
417461
*/
418-
abstract private class PartialDefinitionNode extends PostUpdateNode {
419-
abstract Expr getDefinedExpr();
420-
}
421-
422-
private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
423-
override ChiInstruction instr;
424-
StoreInstruction store;
462+
class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode {
463+
PartialDefinition pd;
425464

426-
ExplicitFieldStoreQualifierNode() {
427-
not instr.isResultConflated() and
428-
instr.getPartial() = store and
429-
(
430-
instr.getUpdatedInterval(_, _) or
431-
store.getDestinationAddress() instanceof FieldAddressInstruction
432-
)
433-
}
434-
435-
// By using an operand as the result of this predicate we avoid the dataflow inconsistency errors
436-
// caused by having multiple nodes sharing the same pre update node. This inconsistency error can cause
437-
// a tuple explosion in the big step dataflow relation since it can make many nodes be the entry node
438-
// into a big step.
439-
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
440-
441-
override Expr getDefinedExpr() {
442-
result =
443-
store
444-
.getDestinationAddress()
445-
.(FieldAddressInstruction)
446-
.getObjectAddress()
447-
.getUnconvertedResultExpression()
448-
}
449-
}
465+
PartialDefinitionNode() { this = TPartialDefinitionNode(pd) }
450466

451-
/**
452-
* Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to.
453-
* For instance, an update to a field of a struct containing only one field. For these cases we
454-
* attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case
455-
* (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`.
456-
*/
457-
private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode {
458-
override StoreInstruction instr;
467+
/** Gets the expression that is partially defined by this node, if any. */
468+
Expr getDefinedExpr() { result = pd.getDefinedExpr() }
459469

460-
ExplicitSingleFieldStoreQualifierNode() {
461-
not exists(ChiInstruction chi | chi.getPartial() = instr) and
462-
// Without this condition any store would create a `PostUpdateNode`.
463-
instr.getDestinationAddress() instanceof FieldAddressInstruction
464-
}
470+
override Node getPreUpdateNode() { result = pd.getPreUpdateNode() }
465471

466-
override Node getPreUpdateNode() { none() }
472+
PartialDefinition getPartialDefinition() { result = pd }
467473

468-
override Expr getDefinedExpr() {
469-
result =
470-
instr
471-
.getDestinationAddress()
472-
.(FieldAddressInstruction)
473-
.getObjectAddress()
474-
.getUnconvertedResultExpression()
475-
}
476-
}
477-
478-
private FieldAddressInstruction getFieldInstruction(Instruction instr) {
479-
result = instr or
480-
result = instr.(CopyValueInstruction).getUnary()
474+
override string toString() { result = getPreUpdateNode().toString() + " [post update]" }
481475
}
482476

483-
/**
484-
* The target of a `fieldStoreStepAfterArraySuppression` store step, which is used to convert
485-
* an `ArrayContent` to a `FieldContent` when the `WriteSideEffect` instruction stores
486-
* into a field. See the QLDoc for `suppressArrayRead` for an example of where such a conversion
487-
* is inserted.
488-
*/
489-
private class WriteSideEffectFieldStoreQualifierNode extends PartialDefinitionNode {
490-
override ChiInstruction instr;
491-
WriteSideEffectInstruction write;
492-
FieldAddressInstruction field;
493-
494-
WriteSideEffectFieldStoreQualifierNode() {
495-
not instr.isResultConflated() and
496-
instr.getPartial() = write and
497-
field = getFieldInstruction(write.getDestinationAddress())
498-
}
499-
500-
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
501-
502-
override Expr getDefinedExpr() {
503-
result = field.getObjectAddress().getUnconvertedResultExpression()
504-
}
477+
private predicate isArrayStoreNode(
478+
InstructionNode node, ChiInstruction chi, PointerAddInstruction add
479+
) {
480+
chi = node.getInstruction() and
481+
not chi.isResultConflated() and
482+
exists(StoreInstruction store |
483+
chi.getPartial() = store and
484+
add = store.getDestinationAddress()
485+
)
505486
}
506487

507488
/**
508489
* The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden
509490
* `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`.
510491
*/
511-
private class ArrayStoreNode extends PartialDefinitionNode {
512-
override ChiInstruction instr;
492+
private class ArrayStoreNode extends PartialDefinition {
493+
override InstructionNode node;
494+
ChiInstruction chi;
513495
PointerAddInstruction add;
514496

515-
ArrayStoreNode() {
516-
not instr.isResultConflated() and
517-
exists(StoreInstruction store |
518-
instr.getPartial() = store and
519-
add = store.getDestinationAddress()
520-
)
521-
}
497+
ArrayStoreNode() { isArrayStoreNode(node, chi, add) }
522498

523-
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
499+
override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() }
524500

525501
override Expr getDefinedExpr() { result = add.getLeft().getUnconvertedResultExpression() }
526502
}
527503

504+
private predicate isPointerStoreNode(InstructionNode node, ChiInstruction chi, LoadInstruction load) {
505+
chi = node.getInstruction() and
506+
not chi.isResultConflated() and
507+
exists(StoreInstruction store |
508+
chi.getPartial() = store and
509+
load = store.getDestinationAddress().(CopyValueInstruction).getUnary()
510+
)
511+
}
512+
528513
/**
529514
* The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden
530515
* `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`.
531516
*/
532-
private class PointerStoreNode extends PostUpdateNode {
533-
override ChiInstruction instr;
534-
535-
PointerStoreNode() {
536-
not instr.isResultConflated() and
537-
exists(StoreInstruction store |
538-
instr.getPartial() = store and
539-
store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction
540-
)
541-
}
517+
private class PointerStoreNode extends PartialDefinition {
518+
override InstructionNode node;
519+
ChiInstruction chi;
520+
LoadInstruction load;
521+
522+
PointerStoreNode() { isPointerStoreNode(node, chi, load) }
523+
524+
override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() }
542525

543-
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
526+
override Expr getDefinedExpr() {
527+
result = load.getSourceAddress().getUnconvertedResultExpression()
528+
}
544529
}
545530

546531
/**
@@ -553,7 +538,7 @@ private class PointerStoreNode extends PostUpdateNode {
553538
* returned. This node will have its `getArgument()` equal to `&x` and its
554539
* `getVariableAccess()` equal to `x`.
555540
*/
556-
class DefinitionByReferenceNode extends InstructionNode {
541+
class DefinitionByReferenceNode extends InstructionNode, PostUpdateNode {
557542
override WriteSideEffectInstruction instr;
558543

559544
/** Gets the unconverted argument corresponding to this node. */
@@ -581,6 +566,22 @@ class DefinitionByReferenceNode extends InstructionNode {
581566
not exists(instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget()) and
582567
result = "output argument"
583568
}
569+
570+
override Function getFunction() { result = instr.getEnclosingFunction() }
571+
572+
override IRType getType() { result = instr.getResultIRType() }
573+
574+
override Location getLocation() { result = instr.getLocation() }
575+
576+
// Make the read side effect's side effect operand the pre update node of this write side effect.
577+
// This ensures that we match up the parameter index of the parameter indirection's modification.
578+
override Node getPreUpdateNode() {
579+
exists(ReadSideEffectInstruction read |
580+
read.getPrimaryInstruction() = instr.getPrimaryInstruction() and
581+
read.getArgumentDef() = instr.getDestinationAddress() and
582+
result.asOperand() = read.getSideEffectOperand()
583+
)
584+
}
584585
}
585586

586587
/**
@@ -673,6 +674,35 @@ Node uninitializedNode(LocalVariable v) { none() }
673674
*/
674675
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) }
675676

677+
private predicate flowOutOfPostUpdate(PartialDefinitionNode nodeFrom, Node nodeTo) {
678+
// flow from the "outermost" field to the `ChiInstruction`, or `StoreInstruction`
679+
// if no `ChiInstruction` exists.
680+
exists(AddressOperand addressOperand, PostUpdateFieldNode pd |
681+
pd = nodeFrom.getPartialDefinition() and
682+
not exists(pd.getPreUpdateNode().getObjectNode()) and
683+
pd.getPreUpdateNode().getNextNode*() = getFieldNodeForFieldInstruction(addressOperand.getDef()) and
684+
(
685+
exists(ChiInstruction chi |
686+
nodeTo.asInstruction() = chi and
687+
chi.getPartial().getAnOperand() = addressOperand
688+
)
689+
or
690+
exists(StoreInstruction store |
691+
not exists(ChiInstruction chi | chi.getPartial() = store) and
692+
nodeTo.asInstruction() = store and
693+
store.getDestinationAddressOperand() = addressOperand
694+
)
695+
)
696+
)
697+
or
698+
// Note: This partial definition cannot be a `PostUpdateFieldNode` since these nodes do not have an
699+
// operand node as their pre update node.
700+
exists(PartialDefinition pd |
701+
pd = nodeFrom.getPartialDefinition() and
702+
nodeTo.asInstruction().(ChiInstruction).getTotalOperand() = pd.getPreUpdateNode().asOperand()
703+
)
704+
}
705+
676706
private predicate flowIntoReadNode(Node nodeFrom, Node nodeTo) {
677707
// flow from the "innermost" field to the load of that field.
678708
exists(FieldNode fieldNode | nodeTo = fieldNode |
@@ -715,6 +745,8 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
715745
simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand())
716746
or
717747
flowIntoReadNode(nodeFrom, nodeTo)
748+
or
749+
flowOutOfPostUpdate(nodeFrom, nodeTo)
718750
}
719751

720752
pragma[noinline]

0 commit comments

Comments
 (0)