-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Shared: Add a shared SuccessorType implementation #20300
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
Conversation
| ExceptionClass getExceptionClass() { result = ec } | ||
|
|
||
| override ExceptionSuccessor getAMatchingSuccessorType() { result.getExceptionClass() = ec } | ||
| override ExceptionSuccessor getAMatchingSuccessorType() { any() } |
Check warning
Code scanning / CodeQL
Override with unmentioned parameter Warning
result
| } | ||
|
|
||
| override RaiseSuccessor getAMatchingSuccessorType() { any() } | ||
| override ExceptionSuccessor getAMatchingSuccessorType() { any() } |
Check warning
Code scanning / CodeQL
Override with unmentioned parameter Warning
result
ce85279 to
75ea5f2
Compare
| FallthroughCompletion() { this = TFallthroughCompletion(dest) } | ||
|
|
||
| override FallthroughSuccessor getAMatchingSuccessorType() { any() } | ||
| override DirectSuccessor getAMatchingSuccessorType() { any() } |
Check warning
Code scanning / CodeQL
Override with unmentioned parameter Warning
result
d9a59a2 to
01fcc41
Compare
| string getLabel() { result = label } | ||
|
|
||
| override GotoSuccessor getAMatchingSuccessorType() { result.getLabel() = label } | ||
| override GotoSuccessor getAMatchingSuccessorType() { any() } |
Check warning
Code scanning / CodeQL
Override with unmentioned parameter Warning
result
| } | ||
|
|
||
| override NextSuccessor getAMatchingSuccessorType() { any() } | ||
| override ContinueSuccessor getAMatchingSuccessorType() { any() } |
Check warning
Code scanning / CodeQL
Override with unmentioned parameter Warning
result
01fcc41 to
0df7d6f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds a shared implementation of the SuccessorType class used as edge labels in control flow graphs (CFGs). The implementation centralizes successor type definitions in the shared/controlflow module and updates all languages to use this shared code instead of maintaining language-specific implementations.
Key changes include:
- Adding a comprehensive shared
SuccessorTypeimplementation with a well-defined hierarchy - Removing language-specific successor type implementations
- Updating all languages to import and use the shared successor types
Reviewed Changes
Copilot reviewed 64 out of 68 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| shared/controlflow/codeql/controlflow/SuccessorType.qll | New shared successor type implementation with comprehensive hierarchy |
| shared/controlflow/codeql/controlflow/Guards.qll | Updated to import shared successor types |
| shared/controlflow/codeql/controlflow/Cfg.qll | Updated to use shared successor types and removed language-specific definitions |
| shared/controlflow/codeql/controlflow/BasicBlock.qll | Updated to import shared successor types |
| swift/ql/lib/codeql/swift/security/PathInjectionExtensions.qll | Updated to use shared BooleanSuccessor type |
| swift/ql/lib/codeql/swift/controlflow/* | Removed Swift-specific successor types and updated to use shared implementation |
| rust/ql/lib/codeql/rust/controlflow/* | Removed Rust-specific successor types and updated to use shared implementation |
| ruby/ql/lib/codeql/ruby/controlflow/* | Removed Ruby-specific successor types and updated to use shared implementation |
| java/ql/lib/semmle/code/java/controlflow/SuccessorType.qll | Removed Java-specific successor type implementation |
| csharp/ql/test/library-tests/goto/Goto1.expected | Updated test expectations for goto successor label changes |
| ruby/ql/test/library-tests/controlflow/graph/*.expected | Updated test expectations for successor type label changes |
Comments suppressed due to low confidence (1)
swift/ql/lib/codeql/swift/controlflow/internal/Completion.qll:1
- The change from
MatchSuccessortoMatchingSuccessorsuggests a naming inconsistency between the old Swift implementation and the new shared implementation. Ensure all references are updated consistently.
/**
Mostly toString changes, and a slight change to splitting in C#.
bcc61a5 to
4e70627
Compare
| private import codeql.util.Boolean | ||
|
|
||
| /* | ||
| * SuccessorType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add this as ```text QL doc to the class.
| */ | ||
| class SuccessorType extends TSuccessorType { | ||
| /** Gets a textual representation of this successor type. */ | ||
| abstract string toString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not be exposing abstract classes or predicates. Instead, apply the usual private Impl + final external alias trick.
| * | ||
| * has a control flow graph containing Boolean successors: | ||
| * | ||
| * ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add a text suffix to prevent VS code from attempting to syntax highlighting this. Same for other examples.
| } | ||
|
|
||
| /** A Java `yield` control flow successor. */ | ||
| class JavaYieldSuccessor extends JumpSuccessor, TJavaYieldSuccessor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be weird for Java to reuse Break instead for this (it looks similar to how one can break with a value in Ruby)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No that's probably sensible. I'll delete JavaYieldSuccessor.
| * the `ensure` block executes normally). | ||
| */ | ||
| class EnsureSplitType extends SuccessorType { | ||
| class EnsureSplitType instanceof SuccessorType { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert this when SuccessorType is no longer abstract.
| EnsureSplitType() { not this instanceof ConditionalSuccessor } | ||
|
|
||
| /** Gets a textual representation of this successor type. */ | ||
| string toString() { result = super.toString() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
revert
| | CompileTimeOperators.cs:37:13:37:40 | [finally: goto(End)] call to method WriteLine | CompileTimeOperators.cs:28:10:28:10 | M | | ||
| | CompileTimeOperators.cs:37:13:37:41 | [finally: goto(End)] ...; | CompileTimeOperators.cs:28:10:28:10 | M | | ||
| | CompileTimeOperators.cs:37:31:37:39 | [finally: goto(End)] "Finally" | CompileTimeOperators.cs:28:10:28:10 | M | | ||
| | CompileTimeOperators.cs:36:9:38:9 | [finally: goto] {...} | CompileTimeOperators.cs:28:10:28:10 | M | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, when we no longer store the target of the goto, how can we make the correct jump after finally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed offline. Summary: This is an intentional trade-off. We can still get the same level of precision in a non-split CFG as we typically use a more precise internal edge label called Completion during CFG construction. So this trade-off only relates to any splitting we may do based on SuccessorType. Dca didn't show any impact and having multiple different goto statements inside a try block is fairly corner-case.
| | Finally.cs:114:19:114:35 | [finally: exception(Exception)] ... == ... | Finally.cs:114:17:114:36 | [false, finally: exception(Exception)] !... | true | | ||
| | Finally.cs:114:19:114:35 | [finally: exception(Exception)] ... == ... | Finally.cs:114:17:114:36 | [true, finally: exception(Exception)] !... | false | | ||
| | Finally.cs:114:19:114:35 | [finally: exception(NullReferenceException)] ... == ... | Finally.cs:114:17:114:36 | [false, finally: exception(NullReferenceException)] !... | true | | ||
| | Finally.cs:114:19:114:35 | [finally: exception(NullReferenceException)] ... == ... | Finally.cs:114:17:114:36 | [true, finally: exception(NullReferenceException)] !... | false | | ||
| | Finally.cs:114:19:114:35 | [finally: exception(OutOfMemoryException)] ... == ... | Finally.cs:114:17:114:36 | [false, finally: exception(OutOfMemoryException)] !... | true | | ||
| | Finally.cs:114:19:114:35 | [finally: exception(OutOfMemoryException)] ... == ... | Finally.cs:114:17:114:36 | [true, finally: exception(OutOfMemoryException)] !... | false | | ||
| | Finally.cs:114:19:114:35 | [finally: exception] ... == ... | Finally.cs:114:17:114:36 | [false, finally: exception] !... | true | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same: When we don't record the exception type, we may not be able to get control flow right when a finally is inside a try.
| } | ||
|
|
||
| /** Holds if `t` is an abnormal exit type out of a CFG scope. */ | ||
| predicate isAbnormalExitType(SuccessorType t) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is reexported elsewhere, so not nice to have a top-level predicate reexported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about I'll make it a member on AbruptSuccessor instead, then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe I'll just move it to Cfg.qll...
This adds a shared implementation of the
SuccessorTypeclass that's used as edge labels in our CFGs. I've also updated all languages and all shared libraries to use this new shared code.Commit-by-commit review is encouraged.
A few notes:
SuccessorTypeis now a shared non-parameterized implementation. This means that it's not using language-specific details like exception type or goto-labels.SuccessorType, so the change has a slight semantic impact here. Initially I tried a version that bunched all of the jump successors together, but that gave a single new FP in C# nullness, so I choose to have a more detailed distinction between different jump successors.successorTypeIsConditionpredicate in a few places in order to not disrupt basic block boundaries too much. Streamlining this across languages is left as a potential follow-up consideration.