Merge pull request #16677 from MathiasVP/phi-input-nodes

C++: Extend barrier guards to handle phi inputs
This commit is contained in:
Mathias Vorreiter Pedersen
2024-06-06 19:21:30 +01:00
committed by GitHub
15 changed files with 361 additions and 103 deletions

View File

@@ -1336,6 +1336,8 @@ predicate nodeIsHidden(Node n) {
n instanceof FinalGlobalValue
or
n instanceof InitialGlobalValue
or
n instanceof SsaPhiInputNode
}
predicate neverSkipInPathGraph(Node n) {
@@ -1634,6 +1636,8 @@ private Instruction getAnInstruction(Node n) {
or
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction()
or
result = n.(SsaPhiInputNode).getBasicBlock().getFirstInstruction()
or
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _)
or
not n instanceof IndirectInstruction and
@@ -1763,7 +1767,7 @@ module IteratorFlow {
crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and
sv = def.getSourceVariable() and
bb.getInstruction(i) = crementCall and
Ssa::ssaDefReachesRead(sv, result.asDef(), bb, i)
Ssa::ssaDefReachesReadExt(sv, result.asDef(), bb, i)
)
}
@@ -1797,7 +1801,7 @@ module IteratorFlow {
isIteratorWrite(writeToDeref, address) and
operandForFullyConvertedCall(address, starCall) and
bbStar.getInstruction(iStar) = starCall and
Ssa::ssaDefReachesRead(_, def.asDef(), bbStar, iStar) and
Ssa::ssaDefReachesReadExt(_, def.asDef(), bbStar, iStar) and
ultimate = getAnUltimateDefinition*(def) and
beginStore = ultimate.getValue().asInstruction() and
operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)

View File

