Merge branch 'main' into http

This commit is contained in:
Geoffrey White
2025-02-10 09:07:34 +00:00
220 changed files with 48555 additions and 47627 deletions

View File

@@ -4,3 +4,4 @@
private import codeql.rust.frameworks.rustcrypto.RustCrypto
private import codeql.rust.frameworks.Sqlx
private import codeql.rust.frameworks.stdlib.Clone

View File

@@ -241,7 +241,7 @@ final class RecordExprCfgNode extends Nodes::RecordExprCfgNode {
exists(RecordExprField ref |
ref = node.getRecordExprFieldList().getAField() and
any(ChildMapping mapping).hasCfgChild(node, ref.getExpr(), this, result) and
field = ref.getNameRef().getText()
field = ref.getFieldName()
)
}
}
@@ -265,12 +265,8 @@ final class RecordPatCfgNode extends Nodes::RecordPatCfgNode {
PatCfgNode getFieldPat(string field) {
exists(RecordPatField rpf |
rpf = node.getRecordPatFieldList().getAField() and
any(ChildMapping mapping).hasCfgChild(node, rpf.getPat(), this, result)
|
field = rpf.getNameRef().getText()
or
not rpf.hasNameRef() and
field = result.(IdentPatCfgNode).getName().getText()
any(ChildMapping mapping).hasCfgChild(node, rpf.getPat(), this, result) and
field = rpf.getFieldName()
)
}
}

View File

