Skip to content

Commit 45f3eda

Browse files
DIvanov503Oberon Swings
authored andcommitted
Refactor JvmTransferRelation to handle increments separately from other arithmetic instructions
Summary: closes T19485 The old workflow for `IINC` despite being correct was confusing and inconvenient to support. Now the JVM transfer relation should compute the incremented abstract state in a separate `computeIncrement` method.
1 parent c7d9c23 commit 45f3eda

File tree

5 files changed

+43
-24
lines changed

5 files changed

+43
-24
lines changed

base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmReferenceTransferRelation.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
package proguard.analysis.cpa.jvm.domain.reference;
2020

2121
import java.util.ArrayList;
22-
import java.util.Collections;
2322
import java.util.List;
2423
import proguard.analysis.datastructure.callgraph.Call;
2524
import proguard.classfile.instruction.Instruction;
@@ -63,11 +62,6 @@ public SetAbstractState<Reference> getAbstractDefault()
6362
@Override
6463
protected List<SetAbstractState<Reference>> applyInstruction(Instruction instruction, List<SetAbstractState<Reference>> operands, int resultCount)
6564
{
66-
// the increment doesn't affect the reference
67-
if (instruction.opcode == Instruction.OP_IINC)
68-
{
69-
return Collections.singletonList(operands.get(0));
70-
}
7165
List<SetAbstractState<Reference>> answer = new ArrayList<>(resultCount);
7266
for (int i = 0; i < resultCount; i++)
7367
{
@@ -76,6 +70,13 @@ protected List<SetAbstractState<Reference>> applyInstruction(Instruction instruc
7670
return answer;
7771
}
7872

73+
@Override
74+
protected SetAbstractState<Reference> computeIncrement(SetAbstractState<Reference> state, int value)
75+
{
76+
// references cannot be incremented
77+
return getAbstractDefault();
78+
}
79+
7980
@Override
8081
public void invokeMethod(JvmAbstractState<SetAbstractState<Reference>> state, Call call, List<SetAbstractState<Reference>> operands)
8182
{

base/src/main/java/proguard/analysis/cpa/jvm/transfer/JvmTransferRelation.java

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@ protected List<StateT> applyInstruction(Instruction instruction, List<StateT> op
124124
return answer;
125125
}
126126

127+
/**
128+
* Returns the abstract state of the incremented input {@code state} by {@code value}. The default implementation computes the join.
129+
*/
130+
protected StateT computeIncrement(StateT state, int value)
131+
{
132+
return state.join(getAbstractIntegerConstant(value));
133+
}
134+
127135
/**
128136
* Returns an abstract representation of a byte constant {@code b}.
129137
*/
@@ -459,31 +467,25 @@ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute c
459467
{
460468
if (variableInstruction.opcode == Instruction.OP_IINC)
461469
{
462-
List<StateT> operands = new ArrayList<>(2);
463-
operands.add(abstractState.getVariableOrDefault(variableInstruction.variableIndex, getAbstractDefault()));
464-
operands.add(getAbstractIntegerConstant(variableInstruction.constant));
465-
List<StateT> res = applyInstruction(variableInstruction, operands, 1);
466-
if (res.size() != 1)
467-
{
468-
throw new IllegalStateException("applyInstruction should return a list of size 1");
469-
}
470-
abstractState.setVariable(variableInstruction.variableIndex, res.get(0), getAbstractDefault());
470+
abstractState.setVariable(variableInstruction.variableIndex,
471+
computeIncrement(abstractState.getVariableOrDefault(variableInstruction.variableIndex, getAbstractDefault()), variableInstruction.constant),
472+
getAbstractDefault());
473+
return;
471474
}
472-
else if (variableInstruction.isLoad())
475+
if (variableInstruction.isLoad())
473476
{
474477
if (variableInstruction.isCategory2())
475478
{
476479
abstractState.push(abstractState.getVariableOrDefault(variableInstruction.variableIndex + 1, getAbstractDefault()));
477480
}
478481
abstractState.push(abstractState.getVariableOrDefault(variableInstruction.variableIndex, getAbstractDefault()));
482+
return;
479483
}
480-
else if (variableInstruction.isStore())
484+
// process store instruction
485+
abstractState.setVariable(variableInstruction.variableIndex, abstractState.pop(), getAbstractDefault());
486+
if (variableInstruction.isCategory2())
481487
{
482-
abstractState.setVariable(variableInstruction.variableIndex, abstractState.pop(), getAbstractDefault());
483-
if (variableInstruction.isCategory2())
484-
{
485-
abstractState.setVariable(variableInstruction.variableIndex + 1, abstractState.pop(), getAbstractDefault());
486-
}
488+
abstractState.setVariable(variableInstruction.variableIndex + 1, abstractState.pop(), getAbstractDefault());
487489
}
488490
}
489491

base/src/test/kotlin/proguard/analysis/cpa/JvmTransferRelationTest.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -736,8 +736,7 @@ class JvmTransferRelationTest : FreeSpec({
736736
InstructionExpression(
737737
VariableInstruction(Instruction.OP_IINC, 0, 1),
738738
listOf(
739-
ExpressionAbstractState(setOf(ValueExpression(ParticularIntegerValue(2)))),
740-
ExpressionAbstractState(setOf(ValueExpression(ParticularIntegerValue(1))))
739+
ExpressionAbstractState(setOf(ValueExpression(ParticularIntegerValue(2))))
741740
)
742741
)
743742
)

base/src/testFixtures/kotlin/proguard/testutils/cpa/ExpressionTransferRelation.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import proguard.analysis.cpa.jvm.state.JvmAbstractState
2222
import proguard.analysis.cpa.jvm.transfer.JvmTransferRelation
2323
import proguard.analysis.datastructure.callgraph.Call
2424
import proguard.classfile.instruction.Instruction
25+
import proguard.classfile.instruction.VariableInstruction
2526
import proguard.classfile.util.ClassUtil
2627
import proguard.evaluation.value.ParticularDoubleValue
2728
import proguard.evaluation.value.ParticularFloatValue
@@ -61,6 +62,17 @@ class ExpressionTransferRelation : JvmTransferRelation<ExpressionAbstractState>(
6162
)
6263
}
6364

65+
override fun computeIncrement(state: ExpressionAbstractState, value: Int): ExpressionAbstractState {
66+
return ExpressionAbstractState(
67+
setOf(
68+
InstructionExpression(
69+
VariableInstruction(Instruction.OP_IINC, 0, value),
70+
listOf(state)
71+
)
72+
)
73+
)
74+
}
75+
6476
override fun getAbstractDoubleConstant(d: Double): MutableList<ExpressionAbstractState> {
6577
return mutableListOf(
6678
abstractDefault,

docs/md/releasenotes.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## Version 9.0.8
2+
3+
### API changes
4+
- `JvmTransferRelation` has been refactored to model `IINC` in a separate `computeIncrement` method.
5+
16
## Version 9.0.7
27

38
### Improved

0 commit comments

Comments
 (0)