diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index c47ad8ea5..1d5e09846 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -1086,6 +1086,45 @@ public class AVM2Graph extends Graph { return false; } + @Override + protected boolean canHandleLoop(BaseLocalData localData, GraphPart part, List loops) { + Loop toBeLoop = null; + for (Loop el : loops) { + if ((el.loopContinue == part) && (el.phase == 0)) { + toBeLoop = el; + break; + } + } + if (toBeLoop == null) { + return true; + } + AVM2LocalData aLocalData = (AVM2LocalData) localData; + + boolean inTry = false; + for (ABCException ex : body.exceptions) { + if (aLocalData.parsedExceptions.contains(ex)) { + continue; + } + int fixStart = avm2code.adr2pos(ex.start, true); + int fixEnd = avm2code.adr2pos(ex.end, true); + if (part.start == fixStart) { + inTry = true; + for (GraphPart be : toBeLoop.backEdges) { + if (be.start < fixStart || be.start >= fixEnd) { + //exists a backedge that is outside of try..catch + return true; + } + } + } + } + if (inTry) { + //it is in try and there's no backedge that's outside try + return false; + } + return true; + } + + @Override protected boolean checkPartOutput(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List loops, Loop currentLoop, int staticOperation, String path) throws InterruptedException { AVM2LocalData aLocalData = (AVM2LocalData) localData; @@ -1338,7 +1377,7 @@ public class AVM2Graph extends Graph { if (ft instanceof WithAVM2Item) { pos++; List withCommands = new ArrayList<>(); - while (!(w.commands.get(pos) instanceof WithEndAVM2Item)) { + while (pos < w.commands.size() && !(w.commands.get(pos) instanceof WithEndAVM2Item)) { withCommands.add(w.commands.get(pos)); pos++; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index 386c66989..695a221e8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -1448,6 +1448,9 @@ public class Graph { return false; } + protected boolean canHandleLoop(BaseLocalData localData, GraphPart part, List loops) { + return true; + } protected List printGraph(List foundGotos, Map> partCodes, Map partCodePos, Set visited, BaseLocalData localData, TranslateStack stack, Set allParts, GraphPart parent, GraphPart part, List stopPart, List loops, List ret, int staticOperation, String path, int recursionLevel) throws InterruptedException { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -1495,11 +1498,19 @@ public class Graph { //List loopContinues = getLoopsContinues(loops); boolean isLoop = false; Loop currentLoop = null; + + boolean vCanHandleLoop = canHandleLoop(localData, part, loops); + Loop ignoredLoop = null; for (Loop el : loops) { if ((el.loopContinue == part) && (el.phase == 0)) { - currentLoop = el; - currentLoop.phase = 1; - isLoop = true; + if (vCanHandleLoop) { + currentLoop = el; + currentLoop.phase = 1; + isLoop = true; + } else { + ignoredLoop = el; + } + break; } } @@ -1509,6 +1520,12 @@ public class Graph { } for (int l = loops.size() - 1; l >= 0; l--) { Loop el = loops.get(l); + if (el == ignoredLoop) { + if (debugPrintGraph) { + System.err.println("ignoring to be loop " + el); + } + continue; + } if (el == currentLoop) { if (debugPrintGraph) { System.err.println("ignoring current loop " + el); diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java index 124102780..73d81e560 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java @@ -158,4 +158,46 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT + "}\r\n", false); } + + @Test + public void testTryDoWhile() { + decompileMethod("assembled", "testTryDoWhile", "trace(\"first\");\r\n" + + "var _loc5_:* = rnd();\r\n" + + "try\r\n" + + "{\r\n" + + "do\r\n" + + "{\r\n" + + "trace(\"second\");\r\n" + + "}\r\n" + + "while(_loc5_ <= 100);\r\n" + + "\r\n" + + "}\r\n" + + "catch(e:Error)\r\n" + + "{\r\n" + + "trace(\"in catch\");\r\n" + + "}\r\n" + + "trace(\"after\");\r\n", + false); + } + + @Test + public void testTryDoWhile2() { + decompileMethod("assembled", "testTryDoWhile2", "trace(\"hello\");\r\n" + + "var _loc5_:* = Math.random();\r\n" + + "do\r\n" + + "{\r\n" + + "try\r\n" + + "{\r\n" + + "continue;\r\n" + + "}\r\n" + + "catch(e:Error)\r\n" + + "{\r\n" + + "trace(\"in catch\");\r\n" + + "continue;\r\n" + + "}\r\n" + + "}\r\n" + + "while(_loc5_ <= 100);\r\n" + + "trace(\"after\");\r\n", + false); + } } diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc index b63178b10..58cd749ca 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc and b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc differ diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm index 9f530cdd3..2132415f1 100644 --- a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm @@ -17,5 +17,7 @@ program #include "tests/TestSwitchDefault.script.asasm" #include "tests/TestSwitch.script.asasm" #include "tests/TestDeclareReg.script.asasm" + #include "tests/TestTryDoWhile.script.asasm" + #include "tests/TestTryDoWhile2.script.asasm" ; place to add next end ; program diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile.class.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile.class.asasm new file mode 100644 index 000000000..3794cd5e3 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile.class.asasm @@ -0,0 +1,93 @@ +class + refid "tests:TestTryDoWhile" + instance QName(PackageNamespace("tests"), "TestTryDoWhile") + extends QName(PackageNamespace(""), "Object") + flag SEALED + flag PROTECTEDNS + protectedns ProtectedNamespace("tests:TestTryDoWhile") + iinit + refid "tests:TestTryDoWhile/instance/init" + body + maxstack 1 + localcount 1 + initscopedepth 4 + maxscopedepth 5 + code + getlocal0 + pushscope + + getlocal0 + constructsuper 0 + + returnvoid + end ; code + end ; body + end ; method + trait method QName(PackageNamespace(""), "run") + method + refid "tests:TestTryDoWhile/instance/run" + returns QName(PackageNamespace(""), "void") + body + maxstack 2 + localcount 4 + initscopedepth 4 + maxscopedepth 5 + code + getlocal0 + pushscope + findproperty QName(PackageNamespace(""),"trace") + pushstring "first" + callpropvoid QName(PackageNamespace(""),"trace"), 1 + findproperty QName(PackageNamespace(""),"rnd") + callproperty QName(PackageNamespace(""),"rnd"), 0 + setlocal 5 + ofs0010: + jump ofs0029 + ofs0014: + label + findproperty QName(PackageNamespace(""),"trace") + pushstring "second" + callpropvoid QName(PackageNamespace(""),"trace"), 1 + getlocal 5 + pushbyte 100 + ifngt ofs0029 + jump ofs002d + ofs0029: + jump ofs0014 + ofs002d: + jump ofs0035 + ofs0031: + getlocal0 + pushscope + setlocal 6 + findproperty QName(PackageNamespace(""),"trace") + pushstring "in catch" + callpropvoid QName(PackageNamespace(""),"trace"), 1 + ofs0035: + findproperty QName(PackageNamespace(""),"trace") + pushstring "after" + callpropvoid QName(PackageNamespace(""),"trace"), 1 + returnvoid + end ; code + try from ofs0010 to ofs002d target ofs0031 type QName(PackageNamespace(""),"Error") name QName(PackageNamespace(""),"e") end + + end ; body + end ; method + end ; trait + end ; instance + cinit + refid "tests:TestTryDoWhile/class/init" + body + maxstack 1 + localcount 1 + initscopedepth 3 + maxscopedepth 4 + code + getlocal0 + pushscope + + returnvoid + end ; code + end ; body + end ; method +end ; class diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile.script.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile.script.asasm new file mode 100644 index 000000000..1ca4a5d24 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile.script.asasm @@ -0,0 +1,29 @@ +script + sinit + refid "tests:TestTryDoWhile/init" + body + maxstack 2 + localcount 1 + initscopedepth 1 + maxscopedepth 3 + code + getlocal0 + pushscope + + findpropstrict Multiname("TestTryDoWhile", [PackageNamespace("tests")]) + getlex QName(PackageNamespace(""), "Object") + pushscope + + getlex Multiname("Object", [PrivateNamespace(null, "tests:TestTryDoWhile"), PackageNamespace(""), PackageNamespace("tests"), PackageInternalNs("tests"), Namespace("http://adobe.com/AS3/2006/builtin")]) + newclass "tests:TestTryDoWhile" + popscope + initproperty QName(PackageNamespace("tests"), "TestTryDoWhile") + + returnvoid + end ; code + end ; body + end ; method + trait class QName(PackageNamespace("tests"), "TestTryDoWhile") + #include "TestTryDoWhile.class.asasm" + end ; trait +end ; script diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile2.class.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile2.class.asasm new file mode 100644 index 000000000..4a4706f73 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile2.class.asasm @@ -0,0 +1,118 @@ +class + refid "tests:TestTryDoWhile2" + instance QName(PackageNamespace("tests"), "TestTryDoWhile2") + extends QName(PackageNamespace(""), "Object") + flag SEALED + flag PROTECTEDNS + protectedns ProtectedNamespace("tests:TestTryDoWhile2") + iinit + refid "tests:TestTryDoWhile2/instance/init" + body + maxstack 1 + localcount 1 + initscopedepth 4 + maxscopedepth 5 + code + getlocal0 + pushscope + + getlocal0 + constructsuper 0 + + returnvoid + end ; code + end ; body + end ; method + trait method QName(PackageNamespace(""), "run") + method + refid "tests:TestTryDoWhile2/instance/run" + returns QName(PackageNamespace(""), "void") + body + maxstack 2 + localcount 4 + initscopedepth 4 + maxscopedepth 5 + maxstack 3 + localcount 3 + initscopedepth 5 + maxscopedepth 10 + trait slot QName(PackageInternalNs("tests"),"_loc5_") + slotid 1 + type null + end ; trait + + code + getlocal0 + pushscope + newactivation + dup + setlocal1 + pushscope + findpropstrict QName(PackageNamespace(""),"trace") + pushstring "hello" + callproperty QName(PackageNamespace(""),"trace"), 1 + pop + getscopeobject 1 + findpropstrict QName(PackageNamespace(""),"Math") + getproperty QName(PackageNamespace(""),"Math") + callproperty QName(PackageNamespace(""),"random"), 0 + coerce_a + setslot 1 + xxx: + + findpropstrict QName(PackageNamespace(""),"trace") + pushstring "second" + callproperty QName(PackageNamespace(""),"trace"), 1 + pop + ofs0036: + jump ofs0056 + ofs003c: + getlocal0 + pushscope + getlocal1 + pushscope + newcatch 0 + dup + setlocal2 + dup + pushscope + swap + setslot 1 + findpropstrict QName(PackageNamespace(""),"trace") + pushstring "in catch" + callproperty QName(PackageNamespace(""),"trace"), 1 + pop + popscope + kill 2 + ofs0056: + getscopeobject 1 + getslot 1 + pushbyte 100 + ifle xxx + findpropstrict QName(PackageNamespace(""),"trace") + pushstring "after" + callproperty QName(PackageNamespace(""),"trace"), 1 + pop + returnvoid + end ; code + try from xxx to ofs0036 target ofs003c type QName(PackageNamespace(""),"Error") name QName(PackageNamespace(""),"e") end + end ; body + end ; method + end ; trait + end ; instance + cinit + refid "tests:TestTryDoWhile2/class/init" + body + maxstack 1 + localcount 1 + initscopedepth 3 + maxscopedepth 4 + code + getlocal0 + pushscope + + returnvoid + end ; code + end ; body + end ; method +end ; class diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile2.script.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile2.script.asasm new file mode 100644 index 000000000..f42ab4b36 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryDoWhile2.script.asasm @@ -0,0 +1,29 @@ +script + sinit + refid "tests:TestTryDoWhile2/init" + body + maxstack 2 + localcount 1 + initscopedepth 1 + maxscopedepth 3 + code + getlocal0 + pushscope + + findpropstrict Multiname("TestTryDoWhile2", [PackageNamespace("tests")]) + getlex QName(PackageNamespace(""), "Object") + pushscope + + getlex Multiname("Object", [PrivateNamespace(null, "tests:TestTryDoWhile2"), PackageNamespace(""), PackageNamespace("tests"), PackageInternalNs("tests"), Namespace("http://adobe.com/AS3/2006/builtin")]) + newclass "tests:TestTryDoWhile2" + popscope + initproperty QName(PackageNamespace("tests"), "TestTryDoWhile2") + + returnvoid + end ; code + end ; body + end ; method + trait class QName(PackageNamespace("tests"), "TestTryDoWhile2") + #include "TestTryDoWhile2.class.asasm" + end ; trait +end ; script diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf b/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf index eb826ef39..6daed0f0a 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf and b/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf index c78efad36..5c96c6ba1 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf index 8529df168..165b4821c 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/obj/as3_newConfig.old b/libsrc/ffdec_lib/testdata/as3_new/obj/as3_newConfig.old index 45fb0f23a..6970c2c97 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/obj/as3_newConfig.old +++ b/libsrc/ffdec_lib/testdata/as3_new/obj/as3_newConfig.old @@ -16,7 +16,7 @@ CONFIG::timeStamp - '05.02.2021' + '06.02.2021' CONFIG::air diff --git a/libsrc/ffdec_lib/testdata/as3_new/obj/as3_newConfig.xml b/libsrc/ffdec_lib/testdata/as3_new/obj/as3_newConfig.xml index 45fb0f23a..6970c2c97 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/obj/as3_newConfig.xml +++ b/libsrc/ffdec_lib/testdata/as3_new/obj/as3_newConfig.xml @@ -16,7 +16,7 @@ CONFIG::timeStamp - '05.02.2021' + '06.02.2021' CONFIG::air