From 236126dc84f701834757d5800ddb7a0ebba3f453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 22 Sep 2024 12:20:19 +0200 Subject: [PATCH] Fixed: #2291 AS1/2 Incorrect var keyword placement causing registers to compile wrong --- CHANGELOG.md | 2 + .../decompiler/flash/abc/avm2/AVM2Code.java | 3 +- .../flash/abc/avm2/graph/AVM2Graph.java | 6 +- .../jpexs/decompiler/flash/action/Action.java | 7 ++- .../decompiler/flash/action/ActionGraph.java | 55 ++++++++++++++----- .../as2/ActionScript2ClassDetector.java | 6 +- .../as2/UninitializedClassFieldsDetector.java | 6 +- .../graph/AbstractGraphTargetVisitor.java | 3 +- .../decompiler/graph/GraphTargetItem.java | 23 +++++--- .../graph/GraphTargetVisitorInterface.java | 3 +- 10 files changed, 80 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60280d471..cdd847682 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file. - [#2295], [#2311] AS1/2 p-code freezing on highlighting ConstantPool - [#2304] GFX files truncated - [#2297] AS1/2/3 direct editation - if..else clause broken when using continue/break +- [#2291] AS1/2 Incorrect var keyword placement causing registers to compile wrong ## [21.0.5] - 2024-09-05 ### Fixed @@ -3561,6 +3562,7 @@ Major version of SWF to XML export changed to 2. [#2311]: https://www.free-decompiler.com/flash/issues/2311 [#2304]: https://www.free-decompiler.com/flash/issues/2304 [#2297]: https://www.free-decompiler.com/flash/issues/2297 +[#2291]: https://www.free-decompiler.com/flash/issues/2291 [#2293]: https://www.free-decompiler.com/flash/issues/2293 [#2294]: https://www.free-decompiler.com/flash/issues/2294 [#2299]: https://www.free-decompiler.com/flash/issues/2299 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index ccde64c87..5dce393fe 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -2775,7 +2775,7 @@ public class AVM2Code implements Cloneable { //Check whether the command references internal traits of other package ti.visitRecursively(new AbstractGraphTargetVisitor() { @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { if (item instanceof GetSlotAVM2Item) { GetSlotAVM2Item gs = (GetSlotAVM2Item) item; if ((gs.slotObject instanceof GlobalAVM2Item) && (initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER)) { @@ -2798,6 +2798,7 @@ public class AVM2Code implements Cloneable { } } } + return true; } }); 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 900b91117..2c6e88841 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 @@ -2277,9 +2277,9 @@ public class AVM2Graph extends Graph { private boolean handled = false; @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { if (handled) { - return; + return false; } if ((item instanceof NextNameAVM2Item) || (item instanceof NextValueAVM2Item)) { handled = true; @@ -2293,7 +2293,9 @@ public class AVM2Graph extends Graph { nn.localReg = hn.index; kindRef.setVal(2); } + return false; } + return true; } }); 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 f60ddc8f3..7fd40f913 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 @@ -50,6 +50,7 @@ import com.jpexs.decompiler.flash.action.swf4.RegisterNumber; import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool; import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction; import com.jpexs.decompiler.flash.action.swf5.ActionEquals2; +import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister; import com.jpexs.decompiler.flash.action.swf5.ActionWith; import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; import com.jpexs.decompiler.flash.action.swf7.ActionTry; @@ -58,9 +59,11 @@ import com.jpexs.decompiler.flash.ecma.EcmaScript; import com.jpexs.decompiler.flash.ecma.Null; import com.jpexs.decompiler.flash.ecma.Undefined; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.CodeFormatting; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.flash.helpers.NulWriter; import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; +import com.jpexs.decompiler.flash.helpers.StringBuilderTextWriter; import com.jpexs.decompiler.flash.tags.DoInitActionTag; import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.graph.Graph; @@ -1243,7 +1246,7 @@ public abstract class Action implements GraphSourceItem { loopip: while (ip <= end) { - long addr = ip2adr(actions, ip); + long addr = ip2adr(actions, ip); if (ip > end) { break; } @@ -1254,7 +1257,7 @@ public abstract class Action implements GraphSourceItem { if (Configuration.simplifyExpressions.get()) { stack.simplify(); } - Action action = actions.get(ip); + Action action = actions.get(ip); if (action.isIgnored()) { ip++; continue; 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 48a7b89df..84f9dcb53 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 @@ -32,6 +32,7 @@ import com.jpexs.decompiler.flash.action.model.SetTypeActionItem; import com.jpexs.decompiler.flash.action.model.StoreRegisterActionItem; import com.jpexs.decompiler.flash.action.model.TemporaryRegister; import com.jpexs.decompiler.flash.action.model.TemporaryRegisterMark; +import com.jpexs.decompiler.flash.action.model.TraceActionItem; import com.jpexs.decompiler.flash.action.model.clauses.ForInActionItem; import com.jpexs.decompiler.flash.action.model.clauses.TellTargetActionItem; import com.jpexs.decompiler.flash.action.model.operations.EqActionItem; @@ -58,6 +59,7 @@ import com.jpexs.decompiler.graph.GraphSource; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphSourceItemContainer; import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.GraphTargetVisitorInterface; import com.jpexs.decompiler.graph.Loop; import com.jpexs.decompiler.graph.SecondPassData; import com.jpexs.decompiler.graph.StopPartKind; @@ -74,10 +76,12 @@ import com.jpexs.decompiler.graph.model.SwitchItem; import com.jpexs.decompiler.graph.model.TrueItem; import com.jpexs.decompiler.graph.model.WhileItem; import com.jpexs.helpers.Helper; +import com.jpexs.helpers.LinkedIdentityHashSet; import com.jpexs.helpers.Reference; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -215,13 +219,13 @@ public class ActionGraph extends Graph { * @return List of graph target items * @throws InterruptedException On interrupt */ - public static List translateViaGraph(Map> uninitializedClassTraits, SecondPassData secondPassData, boolean insideDoInitAction, boolean insideFunction, HashMap registerNames, HashMap variables, HashMap functions, List code, int version, int staticOperation, String path, String charset) throws InterruptedException { + public static List translateViaGraph(Map> uninitializedClassTraits, SecondPassData secondPassData, boolean insideDoInitAction, boolean insideFunction, HashMap registerNames, HashMap variables, HashMap functions, List code, int version, int staticOperation, String path, String charset) throws InterruptedException { ActionGraph g = new ActionGraph(uninitializedClassTraits, path, insideDoInitAction, insideFunction, code, registerNames, variables, functions, version, charset); ActionLocalData localData = new ActionLocalData(secondPassData, insideDoInitAction, registerNames, uninitializedClassTraits); g.init(localData); return g.translate(localData, staticOperation, path); } - + /** * Final process stack. Override this method to provide custom behavior. * @@ -621,7 +625,7 @@ public class ActionGraph extends Graph { ActionScript2ClassDetector detector = new ActionScript2ClassDetector(); detector.checkClass(uninitializedClassTraits, ret, ((ActionGraphSource) code).getVariables(), path); } - makeDefineRegistersUp(ret); + makeDefineRegistersUp(ret, new HashSet<>()); return ret; } @@ -640,52 +644,73 @@ public class ActionGraph extends Graph { trace("x"); } + It also makes sure that var keyword is on the first occurrence of that register. */ /** * Makes define registers up. * * @param list List of GraphTargetItems + * @param definedRegisters Defined registers */ - private void makeDefineRegistersUp(List list) { + private void makeDefineRegistersUp(List list, Set definedRegisters) { for (int i = 0; i < list.size(); i++) { - final int fi = i; GraphTargetItem ti = list.get(i); + Reference ri = new Reference<>(i); if (ti instanceof TemporaryRegister) { continue; } - Set visitedItems = new HashSet<>(); - ti.visitNoBlock(new AbstractGraphTargetVisitor() { + Set visitedItems = new LinkedIdentityHashSet<>(); + GraphTargetVisitorInterface visitor = new AbstractGraphTargetVisitor() { @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { if (item != null && !visitedItems.contains(item)) { visitedItems.add(item); if (item instanceof TemporaryRegister) { - return; + return true; } //can has definition in for in... if ((ti instanceof ForInActionItem) && (item == ((ForInActionItem) ti).variableName)) { - return; + return true; } if (item instanceof StoreRegisterActionItem) { StoreRegisterActionItem sr = (StoreRegisterActionItem) item; - if (sr.define) { - list.add(fi, new StoreRegisterActionItem(null, null, sr.register, new DirectValueActionItem(Null.INSTANCE), true)); - sr.define = false; + sr.define = !definedRegisters.contains(sr.register.number); + definedRegisters.add(sr.register.number); + if (sr.define && sr != ti) { + list.add(ri.getVal(), new StoreRegisterActionItem(null, null, sr.register, new DirectValueActionItem(Null.INSTANCE), true)); + sr.define = false; + ri.setVal(ri.getVal() + 1); } } + + if (item instanceof FunctionActionItem) { + return false; + } item.visitNoBlock(this); } + return true; } - }); + }; + + if (ti instanceof StoreRegisterActionItem) { + StoreRegisterActionItem sr = (StoreRegisterActionItem) ti; + sr.define = !definedRegisters.contains(sr.register.number); + definedRegisters.add(sr.register.number); + } + + ti.visitNoBlock(visitor); + //visitor.visit(ti); + //ti.visitRecursively(visitor); + i = ri.getVal(); if (ti instanceof Block) { Block b = (Block) ti; for (List items : b.getSubs()) { - makeDefineRegistersUp(items); + makeDefineRegistersUp(items, definedRegisters); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/ActionScript2ClassDetector.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/ActionScript2ClassDetector.java index 09f5b7e80..12290c283 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/ActionScript2ClassDetector.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/ActionScript2ClassDetector.java @@ -678,7 +678,7 @@ public class ActionScript2ClassDetector { AbstractGraphTargetVisitor visitor = new AbstractGraphTargetVisitor() { @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { if (item instanceof ReturnActionItem) { ReturnActionItem ret = (ReturnActionItem) item; if (ret.value instanceof DirectValueActionItem) { @@ -688,6 +688,7 @@ public class ActionScript2ClassDetector { } } } + return true; } }; for (GraphTargetItem ti : func.actions) { @@ -790,7 +791,7 @@ public class ActionScript2ClassDetector { AbstractGraphTargetVisitor visitor = new AbstractGraphTargetVisitor() { @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { if (item instanceof ReturnActionItem) { ReturnActionItem ret = (ReturnActionItem) item; if (ret.value instanceof DirectValueActionItem) { @@ -800,6 +801,7 @@ public class ActionScript2ClassDetector { } } } + return true; } }; for (GraphTargetItem ti : ((FunctionActionItem) constructor).actions) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/UninitializedClassFieldsDetector.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/UninitializedClassFieldsDetector.java index d7839812c..18c9267a5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/UninitializedClassFieldsDetector.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/UninitializedClassFieldsDetector.java @@ -301,7 +301,7 @@ public class UninitializedClassFieldsDetector { if (value instanceof GraphTargetItem) { AbstractGraphTargetVisitor visitor = new AbstractGraphTargetVisitor() { @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { List path = getFullPath(item); if (path != null) { List parent = new ArrayList<>(path); @@ -319,6 +319,7 @@ public class UninitializedClassFieldsDetector { } } } + return true; } }; visitor.visit(value); @@ -339,7 +340,7 @@ public class UninitializedClassFieldsDetector { for (GraphTargetItem item : tree) { AbstractGraphTargetVisitor visitor = new AbstractGraphTargetVisitor() { @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { if ((item instanceof SetMemberActionItem) || (item instanceof CallMethodActionItem) || (item instanceof NewMethodActionItem) @@ -364,6 +365,7 @@ public class UninitializedClassFieldsDetector { } } } + return true; } }; visitor.visit(item); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/AbstractGraphTargetVisitor.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/AbstractGraphTargetVisitor.java index 96f0cdfad..a4f55dce5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/AbstractGraphTargetVisitor.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/AbstractGraphTargetVisitor.java @@ -35,9 +35,10 @@ public abstract class AbstractGraphTargetVisitor implements GraphTargetVisitorIn * Visits a graph target item. * * @param item Graph target item + * @return True if continue */ @Override - public abstract void visit(GraphTargetItem item); + public abstract boolean visit(GraphTargetItem item); /** * Visits all graph target items. diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java index 968b632db..7f50e1f5f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java @@ -41,6 +41,7 @@ import com.jpexs.decompiler.graph.model.FalseItem; import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.decompiler.graph.model.NotItem; import com.jpexs.decompiler.graph.model.TrueItem; +import com.jpexs.helpers.LinkedIdentityHashSet; import com.jpexs.helpers.Reference; import java.io.Serializable; import java.util.ArrayList; @@ -624,10 +625,11 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { Reference ref = new Reference<>(false); visitRecursively(new AbstractGraphTargetVisitor() { @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { if (item.hasSideEffect()) { ref.setVal(Boolean.TRUE); } + return true; } }); return ref.getVal(); @@ -923,10 +925,11 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { List ret = new ArrayList<>(); visit(new AbstractGraphTargetVisitor() { @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { if (item != null) { ret.add(item); } + return true; } }); return ret; @@ -941,8 +944,9 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { Set ret = new HashSet<>(); visitRecursively(new AbstractGraphTargetVisitor() { @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { ret.add(item); + return true; } }); return ret; @@ -954,15 +958,17 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { * @param visitor Visitor */ public final void visitRecursively(GraphTargetVisitorInterface visitor) { - Set visitedItems = new HashSet<>(); + Set visitedItems = new LinkedIdentityHashSet<>(); visit(new AbstractGraphTargetVisitor() { @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { if (item != null && !visitedItems.contains(item)) { visitedItems.add(item); - visitor.visit(item); - item.visit(this); + if (visitor.visit(item)) { + item.visit(this); + } } + return true; } }); } @@ -978,7 +984,7 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { parentStack.add(this); visitNoBlock(new AbstractGraphTargetVisitor() { @Override - public void visit(GraphTargetItem item) { + public boolean visit(GraphTargetItem item) { if (item != null && !visitedItems.contains(item)) { visitedItems.add(item); visitor.visit(item, parentStack); @@ -986,6 +992,7 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { item.visitNoBlock(this); parentStack.pop(); } + return true; } }); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetVisitorInterface.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetVisitorInterface.java index 559f999fb..974415ed1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetVisitorInterface.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetVisitorInterface.java @@ -29,8 +29,9 @@ public interface GraphTargetVisitorInterface { * Visits a graph target item. * * @param item Graph target item + * @return True if continue */ - public void visit(GraphTargetItem item); + public boolean visit(GraphTargetItem item); /** * Visits all graph target items.