Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c4f0868
Java: Move SSA entry defs to index -1.
aschackmull Oct 21, 2025
f2181ec
Java: Get rid of untracked SSA definitions.
aschackmull Oct 21, 2025
374c772
Java: Remove getAFirstUse in BaseSSA.
aschackmull Oct 21, 2025
79b2f21
SSA: Fix phi defs.
aschackmull Oct 27, 2025
289d337
SSA: Improve toString.
aschackmull Oct 27, 2025
551944b
Java: Add VariableWrite class.
aschackmull Oct 24, 2025
942dc2b
Java: Replace BaseSSA class wrappers with shared code.
aschackmull Oct 23, 2025
d5708fd
Java: Instantiate shared SSA wrappers for main SSA.
aschackmull Nov 5, 2025
154f077
Java: Simplify instantiation of Guards and ControlFlowReachability.
aschackmull Nov 6, 2025
99aa033
Java: Replace usages of isParameterDefinition.
aschackmull Nov 6, 2025
07e6356
Java: Replace getAFirstUse with top-level predicate.
aschackmull Nov 7, 2025
483b2d8
Java: Replace uses of SsaExplicitUpdate.
aschackmull Nov 7, 2025
06df5c0
Java: Introduce SsaCapturedDefinition and replace uses of getAnUltima…
aschackmull Nov 7, 2025
3e43c53
Java: Update some qldoc deprecation notices.
aschackmull Nov 7, 2025
35caede
Java: Replace SsaPhiNode with SsaPhiDefinition.
aschackmull Nov 7, 2025
f4b9efc
Java: Replace getAUse with getARead.
aschackmull Nov 7, 2025
8594ae0
Java: Replace remaining SsaImplicitInit.
aschackmull Nov 7, 2025
f0bd034
Java: Replace usages of SsaVariable.
aschackmull Nov 7, 2025
ee5d65e
Java: Update toString for implicit writes.
aschackmull Nov 7, 2025
5849d85
Java: Deprecate two more SSA classes.
aschackmull Nov 7, 2025
95ac61d
Java: Drop caching of deprecated predicates.
aschackmull Oct 27, 2025
e059ded
Java: Accept toString changes in qltest.
aschackmull Nov 6, 2025
109a5eb
Java: Accept qltest changes due to dropped UntrackedDef.
aschackmull Nov 6, 2025
437ca58
Java: Add change note.
aschackmull Nov 7, 2025
4a58a01
Java: Reinstate useless null check results for fields that are no lon…
aschackmull Nov 11, 2025
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
32 changes: 5 additions & 27 deletions java/ql/lib/semmle/code/java/controlflow/Guards.qll
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ private predicate isNonFallThroughPredecessor(SwitchCase sc, ControlFlowNode pre

private module GuardsInput implements SharedGuards::InputSig<Location, ControlFlowNode, BasicBlock> {
private import java as J
private import semmle.code.java.dataflow.internal.BaseSSA
private import semmle.code.java.dataflow.internal.BaseSSA as Base
private import semmle.code.java.dataflow.NullGuards as NullGuards

class NormalExitNode = ControlFlow::NormalExitNode;
Expand Down Expand Up @@ -211,10 +211,10 @@ private module GuardsInput implements SharedGuards::InputSig<Location, ControlFl
f.getInitializer() = NullGuards::baseNotNullExpr()
)
or
exists(CatchClause cc, LocalVariableDeclExpr decl, BaseSsaUpdate v |
exists(CatchClause cc, LocalVariableDeclExpr decl, Base::SsaExplicitWrite v |
decl = cc.getVariable() and
decl = v.getDefiningExpr() and
this = v.getAUse()
this = v.getARead()
)
}
}
Expand Down Expand Up @@ -407,30 +407,8 @@ private module LogicInputCommon {
}

