Skip to content

Commit 1fd31d0

Browse files
committed
Rust: Data flow for consts and statics
1 parent c4e3720 commit 1fd31d0

15 files changed

Lines changed: 145 additions & 21 deletions

File tree

rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ class FormatTemplateVariableAccessTree extends LeafTree, FormatTemplateVariableA
9999
class ItemTree extends LeafTree, Item {
100100
ItemTree() {
101101
not this instanceof MacroCall and
102+
not this instanceof Const and
103+
not this instanceof Static and
102104
this = any(StmtList s).getAStatement()
103105
}
104106
}

rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,14 @@ final class CallableScope extends CfgScopeImpl, Callable {
4545
/** Holds if `scope` is exited when `last` finishes with completion `c`. */
4646
override predicate scopeLast(AstNode last, Completion c) { last(this.getBody(), last, c) }
4747
}
48+
49+
/**
50+
* A special scope used to represent the context in which `const`s and
51+
* `static`s are initialized. We do not actually compute a CFG for such
52+
* scopes.
53+
*/
54+
final class SourceFileScope extends CfgScopeImpl, SourceFile {
55+
override predicate scopeFirst(AstNode first) { none() }
56+
57+
override predicate scopeLast(AstNode last, Completion c) { none() }
58+
}

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,8 +653,22 @@ module RustDataFlowGen<RustDataFlowInputSig Input> implements InputSig<Location>
653653
*/
654654
predicate jumpStep(Node node1, Node node2) {
655655
FlowSummaryImpl::Private::Steps::summaryJumpStep(node1.(FlowSummaryNode).getSummaryNode(),
656-
node2.(FlowSummaryNode).getSummaryNode()) or
656+
node2.(FlowSummaryNode).getSummaryNode())
657+
or
657658
FlowSummaryImpl::Private::Steps::sourceJumpStep(node1.(FlowSummaryNode).getSummaryNode(), node2)
659+
or
660+
exists(Const c |
661+
node1.asExpr() = c.getBody() and
662+
node2.asExpr() = c.getAnAccess()
663+
)
664+
or
665+
exists(StaticNode sn, Static s | s = sn.getStatic() |
666+
node1 = sn and
667+
node2.asExpr() = s.getAnAccess().(StaticReadAccess)
668+
or
669+
node1.asExpr() = [s.getBody(), s.getAnAccess().(StaticWriteAccess)] and
670+
node2 = sn
671+
)
658672
}
659673

660674
pragma[nomagic]

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,17 @@ final class CastNode extends ExprNode {
704704
CastNode() { none() }
705705
}
706706

707+
/**
708+
* A node in the data flow graph that corresponds to a `static`.
709+
*/
710+
class StaticNode extends AstNodeNode, TStaticNode {
711+
override Static n;
712+
713+
StaticNode() { this = TStaticNode(n) }
714+
715+
Static getStatic() { result = n }
716+
}
717+
707718
cached
708719
newtype TNode =
709720
TExprNode(Expr e) { e.hasEnclosingCfgScope() and Stages::DataFlowStage::ref() } or
@@ -755,4 +766,5 @@ newtype TNode =
755766
)
756767
} or
757768
TClosureSelfReferenceNode(CfgScope c) { lambdaCreationExpr(c) } or
758-
TCaptureNode(VariableCapture::Flow::SynthesizedCaptureNode cn)
769+
TCaptureNode(VariableCapture::Flow::SynthesizedCaptureNode cn) or
770+
TStaticNode(Static s)

rust/ql/lib/codeql/rust/elements/StaticAccess.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@
55
private import internal.StaticImpl
66

77
final class StaticAccess = Impl::StaticAccess;
8+
9+
final class StaticWriteAccess = Impl::StaticWriteAccess;
10+
11+
final class StaticReadAccess = Impl::StaticReadAccess;

rust/ql/lib/codeql/rust/elements/internal/AstNodeImpl.qll

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,29 @@ module Impl {
4848
)
4949
}
5050

51+
pragma[nomagic]
52+
private predicate isConstOrStatic(File f) {
53+
f = this.getFile() and
54+
(
55+
this instanceof Const
56+
or
57+
this instanceof Static
58+
)
59+
}
60+
5161
/** Gets the CFG scope that encloses this node, if any. */
5262
cached
5363
CfgScope getEnclosingCfgScope() {
5464
exists(AstNode p | p = this.getParentNode() |
55-
result = p
65+
result = p and
66+
not result instanceof SourceFile
5667
or
5768
not p instanceof CfgScope and
69+
not this.isConstOrStatic(_) and
5870
result = p.getEnclosingCfgScope()
5971
)
72+
or
73+
this.isConstOrStatic(result.(SourceFile).getFile())
6074
}
6175

