C++: Add VariableNode

This commit is contained in:
Jonas Jensen
2020-02-04 13:21:33 +01:00
parent 73e34f1447
commit 6d081a997a
2 changed files with 55 additions and 10 deletions

View File

@@ -185,7 +185,13 @@ class CastNode extends InstructionNode {
CastNode() { none() } // stub implementation 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; class DataFlowExpr = Expr;

View File

@@ -8,12 +8,9 @@ private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.ir.ValueNumbering private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.models.interfaces.DataFlow private import semmle.code.cpp.models.interfaces.DataFlow
/** private newtype TIRDataFlowNode =
* A newtype wrapper to prevent accidental casts between `Node` and TInstructionNode(Instruction i) or
* `Instruction`. This ensures we can add `Node`s that are not `Instruction`s TVariableNode(Variable var)
* in the future.
*/
private newtype TIRDataFlowNode = TInstructionNode(Instruction i)
/** /**
* A node in a data flow graph. * A node in a data flow graph.
@@ -24,11 +21,11 @@ private newtype TIRDataFlowNode = TInstructionNode(Instruction i)
*/ */
class Node extends TIRDataFlowNode { 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 Function getFunction() { none() } // overridden in subclasses
/** Gets the type of this node. */ /** Gets the type of this node. */
@@ -57,6 +54,12 @@ class Node extends TIRDataFlowNode {
/** Gets the parameter corresponding to this node, if any. */ /** Gets the parameter corresponding to this node, if any. */
Parameter asParameter() { result = this.(ParameterNode).getParameter() } 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. * DEPRECATED: See UninitializedNode.
* *
@@ -98,6 +101,8 @@ class InstructionNode extends Node, TInstructionNode {
/** Gets the instruction corresponding to this node. */ /** Gets the instruction corresponding to this node. */
Instruction getInstruction() { result = instr } Instruction getInstruction() { result = instr }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Function getFunction() { result = instr.getEnclosingFunction() } override Function getFunction() { result = instr.getEnclosingFunction() }
override Type getType() { result = instr.getResultType() } 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`. * Gets the node corresponding to `instr`.
*/ */
@@ -260,6 +296,9 @@ ExprNode convertedExprNode(Expr e) { result.getExpr() = e }
*/ */
ParameterNode parameterNode(Parameter p) { result.getParameter() = p } 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 * Gets the `Node` corresponding to the value of an uninitialized local
* variable `v`. * variable `v`.