@@ -45,6 +45,7 @@ private newtype TIRDataFlowNode =
or
Ssa::isModifiableByCall(operand, indirectionIndex)
} or
TSsaPhiInputNode(Ssa::PhiNode phi, IRBlock input) { phi.hasInputFromBlock(_, _, _, _, input) } or
TSsaPhiNode(Ssa::PhiNode phi) or
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
@@ -165,6 +166,12 @@ class Node extends TIRDataFlowNode {
/** Gets the operands corresponding to this node, if any. */
Operand asOperand() { result = this.(OperandNode).getOperand() }
/**
* Gets the operand that is indirectly tracked by this node behind `index`
* number of indirections.
*/
Operand asIndirectOperand(int index) { hasOperandAndIndex(this, result, index) }
/**
* Holds if this node is at index `i` in basic block `block`.
*
@@ -177,6 +184,9 @@ class Node extends TIRDataFlowNode {
or
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
or
this.(SsaPhiInputNode).getBlock() = block and
i = block.getInstructionCount()
or
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
or
this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
@@ -629,7 +639,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
override string toStringImpl() { result = "Phi" }
override string toStringImpl() { result = phi.toString() }
/**
* Gets a node that is used as input to this phi node.
@@ -638,7 +648,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
*/
cached
final Node getAnInput(boolean fromBackEdge) {
localFlowStep(result, this) and
result.(SsaPhiInputNode).getPhiNode() = phi and
exists(IRBlock bPhi, IRBlock bResult |
bPhi = phi.getBasicBlock() and bResult = result.getBasicBlock()
|
@@ -661,6 +671,58 @@ class SsaPhiNode extends Node, TSsaPhiNode {
predicate isPhiRead() { phi.isPhiRead() }
}
/**
* INTERNAL: Do not use.
*
* A node that is used as an input to a phi node.
*
* This class exists to allow more powerful barrier guards. Consider this
* example:
*
* ```cpp
* int x = source();
* if(!safe(x)) {
* x = clear();
* }
* // phi node for x here
* sink(x);
* ```
*
* At the phi node for `x` it is neither the case that `x` is dominated by
* `safe(x)`, or is the case that the phi is dominated by a clearing of `x`.
*
* By inserting a "phi input" node as the last entry in the basic block that
* defines the inputs to the phi we can conclude that each of those inputs are
* safe to pass to `sink`.
*/
class SsaPhiInputNode extends Node, TSsaPhiInputNode {
Ssa::PhiNode phi;
IRBlock block;
SsaPhiInputNode() { this = TSsaPhiInputNode(phi, block) }
/** Gets the phi node associated with this node. */
Ssa::PhiNode getPhiNode() { result = phi }
/** Gets the basic block in which this input originates. */
IRBlock getBlock() { result = block }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
override DataFlowType getType() { result = this.getSourceVariable().getType() }
override predicate isGLValue() { phi.getSourceVariable().isGLValue() }
final override Location getLocationImpl() { result = block.getLastInstruction().getLocation() }
override string toStringImpl() { result = "Phi input" }
/** Gets the source variable underlying this phi node. */
Ssa::SourceVariable getSourceVariable() { result = phi.getSourceVariable() }
}
/**
* INTERNAL: do not use.
*
@@ -2183,6 +2245,9 @@ private module Cached {
// Def-use/Use-use flow
Ssa::ssaFlow(nodeFrom, nodeTo)
or
// Phi input -> Phi
nodeFrom.(SsaPhiInputNode).getPhiNode() = nodeTo.(SsaPhiNode).getPhiNode()
or
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
or
// Operand -> Instruction flow
@@ -2621,6 +2686,22 @@ class ContentSet instanceof Content {
}
}
pragma[nomagic]
private predicate guardControlsPhiInput(
IRGuardCondition g, boolean branch, Ssa::Definition def, IRBlock input, Ssa::PhiNode phi
) {
phi.hasInputFromBlock(def, _, _, _, input) and
(
g.controls(input, branch)
or
exists(EdgeKind kind |
g.getBlock() = input and
kind = getConditionalEdge(branch) and
input.getSuccessor(kind) = phi.getBasicBlock()
)
)
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*
@@ -2669,13 +2750,21 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
*
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
*/
ExprNode getABarrierNode() {
Node getABarrierNode() {
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
e = value.getAnInstruction().getConvertedResultExpression() and
result.getConvertedExpr() = e and
result.asConvertedExpr() = e and
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
g.controls(result.getBasicBlock(), edge)
)
or
exists(
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
guardChecks(g, def.getARead().asOperand().getDef().getConvertedResultExpression(), branch) and
guardControlsPhiInput(g, branch, def, input, phi) and
result = TSsaPhiInputNode(phi, input)
)
}
/**
@@ -2711,7 +2800,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
*
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
*/
IndirectExprNode getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
/**
* Gets an indirect expression node with indirection index `indirectionIndex` that is
@@ -2747,13 +2836,23 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
*
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
*/
IndirectExprNode getAnIndirectBarrierNode(int indirectionIndex) {
Node getAnIndirectBarrierNode(int indirectionIndex) {
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
e = value.getAnInstruction().getConvertedResultExpression() and
result.getConvertedExpr(indirectionIndex) = e and
result.asIndirectConvertedExpr(indirectionIndex) = e and
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
g.controls(result.getBasicBlock(), edge)
)
or
exists(
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
guardChecks(g,
def.getARead().asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(),
branch) and
guardControlsPhiInput(g, branch, def, input, phi) and
result = TSsaPhiInputNode(phi, input)
)
}
}
@@ -2762,6 +2861,14 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
*/
signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch);
private EdgeKind getConditionalEdge(boolean branch) {
branch = true and
result instanceof TrueEdge
or
branch = false and
result instanceof FalseEdge
}
/**
* Provides a set of barrier nodes for a guard that validates an instruction.
*
@@ -2770,12 +2877,20 @@ signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction in
*/
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
Node getABarrierNode() {
exists(IRGuardCondition g, ValueNumber value, boolean edge, Operand use |
instructionGuardChecks(g, value.getAnInstruction(), edge) and
use = value.getAnInstruction().getAUse() and
result.asOperand() = use and
g.controls(use.getDef().getBlock(), edge)
g.controls(result.getBasicBlock(), edge)
)
or
exists(
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
instructionGuardChecks(g, def.getARead().asOperand().getDef(), branch) and
guardControlsPhiInput(g, branch, def, input, phi) and
result = TSsaPhiInputNode(phi, input)
)
}
}

View File

