Merge pull request #12429 from MathiasVP/actually-implement-language-specific-flow-into-call-node-cand1

C++: Implement `getAdditionalFlowIntoCallNodeTerm`
This commit is contained in:
Mathias Vorreiter Pedersen
2023-03-08 11:58:56 +00:00
committed by GitHub
2 changed files with 89 additions and 20 deletions

View File

@@ -5,6 +5,8 @@ private import DataFlowDispatch
private import DataFlowImplConsistency
private import semmle.code.cpp.ir.internal.IRCppLanguage
private import SsaInternals as Ssa
private import DataFlowImplCommon
private import semmle.code.cpp.ir.ValueNumbering
cached
private module Cached {
@@ -890,6 +892,23 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
}
}
/**
* Gets the basic block of `node`.
*/
IRBlock getBasicBlock(Node node) {
node.asInstruction().getBlock() = result
or
node.asOperand().getUse().getBlock() = result
or
node.(SsaPhiNode).getPhiNode().getBasicBlock() = result
or
node.(RawIndirectOperand).getOperand().getUse().getBlock() = result
or
node.(RawIndirectInstruction).getInstruction().getBlock() = result
or
result = getBasicBlock(node.(PostUpdateNode).getPreUpdateNode())
}
/**
* Gets an additional term that is added to the `join` and `branch` computations to reflect
* an additional forward or backwards branching factor that is not taken into account
@@ -897,4 +916,57 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
*
* Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
*/
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) { none() }
pragma[nomagic]
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) {
exists(ParameterNode switchee, SwitchInstruction switch, ConditionOperand op, DataFlowCall call |
viableParamArg(call, p, arg) and
viableParamArg(call, switchee, _) and
switch.getExpressionOperand() = op and
valueNumber(switchee.asInstruction()).getAUse() = op and
result = countNumberOfBranchesUsingParameter(switch, p)
)
}
/** Gets the `IRVariable` associated with the parameter node `p`. */
pragma[nomagic]
private IRVariable getIRVariableForParameterNode(ParameterNode p) {
result = p.(DirectParameterNode).getIRVariable()
or
result.getAst() = p.(IndirectParameterNode).getParameter()
}
/** Holds if `v` is the source variable corresponding to the parameter represented by `p`. */
pragma[nomagic]
private predicate parameterNodeHasSourceVariable(ParameterNode p, Ssa::SourceIRVariable v) {
v.getIRVariable() = getIRVariableForParameterNode(p) and
exists(Position pos | p.isParameterOf(_, pos) |
pos instanceof DirectPosition and
v.getIndirection() = 1
or
pos.(IndirectionPosition).getIndirectionIndex() + 1 = v.getIndirection()
)
}
private EdgeKind caseOrDefaultEdge() {
result instanceof CaseEdge or
result instanceof DefaultEdge
}
/**
* Gets the number of switch branches that that read from (or write to) the parameter `p`.
*/
int countNumberOfBranchesUsingParameter(SwitchInstruction switch, ParameterNode p) {
exists(Ssa::SourceVariable sv |
parameterNodeHasSourceVariable(p, sv) and
// Count the number of cases that use the parameter. We do this by finding the phi node
// that merges the uses/defs of the parameter. There might be multiple such phi nodes, so
// we pick the one with the highest edge count.
result =
max(SsaPhiNode phi |
switch.getSuccessor(caseOrDefaultEdge()).getBlock().dominanceFrontier() = getBasicBlock(phi) and
phi.getSourceVariable() = sv
|
strictcount(phi.getAnInput())
)
)
}

View File

@@ -525,6 +525,9 @@ class SsaPhiNode extends Node, TSsaPhiNode {
/** Gets a node that is used as input to this phi node. */
final Node getAnInput() { result = this.getAnInput(_) }
/** Gets the source variable underlying this phi node. */
Ssa::SourceVariable getSourceVariable() { result = phi.getSourceVariable() }
}
/**
@@ -1202,10 +1205,20 @@ class ParameterNode extends Node {
predicate isParameterOf(Function f, ParameterPosition pos) { none() } // overridden by subclasses
}
/** An explicit positional parameter, not including `this` or `...`. */
private class ExplicitParameterNode extends ParameterNode, InstructionNode {
/** An explicit positional parameter, including `this`, but not `...`. */
class DirectParameterNode extends InstructionNode {
override InitializeParameterInstruction instr;
/**
* INTERNAL: Do not use.
*
* Gets the `IRVariable` that this parameter references.
*/
IRVariable getIRVariable() { result = instr.getIRVariable() }
}
/** An explicit positional parameter, not including `this` or `...`. */
private class ExplicitParameterNode extends ParameterNode, DirectParameterNode {
ExplicitParameterNode() { exists(instr.getParameter()) }
override predicate isParameterOf(Function f, ParameterPosition pos) {
@@ -1219,9 +1232,7 @@ private class ExplicitParameterNode extends ParameterNode, InstructionNode {
}
/** An implicit `this` parameter. */
class ThisParameterNode extends ParameterNode, InstructionNode {
override InitializeParameterInstruction instr;
class ThisParameterNode extends ParameterNode, DirectParameterNode {
ThisParameterNode() { instr.getIRVariable() instanceof IRThisVariable }
override predicate isParameterOf(Function f, ParameterPosition pos) {
@@ -1774,20 +1785,6 @@ class ContentSet instanceof Content {
}
}
private IRBlock getBasicBlock(Node node) {
node.asInstruction().getBlock() = result
or
node.asOperand().getUse().getBlock() = result
or
node.(SsaPhiNode).getPhiNode().getBasicBlock() = result
or
node.(RawIndirectOperand).getOperand().getUse().getBlock() = result
or
node.(RawIndirectInstruction).getInstruction().getBlock() = result
or
result = getBasicBlock(node.(PostUpdateNode).getPreUpdateNode())
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*