Java: Replace getAUse with getARead.

This commit is contained in:
Anders Schack-Mulligen
2025-11-07 10:52:38 +01:00
parent 35caede859
commit f4b9efcdce
20 changed files with 71 additions and 67 deletions

View File

@@ -26,9 +26,9 @@ Expr enumConstEquality(Expr e, boolean polarity, EnumConstant c) {
} }
/** Gets an instanceof expression of `v` with type `type` */ /** Gets an instanceof expression of `v` with type `type` */
InstanceOfExpr instanceofExpr(SsaVariable v, RefType type) { InstanceOfExpr instanceofExpr(SsaDefinition v, RefType type) {
result.getCheckedType() = type and result.getCheckedType() = type and
result.getExpr() = v.getAUse() result.getExpr() = v.getARead()
} }
/** /**
@@ -37,8 +37,8 @@ InstanceOfExpr instanceofExpr(SsaVariable v, RefType type) {
* *
* Note this includes Kotlin's `==` and `!=` operators, which are value-equality tests. * Note this includes Kotlin's `==` and `!=` operators, which are value-equality tests.
*/ */
EqualityTest varEqualityTestExpr(SsaVariable v1, SsaVariable v2, boolean isEqualExpr) { EqualityTest varEqualityTestExpr(SsaDefinition v1, SsaDefinition v2, boolean isEqualExpr) {
result.hasOperands(v1.getAUse(), v2.getAUse()) and result.hasOperands(v1.getARead(), v2.getARead()) and
isEqualExpr = result.polarity() isEqualExpr = result.polarity()
} }
@@ -91,18 +91,18 @@ Expr clearlyNotNullExpr(Expr reason) {
(reason = r1 or reason = r2) (reason = r1 or reason = r2)
) )
or or
exists(SsaVariable v, boolean branch, VarRead rval, Guard guard | exists(SsaDefinition v, boolean branch, VarRead rval, Guard guard |
guard = directNullGuard(v, branch, false) and guard = directNullGuard(v, branch, false) and
guard.controls(rval.getBasicBlock(), branch) and guard.controls(rval.getBasicBlock(), branch) and
reason = guard and reason = guard and
rval = v.getAUse() and rval = v.getARead() and
result = rval and result = rval and
not result = baseNotNullExpr() not result = baseNotNullExpr()
) )
or or
exists(SsaVariable v | exists(SsaDefinition v |
clearlyNotNull(v, reason) and clearlyNotNull(v, reason) and
result = v.getAUse() and result = v.getARead() and
not result = baseNotNullExpr() not result = baseNotNullExpr()
) )
} }

View File