@@ -657,19 +657,9 @@ class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
*/
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
or
exists(PhiNode phi |
lastRefRedefExt(_, sv, bb1, i1, phi) and
phi.definesAt(sv, bb2, i2, _)
)
}
predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
exists(Phi phi |
phi.asPhi().definesAt(sv, bb, i, _) and
nodeTo = phi.getNode()
)
or
exists(UseImpl use |
use.hasIndexInBlock(bb, i, sv) and
nodeTo = use.getNode()
@@ -723,46 +713,26 @@ predicate nodeToDefOrUse(Node node, SourceVariable sv, IRBlock bb, int i, boolea
*/
private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
not exists(SourceVariable sv, IRBlock bb2, int i2 |
nodeToDefOrUse(nTo, sv, bb2, i2, _) and
useToNode(bb2, i2, sv, nTo) and
adjacentDefRead(bb2, i2, sv, _, _)
) and
(
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and
instr = op2.getDef() and
conversionFlow(op1, instr, _, _)
)
or
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
hasOperandAndIndex(nTo, op2, indirectionIndex - 1) and
instr = op2.getDef() and
isDereference(instr, op1, _)
)
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and
instr = op2.getDef() and
conversionFlow(op1, instr, _, _)
)
}
/**
* The reason for this predicate is a bit annoying:
* We cannot mark a `PointerArithmeticInstruction` that computes an offset based on some SSA
* variable `x` as a use of `x` since this creates taint-flow in the following example:
* ```c
* int x = array[source]
* sink(*array)
* ```
* This is because `source` would flow from the operand of `PointerArithmeticInstruction` to the
* result of the instruction, and into the `IndirectOperand` that represents the value of `*array`.
* Then, via use-use flow, flow will arrive at `*array` in `sink(*array)`.
*
* So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the
* first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`.
* Holds if `node` is a phi input node that should receive flow from the
* definition to (or use of) `sv` at `(bb1, i1)`.
*/
private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, IRBlock bb2, int i2) {
exists(IRBlock bb1, int i1, Node adjusted |
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
nodeToDefOrUse(adjusted, sv, bb1, i1, _) and
adjacentDefRead(bb1, i1, sv, bb2, i2)
private predicate phiToNode(SsaPhiInputNode node, SourceVariable sv, IRBlock bb1, int i1) {
exists(PhiNode phi, IRBlock input |
phi.hasInputFromBlock(_, sv, bb1, i1, input) and
node.getPhiNode() = phi and
node.getBlock() = input
)
}
@@ -777,10 +747,14 @@ private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, I
private predicate ssaFlowImpl(
IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain
) {
exists(IRBlock bb2, int i2 |
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
adjacentDefRead(bb1, i1, sv, bb2, i2) and
useToNode(bb2, i2, sv, nodeTo)
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
(
exists(IRBlock bb2, int i2 |
adjacentDefRead(bb1, i1, sv, bb2, i2) and
useToNode(bb2, i2, sv, nodeTo)
)
or
phiToNode(nodeTo, sv, bb1, i1)
) and
nodeFrom != nodeTo
}
@@ -789,7 +763,7 @@ private predicate ssaFlowImpl(
private Node getAPriorDefinition(DefinitionExt next) {
exists(IRBlock bb, int i, SourceVariable sv |
lastRefRedefExt(_, pragma[only_bind_into](sv), pragma[only_bind_into](bb),
pragma[only_bind_into](i), next) and
pragma[only_bind_into](i), _, next) and
nodeToDefOrUse(result, sv, bb, i, _)
)
}
@@ -896,9 +870,31 @@ private predicate isArgumentOfCallable(DataFlowCall call, Node n) {
* Holds if there is use-use flow from `pun`'s pre-update node to `n`.
*/
private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) {
exists(SourceVariable sv, IRBlock bb2, int i2 |
adjustForPointerArith(pun, sv, bb2, i2) and
useToNode(bb2, i2, sv, n)
// We cannot mark a `PointerArithmeticInstruction` that computes an offset
// based on some SSA
// variable `x` as a use of `x` since this creates taint-flow in the
// following example:
// ```c
// int x = array[source]
// sink(*array)
// ```
// This is because `source` would flow from the operand of `PointerArithmetic`
// instruction to the result of the instruction, and into the `IndirectOperand`
// that represents the value of `*array`. Then, via use-use flow, flow will
// arrive at `*array` in `sink(*array)`.
// So this predicate recurses back along conversions and `PointerArithmetic`
// instructions to find the first use that has provides use-use flow, and
// uses that target as the target of the `nodeFrom`.
exists(Node adjusted, IRBlock bb1, int i1, SourceVariable sv |
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
useToNode(bb1, i1, sv, adjusted)
|
exists(IRBlock bb2, int i2 |
adjacentDefRead(bb1, i1, sv, bb2, i2) and
useToNode(bb2, i2, sv, n)
)
or
phiToNode(n, sv, bb1, i1)
)
}
@@ -953,11 +949,16 @@ predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
/** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2 |
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1 |
phi = nodeFrom.getPhiNode() and
phi.definesAt(sv, bb1, i1, _) and
adjacentDefRead(bb1, i1, sv, bb2, i2) and
useToNode(bb2, i2, sv, nodeTo)
phi.definesAt(sv, bb1, i1, _)
|
exists(IRBlock bb2, int i2 |
adjacentDefRead(bb1, i1, sv, bb2, i2) and
useToNode(bb2, i2, sv, nodeTo)
)
or
phiToNode(nodeTo, sv, bb1, i1)
)
}
@@ -1031,22 +1032,26 @@ module SsaCached {
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
* `def`. The reference is last because it can reach another write `next`,
* without passing through another read or write.
*
* The path from node `i` in `bb` to `next` goes via basic block `input`,
* which is either a predecessor of the basic block of `next`, or `input` =
* `bb` in case `next` occurs in basic block `bb`.
*/
cached
predicate lastRefRedefExt(
DefinitionExt def, SourceVariable sv, IRBlock bb, int i, DefinitionExt next
DefinitionExt def, SourceVariable sv, IRBlock bb, int i, IRBlock input, DefinitionExt next
) {
SsaImpl::lastRefRedefExt(def, sv, bb, i, next)
SsaImpl::lastRefRedefExt(def, sv, bb, i, input, next)
}
cached
Definition phiHasInputFromBlock(PhiNode phi, IRBlock bb) {
SsaImpl::phiHasInputFromBlock(phi, result, bb)
Definition phiHasInputFromBlockExt(PhiNode phi, IRBlock bb) {
SsaImpl::phiHasInputFromBlockExt(phi, result, bb)
}
cached
predicate ssaDefReachesRead(SourceVariable v, Definition def, IRBlock bb, int i) {
SsaImpl::ssaDefReachesRead(v, def, bb, i)
predicate ssaDefReachesReadExt(SourceVariable v, DefinitionExt def, IRBlock bb, int i) {
SsaImpl::ssaDefReachesReadExt(v, def, bb, i)
}
predicate variableRead = SsaInput::variableRead/4;
@@ -1198,11 +1203,11 @@ class Phi extends TPhi, SsaDef {
final override Location getLocation() { result = phi.getBasicBlock().getLocation() }
override string toString() { result = "Phi" }
override string toString() { result = phi.toString() }
SsaPhiNode getNode() { result.getPhiNode() = phi }
SsaPhiInputNode getNode(IRBlock block) { result.getPhiNode() = phi and result.getBlock() = block }
predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlock(phi, bb) }
predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlockExt(phi, bb) }
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
}
@@ -1228,13 +1233,21 @@ class PhiNode extends SsaImpl::DefinitionExt {
*/
predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode }
/** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */
predicate hasInputFromBlock(Definition inp, IRBlock bb) {
inp = SsaCached::phiHasInputFromBlock(this, bb)
/**
* Holds if the node at index `i` in `bb` is a last reference to SSA
* definition `def` of `sv`. The reference is last because it can reach
* this phi node, without passing through another read or write.
*
* The path from node `i` in `bb` to this phi node goes via basic block
* `input`, which is either a predecessor of the basic block of this phi
* node, or `input` = `bb` in case this phi node occurs in basic block `bb`.
*/
predicate hasInputFromBlock(DefinitionExt def, SourceVariable sv, IRBlock bb, int i, IRBlock input) {
SsaCached::lastRefRedefExt(def, sv, bb, i, input, this)
}
/** Gets a definition that is an input to this phi node. */
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
final Definition getAnInput() { this.hasInputFromBlock(result, _, _, _, _) }
}
/** An static single assignment (SSA) definition. */
@@ -1249,6 +1262,15 @@ class DefinitionExt extends SsaImpl::DefinitionExt {
result = this.getAPhiInputOrPriorDefinition*() and
not result instanceof PhiNode
}
/** Gets a node that represents a read of this SSA definition. */
Node getARead() {
exists(SourceVariable sv, IRBlock bb, int i | SsaCached::ssaDefReachesReadExt(sv, this, bb, i) |
useToNode(bb, i, sv, result)
or
phiToNode(result, sv, bb, i)
)
}
}
class Definition = SsaImpl::Definition;

View File

@@ -209,6 +209,7 @@ class LoopWithAlloca extends Stmt {
DataFlow::localFlow(result, DataFlow::exprNode(va)) and
// Phi nodes will be preceded by nodes that represent actual definitions
not result instanceof DataFlow::SsaPhiNode and
not result instanceof DataFlow::SsaPhiInputNode and
// A source is outside the loop if it's not inside the loop
not exists(Expr e | e = getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
)

View File

@@ -75,4 +75,54 @@ void bg_indirect_expr() {
if (guarded(buf)) {
sink(buf);
}
}
void test_guard_and_reassign() {
int x = source();
if(!guarded(x)) {
x = 0;
}
sink(x); // $ SPURIOUS: ast,ir
}
void test_phi_read_guard(bool b) {
int x = source();
if(b) {
if(!guarded(x))
return;
}
else {
if(!guarded(x))
return;
}
sink(x); // $ SPURIOUS: ast,ir
}
bool unsafe(int);
void test_guard_and_reassign_2() {
int x = source();
if(unsafe(x)) {
x = 0;
}
sink(x); // $ SPURIOUS: ast
}
void test_phi_read_guard_2(bool b) {
int x = source();
if(b) {
if(unsafe(x))
return;
}
else {
if(unsafe(x))
return;
}
sink(x); // $ SPURIOUS: ast
}

View File

@@ -11,6 +11,10 @@ module AstTest {
g.(FunctionCall).getTarget().getName() = "guarded" and
checked = g.(FunctionCall).getArgument(0) and
isTrue = true
or
g.(FunctionCall).getTarget().getName() = "unsafe" and
checked = g.(FunctionCall).getArgument(0) and
isTrue = false
}
/** Common data flow configuration to be used by tests. */
@@ -105,9 +109,13 @@ module IRTest {
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
exists(Call call |
call = g.getUnconvertedResultExpression() and
checked = call.getArgument(0)
|
call.getTarget().hasName("guarded") and
checked = call.getArgument(0) and
isTrue = true
or
call.getTarget().hasName("unsafe") and
isTrue = false
)
}

View File

@@ -69,45 +69,61 @@
| test.cpp:8:8:8:9 | t1 | test.cpp:9:8:9:9 | t1 |
| test.cpp:9:8:9:9 | t1 | test.cpp:11:7:11:8 | t1 |
| test.cpp:9:8:9:9 | t1 | test.cpp:11:7:11:8 | t1 |
| test.cpp:10:8:10:9 | t2 | test.cpp:11:7:11:8 | Phi input |
| test.cpp:10:8:10:9 | t2 | test.cpp:11:7:11:8 | Phi input |
| test.cpp:10:8:10:9 | t2 | test.cpp:13:10:13:11 | t2 |
| test.cpp:10:8:10:9 | t2 | test.cpp:15:3:15:6 | Phi |
| test.cpp:10:8:10:9 | t2 | test.cpp:15:3:15:6 | Phi |
| test.cpp:11:7:11:8 | Phi input | test.cpp:15:3:15:6 | SSA phi read(t2) |
| test.cpp:11:7:11:8 | Phi input | test.cpp:15:3:15:6 | SSA phi(*t2) |
| test.cpp:11:7:11:8 | t1 | test.cpp:21:8:21:9 | t1 |
| test.cpp:12:5:12:10 | ... = ... | test.cpp:13:10:13:11 | t2 |
| test.cpp:12:10:12:10 | 0 | test.cpp:12:5:12:10 | ... = ... |
| test.cpp:13:10:13:11 | t2 | test.cpp:15:3:15:6 | Phi |
| test.cpp:13:10:13:11 | t2 | test.cpp:15:3:15:6 | Phi |
| test.cpp:15:3:15:6 | Phi | test.cpp:15:8:15:9 | t2 |
| test.cpp:15:3:15:6 | Phi | test.cpp:15:8:15:9 | t2 |
| test.cpp:15:8:15:9 | t2 | test.cpp:23:19:23:19 | Phi |
| test.cpp:15:8:15:9 | t2 | test.cpp:23:19:23:19 | Phi |
| test.cpp:13:5:13:8 | Phi input | test.cpp:15:3:15:6 | SSA phi read(t2) |
| test.cpp:13:5:13:8 | Phi input | test.cpp:15:3:15:6 | SSA phi(*t2) |
| test.cpp:13:10:13:11 | t2 | test.cpp:13:5:13:8 | Phi input |
| test.cpp:13:10:13:11 | t2 | test.cpp:13:5:13:8 | Phi input |
| test.cpp:15:3:15:6 | SSA phi read(t2) | test.cpp:15:8:15:9 | t2 |
| test.cpp:15:3:15:6 | SSA phi(*t2) | test.cpp:15:8:15:9 | t2 |
| test.cpp:15:8:15:9 | t2 | test.cpp:23:15:23:16 | Phi input |
| test.cpp:15:8:15:9 | t2 | test.cpp:23:15:23:16 | Phi input |
| test.cpp:17:3:17:8 | ... = ... | test.cpp:21:8:21:9 | t1 |
| test.cpp:17:8:17:8 | 0 | test.cpp:17:3:17:8 | ... = ... |
| test.cpp:21:8:21:9 | t1 | test.cpp:23:19:23:19 | Phi |
| test.cpp:21:8:21:9 | t1 | test.cpp:23:19:23:19 | Phi |
| test.cpp:21:8:21:9 | t1 | test.cpp:23:15:23:16 | Phi input |
| test.cpp:21:8:21:9 | t1 | test.cpp:23:15:23:16 | Phi input |
| test.cpp:23:15:23:16 | 0 | test.cpp:23:15:23:16 | 0 |
| test.cpp:23:15:23:16 | 0 | test.cpp:23:19:23:19 | Phi |
| test.cpp:23:19:23:19 | Phi | test.cpp:23:19:23:19 | i |
| test.cpp:23:19:23:19 | Phi | test.cpp:23:19:23:19 | i |
| test.cpp:23:19:23:19 | Phi | test.cpp:23:23:23:24 | t1 |
| test.cpp:23:19:23:19 | Phi | test.cpp:23:23:23:24 | t1 |
| test.cpp:23:19:23:19 | Phi | test.cpp:24:10:24:11 | t2 |
| test.cpp:23:19:23:19 | Phi | test.cpp:24:10:24:11 | t2 |
| test.cpp:23:15:23:16 | 0 | test.cpp:23:15:23:16 | Phi input |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(*t2) |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(i) |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t1) |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t2) |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi(*i) |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi(*t1) |
| test.cpp:23:19:23:19 | SSA phi read(*t2) | test.cpp:24:10:24:11 | t2 |
| test.cpp:23:19:23:19 | SSA phi read(i) | test.cpp:23:19:23:19 | i |
| test.cpp:23:19:23:19 | SSA phi read(t1) | test.cpp:23:23:23:24 | t1 |
| test.cpp:23:19:23:19 | SSA phi read(t2) | test.cpp:24:10:24:11 | t2 |
| test.cpp:23:19:23:19 | SSA phi(*i) | test.cpp:23:19:23:19 | i |
| test.cpp:23:19:23:19 | SSA phi(*t1) | test.cpp:23:23:23:24 | t1 |
| test.cpp:23:19:23:19 | i | test.cpp:23:27:23:27 | i |
| test.cpp:23:19:23:19 | i | test.cpp:23:27:23:27 | i |
| test.cpp:23:23:23:24 | t1 | test.cpp:23:19:23:19 | Phi |
| test.cpp:23:23:23:24 | t1 | test.cpp:23:27:23:29 | Phi input |
| test.cpp:23:23:23:24 | t1 | test.cpp:26:8:26:9 | t1 |
| test.cpp:23:23:23:24 | t1 | test.cpp:26:8:26:9 | t1 |
| test.cpp:23:27:23:27 | *i | test.cpp:23:27:23:27 | *i |
| test.cpp:23:27:23:27 | *i | test.cpp:23:27:23:27 | i |
| test.cpp:23:27:23:27 | i | test.cpp:23:19:23:19 | Phi |
| test.cpp:23:27:23:27 | i | test.cpp:23:27:23:27 | i |
| test.cpp:23:27:23:27 | i | test.cpp:23:27:23:27 | i |
| test.cpp:23:27:23:29 | ... ++ | test.cpp:23:19:23:19 | Phi |
| test.cpp:23:27:23:27 | i | test.cpp:23:27:23:29 | Phi input |
| test.cpp:23:27:23:29 | ... ++ | test.cpp:23:27:23:29 | ... ++ |
| test.cpp:24:5:24:11 | ... = ... | test.cpp:23:19:23:19 | Phi |
| test.cpp:24:10:24:11 | t2 | test.cpp:23:19:23:19 | Phi |
| test.cpp:24:10:24:11 | t2 | test.cpp:23:19:23:19 | Phi |
| test.cpp:23:27:23:29 | ... ++ | test.cpp:23:27:23:29 | Phi input |
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(*t2) |
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(i) |
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t1) |
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t2) |
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi(*i) |
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi(*t1) |
| test.cpp:24:5:24:11 | ... = ... | test.cpp:23:27:23:29 | Phi input |
| test.cpp:24:10:24:11 | t2 | test.cpp:23:27:23:29 | Phi input |
| test.cpp:24:10:24:11 | t2 | test.cpp:23:27:23:29 | Phi input |
| test.cpp:24:10:24:11 | t2 | test.cpp:24:5:24:11 | ... = ... |
| test.cpp:382:48:382:54 | source1 | test.cpp:384:16:384:23 | *& ... |
| test.cpp:383:12:383:13 | 0 | test.cpp:383:12:383:13 | 0 |