private module LogicInput_v1 implements GuardsImpl::LogicInputSig {
private import semmle.code.java.dataflow.internal.BaseSSA

final private class FinalBaseSsaVariable = BaseSsaVariable;

class SsaDefinition extends FinalBaseSsaVariable {
GuardsInput::Expr getARead() { result = this.getAUse() }
}

class SsaExplicitWrite extends SsaDefinition instanceof BaseSsaUpdate {
GuardsInput::Expr getValue() {
super.getDefiningExpr().(VariableAssign).getSource() = result or
super.getDefiningExpr().(AssignOp) = result
}
}

class SsaPhiDefinition extends SsaDefinition instanceof BaseSsaPhiNode {
predicate hasInputFromBlock(SsaDefinition inp, BasicBlock bb) {
super.hasInputFromBlock(inp, bb)
}
}

class SsaParameterInit extends SsaDefinition instanceof BaseSsaImplicitInit {
Parameter getParameter() { super.isParameterDefinition(result) }
}
private import semmle.code.java.dataflow.internal.BaseSSA as Base
import Base::Ssa

predicate additionalNullCheck = LogicInputCommon::additionalNullCheck/4;

Expand Down
60 changes: 31 additions & 29 deletions java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module;

import java as J
private import semmle.code.java.dispatch.VirtualDispatch
private import semmle.code.java.dataflow.internal.BaseSSA
private import semmle.code.java.dataflow.internal.BaseSSA as Base
private import semmle.code.java.controlflow.Guards
private import codeql.typeflow.TypeFlow
private import codeql.typeflow.UniversalFlow as UniversalFlow
Expand All @@ -27,7 +27,7 @@ private RefType boxIfNeeded(J::Type t) {
module FlowStepsInput implements UniversalFlow::UniversalFlowInput<Location> {
private newtype TFlowNode =
TField(Field f) { not f.getType() instanceof PrimitiveType } or
TSsa(BaseSsaVariable ssa) { not ssa.getSourceVariable().getType() instanceof PrimitiveType } or
TSsa(Base::SsaDefinition ssa) { not ssa.getSourceVariable().getType() instanceof PrimitiveType } or
TExpr(Expr e) or
TMethod(Method m) { not m.getReturnType() instanceof PrimitiveType }

Expand Down Expand Up @@ -55,7 +55,7 @@ module FlowStepsInput implements UniversalFlow::UniversalFlowInput<Location> {
Field asField() { this = TField(result) }

/** Gets the SSA variable corresponding to this node, if any. */
BaseSsaVariable asSsa() { this = TSsa(result) }
Base::SsaDefinition asSsa() { this = TSsa(result) }

/** Gets the expression corresponding to this node, if any. */
Expr asExpr() { this = TExpr(result) }
Expand Down Expand Up @@ -107,7 +107,7 @@ module FlowStepsInput implements UniversalFlow::UniversalFlowInput<Location> {
not e.(FieldAccess).getField() = f
)
or
n2.asSsa().(BaseSsaPhiNode).getAnUltimateLocalDefinition() = n1.asSsa()
n2.asSsa().(Base::SsaPhiDefinition).getAnUltimateDefinition() = n1.asSsa()
or
exists(ReturnStmt ret |
n2.asMethod() = ret.getEnclosingCallable() and ret.getResult() = n1.asExpr()
Expand All @@ -118,24 +118,24 @@ module FlowStepsInput implements UniversalFlow::UniversalFlowInput<Location> {
exists(Argument arg, Parameter p |
privateParamArg(p, arg) and
n1.asExpr() = arg and
n2.asSsa().(BaseSsaImplicitInit).isParameterDefinition(p) and
n2.asSsa().(Base::SsaParameterInit).getParameter() = p and
// skip trivial recursion
not arg = n2.asSsa().getAUse()
not arg = n2.asSsa().getARead()
)
or
n2.asExpr() = n1.asField().getAnAccess()
or
n2.asExpr() = n1.asSsa().getAUse()
n2.asExpr() = n1.asSsa().getARead()
or
n2.asExpr().(CastingExpr).getExpr() = n1.asExpr() and
not n2.asExpr().getType() instanceof PrimitiveType
or
n2.asExpr().(AssignExpr).getSource() = n1.asExpr() and
not n2.asExpr().getType() instanceof PrimitiveType
or
n2.asSsa().(BaseSsaUpdate).getDefiningExpr().(VariableAssign).getSource() = n1.asExpr()
n2.asSsa().(Base::SsaExplicitWrite).getDefiningExpr().(VariableAssign).getSource() = n1.asExpr()
or
n2.asSsa().(BaseSsaImplicitInit).captures(n1.asSsa())
n2.asSsa().(Base::SsaCapturedDefinition).captures(n1.asSsa())
or
n2.asExpr().(NotNullExpr).getExpr() = n1.asExpr()
}
Expand All @@ -147,7 +147,7 @@ module FlowStepsInput implements UniversalFlow::UniversalFlowInput<Location> {
n.asExpr() instanceof NullLiteral
or
exists(LocalVariableDeclExpr decl |
n.asSsa().(BaseSsaUpdate).getDefiningExpr() = decl and
n.asSsa().(Base::SsaExplicitWrite).getDefiningExpr() = decl and
not decl.hasImplicitInit() and
not exists(decl.getInitOrPatternSource())
)
Expand Down Expand Up @@ -216,7 +216,9 @@ private module Input implements TypeFlowInput<Location> {
)
}

private predicate upcastEnhancedForStmtAux(BaseSsaUpdate v, RefType t, RefType t1, RefType t2) {
private predicate upcastEnhancedForStmtAux(

Check warning

Code scanning / CodeQL

Candidate predicate not marked as `nomagic` Warning

Candidate predicate to
upcastEnhancedForStmt
is not marked as nomagic.
Base::SsaExplicitWrite v, RefType t, RefType t1, RefType t2
) {
exists(EnhancedForStmt for |
for.getVariable() = v.getDefiningExpr() and
v.getSourceVariable().getType().getErasure() = t2 and
Expand All @@ -230,17 +232,17 @@ private module Input implements TypeFlowInput<Location> {
* the type of the elements being iterated over, and this type is more precise
* than the type of `v`.
*/
private predicate upcastEnhancedForStmt(BaseSsaUpdate v, RefType t) {
private predicate upcastEnhancedForStmt(Base::SsaExplicitWrite v, RefType t) {
exists(RefType t1, RefType t2 |
upcastEnhancedForStmtAux(v, t, t1, t2) and
t1.getASourceSupertype+() = t2
)
}

private predicate downcastSuccessorAux(
CastingExpr cast, BaseSsaVariable v, RefType t, RefType t1, RefType t2
CastingExpr cast, Base::SsaDefinition v, RefType t, RefType t1, RefType t2
) {
cast.getExpr() = v.getAUse() and
cast.getExpr() = v.getARead() and
t = cast.getType() and
t1 = t.getErasure() and
t2 = v.getSourceVariable().getType().getErasure()
Expand All @@ -250,10 +252,10 @@ private module Input implements TypeFlowInput<Location> {
* Holds if `va` is an access to a value that has previously been downcast to `t`.
*/
private predicate downcastSuccessor(VarAccess va, RefType t) {
exists(CastingExpr cast, BaseSsaVariable v, RefType t1, RefType t2 |
exists(CastingExpr cast, Base::SsaDefinition v, RefType t1, RefType t2 |
downcastSuccessorAux(pragma[only_bind_into](cast), v, t, t1, t2) and
t1.getASourceSupertype+() = t2 and
va = v.getAUse() and
va = v.getARead() and
dominates(cast.getControlFlowNode(), va.getControlFlowNode()) and
dominates(cast.getControlFlowNode().getANormalSuccessor(), va.getControlFlowNode())
)
Expand All @@ -263,9 +265,9 @@ private module Input implements TypeFlowInput<Location> {
* Holds if `va` is an access to a value that is guarded by `instanceof t` or `case e t`.
*/
private predicate typeTestGuarded(VarAccess va, RefType t) {
exists(Guard typeTest, BaseSsaVariable v |
typeTest.appliesTypeTest(v.getAUse(), t, _) and
va = v.getAUse() and
exists(Guard typeTest, Base::SsaDefinition v |
typeTest.appliesTypeTest(v.getARead(), t, _) and
va = v.getARead() and
guardControls_v1(typeTest, va.getBasicBlock(), true)
)
}
Expand All @@ -274,12 +276,12 @@ private module Input implements TypeFlowInput<Location> {
* Holds if `aa` is an access to a value that is guarded by `instanceof t` or `case e t`.
*/
private predicate arrayTypeTestGuarded(ArrayAccess aa, RefType t) {
exists(Guard typeTest, BaseSsaVariable v1, BaseSsaVariable v2, ArrayAccess aa1 |
exists(Guard typeTest, Base::SsaDefinition v1, Base::SsaDefinition v2, ArrayAccess aa1 |
typeTest.appliesTypeTest(aa1, t, _) and
aa1.getArray() = v1.getAUse() and
aa1.getIndexExpr() = v2.getAUse() and
aa.getArray() = v1.getAUse() and
aa.getIndexExpr() = v2.getAUse() and
aa1.getArray() = v1.getARead() and
aa1.getIndexExpr() = v2.getARead() and
aa.getArray() = v1.getARead() and
aa.getIndexExpr() = v2.getARead() and
guardControls_v1(typeTest, aa.getBasicBlock(), true)
)
}
Expand Down Expand Up @@ -321,14 +323,14 @@ private module Input implements TypeFlowInput<Location> {
* Holds if `ioe` checks `v`, its true-successor is `bb`, and `bb` has multiple
* predecessors.
*/
private predicate instanceofDisjunct(InstanceOfExpr ioe, BasicBlock bb, BaseSsaVariable v) {
ioe.getExpr() = v.getAUse() and
private predicate instanceofDisjunct(InstanceOfExpr ioe, BasicBlock bb, Base::SsaDefinition v) {
ioe.getExpr() = v.getARead() and
strictcount(bb.getAPredecessor()) > 1 and
exists(ConditionBlock cb | cb.getCondition() = ioe and cb.getTestSuccessor(true) = bb)
}

/** Holds if `bb` is disjunctively guarded by multiple `instanceof` tests on `v`. */
private predicate instanceofDisjunction(BasicBlock bb, BaseSsaVariable v) {
private predicate instanceofDisjunction(BasicBlock bb, Base::SsaDefinition v) {
strictcount(InstanceOfExpr ioe | instanceofDisjunct(ioe, bb, v)) =
strictcount(bb.getAPredecessor())
}
Expand All @@ -338,10 +340,10 @@ private module Input implements TypeFlowInput<Location> {
* `instanceof t_i` where `t` is one of those `t_i`.
*/
predicate instanceofDisjunctionGuarded(TypeFlowNode n, RefType t) {
exists(BasicBlock bb, InstanceOfExpr ioe, BaseSsaVariable v, VarAccess va |
exists(BasicBlock bb, InstanceOfExpr ioe, Base::SsaDefinition v, VarAccess va |
instanceofDisjunction(bb, v) and
bb.dominates(va.getBasicBlock()) and
va = v.getAUse() and
va = v.getARead() and
instanceofDisjunct(ioe, bb, v) and
t = ioe.getSyntacticCheckedType() and
n.asExpr() = va
Expand Down
Loading