@@ -25,8 +25,6 @@ module DataFlow {
final class Content = DataFlowImpl::Content;
final class VariantContent = DataFlowImpl::VariantContent;
final class ContentSet = DataFlowImpl::ContentSet;
/**

View File

@@ -14,7 +14,6 @@ private import codeql.rust.controlflow.CfgNodes
private import codeql.rust.dataflow.Ssa
private import codeql.rust.dataflow.FlowSummary
private import FlowSummaryImpl as FlowSummaryImpl
private import codeql.rust.elements.internal.PathResolution as PathResolution
/**
* A return kind. A return kind describes how a value can be returned from a
@@ -661,7 +660,7 @@ private module VariantInLib {
}
/** A tuple variant from library code. */
class VariantInLibTupleFieldContent extends VariantContent, TVariantInLibTupleFieldContent {
class VariantInLibTupleFieldContent extends Content, TVariantInLibTupleFieldContent {
private VariantInLib::VariantInLib v;
private int pos_;
@@ -740,82 +739,73 @@ abstract class Content extends TContent {
abstract Location getLocation();
}
/**
* A variant of an `enum`. In addition to the variant itself, this also includes the
* position (for tuple variants) or the field name (for record variants).
*/
abstract class VariantContent extends Content { }
private TupleField getVariantTupleField(Variant v, int i) {
result = v.getFieldList().(TupleFieldList).getField(i)
/** A field belonging to either a variant or a struct. */
abstract class FieldContent extends Content {
/** Gets an access to this field. */
pragma[nomagic]
abstract FieldExprCfgNode getAnAccess();
}
/** A tuple variant. */
private class VariantTupleFieldContent extends VariantContent, TVariantTupleFieldContent {
private Variant v;
private int pos_;
/** A tuple field belonging to either a variant or a struct. */
class TupleFieldContent extends FieldContent, TTupleFieldContent {
private TupleField field;
VariantTupleFieldContent() { this = TVariantTupleFieldContent(v, pos_) }
TupleFieldContent() { this = TTupleFieldContent(field) }
Variant getVariant(int pos) { result = v and pos = pos_ }
predicate isVariantField(Variant v, int pos) { field.isVariantField(v, pos) }
predicate isStructField(Struct s, int pos) { field.isStructField(s, pos) }
override FieldExprCfgNode getAnAccess() { none() } // TODO
final override string toString() {
exists(string name |
name = v.getName().getText() and
exists(Variant v, int pos, string vname |
this.isVariantField(v, pos) and
vname = v.getName().getText() and
// only print indices when the arity is > 1
if exists(getVariantTupleField(v, 1)) then result = name + "(" + pos_ + ")" else result = name
if exists(v.getTupleField(1)) then result = vname + "(" + pos + ")" else result = vname
)
or
exists(Struct s, int pos, string sname |
this.isStructField(s, pos) and
sname = s.getName().getText() and
// only print indices when the arity is > 1
if exists(s.getTupleField(1)) then result = sname + "(" + pos + ")" else result = sname
)
}
final override Location getLocation() { result = getVariantTupleField(v, pos_).getLocation() }
final override Location getLocation() { result = field.getLocation() }
}
private RecordField getVariantRecordField(Variant v, string field) {
result = v.getFieldList().(RecordFieldList).getAField() and
field = result.getName().getText()
}
/** A record field belonging to either a variant or a struct. */
class RecordFieldContent extends FieldContent, TRecordFieldContent {
private RecordField field;
/** A record variant. */
private class VariantRecordFieldContent extends VariantContent, TVariantRecordFieldContent {
private Variant v;
private string field_;
RecordFieldContent() { this = TRecordFieldContent(field) }
VariantRecordFieldContent() { this = TVariantRecordFieldContent(v, field_) }
predicate isVariantField(Variant v, string name) { field.isVariantField(v, name) }
Variant getVariant(string field) { result = v and field = field_ }
predicate isStructField(Struct s, string name) { field.isStructField(s, name) }
override FieldExprCfgNode getAnAccess() { none() } // TODO
final override string toString() {
exists(string name |
name = v.getName().getText() and
exists(Variant v, string name, string vname |
this.isVariantField(v, name) and
vname = v.getName().getText() and
// only print field when the arity is > 1
if strictcount(string f | exists(getVariantRecordField(v, f))) > 1
then result = name + "{" + field_ + "}"
else result = name
if strictcount(v.getRecordField(_)) > 1 then result = vname + "." + name else result = vname
)
or
exists(Struct s, string name, string sname |
this.isStructField(s, name) and
sname = s.getName().getText() and
// only print field when the arity is > 1
if strictcount(s.getRecordField(_)) > 1 then result = sname + "." + name else result = sname
)
}
final override Location getLocation() {
result = getVariantRecordField(v, field_).getName().getLocation()
}
}
/** Content stored in a field on a struct. */
class StructFieldContent extends Content, TStructFieldContent {
private Struct s;
private string field_;
StructFieldContent() { this = TStructFieldContent(s, field_) }
Struct getStruct(string field) { result = s and field = field_ }
override string toString() { result = s.getName().getText() + "." + field_.toString() }
override Location getLocation() {
exists(Name f | f = s.getFieldList().(RecordFieldList).getAField().getName() |
f.getText() = field_ and
result = f.getLocation()
)
}
final override Location getLocation() { result = field.getLocation() }
}
/** A captured variable. */
@@ -859,13 +849,18 @@ final class ElementContent extends Content, TElementContent {
* NOTE: Unlike `struct`s and `enum`s tuples are structural and not nominal,
* hence we don't store a canonical path for them.
*/
final class TuplePositionContent extends Content, TTuplePositionContent {
final class TuplePositionContent extends FieldContent, TTuplePositionContent {
private int pos;
TuplePositionContent() { this = TTuplePositionContent(pos) }
int getPosition() { result = pos }
override FieldExprCfgNode getAnAccess() {
// TODO: limit to tuple types
result.getNameRef().getText().toInt() = pos
}
override string toString() { result = "tuple." + pos.toString() }
override Location getLocation() { result instanceof EmptyLocation }
@@ -901,11 +896,6 @@ final class FunctionCallReturnContent extends Content, TFunctionCallReturnConten
override Location getLocation() { result instanceof EmptyLocation }
}
/** Holds if `access` indexes a tuple at an index corresponding to `c`. */
private predicate fieldTuplePositionContent(FieldExprCfgNode access, TuplePositionContent c) {
access.getNameRef().getText().toInt() = c.getPosition()
}
/** A value that represents a set of `Content`s. */
abstract class ContentSet extends TContentSet {
/** Gets a textual representation of this element. */
@@ -1128,23 +1118,6 @@ module RustDataFlow implements InputSig<Location> {
node2.(Node::FlowSummaryNode).getSummaryNode())
}
/** Gets the item that `p` resolves to, if any. */
private PathResolution::ItemNode resolvePath(PathAstNode p) {
result = PathResolution::resolvePath(p.getPath())
}
/** Holds if `p` destructs an enum variant `v`. */
pragma[nomagic]
private predicate tupleVariantDestruction(TupleStructPat p, Variant v) { v = resolvePath(p) }
/** Holds if `p` destructs an enum variant `v`. */
pragma[nomagic]
private predicate recordVariantDestruction(RecordPat p, Variant v) { v = resolvePath(p) }
/** Holds if `p` destructs a struct `s`. */
pragma[nomagic]
private predicate structDestruction(RecordPat p, Struct s) { s = resolvePath(p) }
/**
* Holds if data can flow from `node1` to `node2` via a read of `c`. Thus,
* `node1` references an object with a content `c.getAReadContent()` whose
@@ -1156,7 +1129,7 @@ module RustDataFlow implements InputSig<Location> {
pat = node1.asPat() and
node2.asPat() = pat.getField(pos)
|
tupleVariantDestruction(pat.getPat(), c.(VariantTupleFieldContent).getVariant(pos))
c = TTupleFieldContent(pat.getTupleStructPat().getTupleField(pos))
or
VariantInLib::tupleVariantCanonicalDestruction(pat.getPat(), c, pos)
)
@@ -1169,13 +1142,7 @@ module RustDataFlow implements InputSig<Location> {
or
exists(RecordPatCfgNode pat, string field |
pat = node1.asPat() and
(
// Pattern destructs a struct-like variant.
recordVariantDestruction(pat.getPat(), c.(VariantRecordFieldContent).getVariant(field))
or
// Pattern destructs a struct.
structDestruction(pat.getPat(), c.(StructFieldContent).getStruct(field))
) and
c = TRecordFieldContent(pat.getRecordPat().getRecordField(field)) and
node2.asPat() = pat.getFieldPat(field)
)
or
@@ -1183,11 +1150,9 @@ module RustDataFlow implements InputSig<Location> {
node1.asPat().(RefPatCfgNode).getPat() = node2.asPat()
or
exists(FieldExprCfgNode access |
// Read of a tuple entry
fieldTuplePositionContent(access, c) and
// TODO: Handle read of a struct field.
node1.asExpr() = access.getExpr() and
node2.asExpr() = access
node2.asExpr() = access and
access = c.(FieldContent).getAnAccess()
)
or
exists(IndexExprCfgNode arr |
@@ -1236,49 +1201,29 @@ module RustDataFlow implements InputSig<Location> {
cs, node2.(Node::FlowSummaryNode).getSummaryNode())
}
/** Holds if `ce` constructs an enum value of type `v`. */
pragma[nomagic]
private predicate tupleVariantConstruction(CallExpr ce, Variant v) {
v = resolvePath(ce.getFunction().(PathExpr))
}
/** Holds if `re` constructs an enum value of type `v`. */
pragma[nomagic]
private predicate recordVariantConstruction(RecordExpr re, Variant v) { v = resolvePath(re) }
/** Holds if `re` constructs a struct value of type `s`. */
pragma[nomagic]
private predicate structConstruction(RecordExpr re, Struct s) { s = resolvePath(re) }
private predicate tupleAssignment(Node node1, Node node2, TuplePositionContent c) {
private predicate fieldAssignment(Node node1, Node node2, FieldContent c) {
exists(AssignmentExprCfgNode assignment, FieldExprCfgNode access |
assignment.getLhs() = access and
fieldTuplePositionContent(access, c) and
node1.asExpr() = assignment.getRhs() and
node2.asExpr() = access.getExpr()
node2.asExpr() = access.getExpr() and
access = c.getAnAccess()
)
}
pragma[nomagic]
private predicate storeContentStep(Node node1, Content c, Node node2) {
exists(CallExprCfgNode call, int pos |
node1.asExpr() = call.getArgument(pos) and
node1.asExpr() = call.getArgument(pragma[only_bind_into](pos)) and
node2.asExpr() = call
|
tupleVariantConstruction(call.getCallExpr(), c.(VariantTupleFieldContent).getVariant(pos))
c = TTupleFieldContent(call.getCallExpr().getTupleField(pragma[only_bind_into](pos)))
or
VariantInLib::tupleVariantCanonicalConstruction(call.getCallExpr(), c, pos)
)
or
exists(RecordExprCfgNode re, string field |
(
// Expression is for a struct-like enum variant.
recordVariantConstruction(re.getRecordExpr(),
c.(VariantRecordFieldContent).getVariant(field))
or
// Expression is for a struct.
structConstruction(re.getRecordExpr(), c.(StructFieldContent).getStruct(field))
) and
c = TRecordFieldContent(re.getRecordExpr().getRecordField(field)) and
node1.asExpr() = re.getFieldExpr(field) and
node2.asExpr() = re
)
@@ -1295,7 +1240,7 @@ module RustDataFlow implements InputSig<Location> {
node2.asExpr().(ArrayListExprCfgNode).getAnExpr()
]
or
tupleAssignment(node1, node2.(PostUpdateNode).getPreUpdateNode(), c)
fieldAssignment(node1, node2.(PostUpdateNode).getPreUpdateNode(), c)
or
exists(AssignmentExprCfgNode assignment, IndexExprCfgNode index |
c instanceof ElementContent and
@@ -1338,7 +1283,7 @@ module RustDataFlow implements InputSig<Location> {
* in `x.f = newValue`.
*/
predicate clearsContent(Node n, ContentSet cs) {
tupleAssignment(_, n, cs.(SingletonContentSet).getContent())
fieldAssignment(_, n, cs.(SingletonContentSet).getContent())
or
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(Node::FlowSummaryNode).getSummaryNode(),
cs)
@@ -1644,10 +1589,10 @@ private module Cached {
cached
newtype TContent =
TVariantTupleFieldContent(Variant v, int pos) { exists(getVariantTupleField(v, pos)) } or
TTupleFieldContent(TupleField field) or
TRecordFieldContent(RecordField field) or
// TODO: Remove once library types are extracted
TVariantInLibTupleFieldContent(VariantInLib::VariantInLib v, int pos) { pos = v.getAPosition() } or
TVariantRecordFieldContent(Variant v, string field) { exists(getVariantRecordField(v, field)) } or
TElementContent() or
TTuplePositionContent(int pos) {
pos in [0 .. max([
@@ -1656,9 +1601,6 @@ private module Cached {
]
)]
} or
TStructFieldContent(Struct s, string field) {
field = s.getFieldList().(RecordFieldList).getAField().getName().getText()
} or
TFunctionCallReturnContent() or
TFunctionCallArgumentContent(int pos) {
pos in [0 .. any(CallExpr c).getArgList().getNumberOfArgs() - 1]

View File

@@ -61,18 +61,26 @@ module Input implements InputSig<Location, RustDataFlow> {
string encodeContent(ContentSet cs, string arg) {
exists(Content c | cs = TSingletonContentSet(c) |
exists(Variant v | result = "Variant" |
exists(int pos |
c = TVariantTupleFieldContent(v, pos) and
// TODO: calculate in QL
arg = v.getExtendedCanonicalPath() + "(" + pos + ")"
)
exists(Addressable a, int pos |
// TODO: calculate in QL
arg = a.getExtendedCanonicalPath() + "(" + pos + ")"
|
result = "Struct" and
c.(TupleFieldContent).isStructField(a, pos)
or
exists(string field |
// TODO: calculate in QL
c = TVariantRecordFieldContent(v, field) and
arg = v.getExtendedCanonicalPath() + "::" + field
)
result = "Variant" and
c.(TupleFieldContent).isVariantField(a, pos)
)
or
exists(Addressable a, string field |
// TODO: calculate in QL
arg = a.getExtendedCanonicalPath() + "::" + field
|
result = "Struct" and
c.(RecordFieldContent).isStructField(a, field)
or
result = "Variant" and
c.(RecordFieldContent).isVariantField(a, field)
)
or
result = "Variant" and
@@ -81,13 +89,6 @@ module Input implements InputSig<Location, RustDataFlow> {
arg = v.getExtendedCanonicalPath() + "(" + v.getPosition() + ")"
)
or
exists(Struct s, string field |
result = "Struct" and
c = TStructFieldContent(s, field) and
// TODO: calculate in QL
arg = s.getExtendedCanonicalPath() + "::" + field
)
or
result = "Element" and
c = TElementContent() and
arg = ""

View File

@@ -12,6 +12,9 @@ private import codeql.rust.elements.PathExpr
* be referenced directly.
*/
module Impl {
private import rust
private import PathResolution as PathResolution
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* A function call expression. For example:
@@ -24,5 +27,25 @@ module Impl {
*/
class CallExpr extends Generated::CallExpr {
override string toString() { result = this.getFunction().toAbbreviatedString() + "(...)" }
pragma[nomagic]
private PathResolution::ItemNode getResolvedFunction(int pos) {
result = PathResolution::resolvePath(this.getFunction().(PathExpr).getPath()) and
exists(this.getArgList().getArg(pos))
}
/**
* Gets the tuple field that matches the `pos`th argument of this call, if any.
*
* For example, if this call is `Option::Some(42)`, then the tuple field matching
* `42` is the first field of `Option::Some`.
*/
pragma[nomagic]
TupleField getTupleField(int pos) {
exists(PathResolution::ItemNode i | i = this.getResolvedFunction(pos) |
result.isStructField(i, pos) or
result.isVariantField(i, pos)
)
}
}
}

View File

@@ -34,4 +34,24 @@ module Impl {
pragma[nomagic]
string getText() { result = this.getPart().getNameRef().getText() }
}
/** A simple identifier path. */
class IdentPath extends Path {
private string name;
IdentPath() {
not this.hasQualifier() and
exists(PathSegment ps |
ps = this.getPart() and
not ps.hasGenericArgList() and
not ps.hasParenthesizedArgList() and
not ps.hasPathType() and
not ps.hasReturnTypeSyntax() and
name = ps.getNameRef().getText()
)
}
/** Gets the identifier name. */
string getName() { result = name }
}
}

View File

@@ -187,7 +187,7 @@ abstract private class ImplOrTraitItemNode extends ItemNode {
private class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
override string getName() { result = "(impl)" }
override Visibility getVisibility() { none() }
override Visibility getVisibility() { result = Impl.super.getVisibility() }
}
private class MacroCallItemNode extends ItemNode instanceof MacroCall {
@@ -232,6 +232,12 @@ private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
override Visibility getVisibility() { none() }
}
private class TypeParamItemNode extends ItemNode instanceof TypeParam {
override string getName() { result = TypeParam.super.getName().getText() }
override Visibility getVisibility() { none() }
}
/** Holds if `item` has the name `name` and is a top-level item inside `f`. */
private predicate sourceFileEdge(SourceFile f, string name, ItemNode item) {
item = f.getAnItem() and

View File

@@ -11,6 +11,9 @@ private import codeql.rust.elements.internal.generated.RecordExprField
* be referenced directly.
*/
module Impl {
private import rust
private import codeql.rust.elements.internal.PathImpl::Impl as PathImpl
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* A field in a record expression. For example `a: 1` in:
@@ -24,7 +27,27 @@ module Impl {
private string toStringPart(int index) {
index = 0 and result = this.getNameRef().getText()
or
index = 1 and result = ": " + this.getExpr().toAbbreviatedString()
index = 1 and this.hasNameRef() and result = ": "
or
index = 2 and
result = this.getExpr().toAbbreviatedString()
}
/**
* Gets the name of the field. This includes the case when shorthand syntax is used:
*
* ```rust
* Foo {
* a: 1, // field name is `a`
* b // field name is `b`
* }
* ```
*/
string getFieldName() {
result = this.getNameRef().getText()
or
not this.hasNameRef() and
result = this.getExpr().(PathExpr).getPath().(PathImpl::IdentPath).getName()
}
}
}

View File

@@ -11,6 +11,9 @@ private import codeql.rust.elements.internal.generated.RecordExpr
* be referenced directly.
*/
module Impl {
private import rust
private import PathResolution as PathResolution
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* A record expression. For example:
@@ -23,5 +26,17 @@ module Impl {
*/
class RecordExpr extends Generated::RecordExpr {
override string toString() { result = this.getPath().toString() + " {...}" }
/** Gets the record field that matches the `name` field of this record expression. */
pragma[nomagic]
RecordField getRecordField(string name) {
exists(PathResolution::ItemNode i |
i = PathResolution::resolvePath(this.getPath()) and
name = this.getRecordExprFieldList().getAField().getFieldName()
|
result.isStructField(i, name) or
result.isVariantField(i, name)
)
}
}
}

View File

@@ -1,4 +1,3 @@
// generated by codegen, remove this comment if you wish to edit this file
/**
* This module provides a hand-modifiable wrapper around the generated class `RecordField`.
*
@@ -12,11 +11,20 @@ private import codeql.rust.elements.internal.generated.RecordField
* be referenced directly.
*/
module Impl {
private import rust
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* A RecordField. For example:
* ```rust
* todo!()
* ```
*/
class RecordField extends Generated::RecordField { }
class RecordField extends Generated::RecordField {
/** Holds if this record field is named `name` and belongs to the variant `v`. */
predicate isVariantField(Variant v, string name) { this = v.getRecordField(name) }
/** Holds if this record field is named `name` and belongs to the struct `s`. */
predicate isStructField(Struct s, string name) { this = s.getRecordField(name) }
}
}

View File

@@ -1,4 +1,3 @@
// generated by codegen, remove this comment if you wish to edit this file
/**
* This module provides a hand-modifiable wrapper around the generated class `RecordPatField`.
*
@@ -12,11 +11,42 @@ private import codeql.rust.elements.internal.generated.RecordPatField
* be referenced directly.
*/
module Impl {
private import rust
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* A field in a record pattern. For example `a: 1` in:
* ```rust
* let Foo { a: 1, b: 2 } = foo;
* ```
*/
class RecordPatField extends Generated::RecordPatField { }
class RecordPatField extends Generated::RecordPatField {
override string toString() { result = concat(int i | | this.toStringPart(i) order by i) }
private string toStringPart(int index) {
index = 0 and result = this.getNameRef().getText()
or
index = 1 and this.hasNameRef() and result = ": "
or
index = 2 and
result = this.getPat().toAbbreviatedString()
}
/**
* Gets the name of the field. This includes the case when shorthand syntax is used:
*
* ```rust
* match foo {
* Foo { x: a, .. } => ..., // field name is `x`
* Bar { y, .. } => ... // field name is `y`
* }
* ```
*/
string getFieldName() {
result = this.getNameRef().getText()
or
not this.hasNameRef() and
result = this.getPat().(IdentPat).getName().getText()
}
}
}

View File

@@ -11,6 +11,9 @@ private import codeql.rust.elements.internal.generated.RecordPat
* be referenced directly.
*/
module Impl {
private import rust
private import PathResolution as PathResolution
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* A record pattern. For example:
@@ -23,5 +26,17 @@ module Impl {
*/
class RecordPat extends Generated::RecordPat {
override string toString() { result = this.getPath().toAbbreviatedString() + " {...}" }
/** Gets the record field that matches the `name` pattern of this pattern. */
pragma[nomagic]
RecordField getRecordField(string name) {
exists(PathResolution::ItemNode i |
i = PathResolution::resolvePath(this.getPath()) and
name = this.getRecordPatFieldList().getAField().getFieldName()
|
result.isStructField(i, name) or
result.isVariantField(i, name)
)
}
}
}

View File

@@ -4,6 +4,7 @@
* INTERNAL: Do not use.
*/
private import rust
private import codeql.rust.elements.internal.generated.Struct
/**
@@ -20,5 +21,16 @@ module Impl {
*/
class Struct extends Generated::Struct {
override string toString() { result = "struct " + this.getName().getText() }
/** Gets the record field named `name`, if any. */
pragma[nomagic]
RecordField getRecordField(string name) {
result = this.getFieldList().(RecordFieldList).getAField() and
result.getName().getText() = name
}
/** Gets the `i`th tuple field, if any. */
pragma[nomagic]
TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) }
}
}

View File

@@ -1,4 +1,3 @@
// generated by codegen, remove this comment if you wish to edit this file
/**
* This module provides a hand-modifiable wrapper around the generated class `TupleField`.
*
@@ -12,11 +11,20 @@ private import codeql.rust.elements.internal.generated.TupleField
* be referenced directly.
*/
module Impl {
private import rust
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* A TupleField. For example:
* ```rust
* todo!()
* ```
*/
class TupleField extends Generated::TupleField { }
class TupleField extends Generated::TupleField {
/** Holds if this tuple field is the `pos`th field of variant `v`. */
predicate isVariantField(Variant v, int pos) { this = v.getTupleField(pos) }
/** Holds if this tuple field is the `pos`th field of struct `s`. */
predicate isStructField(Struct s, int pos) { this = s.getTupleField(pos) }
}
}

View File

@@ -11,6 +11,9 @@ private import codeql.rust.elements.internal.generated.TupleStructPat
* be referenced directly.
*/
module Impl {
private import rust
private import PathResolution as PathResolution
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* A tuple struct pattern. For example:
@@ -24,5 +27,20 @@ module Impl {
*/
class TupleStructPat extends Generated::TupleStructPat {
override string toString() { result = this.getPath().toAbbreviatedString() + "(...)" }
pragma[nomagic]
private PathResolution::ItemNode getResolvedPath(int pos) {
result = PathResolution::resolvePath(this.getPath()) and
exists(this.getField(pragma[only_bind_into](pos)))
}
/** Gets the tuple field that matches the `pos`th pattern of this pattern. */
pragma[nomagic]
TupleField getTupleField(int pos) {
exists(PathResolution::ItemNode i | i = this.getResolvedPath(pos) |
result.isStructField(i, pos) or
result.isVariantField(i, pos)
)
}
}
}

View File

@@ -1,6 +1,7 @@
private import rust
private import codeql.rust.controlflow.ControlFlowGraph
private import codeql.rust.elements.internal.generated.ParentChild
private import codeql.rust.elements.internal.PathImpl::Impl as PathImpl
private import codeql.rust.elements.internal.PathExprBaseImpl::Impl as PathExprBaseImpl
private import codeql.rust.elements.internal.FormatTemplateVariableAccessImpl::Impl as FormatTemplateVariableAccessImpl
private import codeql.util.DenseRank
@@ -172,16 +173,7 @@ module Impl {
string name_;
VariableAccessCand() {
exists(Path p, PathSegment ps |
p = this.(PathExpr).getPath() and
not p.hasQualifier() and
ps = p.getPart() and
not ps.hasGenericArgList() and
not ps.hasParenthesizedArgList() and
not ps.hasPathType() and
not ps.hasReturnTypeSyntax() and
name_ = ps.getNameRef().getText()
)
name_ = this.(PathExpr).getPath().(PathImpl::IdentPath).getName()
or
this.(FormatTemplateVariableAccess).getName() = name_
}

View File

@@ -4,6 +4,7 @@
* INTERNAL: Do not use.
*/
private import rust
private import codeql.rust.elements.internal.generated.Variant
/**
@@ -20,5 +21,16 @@ module Impl {
*/
class Variant extends Generated::Variant {
override string toString() { result = this.getName().getText() }
/** Gets the record field named `name`, if any. */
pragma[nomagic]
RecordField getRecordField(string name) {
result = this.getFieldList().(RecordFieldList).getAField() and
result.getName().getText() = name
}
/** Gets the `i`th tuple field, if any. */
pragma[nomagic]
TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) }
}
}

View File

@@ -10,6 +10,8 @@ import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
import codeql.rust.elements.Path
import codeql.rust.elements.PathSegment
private class PathAlias = Path;
/**
* INTERNAL: This module contains the fully generated definition of `Path` and should not
* be referenced directly.
@@ -30,7 +32,7 @@ module Generated {
/**
* Gets the qualifier of this path, if it exists.
*/
Path getQualifier() {
PathAlias getQualifier() {
result = Synth::convertPathFromRaw(Synth::convertPathToRaw(this).(Raw::Path).getQualifier())
}

View File

@@ -27,7 +27,7 @@ class StreamCipherInit extends Cryptography::CryptographicOperation::Range {
p.getResolvedCrateOrigin().matches("%/RustCrypto%") and
p.getPath().getText() = ["new", "new_from_slice", "new_from_slices", "new_with_eff_key_len"] and
(
rawAlgorithmName = p.getPath().getQualifier().(Path).getText() or // todo: remove infix cast when codegenerator has been fixed
rawAlgorithmName = p.getPath().getQualifier().getText() or
rawAlgorithmName =
p.getPath()
.getQualifier()

View File

@@ -0,0 +1,21 @@
/** A model for `clone` on the `Clone` trait. */
private import rust
private import codeql.rust.dataflow.FlowSummary
/** A `clone` method. */
final class CloneCallable extends SummarizedCallable::Range {
CloneCallable() {
// NOTE: The function target may not exist in the database, so we base this
// on method calls.
exists(MethodCallExpr c |
c.getNameRef().getText() = "clone" and
c.getArgList().getNumberOfArgs() = 0 and
this = c.getResolvedCrateOrigin() + "::_::" + c.getResolvedPath()
)
}
final override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and output = "ReturnValue" and preservesValue = true
}
}

View File

@@ -3,12 +3,12 @@ extensions:
pack: codeql/rust-all
extensible: sourceModel
data:
- ["lang:std", "crate::env::args", "ReturnValue", "command-line-source", "manual"]
- ["lang:std", "crate::env::args_os", "ReturnValue", "command-line-source", "manual"]
- ["lang:std", "crate::env::args", "ReturnValue.Element", "command-line-source", "manual"]
- ["lang:std", "crate::env::args_os", "ReturnValue.Element", "command-line-source", "manual"]
- ["lang:std", "crate::env::current_dir", "ReturnValue.Variant[crate::result::Result::Ok(0)]", "command-line-source", "manual"]
- ["lang:std", "crate::env::current_exe", "ReturnValue.Variant[crate::result::Result::Ok(0)]", "command-line-source", "manual"]
- ["lang:std", "crate::env::home_dir", "ReturnValue.Variant[crate::option::Option::Some(0)]", "command-line-source", "manual"]
- ["lang:std", "crate::env::var", "ReturnValue.Variant[crate::result::Result::Ok(0)]", "environment-source", "manual"]
- ["lang:std", "crate::env::var_os", "ReturnValue.Variant[crate::option::Option::Some(0)]", "environment-source", "manual"]
- ["lang:std", "crate::env::vars", "ReturnValue", "environment-source", "manual"]
- ["lang:std", "crate::env::vars_os", "ReturnValue", "environment-source", "manual"]
- ["lang:std", "crate::env::vars", "ReturnValue.Element", "environment-source", "manual"]
- ["lang:std", "crate::env::vars_os", "ReturnValue.Element", "environment-source", "manual"]

View File

@@ -7,6 +7,9 @@ extensions:
- ["lang:alloc", "crate::fmt::format", "Argument[0]", "ReturnValue", "taint", "manual"]
# Hint
- ["lang:core", "crate::hint::must_use", "Argument[0]", "ReturnValue", "value", "manual"]
# Iterator
- ["lang:core", "crate::iter::traits::iterator::Iterator::nth", "Argument[self].Element", "ReturnValue.Variant[crate::option::Option::Some(0)]", "value", "manual"]
- ["lang:core", "crate::iter::traits::iterator::Iterator::collect", "Argument[self].Element", "ReturnValue.Element", "value", "manual"]
# Option
- ["lang:core", "<crate::option::Option>::unwrap", "Argument[self].Variant[crate::option::Option::Some(0)]", "ReturnValue", "value", "manual"]
- ["lang:core", "<crate::option::Option>::unwrap_or", "Argument[self].Variant[crate::option::Option::Some(0)]", "ReturnValue", "value", "manual"]

View File

@@ -186,7 +186,7 @@ class ModeledHashOperation extends Cryptography::CryptographicOperation::Range {
sinkNode(input, "hasher-input") and
call = input.(Node::FlowSummaryNode).getSinkElement().getCall() and
call = this.asExpr().getExpr() and
algorithmName = call.getFunction().(PathExpr).getPath().getQualifier().(Path).getText() // todo: remove infix cast when codegenerator has been fixed
algorithmName = call.getFunction().(PathExpr).getPath().getQualifier().getText()
)
}