View File

@@ -12,6 +12,10 @@ astFlow
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:62:14:62:14 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
| BarrierGuard.cpp:81:11:81:16 | call to source | BarrierGuard.cpp:86:8:86:8 | x |
| BarrierGuard.cpp:90:11:90:16 | call to source | BarrierGuard.cpp:101:8:101:8 | x |
| BarrierGuard.cpp:107:11:107:16 | call to source | BarrierGuard.cpp:112:8:112:8 | x |
| BarrierGuard.cpp:116:11:116:16 | call to source | BarrierGuard.cpp:127:8:127:8 | x |
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:22:8:22:20 | & ... |
@@ -141,6 +145,8 @@ irFlow
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
| BarrierGuard.cpp:81:11:81:16 | call to source | BarrierGuard.cpp:86:8:86:8 | x |
| BarrierGuard.cpp:90:11:90:16 | call to source | BarrierGuard.cpp:101:8:101:8 | x |
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:23:17:23:29 | *& ... |

View File

@@ -184,6 +184,7 @@ postWithInFlow
| simple.cpp:65:7:65:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
| simple.cpp:83:12:83:13 | f1 [post update] | PostUpdateNode should not be the target of local flow. |
| simple.cpp:92:7:92:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
| simple.cpp:118:7:118:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
| struct_init.c:24:11:24:12 | ab [inner post update] | PostUpdateNode should not be the target of local flow. |
| struct_init.c:36:17:36:24 | nestedAB [inner post update] | PostUpdateNode should not be the target of local flow. |
viableImplInCallContextTooLarge

