The StackMap attribute stores the OperandStack from bottom entry to top. Earlier implementations of the Purifier1 incorrectly assumed that the order was from top to bottom.
Fix implemented, but not tested yet.
Package | Class | Method | Method # | Effect | Source |
---|---|---|---|---|---|
org.spruce.midp.alarmclock | a | a | 22 | Fails | midlet.org |
AlarmClock | commandAction | 5 | |||
b(boolean) | 16 | ||||
k | 17 | ||||
a | 18 | ||||
e | paint | 5 | |||
e | a | 8 | |||
e | a | 13 | |||
org.spruce.midp.common | c | a | 8 | ||
examples.stock | StockMidlet | checkAlerts(String) | 8 | Wireless Toolkit 1.04 | |
Stock | convert(int) | 11 | |||
example.http | HttpView | run() | 6 | ||
example.chooser | ColorChooser | colorPaint(Graphics) | 19 | ||
com.markcrocker.purifier.testcases | SpecialCases | newObjectOnStack() | 11 | Purifier1 |
A number of methods have been found in a third party free midlet that is being used for testing against Midlets found in "the wild". This Midlet Suite does not have any source code available and has clearly been obfuscated. The StackMap that is in these methods has items on the stack that are out of order compared to what the Purifier1 produces for the same method.
These stack items seem to be out of order, when seen from the point of view of reading the code by hand. However, it is simply an issue of storing the data in reverse order.
The org.spruce.midp.alarmclock.AlarmClock.b(boolean) method provides an example of this situation. No source code is available The following byte code is from the compiled, preverified and obfuscated class file extracted from the Spruce Alarm Clock distribution. The method is quite large, so only excerpts are presented here. The StackMap has also been reformatted for readability. According to both the StackMap and the Purifier1's DFA, the only item on the stack at offset 95 is an org.spruce.midp.alarmclock.e object. Executing the instruction at offset 95, iconst_0 should simply add an integer to the top of the stack. However, the StackMap that is associated with the method has the order of these items on the stack in reverse order for the entry at offset 96. Other ways of evaluating the code lead to the same conclusion. If the control path is followed from after the ifeq instruction at offset 88, the iconst_2 at offset 91 also leaves an integer on the top of the stack before going to offset 96 via the goto instruction at offset 93. Finally, the invokevirtual at offset 96 expects an integer as the argument, so the integer should be on the top of the stack. The StackMap entry produced by an earlier verion of the Purifier1 for offset 96 was: Although this agrees with the DFA above, it disagrees with the StackMap that is included in the method attributes, but only because the StackMap is printed out in the wrong order. Swap the order of the StackMapEntry[] returned by getStackItems in the OperandStack class.Source Code
Bytecode
80: invokespecial org.spruce.midp.alarmclock.AlarmClock.a (Z)V (86)
83: aload_0
84: getfield org.spruce.midp.alarmclock.AlarmClock.c Lorg/spruce/midp/alarmclock/e; (66)
87: iload_1
88: ifeq 7
91: iconst_2
92: goto 4
95: iconst_0
96: invokevirtual org.spruce.midp.alarmclock.e.a (I)V (67)
99: return
StackMap(
(
offset = 95,
locals = {
(type=Object, (183)class=org.spruce.midp.alarmclock.AlarmClock),
(type=Integer)
},
stack items = {
(type=Object, (64)class=org.spruce.midp.alarmclock.e)
}
)
(
offset = 96,
locals = {
(type=Object, (183)class=org.spruce.midp.alarmclock.AlarmClock),
(type=Integer)
},
stack items = {
(type=Object, (64)class=org.spruce.midp.alarmclock.e),
(type=Integer)
}
)
)
Data Flow Analysis
stack items = {
(type=Integer),
(type=Object, (64)class=org.spruce.midp.alarmclock.e)
}
Solutions