6276
/** Holds if this node is inside a CFG scope. */

rust/ql/lib/codeql/rust/elements/internal/ConstImpl.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ module Impl {
2525
* ```
2626
*/
2727
class Const extends Generated::Const {
28+
/** Gets an access to this constant item. */
29+
ConstAccess getAnAccess() { this = result.getConst() }
30+
2831
override string toStringImpl() { result = "const " + this.getName().getText() }
2932
}
3033

rust/ql/lib/codeql/rust/elements/internal/StaticImpl.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
private import codeql.rust.elements.internal.generated.Static
88
private import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
99
private import codeql.rust.elements.internal.PathExprImpl::Impl as PathExprImpl
10+
private import codeql.rust.elements.internal.VariableImpl::Impl as VariableImpl
1011
private import codeql.rust.internal.PathResolution
1112

1213
/**
@@ -24,6 +25,9 @@ module Impl {
2425
* ```
2526
*/
2627
class Static extends Generated::Static {
28+
/** Gets an access to this static item. */
29+
StaticAccess getAnAccess() { this = result.getStatic() }
30+
2731
override string toStringImpl() { result = "static " + this.getName().getText() }
2832
}
2933

@@ -49,4 +53,14 @@ module Impl {
4953

5054
override string getAPrimaryQlClass() { result = "StaticAccess" }
5155
}
56+
57+
/** A static write access. */
58+
class StaticWriteAccess extends StaticAccess {
59+
StaticWriteAccess() { VariableImpl::assignmentOperationDescendant(_, this) }
60+
}
61+
62+
/** A static read access. */
63+
class StaticReadAccess extends StaticAccess {
64+
StaticReadAccess() { not this instanceof StaticWriteAccess }
65+
}
5266
}

rust/ql/test/library-tests/controlflow/Cfg.expected

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,10 +1317,9 @@ edges
13171317
| test.rs:533:21:533:48 | { ... } | test.rs:533:21:533:48 | { ... } | |
13181318
| test.rs:533:48:533:48 | 0 | test.rs:533:21:533:48 | ... > ... | |
13191319
| test.rs:536:9:536:10 | 42 | test.rs:529:41:537:5 | { ... } | |
1320-
| test.rs:539:5:548:5 | enter fn const_block_panic | test.rs:540:9:540:30 | const N | |
1320+
| test.rs:539:5:548:5 | enter fn const_block_panic | test.rs:541:9:546:9 | ExprStmt | |
13211321
| test.rs:539:5:548:5 | exit fn const_block_panic (normal) | test.rs:539:5:548:5 | exit fn const_block_panic | |
13221322
| test.rs:539:35:548:5 | { ... } | test.rs:539:5:548:5 | exit fn const_block_panic (normal) | |
1323-
| test.rs:540:9:540:30 | const N | test.rs:541:9:546:9 | ExprStmt | |
13241323
| test.rs:541:9:546:9 | ExprStmt | test.rs:541:12:541:16 | false | |
13251324
| test.rs:541:9:546:9 | if false {...} | test.rs:547:9:547:9 | N | |
13261325
| test.rs:541:12:541:16 | false | test.rs:541:9:546:9 | if false {...} | false |

rust/ql/test/library-tests/dataflow/global/inline-flow.expected

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,15 @@ edges
222222
| main.rs:415:18:415:38 | i.get_double_number() | main.rs:415:13:415:14 | n4 | provenance | |
223223
| main.rs:418:13:418:14 | n5 | main.rs:419:14:419:15 | n5 | provenance | |
224224
| main.rs:418:18:418:41 | ...::get_default(...) | main.rs:418:13:418:14 | n5 | provenance | |
225+
| main.rs:426:30:426:39 | source(...) | main.rs:430:35:430:45 | CONST_VALUE | provenance | |
226+
| main.rs:427:5:427:46 | static STATIC_VALUE | main.rs:433:32:433:43 | STATIC_VALUE | provenance | |
227+
| main.rs:427:5:427:46 | static STATIC_VALUE | main.rs:437:18:437:29 | STATIC_VALUE | provenance | |
228+
| main.rs:427:36:427:45 | source(...) | main.rs:427:5:427:46 | static STATIC_VALUE | provenance | |
229+
| main.rs:430:35:430:45 | CONST_VALUE | main.rs:431:14:431:25 | CONST_VALUE2 | provenance | |
230+
| main.rs:433:17:433:28 | static_value | main.rs:434:18:434:29 | static_value | provenance | |
231+
| main.rs:433:32:433:43 | STATIC_VALUE | main.rs:433:17:433:28 | static_value | provenance | |
232+
| main.rs:436:13:436:24 | STATIC_VALUE | main.rs:427:5:427:46 | static STATIC_VALUE | provenance | |
233+
| main.rs:436:28:436:37 | source(...) | main.rs:436:13:436:24 | STATIC_VALUE | provenance | |
225234
nodes
226235
| main.rs:12:28:14:1 | { ... } | semmle.label | { ... } |
227236
| main.rs:13:5:13:13 | source(...) | semmle.label | source(...) |
@@ -464,6 +473,17 @@ nodes
464473
| main.rs:418:13:418:14 | n5 | semmle.label | n5 |
465474
| main.rs:418:18:418:41 | ...::get_default(...) | semmle.label | ...::get_default(...) |
466475
| main.rs:419:14:419:15 | n5 | semmle.label | n5 |
476+
| main.rs:426:30:426:39 | source(...) | semmle.label | source(...) |
477+
| main.rs:427:5:427:46 | static STATIC_VALUE | semmle.label | static STATIC_VALUE |
478+
| main.rs:427:36:427:45 | source(...) | semmle.label | source(...) |
479+
| main.rs:430:35:430:45 | CONST_VALUE | semmle.label | CONST_VALUE |
480+
| main.rs:431:14:431:25 | CONST_VALUE2 | semmle.label | CONST_VALUE2 |
481+
| main.rs:433:17:433:28 | static_value | semmle.label | static_value |
482+
| main.rs:433:32:433:43 | STATIC_VALUE | semmle.label | STATIC_VALUE |
483+
| main.rs:434:18:434:29 | static_value | semmle.label | static_value |
484+
| main.rs:436:13:436:24 | STATIC_VALUE | semmle.label | STATIC_VALUE |
485+
| main.rs:436:28:436:37 | source(...) | semmle.label | source(...) |
486+
| main.rs:437:18:437:29 | STATIC_VALUE | semmle.label | STATIC_VALUE |
467487
subpaths
468488
| main.rs:38:16:38:24 | source(...) | main.rs:26:28:26:33 | ...: i64 | main.rs:26:17:26:25 | SelfParam [Return] [&ref, MyStruct] | main.rs:38:5:38:5 | [post] a [MyStruct] |
469489
| main.rs:39:10:39:10 | a [MyStruct] | main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | main.rs:30:31:32:5 | { ... } | main.rs:39:10:39:21 | a.get_data() |
@@ -525,3 +545,8 @@ testFailures
525545
| main.rs:412:14:412:15 | n3 | main.rs:371:13:371:21 | source(...) | main.rs:412:14:412:15 | n3 | $@ | main.rs:371:13:371:21 | source(...) | source(...) |
526546
| main.rs:416:14:416:15 | n4 | main.rs:391:13:391:22 | source(...) | main.rs:416:14:416:15 | n4 | $@ | main.rs:391:13:391:22 | source(...) | source(...) |
527547
| main.rs:419:14:419:15 | n5 | main.rs:395:13:395:21 | source(...) | main.rs:419:14:419:15 | n5 | $@ | main.rs:395:13:395:21 | source(...) | source(...) |
548+
| main.rs:431:14:431:25 | CONST_VALUE2 | main.rs:426:30:426:39 | source(...) | main.rs:431:14:431:25 | CONST_VALUE2 | $@ | main.rs:426:30:426:39 | source(...) | source(...) |
549+
| main.rs:434:18:434:29 | static_value | main.rs:427:36:427:45 | source(...) | main.rs:434:18:434:29 | static_value | $@ | main.rs:427:36:427:45 | source(...) | source(...) |
550+
| main.rs:434:18:434:29 | static_value | main.rs:436:28:436:37 | source(...) | main.rs:434:18:434:29 | static_value | $@ | main.rs:436:28:436:37 | source(...) | source(...) |
551+
| main.rs:437:18:437:29 | STATIC_VALUE | main.rs:427:36:427:45 | source(...) | main.rs:437:18:437:29 | STATIC_VALUE | $@ | main.rs:427:36:427:45 | source(...) | source(...) |
552+
| main.rs:437:18:437:29 | STATIC_VALUE | main.rs:436:28:436:37 | source(...) | main.rs:437:18:437:29 | STATIC_VALUE | $@ | main.rs:436:28:436:37 | source(...) | source(...) |

0 commit comments

Comments
 (0)