Address review comments

This commit is contained in:
Tom Hvitved
2025-12-03 21:08:42 +01:00
parent 38a572dfa0
commit bc6d38ebb4
28 changed files with 328 additions and 247 deletions

View File

@@ -258,7 +258,8 @@ final class CallExprCfgNode extends Nodes::CallExprCfgNode {
/** Gets the `i`th argument of this call. */
ExprCfgNode getSyntacticArgument(int i) {
any(ChildMapping mapping).hasCfgChild(node, node.getSyntacticArgument(i), this, result)
any(ChildMapping mapping)
.hasCfgChild(node, node.getSyntacticPositionalArgument(i), this, result)
}
}

View File

@@ -210,13 +210,18 @@ module ExprTrees {
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
}
class ArgsExprTree extends StandardPostOrderTree instanceof ArgsExpr {
ArgsExprTree() {
class InvocationExprTree extends StandardPostOrderTree instanceof InvocationExpr {
InvocationExprTree() {
not this instanceof CallExpr and
not this instanceof BinaryLogicalOperation
}
override AstNode getChildNode(int i) { result = super.getSyntacticArgument(i) }
override AstNode getChildNode(int i) {
i = 0 and
result = super.getSyntacticReceiver()
or
result = super.getSyntacticPositionalArgument(i - 1)
}
}
class LogicalOrExprTree extends PostOrderTree, LogicalOrExpr {
@@ -295,7 +300,7 @@ module ExprTrees {
override AstNode getChildNode(int i) {
i = 0 and result = super.getFunction()
or
result = super.getSyntacticArgument(i - 1)
result = super.getSyntacticPositionalArgument(i - 1)
}
}
@@ -533,10 +538,6 @@ module ExprTrees {
}
}
class RefExprTree extends StandardPostOrderTree instanceof RefExpr {
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
}
class ReturnExprTree extends StandardPostOrderTree instanceof ReturnExpr {
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
}

View File

@@ -5,6 +5,7 @@
private import rust
private import codeql.rust.frameworks.stdlib.Builtins
private import DataFlowImpl
private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl
/**
* A path to a value contained in an object. For example a field name of a struct.
@@ -168,10 +169,10 @@ final class TuplePositionContent extends FieldContent, TTuplePositionContent {
* Used by the model generator to create flow summaries for higher-order
* functions.
*/
final class ClosureCallArgumentContent extends Content, TClosureCallArgumentContent {
final class FunctionCallArgumentContent extends Content, TFunctionCallArgumentContent {
private int pos;
ClosureCallArgumentContent() { this = TClosureCallArgumentContent(pos) }
FunctionCallArgumentContent() { this = TFunctionCallArgumentContent(pos) }
int getPosition() { result = pos }
@@ -269,8 +270,8 @@ newtype TContent =
)]
} or
TFunctionCallReturnContent() or
TClosureCallArgumentContent(int pos) {
pos in [0 .. any(ClosureCallExpr c).getNumberOfPositionalArguments()]
TFunctionCallArgumentContent(int pos) {
pos in [0 .. any(CallExprImpl::DynamicCallExpr c).getNumberOfPositionalArguments()]
} or
TCapturedVariableContent(VariableCapture::CapturedVariable v) or
TReferenceContent()

View File

@@ -10,6 +10,7 @@ private import codeql.dataflow.internal.DataFlowImpl
private import rust
private import SsaImpl as SsaImpl
private import codeql.rust.controlflow.internal.Scope as Scope
private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl
private import codeql.rust.internal.PathResolution
private import codeql.rust.controlflow.ControlFlowGraph
private import codeql.rust.dataflow.Ssa
@@ -85,62 +86,10 @@ final class DataFlowCall extends TDataFlowCall {
Location getLocation() { result = this.asCall().getLocation() }
}
/**
* The position of a parameter in a function.
*
* In Rust there is a 1-to-1 correspondence between parameter positions and
* arguments positions, so we use the same underlying type for both.
*/
final class ParameterPosition extends TParameterPosition {
/** Gets the underlying integer position, if any. */
int getPosition() { this = TPositionalParameterPosition(result) }
predicate hasPosition() { exists(this.getPosition()) }
/** Holds if this position represents the `self` position. */
predicate isSelf() { this = TSelfParameterPosition() }
/**
* Holds if this position represents a reference to a closure itself. Only
* used for tracking flow through captured variables.
*/
predicate isClosureSelf() { this = TClosureSelfParameterPosition() }
/** Gets a textual representation of this position. */
string toString() {
result = this.getPosition().toString()
or
result = "self" and this.isSelf()
or
result = "closure self" and this.isClosureSelf()
}
ParamBase getParameterIn(ParamList ps) {
result = ps.getParam(this.getPosition())
or
result = ps.getSelfParam() and this.isSelf()
}
}
/**
* The position of an argument in a call.
*
* In Rust there is a 1-to-1 correspondence between parameter positions and
* arguments positions, so we use the same underlying type for both.
*/
final class ArgumentPosition extends ParameterPosition {
/** Gets the argument of `call` at this position, if any. */
Expr getArgument(Call call) {
result = call.getPositionalArgument(this.getPosition())
or
result = call.(MethodCall).getReceiver() and this.isSelf()
}
}
/**
* Holds if `arg` is an argument of `call` at the position `pos`.
*/
predicate isArgumentForCall(Expr arg, Call call, ArgumentPosition pos) {
predicate isArgumentForCall(Expr arg, Call call, RustDataFlow::ArgumentPosition pos) {
// TODO: Handle index expressions as calls in data flow.
not call instanceof IndexExpr and
arg = pos.getArgument(call)
@@ -292,8 +241,8 @@ predicate lambdaCreationExpr(Expr creation) {
* Holds if `call` is a lambda call of kind `kind` where `receiver` is the
* invoked expression.
*/
predicate lambdaCallExpr(ClosureCallExpr call, LambdaCallKind kind, Expr receiver) {
receiver = call.getClosureExpr() and
predicate lambdaCallExpr(CallExprImpl::DynamicCallExpr call, LambdaCallKind kind, Expr receiver) {
receiver = call.getFunction() and
exists(kind)
}
@@ -305,10 +254,6 @@ private module Aliases {
class DataFlowCallAlias = DataFlowCall;
class ParameterPositionAlias = ParameterPosition;
class ArgumentPositionAlias = ArgumentPosition;
class ContentAlias = Content;
class ContentSetAlias = ContentSet;
@@ -340,6 +285,58 @@ module RustDataFlow implements InputSig<Location> {
final class CastNode = Node::CastNode;
/**
* The position of a parameter in a function.
*
* In Rust there is a 1-to-1 correspondence between parameter positions and
* arguments positions, so we use the same underlying type for both.
*/
final class ParameterPosition extends TParameterPosition {
/** Gets the underlying integer position, if any. */
int getPosition() { this = TPositionalParameterPosition(result) }
predicate hasPosition() { exists(this.getPosition()) }
/** Holds if this position represents the `self` position. */
predicate isSelf() { this = TSelfParameterPosition() }
/**
* Holds if this position represents a reference to a closure itself. Only
* used for tracking flow through captured variables.
*/
predicate isClosureSelf() { this = TClosureSelfParameterPosition() }
/** Gets a textual representation of this position. */
string toString() {
result = this.getPosition().toString()
or
result = "self" and this.isSelf()
or
result = "closure self" and this.isClosureSelf()
}
ParamBase getParameterIn(ParamList ps) {
result = ps.getParam(this.getPosition())
or
result = ps.getSelfParam() and this.isSelf()
}
}
/**
* The position of an argument in a call.
*
* In Rust there is a 1-to-1 correspondence between parameter positions and
* arguments positions, so we use the same underlying type for both.
*/
final class ArgumentPosition extends ParameterPosition {
/** Gets the argument of `call` at this position, if any. */
Expr getArgument(Call call) {
result = call.getPositionalArgument(this.getPosition())
or
result = call.(MethodCall).getReceiver() and this.isSelf()
}
}
/** Holds if `p` is a parameter of `c` at the position `pos`. */
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
p.isParameterOf(c, pos)
@@ -449,10 +446,6 @@ module RustDataFlow implements InputSig<Location> {
ContentApprox getContentApprox(Content c) { result = c }
class ParameterPosition = ParameterPositionAlias;
class ArgumentPosition = ArgumentPositionAlias;
/**
* Holds if the parameter position `ppos` matches the argument position
* `apos`.
@@ -664,7 +657,7 @@ module RustDataFlow implements InputSig<Location> {
pragma[nomagic]
additional predicate storeContentStep(Node node1, Content c, Node node2) {
exists(CallExpr ce, TupleField tf, int pos |
node1.asExpr() = ce.getSyntacticArgument(pos) and
node1.asExpr() = ce.getSyntacticPositionalArgument(pos) and
node2.asExpr() = ce and
c = TTupleFieldContent(tf)
|
@@ -716,7 +709,7 @@ module RustDataFlow implements InputSig<Location> {
exists(DataFlowCall call, int i |
isArgumentNode(node1, call, TPositionalParameterPosition(i)) and
lambdaCall(call, _, node2.(PostUpdateNode).getPreUpdateNode()) and
c.(ClosureCallArgumentContent).getPosition() = i
c.(FunctionCallArgumentContent).getPosition() = i
)
or
VariableCapture::storeStep(node1, c, node2)
@@ -825,7 +818,7 @@ module RustDataFlow implements InputSig<Location> {
*/
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
(
receiver.asExpr() = call.asCall().(ClosureCallExpr).getClosureExpr()
receiver.asExpr() = call.asCall().(CallExprImpl::DynamicCallExpr).getFunction()
or
call.isSummaryCall(_, receiver.(FlowSummaryNode).getSummaryNode())
) and

View File

@@ -50,7 +50,7 @@ module Input implements InputSig<Location, RustDataFlow> {
ReturnKind getStandardReturnValueKind() { result = TNormalReturnKind() }
string encodeParameterPosition(ParameterPosition pos) { result = pos.toString() }
string encodeParameterPosition(RustDataFlow::ParameterPosition pos) { result = pos.toString() }
string encodeArgumentPosition(RustDataFlow::ArgumentPosition pos) { result = pos.toString() }
@@ -105,7 +105,9 @@ module Input implements InputSig<Location, RustDataFlow> {
string encodeWithContent(ContentSet c, string arg) { result = "With" + encodeContent(c, arg) }
bindingset[token]
ParameterPosition decodeUnknownParameterPosition(AccessPath::AccessPathTokenBase token) {
RustDataFlow::ParameterPosition decodeUnknownParameterPosition(
AccessPath::AccessPathTokenBase token
) {
// needed to support `Argument[x..y]` ranges
token.getName() = "Argument" and
result.getPosition() = AccessPath::parseInt(token.getAnArgument())
@@ -132,7 +134,7 @@ private module StepsInput implements Impl::Private::StepsInputSig {
/** Gets the argument of `source` described by `sc`, if any. */
private Expr getSourceNodeArgument(Input::SourceBase source, Impl::Private::SummaryComponent sc) {
exists(ArgumentPosition pos |
exists(RustDataFlow::ArgumentPosition pos |
sc = Impl::Private::SummaryComponent::argument(pos) and
result = pos.getArgument(source.getCall())
)
@@ -159,7 +161,7 @@ private module StepsInput implements Impl::Private::StepsInputSig {
s.head() = Impl::Private::SummaryComponent::return(_) and
result.asExpr() = source.getCall()
or
exists(ArgumentPosition pos, Expr arg |
exists(RustDataFlow::ArgumentPosition pos, Expr arg |
s.head() = Impl::Private::SummaryComponent::parameter(pos) and
arg = getSourceNodeArgument(source, s.tail().headOfSingleton()) and
result.asParameter() = getCallable(arg).getParam(pos.getPosition())
@@ -170,7 +172,7 @@ private module StepsInput implements Impl::Private::StepsInputSig {
}
RustDataFlow::Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) {
exists(ArgsExpr call, Expr arg, ArgumentPosition pos |
exists(InvocationExpr call, Expr arg, RustDataFlow::ArgumentPosition pos |
result.asExpr() = arg and
sc = Impl::Private::SummaryComponent::argument(pos) and
call = sink.getCall() and

View File

@@ -167,7 +167,7 @@ final class NameNode extends AstNodeNode, TNameNode {
*/
abstract class ParameterNode extends Node {
/** Holds if this node is a parameter of `c` at position `pos`. */
abstract predicate isParameterOf(DataFlowCallable c, ParameterPosition pos);
abstract predicate isParameterOf(DataFlowCallable c, RustDataFlow::ParameterPosition pos);
}
final class SourceParameterNode extends AstNodeNode, ParameterNode, TSourceParameterNode {
@@ -175,12 +175,12 @@ final class SourceParameterNode extends AstNodeNode, ParameterNode, TSourceParam
SourceParameterNode() { this = TSourceParameterNode(n) }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
override predicate isParameterOf(DataFlowCallable c, RustDataFlow::ParameterPosition pos) {
n = pos.getParameterIn(c.asCfgScope().(Callable).getParamList())
}
/** Get the parameter position of this parameter. */
ParameterPosition getPosition() { this.isParameterOf(_, result) }
RustDataFlow::ParameterPosition getPosition() { this.isParameterOf(_, result) }
/** Gets the parameter in the CFG that this node corresponds to. */
ParamBase getParameter() { result = n }
@@ -188,13 +188,13 @@ final class SourceParameterNode extends AstNodeNode, ParameterNode, TSourceParam
/** A parameter for a library callable with a flow summary. */
final class SummaryParameterNode extends ParameterNode, FlowSummaryNode {
private ParameterPosition pos_;
private RustDataFlow::ParameterPosition pos_;
SummaryParameterNode() {
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), pos_)
}
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
override predicate isParameterOf(DataFlowCallable c, RustDataFlow::ParameterPosition pos) {
this.getSummarizedCallable() = c.asSummarizedCallable() and pos = pos_
}
}
@@ -210,7 +210,7 @@ final class ClosureParameterNode extends ParameterNode, TClosureSelfReferenceNod
final override CfgScope getCfgScope() { result = cfgScope }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
override predicate isParameterOf(DataFlowCallable c, RustDataFlow::ParameterPosition pos) {
cfgScope = c.asCfgScope() and pos.isClosureSelf()
}

View File

@@ -1,7 +0,0 @@
/**
* This module provides the public class `ArgsExpr`.
*/
private import internal.ArgsExprImpl
final class ArgsExpr = Impl::ArgsExpr;

View File

@@ -1,5 +1,5 @@
/**
* This module provides the public class `Call`.
* This module provides the public classes `Call` and `MethodCall`.
*/
private import rust
@@ -9,21 +9,3 @@ private import internal.CallExprImpl::Impl as CallExprImpl
final class Call = Impl::Call;
final class MethodCall = Impl::MethodCall;
/**
* A call expression that targets a closure.
*
* Closure calls never have a static target, and the set of potential
* run-time targets is only available internally to the data flow library.
*/
class ClosureCallExpr extends CallExprImpl::CallExprCall {
ClosureCallExpr() {
exists(Expr f | f = this.getFunction() |
// All calls to complex expressions and local variable accesses are lambda calls
f instanceof PathExpr implies f = any(Variable v).getAnAccess()
)
}
/** Gets the closure expression being called. */
Expr getClosureExpr() { result = super.getFunction() }
}

View File

@@ -0,0 +1,9 @@
/**
* This module provides the public classes `InvocationExpr` and `ArgumentPosition`.
*/
private import internal.InvocationExprImpl
final class InvocationExpr = Impl::InvocationExpr;
final class ArgumentPosition = Impl::ArgumentPosition;

View File

@@ -1,37 +0,0 @@
private import rust
module Impl {
private import codeql.rust.internal.TypeInference as TypeInference
private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
/**
* An expression with arguments.
*
* Either a `CallExpr`, a `MethodCallExpr`, an `Operation`, or an `IndexExpr`.
*/
abstract class ArgsExpr extends ExprImpl::Expr {
/**
* Gets the `i`th syntactic argument of this expression.
*
* Examples:
* ```rust
* foo(42, "bar"); // `42` is argument 0 and `"bar"` is argument 1
* foo.bar(42); // `foo` is argument 0 and `42` is argument 1
* x + y; // `x` is argument 0 and `y` is argument 1
* x[y]; // `x` is argument 0 and `y` is argument 1
* ```
*/
Expr getSyntacticArgument(int i) { none() }
/** Gets an argument of this expression. */
Expr getASyntacticArgument() { result = this.getSyntacticArgument(_) }
/** Gets the number of arguments of this expression. */
int getNumberOfSyntacticArguments() {
result = count(Expr arg | arg = this.getSyntacticArgument(_))
}
/** Gets the resolved target (function or tuple struct/variant), if any. */
Addressable getResolvedTarget() { result = TypeInference::resolveCallTarget(this) }
}
}

View File

@@ -12,7 +12,7 @@ private import codeql.rust.elements.internal.generated.CallExpr
*/
module Impl {
private import rust
private import codeql.rust.elements.internal.ArgsExprImpl::Impl as ArgsExprImpl
private import codeql.rust.elements.internal.InvocationExprImpl::Impl as InvocationExprImpl
private import codeql.rust.elements.internal.CallImpl::Impl as CallImpl
private import codeql.rust.internal.PathResolution as PathResolution
private import codeql.rust.internal.TypeInference as TypeInference
@@ -25,6 +25,8 @@ module Impl {
result = PathResolution::resolvePath(getFunctionPath(ce))
}
private Expr getSyntacticArg(CallExpr ce, int i) { result = ce.getArgList().getArg(i) }
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* NOTE: Consider using `Call` instead, as that excludes call expressions that are
@@ -38,20 +40,20 @@ module Impl {
* Option::Some(42); // tuple variant instantiation
* ```
*/
class CallExpr extends Generated::CallExpr, ArgsExprImpl::ArgsExpr {
class CallExpr extends Generated::CallExpr, InvocationExprImpl::InvocationExpr {
override string toStringImpl() { result = this.getFunction().toAbbreviatedString() + "(...)" }
override Expr getSyntacticArgument(int i) { result = this.getArgList().getArg(i) }
override Expr getSyntacticPositionalArgument(int i) { result = getSyntacticArg(this, i) }
// todo: remove once internal query has been updated
Expr getArg(int i) { result = this.getSyntacticArgument(i) }
Expr getArg(int i) { result = getSyntacticArg(this, i) }
// todo: remove once internal query has been updated
int getNumberOfArgs() { result = this.getNumberOfSyntacticArguments() }
}
/**
* A call expression that is _not_ an instantiation of a tuple struct or a tuple enum variant.
* A call expression that is _not_ an instantiation of a tuple struct or a tuple variant.
*
* For example:
* ```rust
@@ -67,7 +69,23 @@ module Impl {
not this instanceof TupleVariantExpr
}
override Expr getPositionalArgument(int i) { result = super.getSyntacticArgument(i) }
override Expr getPositionalArgument(int i) { result = getSyntacticArg(this, i) }
}
/**
* A call expression that targets a closure (or any value that implements
* `Fn`, `FnMut`, or `FnOnce`).
*
* Dynamic calls never have a static target, and the set of potential
* run-time targets is only available internally to the data flow library.
*/
class DynamicCallExpr extends CallExprCall {
DynamicCallExpr() {
exists(Expr f | f = this.getFunction() |
// All calls to complex expressions and local variable accesses are lambda calls
f instanceof PathExpr implies f = any(Variable v).getAnAccess()
)
}
}
/**
@@ -77,20 +95,20 @@ module Impl {
* layer, we do not check that the resolved target is a method in the charpred,
* instead we check this in `getPositionalArgument` and `getReceiver`.
*/
class CallExprMethodCall extends CallExprCall, CallImpl::MethodCall {
CallExprMethodCall() { not this instanceof ClosureCallExpr }
class CallExprMethodCall extends CallImpl::MethodCall instanceof CallExprCall {
CallExprMethodCall() { not this instanceof DynamicCallExpr }
private predicate isInFactMethodCall() { this.getResolvedTarget() instanceof Method }
override Expr getPositionalArgument(int i) {
if this.isInFactMethodCall()
then result = this.getSyntacticArgument(i + 1)
else result = this.getSyntacticArgument(i)
then result = getSyntacticArg(this, i + 1)
else result = getSyntacticArg(this, i)
}
override Expr getReceiver() {
this.isInFactMethodCall() and
result = super.getSyntacticArgument(0)
result = getSyntacticArg(this, 0)
}
}
@@ -119,7 +137,7 @@ module Impl {
}
/**
* A call expression that instantiates a tuple enum variant.
* A call expression that instantiates a tuple variant.
*
* For example:
* ```rust

View File

@@ -3,31 +3,56 @@ private import rust
module Impl {
private import codeql.rust.internal.TypeInference as TypeInference
private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
private import codeql.rust.elements.internal.ArgsExprImpl::Impl as ArgsExprImpl
private import codeql.rust.elements.internal.InvocationExprImpl::Impl as InvocationExprImpl
/**
* A call.
*
* Either
*
* - a `CallExpr` that is _not_ an instantiation of a tuple struct or a tuple enum variant,
* - a `CallExpr` that is _not_ an instantiation of a tuple struct or a tuple variant,
* - a `MethodCallExpr`,
* - an `Operation` that targets an overloadable operator, or
* - an `IndexExpr`.
*/
abstract class Call extends ArgsExprImpl::ArgsExpr {
abstract class Call extends InvocationExprImpl::InvocationExpr {
/**
* Gets the argument at position `pos` of this call.
*
* Examples:
* ```rust
* foo(42, "bar"); // `42` is argument 0 and `"bar"` is argument 1
* foo.bar(42); // `foo` is receiver and `42` is argument 0
* Foo::bar(foo, 42); // `foo` is receiver and `42` is argument 0
* x + y; // `x` is receiver and `y` is argument 0
* -x; // `x` is receiver
* x[y]; // `x` is receiver and `y` is argument 0
* ```
*/
final Expr getArgument(ArgumentPosition pos) {
result = this.getPositionalArgument(pos.asPosition())
or
pos.isSelf() and
result = this.(MethodCall).getReceiver()
}
/** Gets an argument of this call. */
Expr getAnArgument() { result = this.getArgument(_) }
// todo: remove once internal query has been updated
Expr getReceiver() { none() }
/**
* Gets the `i`th positional argument of this call, if any.
* Gets the `i`th positional argument of this call.
*
* Examples:
* ```rust
* foo(42, "bar"); // `42` is argument 0 and `"bar"` is argument 1
* foo.bar(42); // `42` is argument 0
* x + y; // `y` is argument 0
* x[y]; // `y` is argument 0
* foo(42, "bar"); // `42` is argument 0 and `"bar"` is argument 1
* foo.bar(42); // `42` is argument 0
* Foo::bar(foo, 42); // `42` is argument 0
* x + y; // `y` is argument 0
* -x; // no positional arguments
* x[y]; // `y` is argument 0
* ```
*/
Expr getPositionalArgument(int i) { none() }
@@ -43,10 +68,11 @@ module Impl {
/** Gets the resolved target of this call, if any. */
Function getStaticTarget() { result = TypeInference::resolveCallTarget(this) }
/** Gets the name of the method called, if any. */
string getMethodName() {
result = any(Function m | m = this.getStaticTarget() and m.hasSelfParam()).getName().getText()
}
/** Gets the name of the function called, if any. */
string getTargetName() { result = this.getStaticTarget().getName().getText() }
// todo: remove once internal query has been updated
string getMethodName() { result = this.getTargetName() }
/** Gets a runtime target of this call, if any. */
pragma[nomagic]
@@ -76,10 +102,12 @@ module Impl {
*
* Examples:
* ```rust
* foo(42, "bar"); // no receiver
* foo.bar(42); // `foo` is receiver
* x + y; // `x` is receiver
* x[y]; // `x` is receiver
* foo(42, "bar"); // no receiver
* foo.bar(42); // `foo` is receiver
* Foo::bar(foo, 42); // `foo` is receiver
* x + y; // `x` is receiver
* -x; // `x` is receiver
* x[y]; // `x` is receiver
* ```
*/
override Expr getReceiver() { none() }

View File

@@ -4,6 +4,7 @@
* INTERNAL: Do not use.
*/
private import rust
private import codeql.rust.elements.internal.generated.IndexExpr
/**
@@ -12,7 +13,6 @@ private import codeql.rust.elements.internal.generated.IndexExpr
*/
module Impl {
private import codeql.rust.elements.internal.CallImpl::Impl as CallImpl
private import codeql.rust.elements.internal.ArgsExprImpl::Impl as ArgsExprImpl
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
@@ -28,7 +28,7 @@ module Impl {
this.getBase().toAbbreviatedString() + "[" + this.getIndex().toAbbreviatedString() + "]"
}
override Expr getSyntacticArgument(int i) {
override Expr getSyntacticPositionalArgument(int i) {
i = 0 and result = this.getBase()
or
i = 1 and result = this.getIndex()

View File

@@ -0,0 +1,99 @@
private import rust
module Impl {
private import codeql.rust.internal.TypeInference as TypeInference
private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
private newtype TArgumentPosition =
TPositionalArgumentPosition(int i) {
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1]
} or
TSelfArgumentPosition()
/** An argument position in a call. */
class ArgumentPosition extends TArgumentPosition {
/** Gets the index of the argument in the call, if this is a positional argument. */
int asPosition() { this = TPositionalArgumentPosition(result) }
/** Holds if this call position is a self argument. */
predicate isSelf() { this instanceof TSelfArgumentPosition }
/** Gets a string representation of this argument position. */
string toString() {
result = this.asPosition().toString()
or
this.isSelf() and result = "self"
}
}
/**
* An expression with arguments.
*
* Either a `CallExpr`, a `MethodCallExpr`, an `Operation`, or an `IndexExpr`.
*/
abstract class InvocationExpr extends ExprImpl::Expr {
/**
* Gets the `i`th syntactical argument of this expression.
*
* Examples:
* ```rust
* foo(42, "bar"); // `42` is syntactic argument 0 and `"bar"` is syntactic argument 1
* foo.bar(42); // `42` is syntactic argument 0
* Foo::bar(foo, 42); // `foo` is syntactic argument 0 and `42` is syntactic argument 1
* Option::Some(x); // `x` is syntactic argument 0
* x + y; // `x` is syntactic argument 0 and `y` is syntactic argument 1
* -x; // `x` is syntactic argument 0
* x[y]; // `x` is syntactic argument 0 and `y` is syntactic argument 1
* ```
*/
Expr getSyntacticPositionalArgument(int i) { none() }
/**
* Gets the syntactic receiver of this expression, if any.
*
* Examples:
* ```rust
* foo(42, "bar"); // no syntactic receiver
* foo.bar(42); // `foo` is syntactic receiver
* Foo::bar(foo, 42); // no syntactic receiver
* Option::Some(x); // no syntactic receiver
* x + y; // no syntactic receiver
* -x; // no syntactic receiver
* x[y]; // no syntactic receiver
* ```
*/
Expr getSyntacticReceiver() { none() }
/**
* Gets the argument at syntactic position `pos` of this expression.
*
* Examples:
* ```rust
* foo(42, "bar"); // `42` is syntactic argument 0 and `"bar"` is syntactic argument 1
* foo.bar(42); // `foo` is syntactic receiver and `42` is syntactic argument 0
* Foo::bar(foo, 42); // `foo` is syntactic argument 0 and `42` is syntactic argument 1
* Option::Some(x); // `x` is syntactic argument 0
* x + y; // `x` is syntactic argument 0 and `y` is syntactic argument 1
* -x; // `x` is syntactic argument 0
* x[y]; // `x` is syntactic argument 0 and `y` is syntactic argument 1
* ```
*/
final Expr getSyntacticArgument(ArgumentPosition pos) {
result = this.getSyntacticPositionalArgument(pos.asPosition())
or
pos.isSelf() and
result = this.getSyntacticReceiver()
}
/** Gets a syntactic argument of this expression. */
Expr getASyntacticArgument() { result = this.getSyntacticArgument(_) }
/** Gets the number of syntactic arguments of this expression. */
int getNumberOfSyntacticArguments() {
result = count(Expr arg | arg = this.getSyntacticArgument(_))
}
/** Gets the resolved target (function or tuple struct/variant), if any. */
Addressable getResolvedTarget() { result = TypeInference::resolveCallTarget(this) }
}
}

View File

@@ -13,7 +13,7 @@ private import codeql.rust.elements.internal.generated.MethodCallExpr
*/
module Impl {
private import codeql.rust.elements.internal.CallImpl::Impl as CallImpl
private import codeql.rust.elements.internal.ArgsExprImpl::Impl as ArgsExprImpl
private import codeql.rust.elements.internal.InvocationExprImpl::Impl as InvocationExprImpl
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
@@ -46,11 +46,9 @@ module Impl {
result = strictconcat(int i | | this.toStringPart(i) order by i)
}
override Expr getSyntacticArgument(int i) {
i = 0 and result = this.getReceiver()
or
result = this.getPositionalArgument(i - 1)
}
override Expr getSyntacticPositionalArgument(int i) { result = this.getArgList().getArg(i) }
override Expr getSyntacticReceiver() { result = Generated::MethodCallExpr.super.getReceiver() }
override Expr getPositionalArgument(int i) { result = this.getArgList().getArg(i) }

View File

@@ -13,7 +13,7 @@ private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
*/
module Impl {
private import codeql.rust.elements.internal.CallImpl::Impl as CallImpl
private import codeql.rust.elements.internal.ArgsExprImpl::Impl as ArgsExprImpl
private import codeql.rust.elements.internal.InvocationExprImpl::Impl as InvocationExprImpl
/**
* Holds if the operator `op` with arity `arity` is overloaded to a trait with
@@ -108,14 +108,14 @@ module Impl {
* for `Add::add(x, y)`, and `x += y` is syntactic sugar for
* `AddAssign::add_assign(&mut x, y)`.
*/
abstract class Operation extends ArgsExprImpl::ArgsExpr {
abstract class Operation extends InvocationExprImpl::InvocationExpr {
/** Gets the operator name of this operation, if it exists. */
abstract string getOperatorName();
/** Gets the `n`th operand of this operation, if any. */
abstract Expr getOperand(int n);
override Expr getSyntacticArgument(int i) { result = this.getOperand(i) }
override Expr getSyntacticPositionalArgument(int i) { result = this.getOperand(i) }
/**
* Gets the number of operands of this operation.
@@ -140,7 +140,7 @@ module Impl {
private class OperationMethodCall extends CallImpl::MethodCall instanceof Operation {
OperationMethodCall() { super.isOverloaded(_, _, _) }
override Expr getPositionalArgument(int i) { result = super.getOperand(i + 1) and i >= 0 }
override Expr getPositionalArgument(int i) { result = super.getOperand(i + 1) }
override Expr getReceiver() { result = super.getOperand(0) }
}

View File

@@ -26,8 +26,7 @@ class StreamCipherInit extends Cryptography::CryptographicOperation::Range {
// `cipher::KeyIvInit::new`, `cipher::KeyIvInit::new_from_slices`, `rc2::Rc2::new_with_eff_key_len` or similar.
exists(Call call, string rawAlgorithmName |
call = this.asExpr() and
call.getStaticTarget().getName().getText() =
["new", "new_from_slice", "new_with_eff_key_len", "new_from_slices"] and
call.getTargetName() = ["new", "new_from_slice", "new_with_eff_key_len", "new_from_slices"] and
// extract the algorithm name from the type of `ce` or its receiver.
exists(Type t, TypePath tp |
t = inferType([call, call.(MethodCall).getReceiver()], tp) and

View File

@@ -25,7 +25,7 @@ query predicate multiplePathResolutions(Path p, ItemNode i) {
}
// TODO: Take other calls into account
abstract private class CallExprBase extends ArgsExpr { }
abstract private class CallExprBase extends InvocationExpr { }
private class CallExprCallExprBase extends CallExpr, CallExprBase { }

View File

@@ -1624,10 +1624,7 @@ private module MethodResolution {
}
override Expr getArg(ArgumentPosition pos) {
pos.isSelf() and
result = MethodCallExpr.super.getReceiver()
or
result = super.getArgList().getArg(pos.asPosition())
result = MethodCallExpr.super.getSyntacticArgument(pos)
}
override predicate supportsAutoDerefAndBorrow() { any() }
@@ -1685,9 +1682,9 @@ private module MethodResolution {
override Expr getArg(ArgumentPosition pos) {
pos.isSelf() and
result = super.getSyntacticArgument(0)
result = super.getSyntacticPositionalArgument(0)
or
result = super.getSyntacticArgument(pos.asPosition() + 1)
result = super.getSyntacticPositionalArgument(pos.asPosition() + 1)
}
// needed for `TypeQualifierIsInstantiationOfImplSelfInput`
@@ -2383,7 +2380,7 @@ private module NonMethodResolution {
}
AstNode getNodeAt(FunctionPosition pos) {
result = this.getSyntacticArgument(pos.asPosition())
result = this.getSyntacticArgument(pos.asArgumentPosition())
or
result = this and pos.isReturn()
}
@@ -3415,7 +3412,7 @@ private Type inferDynamicCallExprType(Expr n, TypePath path) {
or
// Propagate the function's parameter type to the arguments
exists(int index |
n = ce.getCall().getSyntacticArgument(index) and
n = ce.getCall().getSyntacticPositionalArgument(index) and
path =
path0.stripPrefix(fnParameterPath(ce.getCall().getArgList().getNumberOfArgs(), index))
)
@@ -3631,7 +3628,7 @@ private module Debug {
result = inferType(n, path)
}
Addressable debugResolveCallTarget(ArgsExpr c) {
Addressable debugResolveCallTarget(InvocationExpr c) {
c = getRelevantLocatable() and
result = resolveCallTarget(c)
}

View File

@@ -4,28 +4,6 @@ private import codeql.rust.internal.PathResolution
private import codeql.rust.internal.Type
private import codeql.rust.internal.TypeMention
private newtype TArgumentPosition =
TPositionalArgumentPosition(int i) {
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1]
} or
TSelfArgumentPosition()
/** An argument position in a call. */
class ArgumentPosition extends TArgumentPosition {
/** Gets the index of the argument in the call, if this is a positional argument. */
int asPosition() { this = TPositionalArgumentPosition(result) }
/** Holds if this call position is a self argument. */
predicate isSelf() { this instanceof TSelfArgumentPosition }
/** Gets a string representation of this argument position. */
string toString() {
result = this.asPosition().toString()
or
this.isSelf() and result = "self"
}
}
private newtype TFunctionPosition =
TArgumentFunctionPosition(ArgumentPosition pos) or
TReturnFunctionPosition()

View File

@@ -28,7 +28,7 @@ private class SensitiveDataCall extends SensitiveData {
SensitiveDataClassification classification;
SensitiveDataCall() {
exists(ArgsExpr call, Addressable target, string name |
exists(InvocationExpr call, Addressable target, string name |
call = this.asExpr() and
target = call.getResolvedTarget() and
name =

View File

@@ -53,9 +53,9 @@ module Xss {
/** A call to a function with "escape" or "encode" in its name. */
private class HeuristicHtmlEncodingBarrier extends Barrier {
HeuristicHtmlEncodingBarrier() {
exists(Call fc |
fc.getStaticTarget().getName().getText().regexpMatch(".*(escape|encode).*") and
fc.getAPositionalArgument() = this.asExpr()
exists(Call c |
c.getStaticTarget().getName().getText().regexpMatch(".*(escape|encode).*") and
c.getAnArgument() = this.asExpr()
)
}
}

View File

@@ -6,7 +6,7 @@ import codeql.Locations
import codeql.files.FileSystem
import codeql.rust.elements.Operation
import codeql.rust.elements.ArithmeticOperation
import codeql.rust.elements.ArgsExpr
import codeql.rust.elements.InvocationExpr
import codeql.rust.elements.AssignmentOperation
import codeql.rust.elements.BitwiseOperation
import codeql.rust.elements.ComparisonOperation

View File

@@ -31,7 +31,7 @@ private module FlowTestImpl implements InputSig<Location, RustDataFlow> {
private string getSourceArgString(DataFlow::Node src) {
defaultSource(src) and
result = src.asExpr().(CallExpr).getSyntacticArgument(0).toString()
result = src.asExpr().(Call).getPositionalArgument(0).toString()
or
sourceNode(src, _) and
result =

View File

@@ -6,6 +6,7 @@
import rust
import codeql.util.ReportStats
import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl
import codeql.rust.internal.TypeInference as TypeInference
/**
@@ -20,7 +21,7 @@ private class RelevantFile extends File {
module CallTargetStats implements StatsSig {
// TODO: Take other calls into account
abstract private class CallExprBase extends ArgsExpr { }
abstract private class CallExprBase extends InvocationExpr { }
private class CallExprCallExprBase extends CallExpr, CallExprBase { }
@@ -34,7 +35,7 @@ module CallTargetStats implements StatsSig {
additional predicate isNotOkCall(CallExprBase c) {
c.getFile() instanceof RelevantFile and
not exists(c.getResolvedTarget()) and
not c instanceof ClosureCallExpr
not c instanceof CallExprImpl::DynamicCallExpr
}
int getNumberOfNotOk() { result = count(CallExprBase c | isNotOkCall(c)) }

View File

@@ -67,8 +67,9 @@ module ModelGeneratorCommonInput implements
string parameterExactAccess(R::ParamBase p) {
result =
"Argument[" + any(DataFlowImpl::ParameterPosition pos | p = pos.getParameterIn(_)).toString() +
"]"
"Argument[" +
any(DataFlowImpl::RustDataFlow::ParameterPosition pos | p = pos.getParameterIn(_))
.toString() + "]"
}
string parameterApproximateAccess(R::ParamBase p) { result = parameterExactAccess(p) }
@@ -78,12 +79,16 @@ module ModelGeneratorCommonInput implements
}
bindingset[c]
string paramReturnNodeAsApproximateOutput(QualifiedCallable c, DataFlowImpl::ParameterPosition pos) {
string paramReturnNodeAsApproximateOutput(
QualifiedCallable c, DataFlowImpl::RustDataFlow::ParameterPosition pos
) {
result = paramReturnNodeAsExactOutput(c, pos)
}
bindingset[c]
string paramReturnNodeAsExactOutput(QualifiedCallable c, DataFlowImpl::ParameterPosition pos) {
string paramReturnNodeAsExactOutput(
QualifiedCallable c, DataFlowImpl::RustDataFlow::ParameterPosition pos
) {
result = parameterExactAccess(c.getFunction().getParam(pos.getPosition()))
or
pos.isSelf() and result = qualifierString()
@@ -134,7 +139,7 @@ private module SummaryModelGeneratorInput implements SummaryModelGeneratorInputS
predicate isCallback(DataFlow::ContentSet cs) {
exists(Content c | c = cs.(SingletonContentSet).getContent() |
c instanceof FunctionCallReturnContent or
c instanceof ClosureCallArgumentContent
c instanceof FunctionCallArgumentContent
)
}
@@ -145,7 +150,7 @@ private module SummaryModelGeneratorInput implements SummaryModelGeneratorInputS
or
exists(Content c | cs = DataFlowImpl::TSingletonContentSet(c) |
exists(int pos |
pos = c.(ClosureCallArgumentContent).getPosition() and
pos = c.(FunctionCallArgumentContent).getPosition() and
result = "Parameter" and
arg = pos.toString()
)

View File

@@ -2,18 +2,15 @@ instances
| gen_call_expr.rs:8:5:8:11 | foo(...) |
| gen_call_expr.rs:9:5:9:23 | foo::<...>(...) |
| gen_call_expr.rs:10:5:10:14 | ...(...) |
| gen_call_expr.rs:11:5:11:10 | foo(...) |
| gen_call_expr.rs:12:5:12:20 | ...::Some(...) |
| gen_call_expr.rs:11:5:11:20 | ...::Some(...) |
getArgList
| gen_call_expr.rs:8:5:8:11 | foo(...) | gen_call_expr.rs:8:8:8:11 | ArgList |
| gen_call_expr.rs:9:5:9:23 | foo::<...>(...) | gen_call_expr.rs:9:20:9:23 | ArgList |
| gen_call_expr.rs:10:5:10:14 | ...(...) | gen_call_expr.rs:10:11:10:14 | ArgList |
| gen_call_expr.rs:11:5:11:10 | foo(...) | gen_call_expr.rs:11:8:11:10 | ArgList |
| gen_call_expr.rs:12:5:12:20 | ...::Some(...) | gen_call_expr.rs:12:17:12:20 | ArgList |
| gen_call_expr.rs:11:5:11:20 | ...::Some(...) | gen_call_expr.rs:11:17:11:20 | ArgList |
getAttr
getFunction
| gen_call_expr.rs:8:5:8:11 | foo(...) | gen_call_expr.rs:8:5:8:7 | foo |
| gen_call_expr.rs:9:5:9:23 | foo::<...>(...) | gen_call_expr.rs:9:5:9:19 | foo::<...> |
| gen_call_expr.rs:10:5:10:14 | ...(...) | gen_call_expr.rs:10:5:10:10 | foo[0] |
| gen_call_expr.rs:11:5:11:10 | foo(...) | gen_call_expr.rs:11:5:11:7 | foo |
| gen_call_expr.rs:12:5:12:20 | ...::Some(...) | gen_call_expr.rs:12:5:12:16 | ...::Some |
| gen_call_expr.rs:11:5:11:20 | ...::Some(...) | gen_call_expr.rs:11:5:11:16 | ...::Some |

View File

@@ -183,7 +183,11 @@ edges
| test.rs:389:61:389:66 | [post] buffer | test.rs:392:23:392:33 | buffer[...] | provenance | |
| test.rs:391:23:391:28 | buffer | test.rs:391:22:391:28 | &buffer | provenance | |
| test.rs:392:23:392:33 | buffer[...] | test.rs:392:22:392:33 | &... | provenance | |
| test.rs:399:63:399:73 | &mut reader [&ref] | test.rs:399:63:399:73 | [post] &mut reader [&ref] | provenance | MaD:13 |
| test.rs:399:63:399:73 | &mut reader [&ref] | test.rs:399:76:399:87 | [post] &mut buffer1 [&ref] | provenance | MaD:13 |
| test.rs:399:63:399:73 | [post] &mut reader [&ref] | test.rs:399:68:399:73 | [post] reader | provenance | |
| test.rs:399:68:399:73 | [post] reader | test.rs:403:31:403:36 | reader | provenance | |
| test.rs:399:68:399:73 | [post] reader | test.rs:408:55:408:60 | reader | provenance | |
| test.rs:399:68:399:73 | reader | test.rs:399:63:399:73 | &mut reader [&ref] | provenance | |
| test.rs:399:76:399:87 | [post] &mut buffer1 [&ref] | test.rs:399:81:399:87 | [post] buffer1 | provenance | |
| test.rs:399:81:399:87 | [post] buffer1 | test.rs:400:19:400:40 | buffer1[...] | provenance | |
@@ -257,7 +261,15 @@ edges
| test.rs:447:61:447:66 | [post] buffer | test.rs:450:23:450:33 | buffer[...] | provenance | |
| test.rs:448:19:448:24 | buffer | test.rs:448:18:448:24 | &buffer | provenance | |
| test.rs:450:23:450:33 | buffer[...] | test.rs:450:22:450:33 | &... | provenance | |
| test.rs:457:63:457:74 | &mut reader2 [&ref] | test.rs:457:63:457:74 | [post] &mut reader2 [&ref] | provenance | MaD:13 |
| test.rs:457:63:457:74 | &mut reader2 [&ref] | test.rs:457:77:457:88 | [post] &mut buffer1 [&ref] | provenance | MaD:13 |
| test.rs:457:63:457:74 | [post] &mut reader2 [&ref] | test.rs:457:68:457:74 | [post] reader2 | provenance | |
| test.rs:457:68:457:74 | [post] reader2 | test.rs:461:31:461:37 | reader2 | provenance | |
| test.rs:457:68:457:74 | [post] reader2 | test.rs:467:44:467:50 | reader2 | provenance | |
| test.rs:457:68:457:74 | [post] reader2 | test.rs:479:26:479:32 | reader2 | provenance | |
| test.rs:457:68:457:74 | [post] reader2 | test.rs:486:31:486:37 | reader2 | provenance | |
| test.rs:457:68:457:74 | [post] reader2 | test.rs:493:31:493:37 | reader2 | provenance | |
| test.rs:457:68:457:74 | [post] reader2 | test.rs:500:31:500:37 | reader2 | provenance | |
| test.rs:457:68:457:74 | reader2 | test.rs:457:63:457:74 | &mut reader2 [&ref] | provenance | |
| test.rs:457:77:457:88 | [post] &mut buffer1 [&ref] | test.rs:457:82:457:88 | [post] buffer1 | provenance | |
| test.rs:457:82:457:88 | [post] buffer1 | test.rs:458:19:458:40 | buffer1[...] | provenance | |
@@ -461,6 +473,8 @@ nodes
| test.rs:392:22:392:33 | &... | semmle.label | &... |
| test.rs:392:23:392:33 | buffer[...] | semmle.label | buffer[...] |
| test.rs:399:63:399:73 | &mut reader [&ref] | semmle.label | &mut reader [&ref] |
| test.rs:399:63:399:73 | [post] &mut reader [&ref] | semmle.label | [post] &mut reader [&ref] |
| test.rs:399:68:399:73 | [post] reader | semmle.label | [post] reader |
| test.rs:399:68:399:73 | reader | semmle.label | reader |
| test.rs:399:76:399:87 | [post] &mut buffer1 [&ref] | semmle.label | [post] &mut buffer1 [&ref] |
| test.rs:399:81:399:87 | [post] buffer1 | semmle.label | [post] buffer1 |
@@ -529,6 +543,8 @@ nodes
| test.rs:450:22:450:33 | &... | semmle.label | &... |
| test.rs:450:23:450:33 | buffer[...] | semmle.label | buffer[...] |
| test.rs:457:63:457:74 | &mut reader2 [&ref] | semmle.label | &mut reader2 [&ref] |
| test.rs:457:63:457:74 | [post] &mut reader2 [&ref] | semmle.label | [post] &mut reader2 [&ref] |
| test.rs:457:68:457:74 | [post] reader2 | semmle.label | [post] reader2 |
| test.rs:457:68:457:74 | reader2 | semmle.label | reader2 |
| test.rs:457:77:457:88 | [post] &mut buffer1 [&ref] | semmle.label | [post] &mut buffer1 [&ref] |
| test.rs:457:82:457:88 | [post] buffer1 | semmle.label | [post] buffer1 |