private import ruby private import DataFlowDispatch private import DataFlowPrivate private import codeql_ruby.CFG private import codeql_ruby.typetracking.TypeTracker /** * An element, viewed as a node in a data flow graph. Either an expression * (`ExprNode`) or a parameter (`ParameterNode`). */ class Node extends TNode { /** Gets the expression corresponding to this node, if any. */ CfgNodes::ExprCfgNode asExpr() { result = this.(ExprNode).getExprNode() } /** Gets the parameter corresponding to this node, if any. */ Parameter asParameter() { result = this.(ParameterNode).getParameter() } /** Gets a textual representation of this node. */ // TODO: cache final string toString() { result = this.(NodeImpl).toStringImpl() } /** Gets the location of this node. */ // TODO: cache final Location getLocation() { result = this.(NodeImpl).getLocationImpl() } final DataFlowCallable getEnclosingCallable() { result = this.(NodeImpl).getCfgScope() } /** * Holds if this element is at the specified location. * The location spans column `startcolumn` of line `startline` to * column `endcolumn` of line `endline` in file `filepath`. * For more information, see * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). */ predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } } /** * An expression, viewed as a node in a data flow graph. * * Note that because of control-flow splitting, one `Expr` may correspond * to multiple `ExprNode`s, just like it may correspond to multiple * `ControlFlow::Node`s. */ class ExprNode extends Node, TExprNode { private CfgNodes::ExprCfgNode n; ExprNode() { this = TExprNode(n) } /** Gets the expression corresponding to this node. */ CfgNodes::ExprCfgNode getExprNode() { result = n } } /** * The value of a parameter at function entry, viewed as a node in a data * flow graph. */ class ParameterNode extends Node, TParameterNode { private Parameter p; ParameterNode() { this = TParameterNode(p) } /** Gets the parameter corresponding to this node, if any. */ Parameter getParameter() { result = p } /** * Holds if this node is the parameter of callable `c` at the specified * (zero-based) position. */ predicate isParameterOf(Callable c, int i) { p = c.getParameter(i) } } /** * A data-flow node that is a source of local flow. */ class LocalSourceNode extends Node { LocalSourceNode() { not simpleLocalFlowStep+(any(ExprNode n), this) } /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ pragma[inline] predicate flowsTo(Node nodeTo) { hasLocalSource(nodeTo, this) } /** * Gets a node that this node may flow to using one heap and/or interprocedural step. * * See `TypeTracker` for more details about how to use this. */ pragma[inline] LocalSourceNode track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) } } predicate hasLocalSource(Node sink, Node source) { // Declaring `source` to be a `SourceNode` currently causes a redundant check in the // recursive case, so instead we check it explicitly here. source = sink and source instanceof LocalSourceNode or exists(Node mid | hasLocalSource(mid, source) and simpleLocalFlowStep(mid, sink) ) } /** Gets a node corresponding to expression `e`. */ ExprNode exprNode(CfgNodes::ExprCfgNode e) { result.getExprNode() = e } /** * Gets the node corresponding to the value of parameter `p` at function entry. */ ParameterNode parameterNode(Parameter p) { result.getParameter() = p } predicate localFlowStep = simpleLocalFlowStep/2; /** * Holds if data flows from `source` to `sink` in zero or more local * (intra-procedural) steps. */ predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } /** * Holds if data can flow from `e1` to `e2` in zero or more * local (intra-procedural) steps. */ predicate localExprFlow(CfgNodes::ExprCfgNode e1, CfgNodes::ExprCfgNode e2) { localFlow(exprNode(e1), exprNode(e2)) } /** * A reference contained in an object. This is either a field, a property, * or an element in a collection. */ class Content extends TContent { /** Gets a textual representation of this content. */ string toString() { none() } /** Gets the location of this content. */ Location getLocation() { none() } }