View File

@@ -842,6 +842,10 @@ edges
| simple.cpp:108:17:108:26 | call to user_input | simple.cpp:108:17:108:26 | call to user_input | provenance | |
| simple.cpp:108:17:108:26 | call to user_input | simple.cpp:109:43:109:43 | x | provenance | |
| simple.cpp:109:43:109:43 | x | simple.cpp:103:24:103:24 | x | provenance | |
| simple.cpp:118:5:118:5 | *a [post update] [i] | simple.cpp:120:8:120:8 | *a [i] | provenance | |
| simple.cpp:118:5:118:22 | ... = ... | simple.cpp:118:5:118:5 | *a [post update] [i] | provenance | |
| simple.cpp:118:11:118:20 | call to user_input | simple.cpp:118:5:118:22 | ... = ... | provenance | |
| simple.cpp:120:8:120:8 | *a [i] | simple.cpp:120:10:120:10 | i | provenance | |
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:14:24:14:25 | *ab [a] | provenance | |
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:8:15:9 | *ab [a] | provenance | |
| struct_init.c:15:8:15:9 | *ab [a] | struct_init.c:15:12:15:12 | a | provenance | |
@@ -1747,6 +1751,11 @@ nodes
| simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input |
| simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input |
| simple.cpp:109:43:109:43 | x | semmle.label | x |
| simple.cpp:118:5:118:5 | *a [post update] [i] | semmle.label | *a [post update] [i] |
| simple.cpp:118:5:118:22 | ... = ... | semmle.label | ... = ... |
| simple.cpp:118:11:118:20 | call to user_input | semmle.label | call to user_input |
| simple.cpp:120:8:120:8 | *a [i] | semmle.label | *a [i] |
| simple.cpp:120:10:120:10 | i | semmle.label | i |
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |
| 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] |
@@ -1957,6 +1966,7 @@ subpaths
| 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:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input |
| simple.cpp:104:14:104:14 | x | simple.cpp:108:17:108:26 | call to user_input | simple.cpp:104:14:104:14 | x | x flows from $@ | simple.cpp:108:17:108:26 | call to user_input | call to user_input |
| simple.cpp:120:10:120:10 | i | simple.cpp:118:11:118:20 | call to user_input | simple.cpp:120:10:120:10 | i | i flows from $@ | simple.cpp:118:11:118:20 | 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 |

