diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 97118da117c8..9d354ba4cf1e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -192,32 +192,14 @@ private class ArrayContent extends Content, TArrayContent { override Type getType() { none() } } -private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) { - exists(FieldAddressInstruction fa, StoreInstruction store | - store = node2.asInstruction() and - store.getDestinationAddress() = fa and - store.getSourceValue() = node1.asInstruction() and - f.(FieldContent).getField() = fa.getField() - ) -} - -private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) { - exists(FieldAddressInstruction fa, StoreInstruction store | - node1.asInstruction() = store and - store.getDestinationAddress() = fa and - node2.asInstruction().(ChiInstruction).getPartial() = store and - f.(FieldContent).getField() = fa.getField() - ) -} - /** * Holds if data can flow from `node1` to `node2` via an assignment to `f`. * Thus, `node2` references an object with a field `f` that contains the * value of `node1`. */ -predicate storeStep(Node node1, Content f, PostUpdateNode node2) { - storeStepNoChi(node1, f, node2) or - storeStepChi(node1, f, node2) +predicate storeStep(Node node1, Content f, StoreStepNode node2) { + node2.getStoredValue() = node1 and + f.(FieldContent).getField() = node2.getAField() } /** @@ -225,13 +207,9 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { * Thus, `node1` references an object with a field `f` whose value ends up in * `node2`. */ -predicate readStep(Node node1, Content f, Node node2) { - exists(FieldAddressInstruction fa, LoadInstruction load | - load.getSourceAddress() = fa and - node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and - fa.getField() = f.(FieldContent).getField() and - load = node2.asInstruction() - ) +predicate readStep(Node node1, Content f, ReadStepNode node2) { + node2.getReadValue() = node1 and + f.(FieldContent).getField() = node2.getAField() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index beb3c8d954d1..8dd9ef4e2e2a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -13,7 +13,9 @@ private import semmle.code.cpp.models.interfaces.DataFlow private newtype TIRDataFlowNode = TInstructionNode(Instruction i) or - TVariableNode(Variable var) + TVariableNode(Variable var) or + TStoreNode(StoreChain chain) or + TLoadNode(LoadChain load) /** * A node in a data flow graph. @@ -271,7 +273,7 @@ deprecated class UninitializedNode extends Node { * This class exists to match the interface used by Java. There are currently no non-abstract * classes that extend it. When we implement field flow, we can revisit this. */ -abstract class PostUpdateNode extends InstructionNode { +abstract class PostUpdateNode extends Node { /** * Gets the node before the state update. */ @@ -286,59 +288,15 @@ abstract class PostUpdateNode extends InstructionNode { * value, but does not necessarily replace it entirely. For example: * ``` * x.y = 1; // a partial definition of the object `x`. - * x.y.z = 1; // a partial definition of the object `x.y`. + * x.y.z = 1; // a partial definition of the objects `x.y` and `x`. * x.setY(1); // a partial definition of the object `x`. * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { +abstract private class PartialDefinitionNode extends PostUpdateNode { abstract Expr getDefinedExpr(); } -private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { - override ChiInstruction instr; - FieldAddressInstruction field; - - ExplicitFieldStoreQualifierNode() { - not instr.isResultConflated() and - exists(StoreInstruction store | - instr.getPartial() = store and field = store.getDestinationAddress() - ) - } - - // There might be multiple `ChiInstructions` that has a particular instruction as - // the total operand - so this definition gives consistency errors in - // DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications - // this consistency failure has. - override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } - - override Expr getDefinedExpr() { - result = field.getObjectAddress().getUnconvertedResultExpression() - } -} - -/** - * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. - * For instance, an update to a field of a struct containing only one field. For these cases we - * attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case - * (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`. - */ -private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { - override StoreInstruction instr; - FieldAddressInstruction field; - - ExplicitSingleFieldStoreQualifierNode() { - field = instr.getDestinationAddress() and - not exists(ChiInstruction chi | chi.getPartial() = instr) - } - - override Node getPreUpdateNode() { none() } - - override Expr getDefinedExpr() { - result = field.getObjectAddress().getUnconvertedResultExpression() - } -} - /** * A node that represents the value of a variable after a function call that * may have changed the variable because it's passed by reference. @@ -430,6 +388,413 @@ class VariableNode extends Node, TVariableNode { override string toString() { result = v.toString() } } +/** The target node of a `readStep`. */ +abstract class ReadStepNode extends Node { + /** Get the field that is read. */ + abstract Field getAField(); + + /** Get the node representing the value that is read. */ + abstract Node getReadValue(); +} + +/** The target node of a `storeStep`. */ +abstract class StoreStepNode extends PostUpdateNode { + /** Get the field that is stored into. */ + abstract Field getAField(); + + /** Get the node representing the value that is stored. */ + abstract Node getStoredValue(); +} + +/** + * Sometimes a sequence of `FieldAddressInstruction`s does not end with a `StoreInstruction`. + * This class abstracts out the information needed to end a `StoreChain`. + */ +abstract private class StoreChainEndInstruction extends Instruction { + abstract FieldAddressInstruction getFieldInstruction(); + + abstract Instruction getBeginInstruction(); + + abstract Node getPreUpdateNode(); +} + +/** + * A `StoreInstruction` that ends a sequence of `FieldAddressInstruction`s. + */ +private class StoreChainEndInstructionStoreWithChi extends StoreChainEndInstruction, ChiInstruction { + StoreInstruction store; + FieldAddressInstruction fi; + + StoreChainEndInstructionStoreWithChi() { + not this.isResultConflated() and + this.getPartial() = store and + fi = skipConversion*(store.getDestinationAddress()) + } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Node getPreUpdateNode() { result.asInstruction() = this.getTotal() } + + override Instruction getBeginInstruction() { result = store } +} + +/** + * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. + * For instance, an update to a field of a struct containing only one field. For these cases we + * attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case + * (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`. + */ +private class StoreChainEndInstructionStoreWithoutChi extends StoreChainEndInstruction, + StoreInstruction { + FieldAddressInstruction fi; + + StoreChainEndInstructionStoreWithoutChi() { + not exists(ChiInstruction chi | chi.getPartial() = this) and + fi = skipConversion*(this.getDestinationAddress()) + } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Node getPreUpdateNode() { none() } + + override Instruction getBeginInstruction() { result = this.getSourceValue() } +} + +/** + * When traversing dependencies between an instruction and its operands + * it is sometimes convenient to ignore certain instructions. For instance, + * the `LoadChain` for `((B&)a.b).c` inserts a `CopyValueInstruction` + * between the computed address for `b` and the `FieldAddressInstruction` + * for `c`. + */ +private Instruction skipConversion(Instruction instr) { + result = instr.(CopyInstruction).getSourceValue() + or + result = instr.(ConvertInstruction).getUnary() + or + result = instr.(CheckedConvertOrNullInstruction).getUnary() + or + result = instr.(InheritanceConversionInstruction).getUnary() +} + +/** + * Ends a `StoreChain` with a `WriteSideEffectInstruction` such that we build up + * the correct access paths. For example in: + * ``` + * void setter(B *b, int data) { + * b->c = data; + * } + * ... + * setter(&a.b, source()); + * sink(a.b.c) + * ``` + * In order to register `a.b.c` as a `readStep`, the access path must + * contain `[a, b, c]`, and thus the access path must be `[a, b]` + * before entering `setter`. + */ +private class StoreChainEndInstructionSideEffect extends StoreChainEndInstruction, ChiInstruction { + WriteSideEffectInstruction sideEffect; + FieldAddressInstruction fi; + + StoreChainEndInstructionSideEffect() { + not this.isResultConflated() and + this.getPartial() = sideEffect and + fi = skipConversion*(sideEffect.getArgumentDef()) + } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Node getPreUpdateNode() { result.asInstruction() = this.getTotal() } + + override Instruction getBeginInstruction() { result = sideEffect } +} + +private newtype TStoreChain = + TStoreChainConsNil(FieldAddressInstruction f, StoreChainEndInstruction end) { + end.getFieldInstruction() = f + } or + TStoreChainConsCons(FieldAddressInstruction f, TStoreChain next) { + exists(FieldAddressInstruction g | skipConversion*(g.getObjectAddress()) = f | + next = TStoreChainConsCons(g, _) or + next = TStoreChainConsNil(g, _) + ) + } + +/** + * A `StoreChain` represents a series of field lookups that compute the destination of a store. + * For example, given an assignment such as `a.b.c = x`, there are two `StoreChain`s: + * One corresponding to the field `b`, and one corresponding to the field `c`. Here, `b` is the parent + * `StoreChain` of `c`. + */ +private class StoreChain extends TStoreChain { + string toString() { none() } + + /** + * Gets the parent of this `StoreChain`, if any. For example, for the assignment + * ``` + * a.b.c = x; + * ``` + * the parent of `c` is `b`, and `b` has no parent. + */ + final StoreChainConsCons getParent() { result.getChild() = this } + + /** Gets the child of this `StoreChain`, if any. */ + StoreChain getChild() { none() } + + /** + * Gets the instruction that receives flow from the outermost `StoreChain` of this chain (i.e., + * the `StoreChain` with no parent). + */ + StoreChainEndInstruction getEndInstruction() { none() } + + /** + * Gets the instruction that flows to the innermost `StoreChain` of this chain (i.e., + * the `StoreChain` with no child). + */ + Instruction getBeginInstruction() { none() } + + /** Gets the `FieldAddressInstruction` of this `StoreChain` */ + FieldAddressInstruction getFieldInstruction() { none() } + + /** Gets the `FieldAddressInstruction` of any `StoreChain` in this chain. */ + FieldAddressInstruction getAFieldInstruction() { none() } + + final Location getLocation() { result = getFieldInstruction().getLocation() } +} + +private class StoreChainConsNil extends StoreChain, TStoreChainConsNil { + FieldAddressInstruction fi; + StoreChainEndInstruction end; + + StoreChainConsNil() { this = TStoreChainConsNil(fi, end) } + + override string toString() { result = fi.getField().toString() } + + override StoreChainEndInstruction getEndInstruction() { result = end } + + override Instruction getBeginInstruction() { result = end.getBeginInstruction() } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override FieldAddressInstruction getAFieldInstruction() { result = fi } +} + +private class StoreChainConsCons extends StoreChain, TStoreChainConsCons { + FieldAddressInstruction fi; + StoreChain next; + + StoreChainConsCons() { this = TStoreChainConsCons(fi, next) } + + override string toString() { result = fi.getField().toString() + "." + next.toString() } + + override StoreChain getChild() { result = next } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override FieldAddressInstruction getAFieldInstruction() { + result = [fi, next.getAFieldInstruction()] + } + + override StoreChainEndInstruction getEndInstruction() { result = next.getEndInstruction() } + + override Instruction getBeginInstruction() { result = next.getBeginInstruction() } +} + +private newtype TLoadChain = + TLoadChainConsNil(FieldAddressInstruction fi, LoadChainEndInstruction end) { + end.getFieldInstruction() = fi + } or + TLoadChainConsCons(FieldAddressInstruction fi, TLoadChain next) { + exists(FieldAddressInstruction nextFi | skipConversion*(nextFi.getObjectAddress()) = fi | + next = TLoadChainConsCons(nextFi, _) or + next = TLoadChainConsNil(nextFi, _) + ) + } + +/** This class abstracts out the information needed to end a `LoadChain`. */ +abstract private class LoadChainEndInstruction extends Instruction { + abstract FieldAddressInstruction getFieldInstruction(); + + abstract Instruction getReadValue(); +} + +/** + * A `LoadInstruction` that ends a sequence of `FieldAddressInstruction`s. + */ +private class LoadChainEndInstructionLoad extends LoadChainEndInstruction, LoadInstruction { + FieldAddressInstruction fi; + + LoadChainEndInstructionLoad() { fi = skipConversion*(this.getSourceAddress()) } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Instruction getReadValue() { result = getSourceValueOperand().getAnyDef() } +} + +/** + * Ends a `LoadChain` with a `ReadSideEffectInstruction`. This ensures that we pop content from the + * access path when passing an argument that reads a field. For example in: + * ``` + * void read_f(Inner* inner) { + * sink(inner->f); + * } + * ... + * outer.inner.f = taint(); + * read_f(&outer.inner); + * ``` + * In order to register `inner->f` as a `readStep`, the head of the access path must + * be `f`, and thus reading `&outer.inner` must pop `inner` from the access path + * before entering `read_f`. + */ +private class LoadChainEndInstructionSideEffect extends LoadChainEndInstruction, + ReadSideEffectInstruction { + FieldAddressInstruction fi; + + LoadChainEndInstructionSideEffect() { fi = skipConversion*(this.getArgumentDef()) } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Instruction getReadValue() { result = getSideEffectOperand().getAnyDef() } +} + +/** + * A `LoadChain` represents a series of field lookups that compute the source address of a load. + * For example, given the field lookup in `f(a.b.c)`, there are two `LoadChains`s: + * One corresponding to the field `b`, and one corresponding to the field `c`. Here, `b` is the parent + * `LoadChain` of `c`. + */ +private class LoadChain extends TLoadChain { + string toString() { none() } + + /** + * Gets the instruction that receives flow from the innermost `LoadChain` of this chain (i.e., + * the `LoadChain` with no child). + */ + LoadChainEndInstruction getEndInstruction() { none() } + + /** + * Gets the parent of this `LoadChain`, if any. For example in `f(a.b.c)` the parent of `c` is `b`, + * and `b` has no parent. + */ + final LoadChainConsCons getParent() { result.getChild() = this } + + /** Gets the child of this `LoadChain`, if any. */ + LoadChain getChild() { none() } + + /** Gets the `FieldAddressInstruction` of this `LoadChain` */ + FieldAddressInstruction getFieldInstruction() { none() } + + final Location getLocation() { result = getFieldInstruction().getLocation() } +} + +private class LoadChainConsNil extends LoadChain, TLoadChainConsNil { + FieldAddressInstruction fi; + LoadChainEndInstruction end; + + LoadChainConsNil() { this = TLoadChainConsNil(fi, end) } + + override string toString() { result = fi.getField().toString() } + + override LoadChainEndInstruction getEndInstruction() { result = end } + + override FieldAddressInstruction getFieldInstruction() { result = fi } +} + +private class LoadChainConsCons extends LoadChain, TLoadChainConsCons { + FieldAddressInstruction fi; + LoadChain next; + + LoadChainConsCons() { this = TLoadChainConsCons(fi, next) } + + override string toString() { result = fi.getField().toString() + "." + next.toString() } + + override LoadChainEndInstruction getEndInstruction() { result = next.getEndInstruction() } + + override LoadChain getChild() { result = next } + + override FieldAddressInstruction getFieldInstruction() { result = fi } +} + +/** + * A dataflow node generated by a partial definition. + * The `StoreNode` class extends `ReadStepNode` to participate in reverse read steps. + * A reverse read is a store step that is "inferred" by the DataFlow library. For example in the + * assignment: + * ``` + * a.b.c = x; + * ``` + * Here, the access path after the store must reflect that a value has been stored into the field `c` of + * the object at field `b`. The field `c` is added to the access path through a `storeStep`, and the + * field `b` is inferred by the DataFlow library because there's a read step (reading the field `b`) from + * the pre update node for `b.c` to the pre update node for `c`. + */ +private class StoreNode extends TStoreNode, StoreStepNode, ReadStepNode, PartialDefinitionNode { + StoreChain storeChain; + + StoreNode() { this = TStoreNode(storeChain) } + + override string toString() { result = storeChain.toString() } + + StoreChain getStoreChain() { result = storeChain } + + override Node getPreUpdateNode() { + result.(StoreNode).getStoreChain() = storeChain.getParent() + or + not exists(storeChain.getParent()) and + result = storeChain.getEndInstruction().getPreUpdateNode() + } + + override Field getAField() { result = storeChain.getFieldInstruction().getField() } + + override Node getStoredValue() { + // Only the `StoreNode` attached to the end of the `StoreChain` has a `getStoredValue()`, so + // this is the only `StoreNode` that matches storeStep. + not exists(storeChain.getChild()) and result.asInstruction() = storeChain.getBeginInstruction() + } + + override Node getReadValue() { result = getPreUpdateNode() } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = storeChain.getEndInstruction().getEnclosingFunction() } + + override Type getType() { result = storeChain.getEndInstruction().getResultType() } + + override Location getLocation() { result = storeChain.getEndInstruction().getLocation() } + + override Expr getDefinedExpr() { + result = storeChain.getAFieldInstruction().getObjectAddress().getUnconvertedResultExpression() + } +} + +/** A dataflow node generated by loading from an address computed by a sequence of fields lookups. */ +private class LoadNode extends TLoadNode, ReadStepNode { + LoadChain loadChain; + + LoadNode() { this = TLoadNode(loadChain) } + + override Field getAField() { result = loadChain.getFieldInstruction().getField() } + + override Node getReadValue() { + result.(LoadNode).getLoadChain() = loadChain.getParent() + or + not exists(loadChain.getParent()) and + result.asInstruction() = loadChain.getEndInstruction().getReadValue() + } + + LoadChain getLoadChain() { result = loadChain } + + override string toString() { result = loadChain.toString() } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = loadChain.getEndInstruction().getEnclosingFunction() } + + override Type getType() { result = loadChain.getEndInstruction().getResultType() } + + override Location getLocation() { result = loadChain.getEndInstruction().getLocation() } +} + /** * Gets the node corresponding to `instr`. */ @@ -483,6 +848,22 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) + or + // When flow has gone all the way through the chain of field accesses + // `[f1,f2, ..., fn]` (from right to left) we add flow from f1 to the end instruction. + exists(StoreNode synthFrom | + synthFrom = nodeFrom and + not exists(synthFrom.getStoreChain().getParent()) and + synthFrom.getStoreChain().getEndInstruction() = nodeTo.asInstruction() + ) + or + // When flow has gone all the way through the chain of field accesses + // `[f1, f2, ..., fn]` (from left to right) we add flow from fn to the end instruction. + exists(LoadNode synthFrom | + synthFrom = nodeFrom and + not exists(synthFrom.getLoadChain().getChild()) and + synthFrom.getLoadChain().getEndInstruction() = nodeTo.asInstruction() + ) } pragma[noinline] diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index ba7e3bc01257..8a8f47145ccc 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -20,7 +20,7 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:65:5:65:22 | i | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 69c088fb260d..fa549f356784 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -1,34 +1,40 @@ edges | A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store | -| A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | -| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] | +| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | a [a] | +| A.cpp:100:5:100:13 | a [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | A.cpp:103:14:103:14 | *c [a] | | A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | -| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | | A.cpp:107:16:107:16 | a | A.cpp:107:12:107:16 | (void *)... | +| A.cpp:107:16:107:16 | a | A.cpp:107:16:107:16 | a | | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | +| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | c [c] | +| A.cpp:142:7:142:20 | c [c] | A.cpp:142:7:142:20 | Chi [c] | | A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | | A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | -| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | | A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | | A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... | +| A.cpp:154:13:154:13 | c | A.cpp:154:13:154:13 | c | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | +| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | m1 [m1] | +| aliasing.cpp:9:3:9:22 | m1 [m1] | aliasing.cpp:9:3:9:22 | Chi [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | | aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | m1 [m1] | +| aliasing.cpp:13:3:13:21 | m1 [m1] | aliasing.cpp:13:3:13:21 | Chi [m1] | | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store | | aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | | aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | +| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:30:11:30:12 | m1 | | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | -| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] | +| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | m1 [m1] | +| aliasing.cpp:60:3:60:22 | m1 [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store | | aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:62:14:62:15 | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | @@ -37,42 +43,113 @@ edges | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | +| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | a [a] | +| by_reference.cpp:84:3:84:25 | a [a] | by_reference.cpp:84:3:84:25 | Chi [a] | | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | a [a] | +| by_reference.cpp:88:3:88:24 | a [a] | by_reference.cpp:88:3:88:24 | Chi [a] | | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store | -| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | -| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | -| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | -| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | -| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | -| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | -| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | -| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | -| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | -| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | +| by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] | by_reference.cpp:110:27:110:27 | inner_nested.a [a] | +| by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] | by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] | +| by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] | by_reference.cpp:114:29:114:29 | inner_nested.a [a] | +| by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] | by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] | +| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:110:27:110:27 | inner_nested.a [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:114:29:114:29 | inner_nested.a [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] | by_reference.cpp:130:27:130:27 | inner_nested.a [a] | +| by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] | by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] | +| by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] | by_reference.cpp:134:29:134:29 | inner_nested.a [a] | +| by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] | by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] | +| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:130:27:130:27 | inner_nested.a [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:134:29:134:29 | inner_nested.a [a] | by_reference.cpp:134:29:134:29 | a | +| simple.cpp:65:5:65:22 | i [i] | simple.cpp:66:12:66:12 | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | i [i] | | simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | -| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | -| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | Chi [f1] | +| simple.cpp:67:13:67:13 | i | simple.cpp:67:13:67:13 | i | +| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | f1 [f1] | +| simple.cpp:83:9:83:28 | f1 [f1] | simple.cpp:83:9:83:28 | f2.f1 [f2, f1] | +| simple.cpp:83:9:83:28 | f2.f1 [f2, f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] | | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store | -| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| simple.cpp:108:30:108:31 | d2 [d1_2, y] | simple.cpp:111:18:111:18 | d1_2.y [y] | +| simple.cpp:111:18:111:18 | d1_2.y [y] | simple.cpp:111:18:111:18 | y | +| simple.cpp:111:18:111:18 | y | simple.cpp:111:18:111:18 | y | +| simple.cpp:114:37:114:38 | *d2 [d1_2, y] | simple.cpp:117:19:117:19 | d1_2.y [y] | +| simple.cpp:117:19:117:19 | d1_2.y [y] | simple.cpp:117:19:117:19 | y | +| simple.cpp:117:19:117:19 | y | simple.cpp:117:19:117:19 | y | +| simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | +| simple.cpp:122:5:122:33 | Store | simple.cpp:122:5:122:33 | x [x] | +| simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | x [x] | simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | +| simple.cpp:122:22:122:31 | call to user_input | simple.cpp:122:5:122:33 | Store | +| simple.cpp:123:27:123:30 | Store [d1_1, x] | simple.cpp:124:20:124:20 | d1_1.x [x] | +| simple.cpp:123:27:123:30 | Store [d1_1, x] | simple.cpp:130:15:130:15 | d1_1.x [x] | +| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:123:27:123:30 | Store [d1_1, x] | +| simple.cpp:124:20:124:20 | d1_1.x [x] | simple.cpp:124:20:124:20 | x | +| simple.cpp:124:20:124:20 | x | simple.cpp:124:20:124:20 | x | +| simple.cpp:130:15:130:15 | d1_1.x [x] | simple.cpp:130:15:130:15 | x | +| simple.cpp:130:15:130:15 | x | simple.cpp:130:15:130:15 | x | +| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | +| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | +| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | +| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | +| simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | +| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | +| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | +| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | +| simple.cpp:136:31:136:40 | call to user_input | simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | +| simple.cpp:139:23:139:23 | d1_2.y [y] | simple.cpp:139:23:139:23 | y | +| simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | simple.cpp:139:23:139:23 | d1_2.y [y] | +| simple.cpp:139:23:139:23 | y | simple.cpp:139:23:139:23 | y | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:108:30:108:31 | d2 [d1_2, y] | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | +| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | simple.cpp:114:37:114:38 | *d2 [d1_2, y] | +| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | +| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | +| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | +| simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | +| simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | simple.cpp:114:37:114:38 | *d2 [d1_2, y] | +| simple.cpp:159:20:159:24 | *inner [f] | simple.cpp:161:17:161:17 | f | +| simple.cpp:161:17:161:17 | f | simple.cpp:161:17:161:17 | f | +| simple.cpp:167:5:167:32 | Chi [inner, f] | simple.cpp:168:12:168:23 | inner [f] | +| simple.cpp:167:5:167:32 | Store | simple.cpp:167:5:167:32 | f [f] | +| simple.cpp:167:5:167:32 | f [f] | simple.cpp:167:5:167:32 | inner.f [inner, f] | +| simple.cpp:167:5:167:32 | inner.f [inner, f] | simple.cpp:167:5:167:32 | Chi [inner, f] | +| simple.cpp:167:21:167:30 | call to user_input | simple.cpp:167:5:167:32 | Store | +| simple.cpp:168:12:168:23 | Argument 0 indirection [f] | simple.cpp:159:20:159:24 | *inner [f] | +| simple.cpp:168:12:168:23 | inner [f] | simple.cpp:168:12:168:23 | Argument 0 indirection [f] | | struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | -| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | -| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | Chi [a] | +| struct_init.c:15:12:15:12 | a | struct_init.c:15:12:15:12 | a | +| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | a [a] | +| struct_init.c:20:20:20:29 | a [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Store | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | -| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | -| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | Chi [a] | +| struct_init.c:27:7:27:16 | Chi [nestedAB, a] | struct_init.c:27:21:27:21 | nestedAB.b [a] | +| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | a [a] | +| struct_init.c:27:7:27:16 | a [a] | struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Store | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | +| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | struct_init.c:27:7:27:16 | Chi [nestedAB, a] | +| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | struct_init.c:28:5:28:7 | Chi [nestedAB, a] | +| struct_init.c:27:21:27:21 | nestedAB.b [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | +| struct_init.c:28:5:28:7 | Chi [nestedAB, a] | struct_init.c:36:10:36:24 | nestedAB [a] | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | +| struct_init.c:36:10:36:24 | nestedAB [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | nodes | A.cpp:98:12:98:18 | new | semmle.label | new | -| A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | | A.cpp:100:5:100:13 | Store | semmle.label | Store | +| A.cpp:100:5:100:13 | a [a] | semmle.label | a [a] | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | | A.cpp:107:12:107:16 | (void *)... | semmle.label | (void *)... | @@ -80,6 +157,7 @@ nodes | A.cpp:107:16:107:16 | a | semmle.label | a | | A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | | A.cpp:142:7:142:20 | Store | semmle.label | Store | +| A.cpp:142:7:142:20 | c [c] | semmle.label | c [c] | | A.cpp:142:14:142:20 | new | semmle.label | new | | A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | | A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | @@ -88,25 +166,30 @@ nodes | A.cpp:154:13:154:13 | c | semmle.label | c | | aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | +| aliasing.cpp:9:3:9:22 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:13:3:13:21 | Store | semmle.label | Store | +| aliasing.cpp:13:3:13:21 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | | aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | | aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | +| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | +| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | | aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | | aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:60:3:60:22 | Store | semmle.label | Store | +| aliasing.cpp:60:3:60:22 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | +| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input | @@ -119,43 +202,112 @@ nodes | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | +| by_reference.cpp:84:3:84:25 | a [a] | semmle.label | a [a] | | by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:88:3:88:24 | Store | semmle.label | Store | +| by_reference.cpp:88:3:88:24 | a [a] | semmle.label | a [a] | | by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | +| by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | +| by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | | by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:110:27:110:27 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | | by_reference.cpp:114:29:114:29 | a | semmle.label | a | -| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:114:29:114:29 | a | semmle.label | a | +| by_reference.cpp:114:29:114:29 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | +| by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | +| by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | +| by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:130:27:130:27 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | +| by_reference.cpp:134:29:134:29 | a | semmle.label | a | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | -| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | +| by_reference.cpp:134:29:134:29 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | +| simple.cpp:65:5:65:22 | i [i] | semmle.label | i [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | | simple.cpp:67:13:67:13 | i | semmle.label | i | -| simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | +| simple.cpp:67:13:67:13 | i | semmle.label | i | | simple.cpp:83:9:83:28 | Store | semmle.label | Store | +| simple.cpp:83:9:83:28 | f1 [f1] | semmle.label | f1 [f1] | +| simple.cpp:83:9:83:28 | f2.f1 [f2, f1] | semmle.label | f2.f1 [f2, f1] | | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | -| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | semmle.label | Argument -1 indirection [f1] | +| simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] | semmle.label | Argument -1 indirection [f2, f1] | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | +| simple.cpp:108:30:108:31 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | +| simple.cpp:111:18:111:18 | d1_2.y [y] | semmle.label | d1_2.y [y] | +| simple.cpp:111:18:111:18 | y | semmle.label | y | +| simple.cpp:111:18:111:18 | y | semmle.label | y | +| simple.cpp:114:37:114:38 | *d2 [d1_2, y] | semmle.label | *d2 [d1_2, y] | +| simple.cpp:117:19:117:19 | d1_2.y [y] | semmle.label | d1_2.y [y] | +| simple.cpp:117:19:117:19 | y | semmle.label | y | +| simple.cpp:117:19:117:19 | y | semmle.label | y | +| simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | semmle.label | Chi [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | Store | semmle.label | Store | +| simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | semmle.label | d1_1.x [d1_1, x] | +| simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | semmle.label | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | x [x] | semmle.label | x [x] | +| simple.cpp:122:22:122:31 | call to user_input | semmle.label | call to user_input | +| simple.cpp:123:27:123:30 | Store [d1_1, x] | semmle.label | Store [d1_1, x] | +| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | +| simple.cpp:124:20:124:20 | d1_1.x [x] | semmle.label | d1_1.x [x] | +| simple.cpp:124:20:124:20 | x | semmle.label | x | +| simple.cpp:124:20:124:20 | x | semmle.label | x | +| simple.cpp:130:15:130:15 | d1_1.x [x] | semmle.label | d1_1.x [x] | +| simple.cpp:130:15:130:15 | x | semmle.label | x | +| simple.cpp:130:15:130:15 | x | semmle.label | x | +| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | semmle.label | Chi [d2_1, d1_2, ... (3)] | +| simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | semmle.label | d2_1 [d2_1, d1_2, ... (3)] | +| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | semmle.label | write_to_d1_2_y output argument [d1_2, y] | +| simple.cpp:136:31:136:40 | call to user_input | semmle.label | call to user_input | +| simple.cpp:139:23:139:23 | d1_2.y [y] | semmle.label | d1_2.y [y] | +| simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | semmle.label | d2_1.d1_2.y [d1_2, y] | +| simple.cpp:139:23:139:23 | y | semmle.label | y | +| simple.cpp:139:23:139:23 | y | semmle.label | y | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | semmle.label | Argument 0 indirection [d1_2, y] | +| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | semmle.label | read_from_y_deref output argument [d1_2, y] | +| simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | semmle.label | Argument 0 indirection [d1_2, y] | +| simple.cpp:159:20:159:24 | *inner [f] | semmle.label | *inner [f] | +| simple.cpp:161:17:161:17 | f | semmle.label | f | +| simple.cpp:161:17:161:17 | f | semmle.label | f | +| simple.cpp:167:5:167:32 | Chi [inner, f] | semmle.label | Chi [inner, f] | +| simple.cpp:167:5:167:32 | Store | semmle.label | Store | +| simple.cpp:167:5:167:32 | f [f] | semmle.label | f [f] | +| simple.cpp:167:5:167:32 | inner.f [inner, f] | semmle.label | inner.f [inner, f] | +| simple.cpp:167:21:167:30 | call to user_input | semmle.label | call to user_input | +| simple.cpp:168:12:168:23 | Argument 0 indirection [f] | semmle.label | Argument 0 indirection [f] | +| simple.cpp:168:12:168:23 | inner [f] | semmle.label | inner [f] | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | -| struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] | +| struct_init.c:15:12:15:12 | a | semmle.label | a | | struct_init.c:20:20:20:29 | Store | semmle.label | Store | +| struct_init.c:20:20:20:29 | a [a] | semmle.label | a [a] | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | -| struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] | +| struct_init.c:27:7:27:16 | Chi [nestedAB, a] | semmle.label | Chi [nestedAB, a] | | struct_init.c:27:7:27:16 | Store | semmle.label | Store | +| struct_init.c:27:7:27:16 | a [a] | semmle.label | a [a] | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | +| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | semmle.label | nestedAB.a [nestedAB, a] | +| struct_init.c:27:21:27:21 | nestedAB.b [a] | semmle.label | nestedAB.b [a] | +| struct_init.c:28:5:28:7 | Chi [nestedAB, a] | semmle.label | Chi [nestedAB, a] | | struct_init.c:31:23:31:23 | a | semmle.label | a | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | +| struct_init.c:36:10:36:24 | nestedAB [a] | semmle.label | nestedAB [a] | #select | A.cpp:107:12:107:16 | (void *)... | A.cpp:98:12:98:18 | new | A.cpp:107:12:107:16 | (void *)... | (void *)... flows from $@ | A.cpp:98:12:98:18 | new | new | | A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | @@ -176,6 +328,12 @@ nodes | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | +| simple.cpp:111:18:111:18 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:111:18:111:18 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:117:19:117:19 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:117:19:117:19 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:124:20:124:20 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:124:20:124:20 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | +| simple.cpp:130:15:130:15 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:130:15:130:15 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | +| simple.cpp:139:23:139:23 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:139:23:139:23 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:161:17:161:17 | f | simple.cpp:167:21:167:30 | call to user_input | simple.cpp:161:17:161:17 | f | f flows from $@ | simple.cpp:167:21:167:30 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 889f789da8d7..28c688cf161d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -155,7 +155,6 @@ | aliasing.cpp:72:5:72:6 | m1 | AST only | | aliasing.cpp:79:6:79:7 | m1 | AST only | | aliasing.cpp:86:5:86:6 | m1 | AST only | -| aliasing.cpp:92:3:92:3 | w | AST only | | aliasing.cpp:92:7:92:8 | m1 | AST only | | by_reference.cpp:12:8:12:8 | a | AST only | | by_reference.cpp:16:11:16:11 | a | AST only | @@ -178,17 +177,13 @@ | by_reference.cpp:84:10:84:10 | a | AST only | | by_reference.cpp:88:9:88:9 | a | AST only | | by_reference.cpp:102:21:102:39 | & ... | AST only | -| by_reference.cpp:102:22:102:26 | outer | AST only | | by_reference.cpp:103:21:103:25 | outer | AST only | | by_reference.cpp:103:27:103:35 | inner_ptr | AST only | | by_reference.cpp:104:15:104:22 | & ... | AST only | -| by_reference.cpp:104:16:104:20 | outer | AST only | | by_reference.cpp:106:21:106:41 | & ... | AST only | -| by_reference.cpp:106:22:106:27 | pouter | AST only | | by_reference.cpp:107:21:107:26 | pouter | AST only | | by_reference.cpp:107:29:107:37 | inner_ptr | AST only | | by_reference.cpp:108:15:108:24 | & ... | AST only | -| by_reference.cpp:108:16:108:21 | pouter | AST only | | by_reference.cpp:110:8:110:12 | outer | AST only | | by_reference.cpp:110:14:110:25 | inner_nested | AST only | | by_reference.cpp:110:27:110:27 | a | AST only | @@ -205,17 +200,13 @@ | by_reference.cpp:115:27:115:27 | a | AST only | | by_reference.cpp:116:8:116:13 | pouter | AST only | | by_reference.cpp:116:16:116:16 | a | AST only | -| by_reference.cpp:122:21:122:25 | outer | AST only | | by_reference.cpp:122:27:122:38 | inner_nested | AST only | | by_reference.cpp:123:21:123:36 | * ... | AST only | | by_reference.cpp:123:22:123:26 | outer | AST only | -| by_reference.cpp:124:15:124:19 | outer | AST only | | by_reference.cpp:124:21:124:21 | a | AST only | -| by_reference.cpp:126:21:126:26 | pouter | AST only | | by_reference.cpp:126:29:126:40 | inner_nested | AST only | | by_reference.cpp:127:21:127:38 | * ... | AST only | | by_reference.cpp:127:22:127:27 | pouter | AST only | -| by_reference.cpp:128:15:128:20 | pouter | AST only | | by_reference.cpp:128:23:128:23 | a | AST only | | by_reference.cpp:130:8:130:12 | outer | AST only | | by_reference.cpp:130:14:130:25 | inner_nested | AST only | @@ -235,23 +226,11 @@ | by_reference.cpp:136:16:136:16 | a | AST only | | complex.cpp:11:22:11:23 | a_ | AST only | | complex.cpp:12:22:12:23 | b_ | AST only | -| complex.cpp:51:8:51:8 | b | AST only | -| complex.cpp:51:10:51:14 | inner | AST only | | complex.cpp:51:16:51:16 | f | AST only | -| complex.cpp:52:8:52:8 | b | AST only | -| complex.cpp:52:10:52:14 | inner | AST only | | complex.cpp:52:16:52:16 | f | AST only | -| complex.cpp:62:3:62:4 | b1 | AST only | -| complex.cpp:62:6:62:10 | inner | AST only | | complex.cpp:62:12:62:12 | f | AST only | -| complex.cpp:63:3:63:4 | b2 | AST only | -| complex.cpp:63:6:63:10 | inner | AST only | | complex.cpp:63:12:63:12 | f | AST only | -| complex.cpp:64:3:64:4 | b3 | AST only | -| complex.cpp:64:6:64:10 | inner | AST only | | complex.cpp:64:12:64:12 | f | AST only | -| complex.cpp:65:3:65:4 | b3 | AST only | -| complex.cpp:65:6:65:10 | inner | AST only | | complex.cpp:65:12:65:12 | f | AST only | | complex.cpp:68:7:68:8 | b1 | AST only | | complex.cpp:71:7:71:8 | b2 | AST only | @@ -317,9 +296,15 @@ | simple.cpp:51:9:51:9 | h | AST only | | simple.cpp:54:9:54:9 | i | AST only | | simple.cpp:65:7:65:7 | i | AST only | -| simple.cpp:83:9:83:10 | this | AST only | | simple.cpp:83:12:83:13 | f1 | AST only | | simple.cpp:84:14:84:20 | this | AST only | +| simple.cpp:105:14:105:14 | y | AST only | +| simple.cpp:122:18:122:18 | x | AST only | +| simple.cpp:136:21:136:28 | & ... | AST only | +| simple.cpp:143:23:143:30 | & ... | AST only | +| simple.cpp:144:23:144:30 | & ... | AST only | +| simple.cpp:167:17:167:17 | f | AST only | +| simple.cpp:168:12:168:23 | & ... | AST only | | struct_init.c:15:8:15:9 | ab | AST only | | struct_init.c:15:12:15:12 | a | AST only | | struct_init.c:16:8:16:9 | ab | AST only | @@ -342,6 +327,5 @@ | struct_init.c:34:14:34:22 | pointerAB | AST only | | struct_init.c:34:25:34:25 | b | AST only | | struct_init.c:36:10:36:24 | & ... | AST only | -| struct_init.c:36:11:36:15 | outer | AST only | | struct_init.c:46:10:46:14 | outer | AST only | | struct_init.c:46:16:46:24 | pointerAB | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index 050f4bc47d55..15dd60e1fd76 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -23,15 +23,38 @@ | aliasing.cpp:54:3:54:4 | s2 | | aliasing.cpp:60:3:60:4 | s2 | | aliasing.cpp:72:3:72:3 | s | +| aliasing.cpp:78:11:78:11 | w | | aliasing.cpp:79:3:79:3 | s | +| aliasing.cpp:85:10:85:10 | w | | aliasing.cpp:86:3:86:3 | s | +| aliasing.cpp:92:3:92:3 | w | | aliasing.cpp:92:5:92:5 | s | | by_reference.cpp:12:5:12:5 | s | | by_reference.cpp:16:5:16:8 | this | | by_reference.cpp:84:3:84:7 | inner | | by_reference.cpp:88:3:88:7 | inner | +| by_reference.cpp:102:22:102:26 | outer | +| by_reference.cpp:104:16:104:20 | outer | +| by_reference.cpp:106:22:106:27 | pouter | +| by_reference.cpp:108:16:108:21 | pouter | +| by_reference.cpp:122:21:122:25 | outer | +| by_reference.cpp:124:15:124:19 | outer | +| by_reference.cpp:126:21:126:26 | pouter | +| by_reference.cpp:128:15:128:20 | pouter | | complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | this | +| complex.cpp:51:8:51:8 | b | +| complex.cpp:51:10:51:14 | inner | +| complex.cpp:52:8:52:8 | b | +| complex.cpp:52:10:52:14 | inner | +| complex.cpp:62:3:62:4 | b1 | +| complex.cpp:62:6:62:10 | inner | +| complex.cpp:63:3:63:4 | b2 | +| complex.cpp:63:6:63:10 | inner | +| complex.cpp:64:3:64:4 | b3 | +| complex.cpp:64:6:64:10 | inner | +| complex.cpp:65:3:65:4 | b3 | +| complex.cpp:65:6:65:10 | inner | | constructors.cpp:20:24:20:25 | this | | constructors.cpp:21:24:21:25 | this | | qualifiers.cpp:9:30:9:33 | this | @@ -41,3 +64,16 @@ | simple.cpp:21:24:21:25 | this | | simple.cpp:65:5:65:5 | a | | simple.cpp:83:9:83:10 | f2 | +| simple.cpp:83:9:83:10 | this | +| simple.cpp:105:5:105:6 | d2 | +| simple.cpp:105:9:105:12 | d1_2 | +| simple.cpp:122:5:122:6 | d3 | +| simple.cpp:122:8:122:11 | d2_1 | +| simple.cpp:122:13:122:16 | d1_1 | +| simple.cpp:136:22:136:23 | d3 | +| simple.cpp:143:24:143:25 | d3 | +| simple.cpp:144:24:144:25 | d3 | +| simple.cpp:167:5:167:9 | outer | +| simple.cpp:167:11:167:15 | inner | +| simple.cpp:168:13:168:17 | outer | +| struct_init.c:36:11:36:15 | outer | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected index 3f5a2e497d85..d53c23cc9a4f 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -363,6 +363,24 @@ | simple.cpp:83:9:83:10 | this | | simple.cpp:83:12:83:13 | f1 | | simple.cpp:84:14:84:20 | this | +| simple.cpp:105:5:105:6 | d2 | +| simple.cpp:105:9:105:12 | d1_2 | +| simple.cpp:105:14:105:14 | y | +| simple.cpp:122:5:122:6 | d3 | +| simple.cpp:122:8:122:11 | d2_1 | +| simple.cpp:122:13:122:16 | d1_1 | +| simple.cpp:122:18:122:18 | x | +| simple.cpp:136:21:136:28 | & ... | +| simple.cpp:136:22:136:23 | d3 | +| simple.cpp:143:23:143:30 | & ... | +| simple.cpp:143:24:143:25 | d3 | +| simple.cpp:144:23:144:30 | & ... | +| simple.cpp:144:24:144:25 | d3 | +| simple.cpp:167:5:167:9 | outer | +| simple.cpp:167:11:167:15 | inner | +| simple.cpp:167:17:167:17 | f | +| simple.cpp:168:12:168:23 | & ... | +| simple.cpp:168:13:168:17 | outer | | struct_init.c:15:8:15:9 | ab | | struct_init.c:15:12:15:12 | a | | struct_init.c:16:8:16:9 | ab | diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected index d505ff5d87e9..7b12e0d3c104 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -332,6 +332,48 @@ edges | simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] | | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... | | simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| simple.cpp:108:30:108:31 | d2 [d1_2, y] | simple.cpp:111:10:111:11 | d2 [d1_2, y] | +| simple.cpp:111:10:111:11 | d2 [d1_2, y] | simple.cpp:111:13:111:16 | d1_2 [y] | +| simple.cpp:111:13:111:16 | d1_2 [y] | simple.cpp:111:18:111:18 | y | +| simple.cpp:114:37:114:38 | d2 [d1_2, y] | simple.cpp:117:10:117:11 | d2 [d1_2, y] | +| simple.cpp:117:10:117:11 | d2 [d1_2, y] | simple.cpp:117:14:117:17 | d1_2 [y] | +| simple.cpp:117:14:117:17 | d1_2 [y] | simple.cpp:117:19:117:19 | y | +| simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] | simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | ... = ... | simple.cpp:122:13:122:16 | d1_1 [post update] [x] | +| simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] | simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] | +| simple.cpp:122:13:122:16 | d1_1 [post update] [x] | simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] | +| simple.cpp:122:22:122:31 | call to user_input | simple.cpp:122:5:122:33 | ... = ... | +| simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] | simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | +| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:124:10:124:13 | d2_1 [d1_1, x] | +| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:129:25:129:28 | d2_1 [d1_1, x] | +| simple.cpp:124:10:124:13 | d2_1 [d1_1, x] | simple.cpp:124:15:124:18 | d1_1 [x] | +| simple.cpp:124:15:124:18 | d1_1 [x] | simple.cpp:124:20:124:20 | x | +| simple.cpp:129:25:129:28 | d2_1 [d1_1, x] | simple.cpp:129:30:129:33 | d1_1 [x] | +| simple.cpp:129:30:129:33 | d1_1 [x] | simple.cpp:130:10:130:12 | pd1 [x] | +| simple.cpp:130:10:130:12 | pd1 [x] | simple.cpp:130:15:130:15 | x | +| simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] | simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] | +| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] | simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | +| simple.cpp:136:31:136:40 | call to user_input | simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] | +| simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:139:13:139:16 | d2_1 [d1_2, y] | +| simple.cpp:139:13:139:16 | d2_1 [d1_2, y] | simple.cpp:139:18:139:21 | d1_2 [y] | +| simple.cpp:139:18:139:21 | d1_2 [y] | simple.cpp:139:23:139:23 | y | +| simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:108:30:108:31 | d2 [d1_2, y] | +| simple.cpp:143:23:143:30 | & ... [d1_2, y] | simple.cpp:114:37:114:38 | d2 [d1_2, y] | +| simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | +| simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | simple.cpp:143:23:143:30 | & ... [d1_2, y] | +| simple.cpp:159:20:159:24 | inner [f] | simple.cpp:161:10:161:14 | inner [f] | +| simple.cpp:161:10:161:14 | inner [f] | simple.cpp:161:17:161:17 | f | +| simple.cpp:167:5:167:9 | outer [post update] [inner, f] | simple.cpp:168:13:168:17 | outer [inner, f] | +| simple.cpp:167:5:167:32 | ... = ... | simple.cpp:167:11:167:15 | inner [post update] [f] | +| simple.cpp:167:11:167:15 | inner [post update] [f] | simple.cpp:167:5:167:9 | outer [post update] [inner, f] | +| simple.cpp:167:21:167:30 | call to user_input | simple.cpp:167:5:167:32 | ... = ... | +| simple.cpp:168:12:168:23 | & ... [f] | simple.cpp:159:20:159:24 | inner [f] | +| simple.cpp:168:13:168:17 | outer [inner, f] | simple.cpp:168:19:168:23 | inner [f] | +| simple.cpp:168:19:168:23 | inner [f] | simple.cpp:168:12:168:23 | & ... [f] | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | @@ -732,6 +774,51 @@ nodes | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | | simple.cpp:84:14:84:20 | this [f2, f1] | semmle.label | this [f2, f1] | +| simple.cpp:108:30:108:31 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | +| simple.cpp:111:10:111:11 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | +| simple.cpp:111:13:111:16 | d1_2 [y] | semmle.label | d1_2 [y] | +| simple.cpp:111:18:111:18 | y | semmle.label | y | +| simple.cpp:114:37:114:38 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | +| simple.cpp:117:10:117:11 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | +| simple.cpp:117:14:117:17 | d1_2 [y] | semmle.label | d1_2 [y] | +| simple.cpp:117:19:117:19 | y | semmle.label | y | +| simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] | semmle.label | d3 [post update] [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | ... = ... | semmle.label | ... = ... | +| simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] | semmle.label | d2_1 [post update] [d1_1, x] | +| simple.cpp:122:13:122:16 | d1_1 [post update] [x] | semmle.label | d1_1 [post update] [x] | +| simple.cpp:122:22:122:31 | call to user_input | semmle.label | call to user_input | +| simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] | semmle.label | d3 [d2_1, d1_1, ... (3)] | +| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | +| simple.cpp:124:10:124:13 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | +| simple.cpp:124:15:124:18 | d1_1 [x] | semmle.label | d1_1 [x] | +| simple.cpp:124:20:124:20 | x | semmle.label | x | +| simple.cpp:129:25:129:28 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | +| simple.cpp:129:30:129:33 | d1_1 [x] | semmle.label | d1_1 [x] | +| simple.cpp:130:10:130:12 | pd1 [x] | semmle.label | pd1 [x] | +| simple.cpp:130:15:130:15 | x | semmle.label | x | +| simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] | semmle.label | ref arg & ... [d1_2, y] | +| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | semmle.label | d3 [post update] [d2_1, d1_2, ... (3)] | +| simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] | semmle.label | d2_1 [inner post update] [d1_2, y] | +| simple.cpp:136:31:136:40 | call to user_input | semmle.label | call to user_input | +| simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:139:13:139:16 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:139:18:139:21 | d1_2 [y] | semmle.label | d1_2 [y] | +| simple.cpp:139:23:139:23 | y | semmle.label | y | +| simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:143:23:143:30 | & ... [d1_2, y] | semmle.label | & ... [d1_2, y] | +| simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:159:20:159:24 | inner [f] | semmle.label | inner [f] | +| simple.cpp:161:10:161:14 | inner [f] | semmle.label | inner [f] | +| simple.cpp:161:17:161:17 | f | semmle.label | f | +| simple.cpp:167:5:167:9 | outer [post update] [inner, f] | semmle.label | outer [post update] [inner, f] | +| simple.cpp:167:5:167:32 | ... = ... | semmle.label | ... = ... | +| simple.cpp:167:11:167:15 | inner [post update] [f] | semmle.label | inner [post update] [f] | +| simple.cpp:167:21:167:30 | call to user_input | semmle.label | call to user_input | +| simple.cpp:168:12:168:23 | & ... [f] | semmle.label | & ... [f] | +| simple.cpp:168:13:168:17 | outer [inner, f] | semmle.label | outer [inner, f] | +| simple.cpp:168:19:168:23 | inner [f] | semmle.label | inner [f] | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -830,6 +917,12 @@ nodes | simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | +| simple.cpp:111:18:111:18 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:111:18:111:18 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:117:19:117:19 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:117:19:117:19 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:124:20:124:20 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:124:20:124:20 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | +| simple.cpp:130:15:130:15 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:130:15:130:15 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | +| simple.cpp:139:23:139:23 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:139:23:139:23 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:161:17:161:17 | f | simple.cpp:167:21:167:30 | call to user_input | simple.cpp:161:17:161:17 | f | f flows from $@ | simple.cpp:167:21:167:30 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 4a3a15a0b176..af60fedd6a08 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -85,4 +85,87 @@ struct C2 } }; +struct DeepStruct1 { + int x; + int y; +}; + +struct DeepStruct2 { + DeepStruct1 d1_1; + DeepStruct1 d1_2; +}; + +struct DeepStruct3 { + DeepStruct2 d2_1; + DeepStruct2 d2_2; + DeepStruct1 d1_1; +}; + +void write_to_d1_2_y(DeepStruct2* d2, int val) { + d2->d1_2.y = val; +} + +void read_from_y(DeepStruct2 d2) { + sink(d2.d1_1.y); + + sink(d2.d1_2.y); //$ast,ir +} + +void read_from_y_deref(DeepStruct2* d2) { + sink(d2->d1_1.y); + + sink(d2->d1_2.y); //$ast,ir +} + +void test_deep_structs() { + DeepStruct3 d3; + d3.d2_1.d1_1.x = user_input(); + DeepStruct2 d2_1 = d3.d2_1; + sink(d2_1.d1_1.x); //$ast,ir + sink(d2_1.d1_1.y); + + sink(d2_1.d1_2.x); + + DeepStruct1* pd1 = &d2_1.d1_1; + sink(pd1->x); //$ast,ir +} + +void test_deep_structs_setter() { + DeepStruct3 d3; + + write_to_d1_2_y(&d3.d2_1, user_input()); + + sink(d3.d2_1.d1_1.y); + sink(d3.d2_1.d1_2.y); //$ast,ir + + read_from_y(d3.d2_1); + read_from_y(d3.d2_2); + read_from_y_deref(&d3.d2_1); + read_from_y_deref(&d3.d2_2); +} + +struct Inner +{ + int f; + int g; +}; + +struct Outer +{ + Inner inner; + int h; +}; + +void read_f(Inner *inner) +{ + sink(inner->f); //$ast,ir +} + +void test() +{ + Outer outer; + outer.inner.f = user_input(); + read_f(&outer.inner); +} + } // namespace Simple diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index dd2598dc9f86..f9f447a94b62 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -659,10 +659,10 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should have one pre-update node but has 0. | -| bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:531:14:531:14 | Store | PostUpdateNode should have one pre-update node but has 0. | +| assignexpr.cpp:9:2:9:12 | i | PostUpdateNode should have one pre-update node but has 0. | +| bad_asts.cpp:15:10:15:12 | x | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:65:19:65:45 | x | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:531:14:531:14 | d | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead