Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Rust: SpeedupAccessAfterLifetime.ql#21071

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
hvitved wants to merge1 commit intogithub:main
base:main
Choose a base branch
Loading
fromhvitved:rust/access-after-lifetime-perf
Draft
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 80 additions & 28 deletionsrust/ql/lib/codeql/rust/security/AccessAfterLifetimeExtensions.qll
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,17 +48,87 @@ module AccessAfterLifetime {
}

/**
* Holds if the pair `(source, sink)`, that represents a flow from a
* pointer or reference to a dereference, has its dereference outside the
* lifetime of the target variable `target`.
* Holds if the pair `(source, sink)` represents a flow from a pointer or reference
* to a dereference.
*/
bindingset[source, sink]
predicate dereferenceAfterLifetime(Source source, Sink sink, Variable target) {
exists(BlockExpr valueScope, BlockExpr accessScope |
sourceValueScope(source, target, valueScope) and
accessScope = sink.asExpr().getEnclosingBlock() and
not mayEncloseOnStack(valueScope, accessScope)
)
signature predicate dereferenceAfterLifetimeCandSig(DataFlow::Node source, DataFlow::Node sink);

/** Provides logic for identifying dereferences after lifetime. */
module DereferenceAfterLifetime<dereferenceAfterLifetimeCandSig/2 dereferenceAfterLifetimeCand> {
private newtype TTcNode =
TSource(Source s, Variable target) {
dereferenceAfterLifetimeCand(s, _) and sourceValueScope(s, target, _)
} or
TBlockExpr(BlockExpr be) or
TSink(Sink s) { dereferenceAfterLifetimeCand(_, s) }

private class TcNode extends TTcNode {
Source asSource(Variable target) { this = TSource(result, target) }

BlockExpr asBlockExpr() { this = TBlockExpr(result) }

Sink asSink() { this = TSink(result) }

string toString() {
result = this.asSource(_).toString()
or
result = this.asBlockExpr().toString()
or
result = this.asSink().toString()
}

Location getLocation() {
result = this.asSource(_).getLocation()
or
result = this.asBlockExpr().getLocation()
or
result = this.asSink().getLocation()
}
}

pragma[nomagic]
private predicate tcStep(TcNode a, TcNode b) {
// `b` is a child of `a`
exists(Source source, Variable target, BlockExpr be |
source = a.asSource(target) and
be = b.asBlockExpr().getEnclosingBlock*() and
sourceValueScope(source, target, be) and
dereferenceAfterLifetimeCand(source, _)
)
or
// propagate through function calls
exists(Call call |
a.asBlockExpr() = call.getEnclosingBlock() and
call.getARuntimeTarget() = b.asBlockExpr().getEnclosingCallable()
)
or
a.asBlockExpr() = b.asSink().asExpr().getEnclosingBlock()
}

private predicate isTcSource(TcNode n) { n instanceof TSource }

private predicate isTcSink(TcNode n) { n instanceof TSink }

/**
* Holds if block `a` contains block `b`, in the sense that a stack allocated variable in
* `a` may still be on the stack during execution of `b`. This is interprocedural,
* but is an overapproximation that doesn't accurately track call contexts
* (for example if `f` and `g` both call `b`, then then depending on the
* caller a variable in `f` or `g` may or may-not be on the stack during `b`).
*/
private predicate mayEncloseOnStack(TcNode a, TcNode b) =
doublyBoundedFastTC(tcStep/2, isTcSource/1, isTcSink/1)(a, b)

/**
* Holds if the pair `(source, sink)`, that represents a flow from a
* pointer or reference to a dereference, has its dereference outside the
* lifetime of the target variable `target`.
*/
predicate dereferenceAfterLifetime(Source source, Sink sink, Variable target) {
dereferenceAfterLifetimeCand(source, sink) and
sourceValueScope(source, target, _) and
not mayEncloseOnStack(TSource(source, target), TSink(sink))
}
}

/**
Expand DownExpand Up@@ -88,24 +158,6 @@ module AccessAfterLifetime {
valueScope(value.(FieldExpr).getContainer(), target, scope)
}

/**
* Holds if block `a` contains block `b`, in the sense that a stack allocated variable in
* `a` may still be on the stack during execution of `b`. This is interprocedural,
* but is an overapproximation that doesn't accurately track call contexts
* (for example if `f` and `g` both call `b`, then then depending on the
* caller a variable in `f` or `g` may or may-not be on the stack during `b`).
*/
private predicate mayEncloseOnStack(BlockExpr a, BlockExpr b) {
// `b` is a child of `a`
a = b.getEnclosingBlock*()
or
// propagate through function calls
exists(Call call |
mayEncloseOnStack(a, call.getEnclosingBlock()) and
call.getARuntimeTarget() = b.getEnclosingCallable()
)
}

/**
* A source that is a `RefExpr`.
*/
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,6 +61,7 @@ where
// flow from a pointer or reference to the dereference
AccessAfterLifetimeFlow::flowPath(sourceNode, sinkNode) and
// check that the dereference is outside the lifetime of the target
AccessAfterLifetime::dereferenceAfterLifetime(sourceNode.getNode(), sinkNode.getNode(), target)
AccessAfterLifetime::DereferenceAfterLifetime<AccessAfterLifetimeFlow::flow/2>::dereferenceAfterLifetime(sourceNode
.getNode(), sinkNode.getNode(), target)
select sinkNode.getNode(), sourceNode, sinkNode,
"Access of a pointer to $@ after its lifetime has ended.", target, target.toString()

[8]ページ先頭

©2009-2025 Movatter.jp