diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ebdf9b05..595a3da42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ All notable changes to this project will be documented in this file. - AS1/2 - switch detection - AS1/2 - nested tellTarget - AS1/2 - switch with nontrivial expressions like and/or,ternar (second pass) +- AS1/2 - ifFrameLoaded with nontrivial items inside ## [14.6.0] - 2021-11-22 ### Added 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 cfb3a9e91..b8d1e7785 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 @@ -82,6 +82,7 @@ import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphException; import com.jpexs.decompiler.graph.GraphPart; +import com.jpexs.decompiler.graph.GraphPartChangeException; import com.jpexs.decompiler.graph.GraphSource; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; @@ -239,7 +240,12 @@ public class AVM2Graph extends Graph { AVM2LocalData localData2 = new AVM2LocalData(localData); localData2.scopeStack = new ScopeStack(); - List targetOutput = translatePart(localData2, finallyTryTargetPart, finallyTryTargetStack, 0 /*??*/, "try_target"); + List targetOutput; + try { + targetOutput = translatePart(localData2, finallyTryTargetPart, finallyTryTargetStack, 0 /*??*/, "try_target"); + } catch (GraphPartChangeException ex1) { //should not happen + targetOutput = new ArrayList<>(); + } int switchedReg = -1; int finallyKind = FINALLY_KIND_UNKNOWN; @@ -1043,8 +1049,12 @@ public class AVM2Graph extends Graph { AVM2LocalData localData2 = new AVM2LocalData(localData); localData2.scopeStack = new ScopeStack(); - //We are assuming Finally target has only 1 part - finallyTargetItems = translatePart(localData2, finallyTryTargetPart, st2, staticOperation, path);//printGraph(foundGotos, partCodes, partCodePos, visited, localData2, st2, allParts, null, finallyTryTargetPart, finallyTargetStopPart, loops, throwStates, 0, path); + try { + //We are assuming Finally target has only 1 part + finallyTargetItems = translatePart(localData2, finallyTryTargetPart, st2, staticOperation, path);//printGraph(foundGotos, partCodes, partCodePos, visited, localData2, st2, allParts, null, finallyTryTargetPart, finallyTargetStopPart, loops, throwStates, 0, path); + } catch (GraphPartChangeException ex) { //should not happen + finallyTargetItems = new ArrayList<>(); + } //boolean targetHasThrow = false; if (!finallyTargetItems.isEmpty() && (finallyTargetItems.get(finallyTargetItems.size() - 1) instanceof ThrowAVM2Item)) { @@ -1132,7 +1142,11 @@ public class AVM2Graph extends Graph { finallyCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, finallyPart, finallyStopPart, finallyStopPartKind, loops, throwStates, staticOperation, path); } if (switchPart != null) { - finallyCommands.addAll(translatePart(localData, switchPart, stack, staticOperation, path)); + try { + finallyCommands.addAll(translatePart(localData, switchPart, stack, staticOperation, path)); + } catch (GraphPartChangeException ex) { + //should not happen + } stack.pop(); //value switched by lookupswitch } } @@ -1421,17 +1435,21 @@ public class AVM2Graph extends Graph { caseBodyParts.add(part.nextParts.get(0)); GraphTargetItem top = null; int cnt = 1; - while (part.nextParts.size() > 1 - && part.nextParts.get(1).getHeight() > 1 - && ((AVM2Instruction) code.get(part.nextParts.get(1).end >= code.size() ? code.size() - 1 : part.nextParts.get(1).end)).definition instanceof IfStrictEqIns - && ((top = translatePartGetStack(localData, part.nextParts.get(1), stack, staticOperation)) instanceof StrictEqAVM2Item)) { - cnt++; - part = part.nextParts.get(1); - caseBodyParts.add(part.nextParts.get(0)); + try { + while (part.nextParts.size() > 1 + && part.nextParts.get(1).getHeight() > 1 + && ((AVM2Instruction) code.get(part.nextParts.get(1).end >= code.size() ? code.size() - 1 : part.nextParts.get(1).end)).definition instanceof IfStrictEqIns + && ((top = translatePartGetStack(localData, part.nextParts.get(1), stack, staticOperation)) instanceof StrictEqAVM2Item)) { + cnt++; + part = part.nextParts.get(1); + caseBodyParts.add(part.nextParts.get(0)); - set = (StrictEqAVM2Item) top; - caseValuesMapLeft.add(set.leftSide); - caseValuesMapRight.add(set.rightSide); + set = (StrictEqAVM2Item) top; + caseValuesMapLeft.add(set.leftSide); + caseValuesMapRight.add(set.rightSide); + } + } catch (GraphPartChangeException gpc) { + //ignore } List caseValuesMap = caseValuesMapLeft; @@ -2331,5 +2349,4 @@ public class AVM2Graph extends Graph { Graph.makeAllCommands(commands, stack); } - } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java index 2eda18870..48eb8c6e1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java @@ -63,6 +63,7 @@ import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; import com.jpexs.decompiler.flash.tags.DoInitActionTag; import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.graph.Graph; +import com.jpexs.decompiler.graph.GraphPartChangeException; import com.jpexs.decompiler.graph.GraphSource; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphSourceItemContainer; @@ -973,7 +974,7 @@ public abstract class Action implements GraphSourceItem { this.ignored = ignored; } - public static List actionsPartToTree(SecondPassData secondPassData, boolean insideDoInitAction, Reference fi, HashMap registerNames, HashMap variables, HashMap functions, TranslateStack stack, List actions, int start, int end, int version, int staticOperation, String path) throws InterruptedException { + public static List actionsPartToTree(SecondPassData secondPassData, boolean insideDoInitAction, Reference fi, HashMap registerNames, HashMap variables, HashMap functions, TranslateStack stack, List actions, int start, int end, int version, int staticOperation, String path) throws InterruptedException, GraphPartChangeException { if (start < actions.size() && (end > 0) && (start > 0)) { logger.log(Level.FINE, "Entering {0}-{1}{2}", new Object[]{start, end, actions.size() > 0 ? (" (" + actions.get(start).toString() + " - " + actions.get(end == actions.size() ? end - 1 : end) + ")") : ""}); } @@ -1106,6 +1107,9 @@ public abstract class Action implements GraphSourceItem { ip++; } + if (ip > end + 1) { + throw new GraphPartChangeException(output, ip); + } logger.log(Level.FINE, "Leaving {0}-{1}", new Object[]{start, end}); return output; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java index 6d8db0870..162710abb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java @@ -50,6 +50,7 @@ import com.jpexs.decompiler.graph.AbstractGraphTargetVisitor; import com.jpexs.decompiler.graph.Block; import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphPart; +import com.jpexs.decompiler.graph.GraphPartChangeException; import com.jpexs.decompiler.graph.GraphSource; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphSourceItemContainer; @@ -455,6 +456,7 @@ public class ActionGraph extends Graph { int cnt = 1; if (!secondSwitchFound) { + try { while (part.nextParts.size() > 1 && part.nextParts.get(1).getHeight() > 1 && code.get(part.nextParts.get(1).end >= code.size() ? code.size() - 1 : part.nextParts.get(1).end) instanceof ActionIf @@ -465,6 +467,9 @@ public class ActionGraph extends Graph { set = (StrictEqActionItem) top; caseValuesMap.add(set.rightSide); + } + } catch (GraphPartChangeException gce) { + //ignore } } if (!secondSwitchFound && cnt == 1) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java index e25c47d13..b7310f7db 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.action; import com.jpexs.decompiler.flash.BaseLocalData; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.graph.GraphPart; +import com.jpexs.decompiler.graph.GraphPartChangeException; import com.jpexs.decompiler.graph.GraphSource; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; @@ -99,7 +100,7 @@ public class ActionGraphSource extends GraphSource { } @Override - public List translatePart(GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException { + public List translatePart(GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException, GraphPartChangeException { Reference fi = new Reference<>(localData.lineStartInstruction); List r = Action.actionsPartToTree(localData.secondPassData, this.insideDoInitAction, fi, registerNames, variables, functions, stack, actions, start, end, version, staticOperation, path); 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 d67773bbf..08a9700c1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -1290,13 +1290,13 @@ public class Graph { } //@SuppressWarnings("unchecked") - protected GraphTargetItem translatePartGetStack(BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation) throws InterruptedException { + protected GraphTargetItem translatePartGetStack(BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation) throws InterruptedException, GraphPartChangeException { stack = (TranslateStack) stack.clone(); translatePart(localData, part, stack, staticOperation, null); return stack.pop(); } - protected List translatePart(BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation, String path) throws InterruptedException { + protected List translatePart(BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation, String path) throws InterruptedException, GraphPartChangeException { List sub = part.getSubParts(); List ret = new ArrayList<>(); int end; @@ -2075,7 +2075,24 @@ public class Graph { if (checkPartOutput(currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, stopPartKind, loops, throwStates, currentLoop, staticOperation, path, recursionLevel)) { parseNext = false; } else { - output.addAll(code.translatePart(part, localData, stack, part.start, part.end, staticOperation, path)); + boolean exHappened = false; + int ipStart = part.start; + do { + exHappened = false; + try { + output.addAll(code.translatePart(part, localData, stack, ipStart, part.end, staticOperation, path)); + } catch (GraphPartChangeException ex) { //Special case for ifFrameLoaded when it's over multiple parts + output.addAll(ex.getOutput()); + for (GraphPart p : allParts) { + if (p.containsIP(ex.getIp())) { + exHappened = true; + ipStart = ex.getIp(); + part = p; + break; + } + } + } + } while (exHappened); if ((part.end >= code.size() - 1) && getNextParts(localData, part).isEmpty()) { output.add(new ScriptEndItem()); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPartChangeException.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPartChangeException.java new file mode 100644 index 000000000..0db3f1f27 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPartChangeException.java @@ -0,0 +1,27 @@ +package com.jpexs.decompiler.graph; + +import java.util.List; + +/** + * + * @author JPEXS + */ +public class GraphPartChangeException extends Exception { + private final int ip; + private final List output; + + public GraphPartChangeException(List output, int ip) { + this.output = output; + this.ip = ip; + } + + public int getIp() { + return ip; + } + + public List getOutput() { + return output; + } + + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java index f25fbbb73..edf9ce491 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java @@ -36,7 +36,7 @@ public abstract class GraphSource implements Serializable { public abstract boolean isEmpty(); - public abstract List translatePart(GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException; + public abstract List translatePart(GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException, GraphPartChangeException; public abstract Set getImportantAddresses();