From 335baaef73968df8c2a2ef49053dbed9eef1f8c3 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 29 May 2020 12:15:39 +0200 Subject: [PATCH 01/11] C++: Add testcases for partial definitions with long access paths --- .../fields/partial-definition-diff.expected | 11 ++++ .../fields/partial-definition-ir.expected | 2 + .../fields/partial-definition.expected | 13 ++++ .../library-tests/dataflow/fields/simple.cpp | 59 +++++++++++++++++++ 4 files changed, 85 insertions(+) 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..69a706e5cf8d 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 @@ -320,6 +320,17 @@ | 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:5:105:6 | d2 | AST only | +| simple.cpp:105:14:105:14 | y | AST only | +| simple.cpp:122:5:122:6 | d3 | AST only | +| simple.cpp:122:8:122:11 | d2_1 | AST only | +| simple.cpp:122:18:122:18 | x | AST only | +| simple.cpp:136:21:136:28 | & ... | AST only | +| simple.cpp:136:22:136:23 | d3 | AST only | +| simple.cpp:143:23:143:30 | & ... | AST only | +| simple.cpp:143:24:143:25 | d3 | AST only | +| simple.cpp:144:23:144:30 | & ... | AST only | +| simple.cpp:144:24:144:25 | d3 | 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 | 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..5ad23eaa65d8 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 @@ -41,3 +41,5 @@ | simple.cpp:21:24:21:25 | this | | simple.cpp:65:5:65:5 | a | | simple.cpp:83:9:83:10 | f2 | +| simple.cpp:105:9:105:12 | d1_2 | +| simple.cpp:122:13:122:16 | d1_1 | 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..749a31128111 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,19 @@ | 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 | | 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/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 678a22148e76..e77bb7d670cc 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -85,4 +85,63 @@ 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); + // Hopefully we will catch this flow when we merge #3123 + sink(d2.d1_2.y); //$ast $f-:ir +} + +void read_from_y_deref(DeepStruct2* d2) { + sink(d2->d1_1.y); + // Hopefully we will catch this flow when we merge #3123 + sink(d2->d1_2.y); //$ast $f-: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 $f-:ir + sink(d2_1.d1_1.y); + + sink(d2_1.d1_2.x); + + DeepStruct1* pd1 = &d2_1.d1_1; + sink(pd1->x); //$ast $f-: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); //$f+:ir + 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); +} + } // namespace Simple From a0603692cb77834a190678af964404bda3f5792a Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 29 May 2020 13:53:53 +0200 Subject: [PATCH 02/11] C++: Add LoadChain and StoreChain nodes to handle reverse reads in dataflow --- .../ir/dataflow/internal/DataFlowPrivate.qll | 34 +- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 416 ++++++++++++++++-- 2 files changed, 374 insertions(+), 76 deletions(-) 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 531fcdfd3681..aba5bf0f215b 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 @@ -180,32 +180,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() } /** @@ -213,13 +195,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 96e4d9137dff..a025c3253385 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. @@ -225,7 +227,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. */ @@ -240,59 +242,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. @@ -372,6 +330,352 @@ 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 { + SideEffectInstruction sideEffect; + FieldAddressInstruction fi; + + StoreChainEndInstructionSideEffect() { + not this.isResultConflated() and + this.getPartial() = sideEffect and + fi = skipConversion*(sideEffect.getAnOperand().getDef()) + } + + 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, _) + ) + } + +private class StoreChain extends TStoreChain { + string toString() { none() } + + StoreChainConsCons getParent() { none() } + + StoreChain getChild() { none() } + + StoreChainEndInstruction getEndInstruction() { none() } + + Instruction getBeginInstruction() { none() } + + FieldAddressInstruction getFieldInstruction() { none() } + + FieldAddressInstruction getAFieldInstruction() { none() } +} + +private class StoreChainConsNil extends StoreChain, TStoreChainConsNil { + FieldAddressInstruction fi; + StoreChainEndInstruction end; + + StoreChainConsNil() { this = TStoreChainConsNil(fi, end) } + + override string toString() { result = fi.getField().toString() } + + override StoreChainConsCons getParent() { result = TStoreChainConsCons(_, this) } + + 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 StoreChainConsCons getParent() { result.getChild() = this } + + 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`. For now the only + * implementation is `LoadChainEndInstructionLoad`, but we may need another implementation similar + * to `StoreChainEndInstructionSideEffect` to handle cases like: + * ``` + * void read_f(Inner* inner) { + * sink(inner->f); + * } + * ... + * outer.inner.f = taint(); + * read_f(&outer.inner); + * ``` + */ +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() } +} + +private class LoadChain extends TLoadChain { + string toString() { none() } + + LoadChainEndInstruction getEndInstruction() { none() } + + final LoadChainConsCons getParent() { result.getChild() = this } + + LoadChain getChild() { none() } + + FieldAddressInstruction getFieldInstruction() { none() } + + Location getLocation() { none() } +} + +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 } + + override Location getLocation() { result = fi.getLocation() } +} + +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 } + + override Location getLocation() { result = fi.getLocation() } +} + +/** `StoreNode` also extends `ReadStepNode` to participate in reverse read steps. */ +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() + } +} + +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`. */ @@ -425,6 +729,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] From 3adc10fdb421e48be2f6d9fa466a40b45aa861e4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 29 May 2020 15:33:55 +0200 Subject: [PATCH 03/11] C++: Accept tests --- .../fields/dataflow-ir-consistency.expected | 2 +- .../fields/partial-definition-diff.expected | 29 ----------------- .../fields/partial-definition-ir.expected | 31 +++++++++++++++++++ .../library-tests/dataflow/fields/simple.cpp | 12 +++---- .../dataflow-ir-consistency.expected | 8 ++--- 5 files changed, 42 insertions(+), 40 deletions(-) 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/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 69a706e5cf8d..b84d1037d806 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,20 +296,13 @@ | 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:5:105:6 | d2 | AST only | | simple.cpp:105:14:105:14 | y | AST only | -| simple.cpp:122:5:122:6 | d3 | AST only | -| simple.cpp:122:8:122:11 | d2_1 | AST only | | simple.cpp:122:18:122:18 | x | AST only | | simple.cpp:136:21:136:28 | & ... | AST only | -| simple.cpp:136:22:136:23 | d3 | AST only | | simple.cpp:143:23:143:30 | & ... | AST only | -| simple.cpp:143:24:143:25 | d3 | AST only | | simple.cpp:144:23:144:30 | & ... | AST only | -| simple.cpp:144:24:144:25 | d3 | 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 | @@ -353,6 +325,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 5ad23eaa65d8..349e822d65cc 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,5 +64,13 @@ | 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 | +| struct_init.c:36:11:36:15 | outer | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index e77bb7d670cc..dc3bf574de02 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -107,8 +107,8 @@ void write_to_d1_2_y(DeepStruct2* d2, int val) { void read_from_y(DeepStruct2 d2) { sink(d2.d1_1.y); - // Hopefully we will catch this flow when we merge #3123 - sink(d2.d1_2.y); //$ast $f-:ir + + sink(d2.d1_2.y); //$ast,ir } void read_from_y_deref(DeepStruct2* d2) { @@ -121,13 +121,13 @@ 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 $f-:ir + 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 $f-:ir + sink(pd1->x); //$ast,ir } void test_deep_structs_setter() { @@ -135,8 +135,8 @@ void test_deep_structs_setter() { write_to_d1_2_y(&d3.d2_1, user_input()); - sink(d3.d2_1.d1_1.y); //$f+:ir - sink(d3.d2_1.d1_2.y); //$ast $ir + 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); 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 f3263593a6c7..66923610d813 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 From ce34d91a0761c6cfe1a02788dc269143585d65b8 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 2 Jun 2020 13:50:00 +0200 Subject: [PATCH 04/11] C++: Add more QLDoc to StoreNode and LoadNode classes, and related predicates. I also simplified the code a bit by moving common implementations of predicates into shared super classes. Finally, I added a getLocation predicate to StoreNode to match the structure of the LoadNode class. --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 69 ++++++++++++++++--- 1 file changed, 58 insertions(+), 11 deletions(-) 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 a025c3253385..1a0e5969a458 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 @@ -462,20 +462,46 @@ private newtype TStoreChain = ) } +/** + * 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() } - StoreChainConsCons getParent() { 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 { @@ -486,8 +512,6 @@ private class StoreChainConsNil extends StoreChain, TStoreChainConsNil { override string toString() { result = fi.getField().toString() } - override StoreChainConsCons getParent() { result = TStoreChainConsCons(_, this) } - override StoreChainEndInstruction getEndInstruction() { result = end } override Instruction getBeginInstruction() { result = end.getBeginInstruction() } @@ -505,8 +529,6 @@ private class StoreChainConsCons extends StoreChain, TStoreChainConsCons { override string toString() { result = fi.getField().toString() + "." + next.toString() } - override StoreChainConsCons getParent() { result.getChild() = this } - override StoreChain getChild() { result = next } override FieldAddressInstruction getFieldInstruction() { result = fi } @@ -563,18 +585,34 @@ private class LoadChainEndInstructionLoad extends LoadChainEndInstruction, LoadI override Instruction getReadValue() { result = getSourceValueOperand().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() } - Location getLocation() { none() } + final Location getLocation() { result = getFieldInstruction().getLocation() } } private class LoadChainConsNil extends LoadChain, TLoadChainConsNil { @@ -588,8 +626,6 @@ private class LoadChainConsNil extends LoadChain, TLoadChainConsNil { override LoadChainEndInstruction getEndInstruction() { result = end } override FieldAddressInstruction getFieldInstruction() { result = fi } - - override Location getLocation() { result = fi.getLocation() } } private class LoadChainConsCons extends LoadChain, TLoadChainConsCons { @@ -605,11 +641,21 @@ private class LoadChainConsCons extends LoadChain, TLoadChainConsCons { override LoadChain getChild() { result = next } override FieldAddressInstruction getFieldInstruction() { result = fi } - - override Location getLocation() { result = fi.getLocation() } } -/** `StoreNode` also extends `ReadStepNode` to participate in reverse read steps. */ +/** + * 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; @@ -649,6 +695,7 @@ private class StoreNode extends TStoreNode, StoreStepNode, ReadStepNode, Partial } } +/** A dataflow node generated by loading from an address computed by a sequence of fields lookups. */ private class LoadNode extends TLoadNode, ReadStepNode { LoadChain loadChain; From b890b162f416542c4dc98f462def7690d1c7b12c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 3 Jun 2020 09:28:06 +0200 Subject: [PATCH 05/11] C++: Restrict the side effect of StoreChainEndInstructionSideEffect to be WriteSideEffectInstructions --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 1a0e5969a458..39a4a269e983 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 @@ -435,13 +435,13 @@ private Instruction skipConversion(Instruction instr) { * before entering `setter`. */ private class StoreChainEndInstructionSideEffect extends StoreChainEndInstruction, ChiInstruction { - SideEffectInstruction sideEffect; + WriteSideEffectInstruction sideEffect; FieldAddressInstruction fi; StoreChainEndInstructionSideEffect() { not this.isResultConflated() and this.getPartial() = sideEffect and - fi = skipConversion*(sideEffect.getAnOperand().getDef()) + fi = skipConversion*(sideEffect.getArgumentDef()) } override FieldAddressInstruction getFieldInstruction() { result = fi } From d295e2139a433189336c253809e7af283a4e560c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 3 Jun 2020 15:13:44 +0200 Subject: [PATCH 06/11] C++: Accept tests after merge from master --- .../dataflow/fields/ir-path-flow.expected | 148 +++++++++++++++--- .../dataflow/fields/path-flow.expected | 73 +++++++++ 2 files changed, 197 insertions(+), 24 deletions(-) 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 2d29d3333c2d..4ba18e79837d 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,54 +1,102 @@ edges | 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 | | 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:67:13:67:13 | i | simple.cpp:67:13:67:13 | i | +| 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: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 | 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: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] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | nodes | 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] | @@ -57,25 +105,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 | @@ -84,26 +137,69 @@ nodes | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | | 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 | -| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | +| by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| 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:67:13:67:13 | i | semmle.label | i | +| 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: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] | | 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:27:7:27:16 | call to user_input | semmle.label | call to user_input | @@ -124,5 +220,9 @@ nodes | by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | 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: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: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 | | 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 | | struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | 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..ef123ff57b08 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,39 @@ 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] | | 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 +765,41 @@ 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] | | 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 +898,11 @@ 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 | | 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 | From 4b16067af25ad542a86b40afa568ef8dd71a6465 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Jun 2020 11:02:03 +0200 Subject: [PATCH 07/11] C++: Fix testcases after merge from master --- .../dataflow/fields/ir-path-flow.expected | 72 +++++++++++++------ .../library-tests/dataflow/fields/simple.cpp | 4 +- 2 files changed, 54 insertions(+), 22 deletions(-) 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 589151e773fd..2d802118db4a 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,11 +1,11 @@ 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 | c [c] | | A.cpp:142:7:142:20 | c [c] | A.cpp:142:7:142:20 | Chi [c] | @@ -75,9 +75,17 @@ edges | 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: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 [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)] | @@ -93,25 +101,41 @@ edges | 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 | 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: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] | +| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | 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:21:27:21 | nestedAB.b [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [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 *)... | @@ -198,12 +222,21 @@ nodes | 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 | -<<<<<<< HEAD | 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 [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] | @@ -228,23 +261,24 @@ nodes | 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:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | -| simple.cpp:83:9:83:28 | Store | semmle.label | Store | -| 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 | call to getf2f1 | semmle.label | call to getf2f1 | +| 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 | 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] | | 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 | ->>>>>>> master +| 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: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] | #select @@ -266,15 +300,13 @@ nodes | by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | 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 | -<<<<<<< HEAD +| 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: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 | | 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 | ->>>>>>> master | 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 | | struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | 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 023c5e6ae1c3..bf303b0abde0 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -113,8 +113,8 @@ void read_from_y(DeepStruct2 d2) { void read_from_y_deref(DeepStruct2* d2) { sink(d2->d1_1.y); - // Hopefully we will catch this flow when we merge #3123 - sink(d2->d1_2.y); //$ast $f-:ir + + sink(d2->d1_2.y); //$ast,ir } void test_deep_structs() { From a4388e92587406a27455b452eca1c9bdcd0c15b3 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 8 Jun 2020 11:03:36 +0200 Subject: [PATCH 08/11] C++: Add example demonstrating missing flow --- .../library-tests/dataflow/fields/simple.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index bf303b0abde0..d49bee912faa 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -144,4 +144,28 @@ void test_deep_structs_setter() { 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 $f-:ir +} + +void test() +{ + Outer outer; + outer.inner.f = user_input(); + read_f(&outer.inner); +} + } // namespace Simple From 01f3793159b54f1e573a57c9b8cb9816a17754ae Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 8 Jun 2020 11:05:30 +0200 Subject: [PATCH 09/11] C++: Add ReadSideEffect as a possible end instruction for load chains --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 40 +++++++++++++------ .../library-tests/dataflow/fields/simple.cpp | 2 +- 2 files changed, 28 insertions(+), 14 deletions(-) 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 00b202792994..e4e01542c5a7 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 @@ -611,19 +611,7 @@ private newtype TLoadChain = ) } -/** - * This class abstracts out the information needed to end a `LoadChain`. For now the only - * implementation is `LoadChainEndInstructionLoad`, but we may need another implementation similar - * to `StoreChainEndInstructionSideEffect` to handle cases like: - * ``` - * void read_f(Inner* inner) { - * sink(inner->f); - * } - * ... - * outer.inner.f = taint(); - * read_f(&outer.inner); - * ``` - */ +/** This class abstracts out the information needed to end a `LoadChain`. */ abstract private class LoadChainEndInstruction extends Instruction { abstract FieldAddressInstruction getFieldInstruction(); @@ -643,6 +631,32 @@ private class LoadChainEndInstructionLoad extends LoadChainEndInstruction, LoadI 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 LoadChainInstructionSideEffect extends LoadChainEndInstruction, + ReadSideEffectInstruction { + FieldAddressInstruction fi; + + LoadChainInstructionSideEffect() { 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: diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index d49bee912faa..af60fedd6a08 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -158,7 +158,7 @@ struct Outer void read_f(Inner *inner) { - sink(inner->f); //$ast $f-:ir + sink(inner->f); //$ast,ir } void test() From 431cc5c926d743e6b58da7107f99ccea58a53a35 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 8 Jun 2020 11:27:09 +0200 Subject: [PATCH 10/11] C++: Fix inconsistent class name --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 e4e01542c5a7..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 @@ -646,11 +646,11 @@ private class LoadChainEndInstructionLoad extends LoadChainEndInstruction, LoadI * be `f`, and thus reading `&outer.inner` must pop `inner` from the access path * before entering `read_f`. */ -private class LoadChainInstructionSideEffect extends LoadChainEndInstruction, +private class LoadChainEndInstructionSideEffect extends LoadChainEndInstruction, ReadSideEffectInstruction { FieldAddressInstruction fi; - LoadChainInstructionSideEffect() { fi = skipConversion*(this.getArgumentDef()) } + LoadChainEndInstructionSideEffect() { fi = skipConversion*(this.getArgumentDef()) } override FieldAddressInstruction getFieldInstruction() { result = fi } From b48168fc0349558f8146e466726a8d207095dae9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 8 Jun 2020 12:26:25 +0200 Subject: [PATCH 11/11] C++: Accept tests --- .../dataflow/fields/ir-path-flow.expected | 28 +++++++++++++++++++ .../fields/partial-definition-diff.expected | 2 ++ .../fields/partial-definition-ir.expected | 3 ++ .../fields/partial-definition.expected | 5 ++++ .../dataflow/fields/path-flow.expected | 20 +++++++++++++ 5 files changed, 58 insertions(+) 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 2d802118db4a..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 @@ -102,6 +102,7 @@ edges | 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] | @@ -114,9 +115,19 @@ edges | 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: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] | @@ -130,8 +141,11 @@ edges | 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 | Store | semmle.label | Store | @@ -263,8 +277,19 @@ nodes | 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:15:12:15:12 | a | semmle.label | a | @@ -279,8 +304,10 @@ nodes | 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 | @@ -306,6 +333,7 @@ nodes | 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 b84d1037d806..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 @@ -303,6 +303,8 @@ | 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 | 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 349e822d65cc..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 @@ -73,4 +73,7 @@ | 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 749a31128111..d53c23cc9a4f 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -376,6 +376,11 @@ | 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 ef123ff57b08..7b12e0d3c104 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -365,6 +365,15 @@ edges | 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] | @@ -800,6 +809,16 @@ nodes | 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 | @@ -903,6 +922,7 @@ nodes | 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 |