From 01bf4af552454c3da2f27d8bd25e13b0e4196818 Mon Sep 17 00:00:00 2001 From: Symere <285844353+symerebysil@users.noreply.github.com> Date: Sun, 24 May 2026 03:07:34 -0400 Subject: [PATCH] fix(as2): correct Decrement cast and guard empty output in ActionSetMember (PR261) handleSetMember crashed while decompiling AS2 code that applies `--` to a virtual (`__get__`/`__set__`) property, e.g. `this.prop--` where `prop` is defined via addProperty. The decrement-setter branch built a PreDecrementActionItem but cast the value to IncrementActionItem instead of DecrementActionItem, throwing ClassCastException. That exception was then masked: it propagated into the finally block before addToOutput ran, so `output` was empty and `output.remove(output.size() - 1)` threw IndexOutOfBoundsException, replacing the real cause. The reported error was therefore always a misleading "Index -1 out of bounds for length 0", which also aborts loading entirely when "automatically rename identifiers" is enabled (deobfuscateIdentifiers decompiles every script on load). Fixes: - Cast value to DecrementActionItem in the PreDecrement setter branch. - Guard the finally against an empty output (mirrors cleanupTemp) so a future exception in the try block is no longer masked. Affected code now decompiles correctly to `++prop` / `--prop`. --- .../flash/action/swf5/ActionSetMember.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java index 90bb6896e..44f655e1b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java @@ -188,7 +188,7 @@ public class ActionSetMember extends Action { ((GetMemberActionItem) ((DecrementActionItem) value).object).object = ((GetMemberActionItem) ((DecrementActionItem) value).object).object.getThroughDuplicate(); cleanupTemp(((GetMemberActionItem) ((DecrementActionItem) value).object).object, object, output, stack); if (setter) { - stack.addToOutput(new PreDecrementActionItem(action, lineStartAction, ((IncrementActionItem) value).object.getThroughDuplicate())); + stack.addToOutput(new PreDecrementActionItem(action, lineStartAction, ((DecrementActionItem) value).object.getThroughDuplicate())); } else { stack.addToOutput(new PostDecrementActionItem(action, lineStartAction, ((DecrementActionItem) value).object.getThroughDuplicate())); } @@ -252,8 +252,14 @@ public class ActionSetMember extends Action { } finally { if (setter) { stack.finishBlock(output); - stack.push(output.remove(output.size() - 1)); - stack.moveToStack(output); + // Guard against an empty output: if the try block exited via an + // exception before producing a statement, removing from an empty + // list would throw IndexOutOfBoundsException here and mask the + // original exception. Mirrors the check used in cleanupTemp(). + if (!output.isEmpty()) { + stack.push(output.remove(output.size() - 1)); + stack.moveToStack(output); + } } } }