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 4e21fb749a5..aec7e3b780e 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 @@ -185,7 +185,13 @@ class CastNode extends InstructionNode { CastNode() { none() } // stub implementation } -class DataFlowCallable = Function; +/** + * A function that may contain code or a variable that may contain itself. When + * flow crosses from one _enclosing callable_ to another, the interprocedural + * data-flow library discards call contexts and inserts a node in the big-step + * relation used for human-readable path explanations. + */ +class DataFlowCallable = Declaration; class DataFlowExpr = Expr; 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 fbcbb3b416d..3fb7474fe08 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 @@ -8,12 +8,9 @@ private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.ir.ValueNumbering private import semmle.code.cpp.models.interfaces.DataFlow -/** - * A newtype wrapper to prevent accidental casts between `Node` and - * `Instruction`. This ensures we can add `Node`s that are not `Instruction`s - * in the future. - */ -private newtype TIRDataFlowNode = TInstructionNode(Instruction i) +private newtype TIRDataFlowNode = + TInstructionNode(Instruction i) or + TVariableNode(Variable var) /** * A node in a data flow graph. @@ -24,11 +21,11 @@ private newtype TIRDataFlowNode = TInstructionNode(Instruction i) */ class Node extends TIRDataFlowNode { /** - * INTERNAL: Do not use. Alternative name for `getFunction`. + * INTERNAL: Do not use. */ - Function getEnclosingCallable() { result = this.getFunction() } + Declaration getEnclosingCallable() { none() } // overridden in subclasses - /** Gets the function to which this node belongs. */ + /** Gets the function to which this node belongs, if any. */ Function getFunction() { none() } // overridden in subclasses /** Gets the type of this node. */ @@ -57,6 +54,12 @@ class Node extends TIRDataFlowNode { /** Gets the parameter corresponding to this node, if any. */ Parameter asParameter() { result = this.(ParameterNode).getParameter() } + /** + * Gets the variable corresponding to this node, if any. This can be used for + * modelling flow in and out of global variables. + */ + Variable asVariable() { result = this.(VariableNode).getVariable() } + /** * DEPRECATED: See UninitializedNode. * @@ -98,6 +101,8 @@ class InstructionNode extends Node, TInstructionNode { /** Gets the instruction corresponding to this node. */ Instruction getInstruction() { result = instr } + override Declaration getEnclosingCallable() { result = this.getFunction() } + override Function getFunction() { result = instr.getEnclosingFunction() } override Type getType() { result = instr.getResultType() } @@ -236,6 +241,37 @@ class DefinitionByReferenceNode extends InstructionNode { } } +/** + * A `Node` corresponding to a variable in the program, as opposed to the + * value of that variable at some particular point. This can be used for + * modelling flow in and out of global variables. + */ +class VariableNode extends Node, TVariableNode { + Variable v; + + VariableNode() { this = TVariableNode(v) } + + /** Gets the variable corresponding to this node. */ + Variable getVariable() { result = v } + + override Function getFunction() { none() } + + override Declaration getEnclosingCallable() { + // When flow crosses from one _enclosing callable_ to another, the + // interprocedural data-flow library discards call contexts and inserts a + // node in the big-step relation used for human-readable path explanations. + // Therefore we want a distinct enclosing callable for each `VariableNode`, + // and that can be the `Variable` itself. + result = v + } + + override Type getType() { result = v.getType() } + + override Location getLocation() { result = v.getLocation() } + + override string toString() { result = v.toString() } +} + /** * Gets the node corresponding to `instr`. */ @@ -260,6 +296,9 @@ ExprNode convertedExprNode(Expr e) { result.getExpr() = e } */ ParameterNode parameterNode(Parameter p) { result.getParameter() = p } +/** Gets the `VariableNode` corresponding to the variable `v`. */ +VariableNode variableNode(Variable v) { result.getVariable() = v } + /** * Gets the `Node` corresponding to the value of an uninitialized local * variable `v`.