Repository navigation
SSA: Split reads in MakeSsa based on explicit/implicit instead of certain/uncertain. - #23071
aschackmull wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
🟢 Approval recommended
There are no active review issues for the change separating explicit and implicit SSA reads.
No open issues 🎉
What changed in this PR
This PR changes the shared SSA API to distinguish explicit and implicit reads instead of certain and uncertain reads. This keeps expression-based SSA reasoning focused on explicit reads while retaining implicit reads for data-flow integration.
Changes:
- Add an
explicitReadinput predicate and use it to classify reads inMakeSsa. - Update Java and C# SSA adapters to identify explicit reads.
- Migrate Java capture handling to
ssaDefReachesImplicitRead.
| File | Description |
|---|---|
shared/ssa/codeql/ssa/Ssa.qll |
Define explicit reads, update reaching-read predicates, and clarify explicit-write documentation. |
java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll |
Identify explicit variable reads and migrate capture handling. |
java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll |
Apply the explicit-read contract and capture API to base SSA. |
csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll |
Identify explicit reads through assignable accesses. |
csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll |
Identify explicit reads by their target variable. |
Review effort: Balanced (auto)
| * Holds if `e` reads the value of `v`. These are the reads that are | ||
| * included in the `SsaDefinition.getARead()` member predicate. | ||
| */ | ||
| predicate explicitRead(Expr e, SourceVariable v); |
There was a problem hiding this comment.
When is not the same as
predicate explicitRead(Expr e, SourceVariable v) {
exists(BasicBlock bb, int i |
variableRead(bb, i, v, true) and
e.getControlFlowNode() = bb.getNode(i)
)
}There was a problem hiding this comment.
The whole point of the PR is to be able to distinguish the two. If we merely use variableRead(bb, i, v, true) and e.getControlFlowNode() = bb.getNode(i) then we make the assumption that the expression implies the variable - and furthermore, in this context we assume that the expression is the variable read. This is true for explicit reads where the expression is a concrete read of a specific variable, but there are several cases where we have certain reads (4th column = true in variableRead) that are implicit, so the expression at the cfg node of the read isn't the actual variable read. E.g. implicit this/self, which is tracked as an SSA variable in unified. Also, Go functions have an epilogue where return variables are implicitly read. These are reads that should have certain = true because they should be included in the data flow integration, but they should not be included in SsaVariable.getARead(), since that returns an expression that's assumed to equal the read.
The
Expr getARead()member predicate onSsaDefinitiondoesn't make sense for implicit reads, and those implicit reads aren't very relevant in the contexts where expression-based SSA reasoning is used (e.g. guards logic, range analysis, or query-specific SSA usage). At the same time, implicit reads can be very relevant for DataFlowIntegration (e.g.this-flow), so the certain/uncertain split isn't appropriate in MakeSsa (and has been blocking adoption in Go and Unified). The straightforward fix is to make the explicit/implicit split explicit in the MakeSsa instantiation.