Fixed: #2636 ActionScript - Incorrect always-break detection causing insertion of while(true)

Fixed: ActionScript - newline after do..while
This commit is contained in:
Jindra Petřík
2026-02-17 18:12:02 +01:00
parent 2a34a642be
commit fe28187a97
8 changed files with 107 additions and 31 deletions

View File

@@ -701,7 +701,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
/**
* SHA 256 hash of original data
*/
private String hashSha256 = null;
private String hashSha256 = "0000000000000000000000000000000000000000000000000000000000000000";
public String getHashSha256() {
return hashSha256;

View File

@@ -1896,6 +1896,11 @@ public class AVM2Graph extends Graph {
return ret;
}
}
if (caseBodyParts.size() < 2) {
stack.push(firstSet);
return ret;
}
//determine whether local register are on left or on right side of === operator
// -1 = there's no register,

View File

@@ -304,7 +304,7 @@ public class ActionGraph extends Graph {
@Override
protected void finalProcess(GraphTargetItem parent, List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) throws InterruptedException {
if (level == 0) {
List<GraphTargetItem> removed = new ArrayList<>();
for (int i = list.size() - 1; i >= 0; i--) {

View File

@@ -1305,6 +1305,41 @@ public class Graph {
LoopItem innerLoop = (LoopItem) lastCommand;
Block blk = (Block) lastCommand;
changeContinueToBreak(blk, li.loop.id, innerLoop.loop.id);
if (innerLoop instanceof UniversalLoopItem) {
UniversalLoopItem loopItem = (UniversalLoopItem) innerLoop;
if (!loopItem.commands.isEmpty() && loopItem.commands.get(loopItem.commands.size() - 1) instanceof IfItem) {
IfItem ifi = (IfItem) loopItem.commands.get(loopItem.commands.size() - 1);
boolean inverted = false;
boolean found = false;
if (ifi.onFalse.isEmpty() && (ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof BreakItem)) {
BreakItem bi = (BreakItem) ifi.onTrue.get(0);
if (bi.loopId == loopItem.loop.id) {
found = true;
inverted = true;
}
} else if (ifi.onTrue.isEmpty() && (ifi.onFalse.size() == 1) && (ifi.onFalse.get(0) instanceof BreakItem)) {
BreakItem bi = (BreakItem) ifi.onFalse.get(0);
if (bi.loopId == loopItem.loop.id) {
found = true;
}
}
if (found) {
loopItem.commands.remove(loopItem.commands.size() - 1);
GraphTargetItem expressionSingle = ifi.expression;
if (inverted) {
expressionSingle = expressionSingle.invert(null);
}
List<GraphTargetItem> expression = new ArrayList<>();
expression.add(expressionSingle);
DoWhileItem doWhile = new DoWhileItem(dialect, loopItem.getSrc(), loopItem.getLineStartItem(), loopItem.loop, loopItem.commands, expression);
currentList.set(currentList.size() - 1, doWhile);
}
}
}
} else if (lastCommand instanceof Block) {
Block blk = (Block) lastCommand;
List<List<GraphTargetItem>> newTodos = new ArrayList<>(blk.getSubs());
@@ -1316,7 +1351,7 @@ public class Graph {
todos.addAll(newTodos);
}
}
}
}
if (li instanceof ForItem) {
ForItem fi = (ForItem) li;
List<ContinueItem> continues = fi.getContinues();
@@ -1823,7 +1858,7 @@ public class Graph {
/**
* Final process. Override this method to provide custom behavior.
*
* @param parent Paren item
* @param parent Parent item
* @param list List of GraphTargetItems
* @param level Level
* @param localData Local data
@@ -2085,6 +2120,10 @@ public class Graph {
if (blk instanceof SwitchItem) {
return;
}
if (blk instanceof LoopItem) {
return;
}
for (List<GraphTargetItem> sub : blk.getSubs()) {
processScriptEnd(sub);
@@ -3312,7 +3351,7 @@ public class Graph {
}
if (debugPrintGraph) {
System.err.println("loopsize:" + loops.size());
}
}
for (int l = loops.size() - 1; l >= 0; l--) {
Loop el = loops.get(l);
if (el == ignoredLoop) {
@@ -3338,7 +3377,7 @@ public class Graph {
}
continue;
}
if (el.loopBreak == part) {
if (el.loopBreak == part) {
if (currentLoop != null) {
currentLoop.phase = 0;
}
@@ -3354,8 +3393,8 @@ public class Graph {
ret.add(br);
return originalRet;
}
if (el.loopPreContinue == part) {
}
if (el.loopPreContinue == part) {
if (currentLoop != null) {
currentLoop.phase = 0;
}
@@ -3382,7 +3421,7 @@ public class Graph {
if (debugPrintGraph) {
System.err.println("stopParts: " + pathToString(stopPart));
}
if (stopPart.contains(part)) {
boolean isRealStopPart = false;
@@ -3433,7 +3472,7 @@ public class Graph {
}
return originalRet;
}
boolean vCanHandleVisited = canHandleVisited(localData, part);
if (vCanHandleVisited) {
@@ -3826,6 +3865,7 @@ public class Graph {
/*
Detect forward jumps (breaks) in always-break loops.
FIXME!!!
*/
if (localData.secondPassData != null) {
if (next != null) {
@@ -3848,7 +3888,15 @@ public class Graph {
while (!s.isEmpty()) {
GraphPart p = s.poll();
v.add(p);
if (p == part) {
continue;
}
for (GraphPart r : p.refs) {
// #2636, it has no test
if (!part.leadsTo(localData, this, code, r, loops, throwStates)) {
//System.err.println("Part " + part + " do not lead");
continue;
}
if (r == part) {
continue;
}
@@ -3867,8 +3915,9 @@ public class Graph {
if (!n.leadsTo(localData, this, code, next, loops, throwStates)) {
GraphPart n2 = getCommonPart(localData, r, Arrays.asList(next, n), loops, throwStates);
if (n2 != null) {
//System.err.println("Found block: start = " + part + ", break = " + n2+", exit = " + r);
//System.err.println("Found block: start = " + part + ", break = " + n2 + ", exit = " + r);
//System.err.println("next = " + next);
//System.err.println("n = " + n + " does not lead to next");
Loop el = new Loop(loops.size(), part, n2);
el.phase = 1;
@@ -4177,7 +4226,11 @@ public class Graph {
if (bi.loopId == currentLoop.id) {
bodyBranch = ifi.onTrue;
}
} else if (loopItem.commands.size() == 2 && (loopItem.commands.get(1) instanceof BreakItem)) {
} else if (loopItem.commands.size() == 2
&& (loopItem.commands.get(1) instanceof BreakItem)
&& ifi.onFalse.isEmpty()
&& !ifi.onTrue.isEmpty()
) {
BreakItem bi = (BreakItem) loopItem.commands.get(1);
if (ifi.onTrue.isEmpty()) {
inverted = true;
@@ -4186,8 +4239,16 @@ public class Graph {
breakpos2 = true;
if (bi.loopId != currentLoop.id) { //it's break of another parent loop
addBreakItem = bi; //we must add it after the loop
} else {
if (
!(bodyBranch.get(bodyBranch.size() - 1) instanceof ContinueItem)
&& !(bodyBranch.get(bodyBranch.size() - 1) instanceof BreakItem)
&& !(bodyBranch.get(bodyBranch.size() - 1) instanceof ExitItem)
) {
bodyBranch.add(loopItem.commands.get(1));
}
}
} else if ((ifi.onTrue.size() == 1)
} /*else if ((ifi.onTrue.size() == 1)
&& (ifi.onTrue.get(0) instanceof ContinueItem)
&& (((ContinueItem) ifi.onTrue.get(0)).loopId != currentLoop.id)) {
addContinueItem = (ContinueItem) ifi.onTrue.get(0);
@@ -4207,8 +4268,8 @@ public class Graph {
}
bodyBranch = inverted ? ifi.onFalse : ifi.onTrue;
breakpos2 = true;
}
if (bodyBranch != null) {
}*/
if (bodyBranch != null) { //FIXME
int index = ret.indexOf(loopItem);
ret.remove(index);
List<GraphTargetItem> exprList = new ArrayList<>();

View File

@@ -150,6 +150,7 @@ public class GraphPart implements Serializable {
Stack<GraphPart> todo = new Stack<>();
todo.push(this);
boolean first = true;
looptodo:
while (!todo.isEmpty()) {
@@ -164,18 +165,23 @@ public class GraphPart implements Serializable {
continue;
}
for (Loop l : loops) {
if (l.phase == 1) {
if (l.phase == 1) {
if (l.loopContinue == thisPart) {
continue looptodo;
if (!first) {
continue looptodo;
}
}
if (l.loopPreContinue == thisPart) {
continue looptodo;
if (!first) {
continue looptodo;
}
}
if (l.loopBreak == thisPart) {
//return false; //?
}
}
}
first = false;
if (visited.contains(thisPart)) {
continue;
}

View File

@@ -53,12 +53,7 @@ public class DoWhileItem extends LoopItem implements Block {
* Label used
*/
private boolean labelUsed;
@Override
public boolean needsSemicolon() {
return false;
}
@Override
public List<List<GraphTargetItem>> getSubs() {
List<List<GraphTargetItem>> ret = new ArrayList<>();
@@ -137,7 +132,7 @@ public class DoWhileItem extends LoopItem implements Block {
}
writer.append(");").newLine();
writer.append(")");
if (writer instanceof NulWriter) {
LoopWithType loopOjb = ((NulWriter) writer).endLoop(loop.id);
labelUsed = loopOjb.used;