mirror of
https://github.com/github/codeql.git
synced 2026-05-01 11:45:14 +02:00
Merge branch 'main' into http
This commit is contained in:
@@ -4,3 +4,4 @@
|
||||
|
||||
private import codeql.rust.frameworks.rustcrypto.RustCrypto
|
||||
private import codeql.rust.frameworks.Sqlx
|
||||
private import codeql.rust.frameworks.stdlib.Clone
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@ module DataFlow {
|
||||
|
||||
final class Content = DataFlowImpl::Content;
|
||||
|
||||
final class VariantContent = DataFlowImpl::VariantContent;
|
||||
|
||||
final class ContentSet = DataFlowImpl::ContentSet;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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 = ""
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
21
rust/ql/lib/codeql/rust/frameworks/stdlib/Clone.qll
Normal file
21
rust/ql/lib/codeql/rust/frameworks/stdlib/Clone.qll
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user