From 1bacb111fef1cc234f551ce5133e6a7df2ef51d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Fri, 12 Feb 2021 11:08:07 +0100 Subject: [PATCH] Fixed: Cannot properly cancel script searching --- CHANGELOG.md | 1 + .../decompiler/flash/abc/ScriptPack.java | 11 ++++++++- .../flash/abc/types/MethodBody.java | 4 +++- .../flash/search/ActionScriptSearch.java | 20 ++++++++++++---- .../com/jpexs/helpers/CancellableWorker.java | 23 ++++++++++++++++++- .../jpexs/decompiler/flash/gui/MainPanel.java | 3 ++- .../decompiler/flash/gui/abc/ABCPanel.java | 2 +- 7 files changed, 54 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8016ae14..fb67675eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. - #1360 Precedence of increment/decrement operations - #1407 NullPointer on Save as in BinaryData SWF subtree - #1596 Infinite loop when sorting traits according to dependencies +- Cannot properly cancel script searching ## [13.0.2] - 2021-02-10 ### Changed diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java index aa93f6c8d..587e6732b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java @@ -62,6 +62,7 @@ import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -255,14 +256,22 @@ public class ScriptPack extends AS3ClassTreeItem { logger.log(Level.SEVERE, "Decompilation timeout", ex); Helper.appendTimeoutCommentAs3(writer, timeout, 0); return; + } catch (CancellationException ex) { + throw new InterruptedException(); } catch (ExecutionException ex) { writer.continueMeasure(); Exception convertException = ex; Throwable cause = ex.getCause(); - if (ex instanceof ExecutionException && cause instanceof Exception) { + if (cause instanceof Exception) { convertException = (Exception) cause; } + if (convertException instanceof CancellationException) { + throw new InterruptedException(); + } + if (convertException instanceof InterruptedException) { + throw (InterruptedException) convertException; + } logger.log(Level.SEVERE, "Decompilation error", convertException); Helper.appendErrorComment(writer, convertException); return; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java index 3a672f9e8..e6cb8b6f0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java @@ -52,6 +52,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -326,9 +327,10 @@ public final class MethodBody implements Cloneable { } } catch (InterruptedException ex) { throw ex; + } catch (CancellationException ex) { + throw new InterruptedException(); } catch (Exception | OutOfMemoryError | StackOverflowError ex) { convertException = ex; - ex.printStackTrace(); Throwable cause = ex.getCause(); if (ex instanceof ExecutionException && cause instanceof Exception) { convertException = (Exception) cause; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionScriptSearch.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionScriptSearch.java index 04c31a6bb..a671fc464 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionScriptSearch.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionScriptSearch.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.search; import com.jpexs.decompiler.flash.SWF; @@ -26,8 +27,10 @@ import com.jpexs.decompiler.flash.helpers.HighlightedText; import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; import com.jpexs.decompiler.flash.tags.base.ASMSource; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.logging.Level; @@ -114,7 +117,7 @@ public class ActionScriptSearch { swf.getFlexMainClass(ignoredClasses, ignoredNss); } - final List found = new ArrayList<>(); + final List found = Collections.synchronizedList(new ArrayList<>()); List allpacks = swf.getAS3Packs(); final Pattern pat = regexp ? Pattern.compile(txt, ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0) @@ -168,6 +171,9 @@ public class ActionScriptSearch { Future text = SWF.getCachedFuture(pack, new ScriptDecompiledListener() { @Override public void onStart() { + if (Thread.currentThread().isInterrupted()) { + return; + } if (listener != null) { listener.onDecompile(fpos, allpacks.size(), pack.getClassPath().toString()); } @@ -175,8 +181,11 @@ public class ActionScriptSearch { @Override public void onComplete(HighlightedText result) { - if (listener != null) { - listener.onSearch(fpos, allpacks.size(), pack.getClassPath().toString()); + + if (!Thread.currentThread().isInterrupted()) { + if (listener != null) { + listener.onSearch(fpos, allpacks.size(), pack.getClassPath().toString()); + } } if (pat.matcher(result.text).find()) { @@ -193,6 +202,8 @@ public class ActionScriptSearch { for (Future future : futures) { try { future.get(); + } catch (CancellationException ex) { + throw new InterruptedException(); } catch (ExecutionException ex) { Logger.getLogger(ActionScriptSearch.class.getName()).log(Level.SEVERE, null, ex); } @@ -205,7 +216,6 @@ public class ActionScriptSearch { return found; } - return null; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/helpers/CancellableWorker.java b/libsrc/ffdec_lib/src/com/jpexs/helpers/CancellableWorker.java index 0034b623a..8b3d47f8d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/helpers/CancellableWorker.java +++ b/libsrc/ffdec_lib/src/com/jpexs/helpers/CancellableWorker.java @@ -12,12 +12,15 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.helpers; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -42,11 +45,16 @@ public abstract class CancellableWorker implements RunnableFuture { private final FutureTask future; + private static final Map threadWorkers = Collections.synchronizedMap(new WeakHashMap<>()); + + private List subWorkers = Collections.synchronizedList(new ArrayList<>()); + public CancellableWorker() { super(); Callable callable = new Callable() { @Override public T call() throws Exception { + threadWorkers.put(Thread.currentThread(), CancellableWorker.this); return doInBackground(); } }; @@ -73,13 +81,22 @@ public abstract class CancellableWorker implements RunnableFuture { protected void done() { } + @SuppressWarnings("unchecked") public final void execute() { + Thread t = Thread.currentThread(); + if (threadWorkers.containsKey(t)) { + threadWorkers.get(t).subWorkers.add(this); + } onStart(); THREAD_POOL.execute(this); } @Override public final boolean cancel(boolean mayInterruptIfRunning) { + List sw = new ArrayList<>(subWorkers); + for (CancellableWorker w : sw) { + w.cancel(mayInterruptIfRunning); + } boolean r = future.cancel(mayInterruptIfRunning); if (r) { workerCancelled(); @@ -118,6 +135,10 @@ public abstract class CancellableWorker implements RunnableFuture { } public static T call(final Callable c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { + Thread t = Thread.currentThread(); + if (t.isInterrupted()) { + throw new InterruptedException(); + } CancellableWorker worker = new CancellableWorker() { @Override diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 9b0a0bc42..c8648bd65 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -1837,7 +1837,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se Main.stopWork(); }); - } + } + }.execute(); } else if (searchDialog.searchInTextsRadioButton.isSelected()) { new CancellableWorker() { diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index 229bf09c9..53981892a 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -1118,7 +1118,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener usages = abc.findMultinameDefinition(multinameIndex); Multiname m = abc.constants.getMultiname(multinameIndex); - if (m == null){ + if (m == null) { return false; } //search other ABC tags if this is not private multiname