@@ -179,9 +179,9 @@ private Expr nonEmptyExpr() {
// An array creation with a known positive size is trivially non-empty. // An array creation with a known positive size is trivially non-empty.
result.(ArrayCreationExpr).getFirstDimensionSize() > 0 result.(ArrayCreationExpr).getFirstDimensionSize() > 0
or or
exists(SsaVariable v | exists(SsaDefinition v |
// A use of an array variable is non-empty if... // A use of an array variable is non-empty if...
result = v.getAUse() and result = v.getARead() and
v.getSourceVariable().getType() instanceof Array v.getSourceVariable().getType() instanceof Array
| |
// ...its definition is non-empty... // ...its definition is non-empty...
@@ -192,13 +192,13 @@ private Expr nonEmptyExpr() {
cond.controls(result.getBasicBlock(), branch) and cond.controls(result.getBasicBlock(), branch) and
cond.getCondition() = nonZeroGuard(length, branch) and cond.getCondition() = nonZeroGuard(length, branch) and
length.getField().hasName("length") and length.getField().hasName("length") and
length.getQualifier() = v.getAUse() length.getQualifier() = v.getARead()
) )
) )
or or
exists(SsaVariable v | exists(SsaDefinition v |
// A use of a Collection variable is non-empty if... // A use of a Collection variable is non-empty if...
result = v.getAUse() and result = v.getARead() and
v.getSourceVariable().getType() instanceof CollectionType and v.getSourceVariable().getType() instanceof CollectionType and
exists(ConditionBlock cond, boolean branch, Expr c | exists(ConditionBlock cond, boolean branch, Expr c |
// ...it is guarded by a condition... // ...it is guarded by a condition...
@@ -216,13 +216,13 @@ private Expr nonEmptyExpr() {
// ...and the condition proves that it is non-empty, either by using the `isEmpty` method... // ...and the condition proves that it is non-empty, either by using the `isEmpty` method...
c.(MethodCall).getMethod().hasName("isEmpty") and c.(MethodCall).getMethod().hasName("isEmpty") and
branch = false and branch = false and
c.(MethodCall).getQualifier() = v.getAUse() c.(MethodCall).getQualifier() = v.getARead()
or or
// ...or a check on its `size`. // ...or a check on its `size`.
exists(MethodCall size | exists(MethodCall size |
c = nonZeroGuard(size, branch) and c = nonZeroGuard(size, branch) and
size.getMethod().hasName("size") and size.getMethod().hasName("size") and
size.getQualifier() = v.getAUse() size.getQualifier() = v.getARead()
) )
) )
) )

View File

@@ -242,10 +242,10 @@ module Sem implements Semantic<Location> {
Type getSsaType(SsaVariable var) { result = var.getSourceVariable().getType() } Type getSsaType(SsaVariable var) { result = var.getSourceVariable().getType() }
final private class FinalSsaVariable = SSA::SsaVariable; final private class FinalSsaVariable = SSA::SsaDefinition;
class SsaVariable extends FinalSsaVariable { class SsaVariable extends FinalSsaVariable {
Expr getAUse() { result = super.getAUse() } Expr getAUse() { result = super.getARead() }
} }
class SsaPhiNode extends SsaVariable instanceof SSA::SsaPhiDefinition { class SsaPhiNode extends SsaVariable instanceof SSA::SsaPhiDefinition {

View File

@@ -74,9 +74,9 @@ ArrayCreationExpr getArrayDef(SsaVariable v) {
* `arrlen` without going through a back edge. * `arrlen` without going through a back edge.
*/ */
private predicate arrayLengthDef(FieldRead arrlen, ArrayCreationExpr def) { private predicate arrayLengthDef(FieldRead arrlen, ArrayCreationExpr def) {
exists(SsaVariable arr | exists(SsaDefinition arr |
arrlen.getField() instanceof ArrayLengthField and arrlen.getField() instanceof ArrayLengthField and
arrlen.getQualifier() = arr.getAUse() and arrlen.getQualifier() = arr.getARead() and
def = getArrayDef(arr) def = getArrayDef(arr)
) )
} }

View File

@@ -417,8 +417,8 @@ private class RefTypeCastingExpr extends CastingExpr {
* *
* The `VarAccess` represents the access to `v` that `result` has the same value as. * The `VarAccess` represents the access to `v` that `result` has the same value as.
*/ */
Expr sameValue(SsaVariable v, VarAccess va) { Expr sameValue(SsaDefinition v, VarAccess va) {
result = v.getAUse() and result = va result = v.getARead() and result = va
or or
result.(AssignExpr).getDest() = va and result = v.(SsaExplicitWrite).getDefiningExpr() result.(AssignExpr).getDest() = va and result = v.(SsaExplicitWrite).getDefiningExpr()
or or

View File

@@ -99,7 +99,7 @@ predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)
* updates. * updates.
*/ */
predicate hasNonlocalValue(FieldRead fr) { predicate hasNonlocalValue(FieldRead fr) {
not exists(SsaVariable v | v.getAUse() = fr) not exists(SsaDefinition v | v.getARead() = fr)
or or
exists(SsaDefinition v, SsaDefinition def | exists(SsaDefinition v, SsaDefinition def |
v.getARead() = fr and def = v.getAnUltimateDefinition() v.getARead() = fr and def = v.getAnUltimateDefinition()

View File

@@ -8,7 +8,9 @@ private import java as J
private import semmle.code.java.dataflow.SSA as Ssa private import semmle.code.java.dataflow.SSA as Ssa
private import semmle.code.java.dataflow.RangeUtils as RU private import semmle.code.java.dataflow.RangeUtils as RU
class SsaVariable = Ssa::SsaVariable; class SsaVariable extends Ssa::SsaDefinition {
Expr getAUse() { result = super.getARead() }
}
class Expr = J::Expr; class Expr = J::Expr;

View File

@@ -11,7 +11,9 @@ module Private {
class BasicBlock = BB::BasicBlock; class BasicBlock = BB::BasicBlock;
class SsaVariable = Ssa::SsaVariable; class SsaVariable extends Ssa::SsaDefinition {
Expr getAUse() { result = super.getARead() }
}
class SsaPhiNode = Ssa::SsaPhiDefinition; class SsaPhiNode = Ssa::SsaPhiDefinition;

View File

@@ -324,7 +324,7 @@ private module Impl {
result = e.(CastingExpr).getExpr() result = e.(CastingExpr).getExpr()
} }
Expr getARead(SsaVariable v) { result = v.getAUse() } Expr getARead(SsaDefinition v) { result = v.getARead() }
Field getField(FieldAccess fa) { result = fa.getField() } Field getField(FieldAccess fa) { result = fa.getField() }

View File

@@ -8,14 +8,14 @@ private import semmle.code.java.dataflow.SSA as Ssa
private import semmle.code.java.controlflow.BasicBlocks as BB private import semmle.code.java.controlflow.BasicBlocks as BB
private import SsaReadPositionCommon private import SsaReadPositionCommon
class SsaVariable = Ssa::SsaVariable; class SsaVariable = Ssa::SsaDefinition;
class SsaPhiNode = Ssa::SsaPhiDefinition; class SsaPhiNode = Ssa::SsaPhiDefinition;
class BasicBlock = BB::BasicBlock; class BasicBlock = BB::BasicBlock;
/** Gets a basic block in which SSA variable `v` is read. */ /** Gets a basic block in which SSA variable `v` is read. */
BasicBlock getAReadBasicBlock(SsaVariable v) { result = v.getAUse().getBasicBlock() } BasicBlock getAReadBasicBlock(SsaVariable v) { result = v.getARead().getBasicBlock() }
private predicate id(BB::ExprParent x, BB::ExprParent y) { x = y } private predicate id(BB::ExprParent x, BB::ExprParent y) { x = y }

View File

@@ -46,14 +46,14 @@ class RightShiftOp extends Expr {
} }
private predicate boundedRead(VarRead read) { private predicate boundedRead(VarRead read) {
exists(SsaVariable v, ConditionBlock cb, ComparisonExpr comp, boolean testIsTrue | exists(SsaDefinition v, ConditionBlock cb, ComparisonExpr comp, boolean testIsTrue |
read = v.getAUse() and read = v.getARead() and
cb.controls(read.getBasicBlock(), testIsTrue) and cb.controls(read.getBasicBlock(), testIsTrue) and
cb.getCondition() = comp cb.getCondition() = comp
| |
comp.getLesserOperand() = v.getAUse() and testIsTrue = true comp.getLesserOperand() = v.getARead() and testIsTrue = true
or or
comp.getGreaterOperand() = v.getAUse() and testIsTrue = false comp.getGreaterOperand() = v.getARead() and testIsTrue = false
) )
} }

View File

@@ -32,9 +32,9 @@ private predicate validationCall(MethodCall ma, VarAccess va) {
} }
private predicate validatedAccess(VarAccess va) { private predicate validatedAccess(VarAccess va) {
exists(SsaVariable v, MethodCall guardcall | exists(SsaDefinition v, MethodCall guardcall |
va = v.getAUse() and va = v.getARead() and
validationCall(guardcall, v.getAUse()) validationCall(guardcall, v.getARead())
| |
guardcall.(Guard).controls(va.getBasicBlock(), _) guardcall.(Guard).controls(va.getBasicBlock(), _)
or or

View File

@@ -19,10 +19,10 @@ import semmle.code.java.dataflow.RangeUtils
import semmle.code.java.dataflow.RangeAnalysis import semmle.code.java.dataflow.RangeAnalysis
pragma[nomagic] pragma[nomagic]
predicate ssaArrayLengthBound(SsaVariable arr, Bound b) { predicate ssaArrayLengthBound(SsaDefinition arr, Bound b) {
exists(FieldAccess len | exists(FieldAccess len |
len.getField() instanceof ArrayLengthField and len.getField() instanceof ArrayLengthField and
len.getQualifier() = arr.getAUse() and len.getQualifier() = arr.getARead() and
b.getExpr() = len b.getExpr() = len
) )
} }
@@ -31,9 +31,9 @@ predicate ssaArrayLengthBound(SsaVariable arr, Bound b) {
* Holds if the index expression of `aa` is less than or equal to the array length plus `k`. * Holds if the index expression of `aa` is less than or equal to the array length plus `k`.
*/ */
predicate boundedArrayAccess(ArrayAccess aa, int k) { predicate boundedArrayAccess(ArrayAccess aa, int k) {
exists(SsaVariable arr, Expr index, Bound b, int delta | exists(SsaDefinition arr, Expr index, Bound b, int delta |
aa.getIndexExpr() = index and aa.getIndexExpr() = index and
aa.getArray() = arr.getAUse() and aa.getArray() = arr.getARead() and
bounded(index, b, delta, true, _) bounded(index, b, delta, true, _)
| |
ssaArrayLengthBound(arr, b) and ssaArrayLengthBound(arr, b) and

View File

@@ -142,22 +142,22 @@ Expr overFlowCand() {
predicate positiveOrNegative(Expr e) { positive(e) or negative(e) } predicate positiveOrNegative(Expr e) { positive(e) or negative(e) }
/** Gets an expression that equals `v` plus a positive or negative value. */ /** Gets an expression that equals `v` plus a positive or negative value. */
Expr increaseOrDecreaseOfVar(SsaVariable v) { Expr increaseOrDecreaseOfVar(SsaDefinition v) {
exists(AssignAddExpr add | exists(AssignAddExpr add |
result = add and result = add and
positiveOrNegative(add.getDest()) and positiveOrNegative(add.getDest()) and
add.getRhs() = v.getAUse() add.getRhs() = v.getARead()
) )
or or
exists(AddExpr add, Expr e | exists(AddExpr add, Expr e |
result = add and result = add and
add.hasOperands(v.getAUse(), e) and add.hasOperands(v.getARead(), e) and
positiveOrNegative(e) positiveOrNegative(e)
) )
or or
exists(SubExpr sub | exists(SubExpr sub |
result = sub and result = sub and
sub.getLeftOperand() = v.getAUse() and sub.getLeftOperand() = v.getARead() and
positiveOrNegative(sub.getRightOperand()) positiveOrNegative(sub.getRightOperand())
) )
or or
@@ -172,7 +172,7 @@ Expr increaseOrDecreaseOfVar(SsaVariable v) {
predicate overFlowTest(ComparisonExpr comp) { predicate overFlowTest(ComparisonExpr comp) {
( (
exists(SsaVariable v | comp.hasOperands(increaseOrDecreaseOfVar(v), v.getAUse())) exists(SsaDefinition v | comp.hasOperands(increaseOrDecreaseOfVar(v), v.getARead()))
or or
comp.getLesserOperand() = overFlowCand() and comp.getLesserOperand() = overFlowCand() and
comp.getGreaterOperand().(IntegerLiteral).getIntValue() = 0 comp.getGreaterOperand().(IntegerLiteral).getIntValue() = 0
@@ -195,9 +195,9 @@ predicate concurrentModificationTest(BinaryExpr test) {
*/ */
pragma[nomagic] pragma[nomagic]
predicate guardedTest(EqualityTest test, Guard guard, boolean isEq, int i1, int i2) { predicate guardedTest(EqualityTest test, Guard guard, boolean isEq, int i1, int i2) {
exists(SsaVariable v, CompileTimeConstantExpr c1, CompileTimeConstantExpr c2 | exists(SsaDefinition v, CompileTimeConstantExpr c1, CompileTimeConstantExpr c2 |
guard.isEquality(v.getAUse(), c1, isEq) and guard.isEquality(v.getARead(), c1, isEq) and
test.hasOperands(v.getAUse(), c2) and test.hasOperands(v.getARead(), c2) and
i1 = c1.getIntValue() and i1 = c1.getIntValue() and
i2 = c2.getIntValue() and i2 = c2.getIntValue() and
v.getSourceVariable().getType() instanceof IntegralType v.getSourceVariable().getType() instanceof IntegralType

View File

@@ -27,14 +27,14 @@ class BoundKind extends string {
*/ */
predicate uselessTest(ConditionNode s1, BinaryExpr test, boolean testIsTrue) { predicate uselessTest(ConditionNode s1, BinaryExpr test, boolean testIsTrue) {
exists( exists(
ConditionBlock cb, SsaVariable v, BinaryExpr cond, boolean condIsTrue, int k1, int k2, ConditionBlock cb, SsaDefinition v, BinaryExpr cond, boolean condIsTrue, int k1, int k2,
CompileTimeConstantExpr c1, CompileTimeConstantExpr c2 CompileTimeConstantExpr c1, CompileTimeConstantExpr c2
| |
s1.getCondition() = cond and s1.getCondition() = cond and
cb.getCondition() = cond and cb.getCondition() = cond and
cond.hasOperands(v.getAUse(), c1) and cond.hasOperands(v.getARead(), c1) and
c1.getIntValue() = k1 and c1.getIntValue() = k1 and
test.hasOperands(v.getAUse(), c2) and test.hasOperands(v.getARead(), c2) and
c2.getIntValue() = k2 and c2.getIntValue() = k2 and
v.getSourceVariable().getVariable() instanceof LocalScopeVariable and v.getSourceVariable().getVariable() instanceof LocalScopeVariable and
cb.controls(test.getBasicBlock(), condIsTrue) and cb.controls(test.getBasicBlock(), condIsTrue) and
@@ -49,7 +49,7 @@ predicate uselessTest(ConditionNode s1, BinaryExpr test, boolean testIsTrue) {
) )
or or
exists(ComparisonExpr comp | comp = cond | exists(ComparisonExpr comp | comp = cond |
comp.getLesserOperand() = v.getAUse() and comp.getLesserOperand() = v.getARead() and
( (
condIsTrue = true and condIsTrue = true and
boundKind.isUpper() and boundKind.isUpper() and
@@ -60,7 +60,7 @@ predicate uselessTest(ConditionNode s1, BinaryExpr test, boolean testIsTrue) {
(if comp.isStrict() then bound = k1 else bound = k1 + 1) (if comp.isStrict() then bound = k1 else bound = k1 + 1)
) )
or or
comp.getGreaterOperand() = v.getAUse() and comp.getGreaterOperand() = v.getARead() and
( (
condIsTrue = true and condIsTrue = true and
boundKind.isLower() and boundKind.isLower() and
@@ -88,7 +88,7 @@ predicate uselessTest(ConditionNode s1, BinaryExpr test, boolean testIsTrue) {
) )
or or
exists(ComparisonExpr comp | comp = test | exists(ComparisonExpr comp | comp = test |
comp.getLesserOperand() = v.getAUse() and comp.getLesserOperand() = v.getARead() and
( (
boundKind.providesLowerBound() and boundKind.providesLowerBound() and
testIsTrue = false and testIsTrue = false and
@@ -107,7 +107,7 @@ predicate uselessTest(ConditionNode s1, BinaryExpr test, boolean testIsTrue) {
) )
) )
or or
comp.getGreaterOperand() = v.getAUse() and comp.getGreaterOperand() = v.getARead() and
( (
boundKind.providesLowerBound() and boundKind.providesLowerBound() and
testIsTrue = true and testIsTrue = true and

View File

@@ -37,11 +37,11 @@ predicate requiresInstanceOf(Expr e, VarAccess va, RefType t) {
* `v` is not of type `sup`, which is a supertype of `t`. * `v` is not of type `sup`, which is a supertype of `t`.
*/ */
predicate contradictoryTypeCheck(Expr e, Variable v, RefType t, RefType sup, Expr cond) { predicate contradictoryTypeCheck(Expr e, Variable v, RefType t, RefType sup, Expr cond) {
exists(SsaVariable ssa | exists(SsaDefinition ssa |
ssa.getSourceVariable().getVariable() = v and ssa.getSourceVariable().getVariable() = v and
requiresInstanceOf(e, ssa.getAUse(), t) and requiresInstanceOf(e, ssa.getARead(), t) and
sup = t.getAnAncestor() and sup = t.getAnAncestor() and
instanceOfCheck(cond, ssa.getAUse(), sup) and instanceOfCheck(cond, ssa.getARead(), sup) and
cond.(Guard).controls(e.getBasicBlock(), false) and cond.(Guard).controls(e.getBasicBlock(), false) and
not t instanceof ErrorType and not t instanceof ErrorType and
not sup instanceof ErrorType not sup instanceof ErrorType

View File

@@ -75,9 +75,9 @@ where
loopWhileTrue(loop) and loopExitGuard(loop, cond) loopWhileTrue(loop) and loopExitGuard(loop, cond)
) and ) and
// None of the ssa variables in `cond` are updated inside the loop. // None of the ssa variables in `cond` are updated inside the loop.
forex(SsaVariable ssa, VarRead use | ssa.getAUse() = use and use.getParent*() = cond | forex(SsaDefinition ssa, VarRead use | ssa.getARead() = use and use.getParent*() = cond |
not ssa.getCfgNode().getEnclosingStmt().getEnclosingStmt*() = loop or not ssa.getControlFlowNode().getEnclosingStmt().getEnclosingStmt*() = loop or
ssa.getCfgNode().asExpr().getParent*() = loop.(ForStmt).getAnInit() ssa.getControlFlowNode().asExpr().getParent*() = loop.(ForStmt).getAnInit()
) and ) and
// And `cond` does not use method calls, field reads, or array reads. // And `cond` does not use method calls, field reads, or array reads.
not exists(MethodCall ma | ma.getParent*() = cond) and not exists(MethodCall ma | ma.getParent*() = cond) and

View File

@@ -42,9 +42,9 @@ class CheckSignaturesGuard extends Guard instanceof EqualityTest {
} }
predicate signatureChecked(Expr safe) { predicate signatureChecked(Expr safe) {
exists(CheckSignaturesGuard g, SsaVariable v | exists(CheckSignaturesGuard g, SsaDefinition v |
v.getAUse() = g.getCheckedExpr() and v.getARead() = g.getCheckedExpr() and
safe = v.getAUse() and safe = v.getARead() and
g.controls(safe.getBasicBlock(), g.(EqualityTest).polarity()) g.controls(safe.getBasicBlock(), g.(EqualityTest).polarity())
) )
} }

View File

@@ -3,6 +3,6 @@ import semmle.code.java.dataflow.SSA
from int uses, int live from int uses, int live
where where
uses = strictcount(SsaVariable ssa, VarRead use | use = ssa.getAUse()) and uses = strictcount(SsaDefinition ssa, VarRead use | use = ssa.getARead()) and
live = strictcount(SsaVariable ssa, BasicBlock b | ssa.isLiveAtEndOfBlock(b)) live = strictcount(SsaDefinition ssa, BasicBlock b | ssa.isLiveAtEndOfBlock(b))
select uses, live select uses, live

View File

@@ -1,6 +1,6 @@
import java import java
import semmle.code.java.dataflow.SSA import semmle.code.java.dataflow.SSA
from SsaVariable ssa, SsaSourceVariable v, Expr use from SsaDefinition ssa, SsaSourceVariable v, Expr use
where use = ssa.getAUse() and ssa.getSourceVariable() = v where use = ssa.getARead() and ssa.getSourceVariable() = v
select v, ssa.getCfgNode(), ssa.toString(), use select v, ssa.getControlFlowNode(), ssa.toString(), use