Skip to content

Commit 4e1a5d4

Browse files
committed
Rust: Improve handling of deref expressions in data flow
1 parent 0dd99f6 commit 4e1a5d4

File tree

9 files changed

+157
-121
lines changed

9 files changed

+157
-121
lines changed

rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ module RustDataFlow implements InputSig<Location> {
365365
node instanceof CaptureNode or
366366
node instanceof ClosureParameterNode or
367367
node instanceof DerefBorrowNode or
368+
node instanceof DerefOutNode or
368369
node.asExpr() instanceof ParenExpr or
369370
nodeIsHidden(node.(PostUpdateNode).getPreUpdateNode())
370371
}
@@ -586,10 +587,9 @@ module RustDataFlow implements InputSig<Location> {
586587
.isVariantField([any(OptionEnum o).getSome(), any(ResultEnum r).getOk()], 0)
587588
)
588589
or
589-
exists(PrefixExpr deref |
590+
exists(DerefExpr deref |
590591
c instanceof ReferenceContent and
591-
deref.getOperatorName() = "*" and
592-
node1.asExpr() = deref.getExpr() and
592+
node1.(DerefOutNode).getDerefExpr() = deref and
593593
node2.asExpr() = deref
594594
)
595595
or

rust/ql/lib/codeql/rust/dataflow/internal/Node.qll

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,15 +348,46 @@ abstract class OutNode extends Node {
348348
}
349349

350350
final private class ExprOutNode extends ExprNode, OutNode {
351-
ExprOutNode() { this.asExpr() instanceof Call }
351+
ExprOutNode() {
352+
exists(Call call |
353+
call = this.asExpr() and
354+
not call instanceof DerefExpr // Handled by `DerefOutNode`
355+
)
356+
}
352357

353-
/** Gets the underlying call CFG node that includes this out node. */
358+
/** Gets the underlying call node that includes this out node. */
354359
override DataFlowCall getCall(ReturnKind kind) {
355360
result.asCall() = n and
356361
kind = TNormalReturnKind()
357362
}
358363
}
359364

365+
/**
366+
* A node that represents the value of a `*` expression _before_ implicit
367+
* dereferencing:
368+
*
369+
* `*v` equivalent to `*Deref::deref(&v)`, and this node represents the
370+
* `Deref::deref(&v)` part.
371+
*/
372+
class DerefOutNode extends OutNode, TDerefOutNode {
373+
DerefExpr de;
374+
375+
DerefOutNode() { this = TDerefOutNode(de) }
376+
377+
DerefExpr getDerefExpr() { result = de }
378+
379+
override CfgScope getCfgScope() { result = de.getEnclosingCfgScope() }
380+
381+
override DataFlowCall getCall(ReturnKind kind) {
382+
result.asCall() = de and
383+
kind = TNormalReturnKind()
384+
}
385+
386+
override Location getLocation() { result = de.getLocation() }
387+
388+
override string toString() { result = de.toString() + " [pre-dereferenced]" }
389+
}
390+
360391
final class SummaryOutNode extends FlowSummaryNode, OutNode {
361392
private DataFlowCall call;
362393
private ReturnKind kind_;
@@ -499,6 +530,7 @@ newtype TNode =
499530
TypeInference::implicitBorrow(n) and
500531
borrow = true
501532
} or
533+
TDerefOutNode(DerefExpr de) or
502534
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or
503535
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) {
504536
forall(AstNode n | n = sn.getSinkElement() or n = sn.getSourceElement() |

rust/ql/lib/codeql/rust/frameworks/stdlib/Builtins.qll

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,19 @@ private class BuiltinsTypesFile extends File {
2727
class BuiltinType extends Struct {
2828
BuiltinType() { this.getFile() instanceof BuiltinsTypesFile }
2929

30-
/** Gets the name of this type. */
30+
/**
31+
* Gets the name of this type.
32+
*
33+
* This is the name used internally to represent the type, for example `Ref`.
34+
*/
3135
string getName() { result = super.getName().getText() }
36+
37+
/**
38+
* Gets a display name for this type.
39+
*
40+
* This is the name used in code, for example `&`.
41+
*/
42+
string getDisplayName() { result = this.getName() }
3243
}
3344

3445
/**
@@ -147,9 +158,18 @@ class ArrayType extends BuiltinType {
147158
ArrayType() { this.getName() = "Array" }
148159
}
149160

150-
/** The builtin reference type `&T` or `&mut T`. */
161+
/** The builtin reference type `&T`. */
151162
class RefType extends BuiltinType {
152163
RefType() { this.getName() = "Ref" }
164+
165+
override string getDisplayName() { result = "&" }
166+
}
167+
168+
/** The builtin reference type `&mut T`. */
169+
class RefMutType extends BuiltinType {
170+
RefMutType() { this.getName() = "RefMut" }
171+
172+
override string getDisplayName() { result = "&mut" }
153173
}
154174

155175
/** The builtin pointer type `*const T` or `*mut T`. */

rust/ql/lib/codeql/rust/frameworks/stdlib/alloc.model.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ extensions:
2424
extensible: summaryModel
2525
data:
2626
# Box
27-
- ["<alloc::boxed::Box>::pin", "Argument[0]", "ReturnValue.Reference", "value", "manual"]
28-
- ["<alloc::boxed::Box>::new", "Argument[0]", "ReturnValue.Reference", "value", "manual"]
29-
- ["<alloc::boxed::Box>::into_pin", "Argument[0]", "ReturnValue", "value", "manual"]
27+
- ["<alloc::boxed::Box as core::ops::deref::Deref>::deref", "Argument[self].Field[alloc::boxed::Box(0)]", "ReturnValue.Reference", "value", "manual"]
28+
- ["<alloc::boxed::Box>::pin", "Argument[0]", "ReturnValue.Field[core::pin::Pin::pointer].Field[alloc::boxed::Box(0)]", "value", "manual"]
29+
- ["<alloc::boxed::Box>::new", "Argument[0]", "ReturnValue.Field[alloc::boxed::Box(0)]", "value", "manual"]
30+
- ["<alloc::boxed::Box>::into_pin", "Argument[0]", "ReturnValue.Field[core::pin::Pin::pointer]", "value", "manual"]
3031
# Fmt
3132
- ["alloc::fmt::format", "Argument[0]", "ReturnValue", "taint", "manual"]
3233
# Layout

rust/ql/lib/codeql/rust/frameworks/stdlib/core.model.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ extensions:
33
pack: codeql/rust-all
44
extensible: summaryModel
55
data:
6+
# Builtin deref
7+
- ["<& as core::ops::deref::Deref>::deref", "Argument[self].Reference", "ReturnValue", "value", "manual"]
8+
- ["<&mut as core::ops::deref::Deref>::deref", "Argument[self].Reference", "ReturnValue", "value", "manual"]
69
# Arithmetic
710
- ["<_ as core::ops::arith::Add>::add", "Argument[self]", "ReturnValue", "taint", "manual"]
811
- ["<_ as core::ops::arith::Add>::add", "Argument[0]", "ReturnValue", "taint", "manual"]
@@ -41,8 +44,9 @@ extensions:
4144
- ["core::ptr::write", "Argument[1]", "Argument[0].Reference", "value", "manual"]
4245
- ["core::ptr::write_unaligned", "Argument[1]", "Argument[0].Reference", "value", "manual"]
4346
- ["core::ptr::write_volatile", "Argument[1]", "Argument[0].Reference", "value", "manual"]
44-
# https://doc.rust-lang.org/std/pin/struct.Pin.html#impl-Deref-for-Pin%3CPtr%3E, but limited to `Ptr = &`
47+
# https://doc.rust-lang.org/std/pin/struct.Pin.html#impl-Deref-for-Pin%3CPtr%3E, but limited to `Ptr = &` and `Ptr = Box`
4548
- ["<core::pin::Pin as core::ops::deref::Deref>::deref", "Argument[self].Reference.Field[core::pin::Pin::pointer].Reference", "ReturnValue.Reference", "value", "manual"]
49+
- ["<core::pin::Pin as core::ops::deref::Deref>::deref", "Argument[self].Reference.Field[core::pin::Pin::pointer].Field[alloc::boxed::Box(0)]", "ReturnValue.Reference", "value", "manual"]
4650
# Str
4751
- ["<core::str>::as_str", "Argument[self]", "ReturnValue", "value", "manual"]
4852
- ["<core::str>::as_bytes", "Argument[self]", "ReturnValue", "value", "manual"]

rust/ql/lib/codeql/rust/internal/PathResolution.qll

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,16 @@ private class StructItemNode extends TypeItemNode, ParameterizableItemNode insta
958958
language[monotonicAggregates]
959959
override string getCanonicalPath(Crate c) {
960960
this.hasCanonicalPath(c) and
961-
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
961+
(
962+
this =
963+
any(Builtins::BuiltinType t |
964+
not t.hasVisibility() and
965+
result = t.getDisplayName()
966+
)
967+
or
968+
not this = any(Builtins::BuiltinType t | not t.hasVisibility()) and
969+
result = strictconcat(int i | i in [0 .. 2] | this.getCanonicalPathPart(c, i) order by i)
970+
)
962971
}
963972
}
964973

0 commit comments

Comments
 (0)