Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust: Adopt shared flow summaries library #18130

Merged
merged 4 commits into from
Dec 3, 2024

Conversation

hvitved
Copy link
Contributor

@hvitved hvitved commented Nov 27, 2024

Introduces the class SummarizedCallable for defining flow summaries in QL. Models-as-data will be added follow-up.

@github-actions github-actions bot added the Rust Pull requests that update Rust code label Nov 27, 2024
1000 + i
}

fn sink(s: i64) {

Check notice

Code scanning / CodeQL

Unused variable Note test

Variable 's' is not used.
}

// has a flow model
fn identity(i: i64) -> i64 {

Check notice

Code scanning / CodeQL

Unused variable Note test

Variable 'i' is not used.
}

// has a flow model
fn get_var_pos(e: MyPosEnum) -> i64 {

Check notice

Code scanning / CodeQL

Unused variable Note test

Variable 'e' is not used.
}

// has a flow model
fn set_var_pos(i: i64) -> MyPosEnum {

Check notice

Code scanning / CodeQL

Unused variable Note test

Variable 'i' is not used.
}

// has a flow model
fn get_var_field(e: MyFieldEnum) -> i64 {

Check notice

Code scanning / CodeQL

Unused variable Note test

Variable 'e' is not used.
}

// has a flow model
fn set_var_field(i: i64) -> MyFieldEnum {

Check notice

Code scanning / CodeQL

Unused variable Note test

Variable 'i' is not used.
result.asLibraryCallable() = this.getSummarizedCallable()
}

override EmptyLocation getLocation() { any() }

Check warning

Code scanning / CodeQL

Override with unmentioned parameter Warning

Override predicate doesn't mention
result
. Maybe mention it in a 'exists(result)'?
(
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
exists(SsaImpl::DefinitionExt def, boolean isUseStep |

Check warning

Code scanning / CodeQL

Omittable 'exists' variable Warning

This exists variable can be omitted by using a don't-care expression
in this argument
.
@hvitved hvitved force-pushed the rust/flow-summary-impl branch from 5812246 to 93367bb Compare November 27, 2024 13:44
@hvitved hvitved force-pushed the rust/flow-summary-impl branch from 06355a0 to 3bb1ae0 Compare November 27, 2024 14:41
@hvitved hvitved added the no-change-note-required This PR does not need a change note label Nov 27, 2024
@hvitved hvitved marked this pull request as ready for review November 27, 2024 14:42
@hvitved hvitved requested review from a team as code owners November 27, 2024 14:42
@hvitved hvitved force-pushed the rust/flow-summary-impl branch 2 times, most recently from 7c47ade to e6e4f92 Compare December 2, 2024 09:59
Copy link
Contributor

@paldepind paldepind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really great. Super nice to get flow through unwrap.

I've left a few nitpick comments.

@@ -490,6 +638,13 @@ private module Aliases {
class ContentSetAlias = ContentSet;
}

pragma[nomagic]
Resolvable getCallResolvable(CallExprBase call) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates the private getCallResolvable on CallExprBase. I think we should make that public or remove the duplication some other way.

private module Summaries {
private import codeql.rust.Frameworks

// TODO: Used models-as-data when it's available
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// TODO: Used models-as-data when it's available
// TODO: Use models-as-data when it's available

Comment on lines +751 to +798
exists(SsaImpl::DefinitionExt def, boolean isUseStep |
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, isUseStep)
|
isUseStep = false
or
isUseStep = true and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit shorter:

Suggested change
exists(SsaImpl::DefinitionExt def, boolean isUseStep |
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, isUseStep)
|
isUseStep = false
or
isUseStep = true and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
)
exists(boolean isUseStep | SsaFlow::localFlowStep(_, nodeFrom, nodeTo, isUseStep) |
isUseStep = true
implies
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
)

Copy link
Contributor Author

@hvitved hvitved Dec 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it preserves semantics, it will introduce unnecessary tuple duplication. a implies b is syntactic sugar for not a or b, so the rewrite becomes

SsaFlow::localFlowStep(def, nodeFrom, nodeTo, isUseStep) and
not (isUseStep = true)
or
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, isUseStep) and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)

Note how isUseStep = true is not part of the last disjunct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit hard for me to wrap my head around. If isUseStep = true is not the case then the first disjunct will always hold, so I would've thought that adding it to the last disjunct wouldn't make a difference. But I guess that's only the "preserves semantics" part.

Is it something along the lines of: For a disjunction P or Q all the tuples satisfying P will be created, then all tuples satisfying Q will be created, and only then will they be joined together (and de-duplicated). With my rewrite Q could be a larger stream of tuples overlapping with P, and hence the result will be the same but more de-duplication is going on?

I guess turning def into _ is still applicable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it something along the lines of: For a disjunction P or Q all the tuples satisfying P will be created, then all tuples satisfying Q will be created, and only then will they be joined together (and de-duplicated). With my rewrite Q could be a larger stream of tuples overlapping with P, and hence the result will be the same but more de-duplication is going on?

Exactly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I oversaw the _ part; that is certainly valid, let's do it follow-up.

@@ -126,6 +126,11 @@ fn option_pattern_match_unqualified() {
}
}

fn option_unwrap() {
let s1 = Some(source(19));
sink(s1.unwrap()); // $ hasValueFlow=19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! 😎

final class ReturnNode extends ExprNode {
ReturnNode() { this.getCfgNode().getASuccessor() instanceof AnnotatedExitCfgNode }
abstract class ReturnNode extends Node {
abstract ReturnKind getKind();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we think we'll get additional return kinds for Rust? If not, could we leave this as it was before and remove kind in getCall, etc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who knows what Future Rust brings :-) If you prefer, I can change it back.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:D My preference would be to await the Rust future and just keep it simple for now without carrying around the return kind, but it obviously doesn't matter much.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, given that all the other comments are addressed I think that we should just move forward and merge instead of changing this back.

Comment on lines 19 to 22
result = pos.getPosition().toString()
or
pos.isSelf() and
result = "self"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same as the toString implementation on ParameterPosition.

Suggested change
result = pos.getPosition().toString()
or
pos.isSelf() and
result = "self"
result = pos.toString()

@@ -148,6 +173,26 @@ module Node {
override Location getLocation() { none() }
}

/** A data-flow node used to model flow summaries. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** A data-flow node used to model flow summaries. */
/** A data flow node used to model flow summaries. */

Comment on lines 402 to 404
override CfgScope getCfgScope() { result = PostUpdateNode.super.getCfgScope() }

final override Location getLocation() { result = n.getLocation() }
override EmptyLocation getLocation() { result = PostUpdateNode.super.getLocation() }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the overloading is a bit convoluted here. PostUpdateNode.super.getLocation ends up calling getLocation on the pre node which is a FlowSummaryNode whose getLocation returns and empty location. Why not just call FlowSummaryNode.super.getLocation directly? And in that case, we don't need the getCfgScope and getLocation inside PostUpdateNode. These two can be moved to ArgumentPostUpdateNode and then these two overrides can just be deleted.

@hvitved hvitved force-pushed the rust/flow-summary-impl branch from e6e4f92 to 52dc79e Compare December 3, 2024 08:28
@hvitved hvitved requested a review from paldepind December 3, 2024 08:28
@hvitved hvitved merged commit 0bebfa6 into github:main Dec 3, 2024
58 checks passed
@hvitved hvitved deleted the rust/flow-summary-impl branch December 3, 2024 09:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C# DataFlow Library Java no-change-note-required This PR does not need a change note Ruby Rust Pull requests that update Rust code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants