From 0ef3a7dea1550ea743d20b5d29b21d8648dee9f9 Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 19:18:01 +0200 Subject: [PATCH] decompilation timeouts --- .../jpexs/decompiler/flash/Configuration.java | 10 ++- trunk/src/com/jpexs/decompiler/flash/SWF.java | 4 +- .../flash/abc/types/MethodBody.java | 63 ++++++++++++------- .../jpexs/decompiler/flash/action/Action.java | 30 ++++++--- .../jpexs/decompiler/flash/gui/MainFrame.java | 6 ++ .../flash/gui/action/ActionPanel.java | 6 +- .../decompiler/flash/helpers/Helper.java | 42 +++++++++++++ 7 files changed, 129 insertions(+), 32 deletions(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/Configuration.java b/trunk/src/com/jpexs/decompiler/flash/Configuration.java index 767ea9e8a..443a128b5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/Configuration.java +++ b/trunk/src/com/jpexs/decompiler/flash/Configuration.java @@ -53,7 +53,15 @@ public class Configuration { * Limit of code subs (for obfuscated code) */ public static final int SUBLIMITER = 500; - //using parameter names in decompiling may cause problems because oficial programs like Flash CS 5.5 inserts wrong parameter names indices + /** + * Decompilation timeout in seconds + */ + public static final int DECOMPILATION_TIMEOUT = 30 * 60; + /** + * Decompilation timeout for a single method in AS3 or single action in AS1/2 in seconds + */ + public static final int DECOMPILATION_TIMEOUT_SINGLE_METHOD = 5; + //using parameter names in decompiling may cause problems because official programs like Flash CS 5.5 inserts wrong parameter names indices public static final boolean PARAM_NAMES_ENABLE = false; private static HashMap config = new HashMap<>(); /** diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index 94ceb8d73..f959a2c8d 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -622,9 +622,9 @@ public class SWF { try { executor.shutdown(); - executor.awaitTermination(30, TimeUnit.MINUTES); + executor.awaitTermination(Configuration.DECOMPILATION_TIMEOUT, TimeUnit.SECONDS); } catch (InterruptedException ex) { - Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, "30 minutes ActionScript export limit reached", ex); + Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT) + " ActionScript export limit reached", ex); } return ret; } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java index 45bcdd748..698e165b6 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.CodeStats; import com.jpexs.decompiler.flash.abc.avm2.ConstantPool; import com.jpexs.decompiler.flash.abc.types.traits.Traits; +import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.helpers.Helper; import com.jpexs.decompiler.flash.helpers.Highlighting; import com.jpexs.decompiler.graph.Graph; @@ -31,6 +32,10 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Stack; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; @@ -103,7 +108,7 @@ public class MethodBody implements Cloneable, Serializable { return ret; } - public String toString(String path, boolean pcode, boolean isStatic, int scriptIndex, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], Stack scopeStack, boolean isStaticInitializer, boolean hilight, List fullyQualifiedNames, Traits initTraits) { + public String toString(final String path, boolean pcode, final boolean isStatic, final int scriptIndex, final int classIndex, final ABC abc, final ConstantPool constants, final MethodInfo method_info[], final Stack scopeStack, final boolean isStaticInitializer, final boolean hilight, final List fullyQualifiedNames, final Traits initTraits) { if (debugMode) { System.err.println("Decompiling " + path); } @@ -118,30 +123,46 @@ public class MethodBody implements Cloneable, Serializable { if (pcode) { s += code.toASMSource(constants, this, false); } else { - AVM2Code deobfuscated = null; - MethodBody b = (MethodBody) Helper.deepCopy(this); - deobfuscated = b.code; - deobfuscated.markMappedOffsets(); - if ((Boolean) Configuration.getConfig("autoDeobfuscate", true)) { - try { - deobfuscated.removeTraps(constants, b, abc, scriptIndex, classIndex, isStatic, path); - } catch (Exception | StackOverflowError ex) { - Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Error during remove traps in " + path, ex); - } - } - //deobfuscated.restoreControlFlow(constants, b); - //try { - s += deobfuscated.toSource(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, b, hilight, getLocalRegNames(abc), scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap(), deobfuscated.visitCode(b)); - s = s.trim(); - if (s.equals("")) { - s = " "; - } - if (hilight) { - s = Highlighting.hilighMethod(s, this.method_info); + try { + s += Helper.timedCall(new Callable() { + @Override + public String call() throws Exception { + return toSource(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, scopeStack, isStaticInitializer, hilight, fullyQualifiedNames, initTraits); + } + }, Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException ex) { + Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error", ex); + s += "/*\r\n * Decompilation error\r\n * Timeout (" + Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD) + ") was reached\r\n */"; } } return s; } + + public String toSource(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], Stack scopeStack, boolean isStaticInitializer, boolean hilight, List fullyQualifiedNames, Traits initTraits) { + AVM2Code deobfuscated = null; + MethodBody b = (MethodBody) Helper.deepCopy(this); + deobfuscated = b.code; + deobfuscated.markMappedOffsets(); + if ((Boolean) Configuration.getConfig("autoDeobfuscate", true)) { + try { + deobfuscated.removeTraps(constants, b, abc, scriptIndex, classIndex, isStatic, path); + } catch (Exception | StackOverflowError ex) { + Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Error during remove traps in " + path, ex); + } + } + //deobfuscated.restoreControlFlow(constants, b); + //try { + String s = deobfuscated.toSource(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, b, hilight, getLocalRegNames(abc), scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap(), deobfuscated.visitCode(b)); + s = s.trim(); + if (s.equals("")) { + s = " "; + } + if (hilight) { + s = Highlighting.hilighMethod(s, this.method_info); + } + + return s; + } @Override public Object clone() throws CloneNotSupportedException { diff --git a/trunk/src/com/jpexs/decompiler/flash/action/Action.java b/trunk/src/com/jpexs/decompiler/flash/action/Action.java index a823ec23b..97f1d4661 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/Action.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/Action.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.action; +import com.jpexs.decompiler.flash.Configuration; import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; @@ -49,6 +50,7 @@ import com.jpexs.decompiler.flash.ecma.Null; import com.jpexs.decompiler.flash.helpers.Helper; import com.jpexs.decompiler.flash.helpers.Highlighting; import com.jpexs.decompiler.flash.helpers.collections.MyEntry; +import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphSource; import com.jpexs.decompiler.graph.GraphSourceItem; @@ -62,6 +64,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; @@ -408,7 +413,7 @@ public class Action implements GraphSourceItem { * @param path * @return ASM source as String */ - public static String actionsToString(List listeners, long address, List list, List importantOffsets, List constantPool, int version, boolean hex, long swfPos, String path) { + private static String actionsToString(List listeners, long address, List list, List importantOffsets, List constantPool, int version, boolean hex, long swfPos, String path) { long offset; if (importantOffsets == null) { //setActionsAddresses(list, 0, version); @@ -434,6 +439,10 @@ public class Action implements GraphSourceItem { } pos++; if (hex) { + if (lastPush) { + ret.append("\r\n"); + lastPush = false; + } ret.append("");/* +"0x"+Helper.formatAddress(a.getFileAddress())+": "+*/; ret.append(Helper.bytesToHexString(a.getBytes(version))); ret.append("\r\n"); @@ -707,15 +716,22 @@ public class Action implements GraphSourceItem { * @param path * @return String with Source code */ - public static String actionsToSource(List actions, int version, String path) { + public static String actionsToSource(final List actions, final int version, final String path) { try { - //List tree = actionsToTree(new HashMap(), actions, version); - int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC; + return Helper.timedCall(new Callable() { + @Override + public String call() throws Exception { + //List tree = actionsToTree(new HashMap(), actions, version); + int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC; - List tree = actionsToTree(new HashMap(), new HashMap(), new HashMap(), actions, version, staticOperation, path); + List tree = actionsToTree(new HashMap(), new HashMap(), new HashMap(), actions, version, staticOperation, path); - - return Graph.graphToString(tree); + return Graph.graphToString(tree); + } + }, Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD, TimeUnit.SECONDS); + } catch (TimeoutException ex) { + Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error", ex); + return "/*\r\n * Decompilation error\r\n * Timeout (" + Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD) + ") was reached\r\n */"; } catch (Exception | OutOfMemoryError | StackOverflowError ex2) { Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error", ex2); if (ex2 instanceof OutOfMemoryError) { diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java index d6535ae6b..0e96799ad 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java @@ -1404,6 +1404,12 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel @Override public void run() { if (record.getLevel() == Level.SEVERE) { + if (errorNotificationButton == null) { + // todo: honfika + // why null? + return; + } + errorNotificationButton.setIcon(View.getIcon("error16")); errorNotificationButton.setToolTipText(translate("errors.present")); if (timer != null) { diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java index a313c381e..c59f3ead4 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java @@ -168,7 +168,7 @@ public class ActionPanel extends JPanel implements ActionListener { private void cacheScript(ASMSource src) { if (!cache.contains(src)) { List as = src.getActions(SWF.DEFAULT_VERSION); - String s = com.jpexs.decompiler.flash.action.Action.actionsToSource(as, SWF.DEFAULT_VERSION, src.toString()/*FIXME?*/); + String s = Action.actionsToSource(as, SWF.DEFAULT_VERSION, src.toString()/*FIXME?*/); List hilights = Highlighting.getInstrHighlights(s); String srcNoHex = Highlighting.stripHilights(s); cache.put(src, new CachedScript(srcNoHex, hilights)); @@ -567,6 +567,10 @@ public class ActionPanel extends JPanel implements ActionListener { } public void setDecompiledEditMode(boolean val) { + if (lastASM == null) { + return; + } + String pref = lastASM.getActionSourcePrefix(); int lastPos = decompiledEditor.getCaretPosition(); int lastLine = decompiledEditor.getLine(); diff --git a/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java b/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java index 8d42a55b1..12d1a1a36 100644 --- a/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java +++ b/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java @@ -34,6 +34,13 @@ import java.util.BitSet; import java.util.Collection; import java.util.List; import java.util.Stack; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -46,6 +53,8 @@ import java.util.regex.Pattern; */ public class Helper { + private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); + /** * Converts array of int values to string * @@ -504,4 +513,37 @@ public class Helper { timeStr += Helper.padZeros(timeS, 2) + "." + Helper.padZeros(timeMs, 3); return timeStr; } + + public static String formatTimeToText(int timeS) { + long timeM = timeS / 60; + timeS = timeS % 60; + long timeH = timeM / 60; + timeM = timeM % 60; + + String timeStr = ""; + if (timeH > 0) { + timeStr += timeH + (timeH > 1 ? " hours" : " hour"); + } + if (timeM > 0) { + if (timeStr.length() > 0) { + timeStr += " and "; + } + timeStr += timeM + (timeM > 1 ? " minutes" : " minute"); + } + if (timeS > 0) { + if (timeStr.length() > 0) { + timeStr += " and "; + } + timeStr += timeS + (timeS > 1 ? " seconds" : " second"); + } + + // (currently) used only in log, so no localization is required + return timeStr; + } + + public static T timedCall(Callable c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { + FutureTask task = new FutureTask(c); + THREAD_POOL.execute(task); + return task.get(timeout, timeUnit); + } }