-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Rust: Implement enclosing callable #17921
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,65 @@ private import codeql.rust.controlflow.ControlFlowGraph | |
private import codeql.rust.controlflow.CfgNodes | ||
private import codeql.rust.dataflow.Ssa | ||
|
||
private newtype TReturnKind = TNormalReturnKind() | ||
|
||
/** | ||
* A return kind. A return kind describes how a value can be returned from a | ||
* callable. | ||
* | ||
* The only return kind is a "normal" return from a `return` statement or an | ||
* expression body. | ||
*/ | ||
final class ReturnKind extends TNormalReturnKind { | ||
string toString() { result = "return" } | ||
} | ||
|
||
/** | ||
* A callable. This includes callables from source code, as well as callables | ||
* defined in library code. | ||
*/ | ||
final class DataFlowCallable extends TDataFlowCallable { | ||
/** | ||
* Gets the underlying CFG scope, if any. | ||
*/ | ||
CfgScope asCfgScope() { this = TCfgScope(result) } | ||
|
||
/** Gets a textual representation of this callable. */ | ||
string toString() { result = this.asCfgScope().toString() } | ||
|
||
/** Gets the location of this callable. */ | ||
Location getLocation() { result = this.asCfgScope().getLocation() } | ||
} | ||
|
||
abstract class DataFlowCall extends TDataFlowCall { | ||
/** Gets the enclosing callable. */ | ||
abstract DataFlowCallable getEnclosingCallable(); | ||
|
||
/** Gets the underlying source code call, if any. */ | ||
abstract CallCfgNode asCall(); | ||
|
||
/** Gets a textual representation of this call. */ | ||
abstract string toString(); | ||
|
||
/** Gets the location of this call. */ | ||
abstract Location getLocation(); | ||
} | ||
|
||
final class NormalCall extends DataFlowCall, TNormalCall { | ||
private CallCfgNode c; | ||
|
||
NormalCall() { this = TNormalCall(c) } | ||
|
||
/** Gets the underlying call in the CFG, if any. */ | ||
override CallCfgNode asCall() { result = c } | ||
|
||
override DataFlowCallable getEnclosingCallable() { none() } | ||
|
||
override string toString() { result = c.toString() } | ||
|
||
override Location getLocation() { result = c.getLocation() } | ||
} | ||
|
||
module Node { | ||
/** | ||
* An element, viewed as a node in a data flow graph. Either an expression | ||
|
@@ -29,6 +88,12 @@ module Node { | |
*/ | ||
Expr asExpr() { none() } | ||
|
||
/** Gets the enclosing callable. */ | ||
DataFlowCallable getEnclosingCallable() { result = TCfgScope(this.getCfgScope()) } | ||
|
||
/** Do not call: use `getEnclosingCallable()` instead. */ | ||
abstract CfgScope getCfgScope(); | ||
|
||
/** | ||
* Gets the control flow node that corresponds to this data flow node. | ||
*/ | ||
|
@@ -49,6 +114,8 @@ module Node { | |
final class NaNode extends Node { | ||
NaNode() { none() } | ||
|
||
override CfgScope getCfgScope() { none() } | ||
|
||
override string toString() { result = "N/A" } | ||
|
||
override Location getLocation() { none() } | ||
|
@@ -62,11 +129,13 @@ module Node { | |
* to multiple `ExprNode`s, just like it may correspond to multiple | ||
* `ControlFlow::Node`s. | ||
*/ | ||
final class ExprNode extends Node, TExprNode { | ||
class ExprNode extends Node, TExprNode { | ||
ExprCfgNode n; | ||
|
||
ExprNode() { this = TExprNode(n) } | ||
|
||
override CfgScope getCfgScope() { result = this.asExpr().getEnclosingCallable() } | ||
|
||
override Location getLocation() { result = n.getExpr().getLocation() } | ||
|
||
override string toString() { result = n.getExpr().toString() } | ||
|
@@ -85,6 +154,8 @@ module Node { | |
|
||
ParameterNode() { this = TParameterNode(parameter) } | ||
|
||
override CfgScope getCfgScope() { result = parameter.getEnclosingCallable() } | ||
|
||
override Location getLocation() { result = parameter.getLocation() } | ||
|
||
override string toString() { result = parameter.toString() } | ||
|
@@ -105,6 +176,8 @@ module Node { | |
def = node.getDefinitionExt() | ||
} | ||
|
||
override CfgScope getCfgScope() { result = def.getBasicBlock().getScope() } | ||
|
||
SsaImpl::DefinitionExt getDefinitionExt() { result = def } | ||
|
||
/** Holds if this node should be hidden from path explanations. */ | ||
|
@@ -115,11 +188,25 @@ module Node { | |
override string toString() { result = node.toString() } | ||
} | ||
|
||
final class ReturnNode extends NaNode { | ||
RustDataFlow::ReturnKind getKind() { none() } | ||
/** A data flow node that represents a value returned by a callable. */ | ||
final class ReturnNode extends ExprNode { | ||
ReturnNode() { this.getCfgNode().getASuccessor() instanceof ExitCfgNode } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should just be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, so we don't want to include implicit returns like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, we need to include that as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've reinstated the old implementation again :). If we want to include implicit returns then I think just looking at edges into the exit node handles all cases.
|
||
|
||
ReturnKind getKind() { any() } | ||
} | ||
|
||
/** A data-flow node that represents the output of a call. */ | ||
abstract class OutNode extends Node, ExprNode { | ||
/** Gets the underlying call for this node. */ | ||
abstract DataFlowCall getCall(); | ||
} | ||
|
||
final class OutNode = NaNode; | ||
final private class ExprOutNode extends OutNode { | ||
ExprOutNode() { this.asExpr() instanceof CallExpr } | ||
|
||
/** Gets the underlying call CFG node that includes this out node. */ | ||
override DataFlowCall getCall() { result.(NormalCall).asCall() = this.getCfgNode() } | ||
} | ||
|
||
/** | ||
* A node associated with an object after an operation that might have | ||
|
@@ -198,6 +285,12 @@ module LocalFlow { | |
} | ||
} | ||
|
||
private class DataFlowCallableAlias = DataFlowCallable; | ||
|
||
private class ReturnKindAlias = ReturnKind; | ||
|
||
private class DataFlowCallAlias = DataFlowCall; | ||
|
||
module RustDataFlow implements InputSig<Location> { | ||
/** | ||
* An element, viewed as a node in a data flow graph. Either an expression | ||
|
@@ -221,7 +314,7 @@ module RustDataFlow implements InputSig<Location> { | |
|
||
predicate isArgumentNode(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) { none() } | ||
|
||
DataFlowCallable nodeGetEnclosingCallable(Node node) { none() } | ||
DataFlowCallable nodeGetEnclosingCallable(Node node) { result = node.getEnclosingCallable() } | ||
|
||
DataFlowType getNodeType(Node node) { any() } | ||
|
||
|
@@ -232,26 +325,22 @@ module RustDataFlow implements InputSig<Location> { | |
/** Gets the node corresponding to `e`. */ | ||
Node exprNode(DataFlowExpr e) { result.getCfgNode() = e } | ||
|
||
final class DataFlowCall extends TNormalCall { | ||
private CallExpr c; | ||
|
||
DataFlowCall() { this = TNormalCall(c) } | ||
|
||
DataFlowCallable getEnclosingCallable() { none() } | ||
|
||
string toString() { result = c.toString() } | ||
|
||
Location getLocation() { result = c.getLocation() } | ||
} | ||
final class DataFlowCall = DataFlowCallAlias; | ||
|
||
final class DataFlowCallable = CfgScope; | ||
final class DataFlowCallable = DataFlowCallableAlias; | ||
|
||
final class ReturnKind = Void; | ||
final class ReturnKind = ReturnKindAlias; | ||
|
||
/** Gets a viable implementation of the target of the given `Call`. */ | ||
DataFlowCallable viableCallable(DataFlowCall c) { none() } | ||
|
||
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { none() } | ||
/** | ||
* Gets a node that can read the value returned from `call` with return kind | ||
* `kind`. | ||
*/ | ||
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { | ||
call = result.getCall() and exists(kind) | ||
} | ||
|
||
// NOTE: For now we use the type `Unit` and do not benefit from type | ||
// information in the data flow analysis. | ||
|
@@ -400,7 +489,7 @@ private module Cached { | |
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) | ||
|
||
cached | ||
newtype TDataFlowCall = TNormalCall(CallExpr c) | ||
newtype TDataFlowCall = TNormalCall(CallCfgNode c) | ||
|
||
cached | ||
newtype TOptionalContentSet = | ||
|
@@ -410,6 +499,9 @@ private module Cached { | |
cached | ||
class TContentSet = TAnyElementContent or TAnyContent; | ||
|
||
cached | ||
newtype TDataFlowCallable = TCfgScope(CfgScope scope) | ||
|
||
/** This is the local flow predicate that is exposed. */ | ||
cached | ||
predicate localFlowStepImpl(Node::Node nodeFrom, Node::Node nodeTo) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,2 @@ | ||
uniqueEnclosingCallable | ||
| gen_become_expr.rs:4:11:4:16 | Param | Node should have one enclosing callable but has 0. | | ||
| gen_become_expr.rs:4:19:4:24 | Param | Node should have one enclosing callable but has 0. | | ||
uniqueCallEnclosingCallable | ||
| gen_become_expr.rs:8:17:8:36 | CallExpr | Call should have one enclosing callable but has 0. | |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
uniqueCallEnclosingCallable | ||
| gen_continue_expr.rs:6:12:6:22 | CallExpr | Call should have one enclosing callable but has 0. | | ||
| gen_continue_expr.rs:11:12:11:22 | CallExpr | Call should have one enclosing callable but has 0. | |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,2 @@ | ||
uniqueEnclosingCallable | ||
| gen_let_expr.rs:3:18:3:43 | Param | Node should have one enclosing callable but has 0. | | ||
uniqueCallEnclosingCallable | ||
| gen_let_expr.rs:6:18:6:24 | CallExpr | Call should have one enclosing callable but has 0. | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
uniqueCallEnclosingCallable | ||
| gen_loop_expr.rs:6:18:6:40 | CallExpr | Call should have one enclosing callable but has 0. | | ||
| gen_loop_expr.rs:9:18:9:39 | CallExpr | Call should have one enclosing callable but has 0. | |
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add QL doc:
Gets a textual representation of this call.