View File

@@ -289,3 +289,5 @@ WARNING: Module DataFlow has been deprecated and may be removed in future (parti
| simple.cpp:83:12:83:13 | f1 | AST only |
| simple.cpp:92:7:92:7 | i | AST only |
| simple.cpp:94:10:94:11 | a2 | IR only |
| simple.cpp:118:7:118:7 | i | AST only |
| simple.cpp:120:8:120:8 | a | IR only |

View File

@@ -649,6 +649,8 @@
| simple.cpp:84:14:84:20 | this |
| simple.cpp:92:5:92:5 | a |
| simple.cpp:94:10:94:11 | a2 |
| simple.cpp:118:5:118:5 | a |
| simple.cpp:120:8:120:8 | a |
| struct_init.c:15:8:15:9 | ab |
| struct_init.c:15:12:15:12 | a |
| struct_init.c:16:8:16:9 | ab |

View File

@@ -579,6 +579,8 @@ WARNING: Module DataFlow has been deprecated and may be removed in future (parti
| simple.cpp:84:14:84:20 | this |
| simple.cpp:92:5:92:5 | a |
| simple.cpp:92:7:92:7 | i |
| simple.cpp:118:5:118:5 | a |
| simple.cpp:118:7:118:7 | i |
| struct_init.c:15:8:15:9 | ab |
| struct_init.c:15:12:15:12 | a |
| struct_init.c:16:8:16:9 | ab |

View File

@@ -731,6 +731,10 @@ edges
| simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] | provenance | |
| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... | provenance | |
| simple.cpp:94:10:94:11 | a2 [i] | simple.cpp:94:13:94:13 | i | provenance | |
| simple.cpp:118:5:118:5 | a [post update] [i] | simple.cpp:120:8:120:8 | a [i] | provenance | |
| simple.cpp:118:5:118:22 | ... = ... | simple.cpp:118:5:118:5 | a [post update] [i] | provenance | |
| simple.cpp:118:11:118:20 | call to user_input | simple.cpp:118:5:118:22 | ... = ... | provenance | |
| simple.cpp:120:8:120:8 | a [i] | simple.cpp:120:10:120:10 | i | provenance | |
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:14:24:14:25 | ab [a] | provenance | |
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | provenance | |
| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | provenance | |
@@ -1538,6 +1542,11 @@ nodes
| simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input |
| simple.cpp:94:10:94:11 | a2 [i] | semmle.label | a2 [i] |
| simple.cpp:94:13:94:13 | i | semmle.label | i |
| simple.cpp:118:5:118:5 | a [post update] [i] | semmle.label | a [post update] [i] |
| simple.cpp:118:5:118:22 | ... = ... | semmle.label | ... = ... |
| simple.cpp:118:11:118:20 | call to user_input | semmle.label | call to user_input |
| simple.cpp:120:8:120:8 | a [i] | semmle.label | a [i] |
| simple.cpp:120:10:120:10 | i | semmle.label | i |
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
| 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] |
@@ -1751,6 +1760,7 @@ subpaths
| 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:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input |
| simple.cpp:120:10:120:10 | i | simple.cpp:118:11:118:20 | call to user_input | simple.cpp:120:10:120:10 | i | i flows from $@ | simple.cpp:118:11:118:20 | 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 |

View File

@@ -111,4 +111,13 @@ namespace TestAdditionalCallTargets {
}
void post_update_to_phi_input(bool b)
{
A a;
if(b) {
a.i = user_input();
}
sink(a.i); // $ ast,ir
}
} // namespace Simple