Fixed #1937 AS3 - declarations vs null

This commit is contained in:
Jindra Petřík
2023-01-14 18:20:31 +01:00
parent 2a8c6a7858
commit 313b51cd8c
10 changed files with 245 additions and 159 deletions

View File

@@ -26,6 +26,7 @@ All notable changes to this project will be documented in this file.
- [#1936] AS3 Direct editation - scope of nested functions
- AS3 - empty P-code shown on clicking script
- [#1888] AS3 - Coerces, module operator
- [#1937] AS3 - declarations vs null
## [18.3.2] - 2023-01-10
### Removed
@@ -2889,6 +2890,7 @@ All notable changes to this project will be documented in this file.
[#1801]: https://www.free-decompiler.com/flash/issues/1801
[#1892]: https://www.free-decompiler.com/flash/issues/1892
[#1936]: https://www.free-decompiler.com/flash/issues/1936
[#1937]: https://www.free-decompiler.com/flash/issues/1937
[#1935]: https://www.free-decompiler.com/flash/issues/1935
[#1931]: https://www.free-decompiler.com/flash/issues/1931
[#1934]: https://www.free-decompiler.com/flash/issues/1934

View File

@@ -1193,14 +1193,14 @@ public class AVM2Code implements Cloneable {
}
public GraphTextWriter toASMSource(ABC abc, AVM2ConstantPool constants, MethodInfo info, MethodBody body, List<Integer> outputMap, ScriptExportMode exportMode, GraphTextWriter writer) {
if (info != null) {
writer.appendNoHilight("method");
if (Configuration.indentAs3PCode.get()) {
writer.indent();
}
writer.newLine();
info.toASMSource(constants, writer);
}
writer.newLine();
@@ -1780,22 +1780,31 @@ public class AVM2Code implements Cloneable {
} else if (assignment.value instanceof CoerceAVM2Item) {
vtype = ((CoerceAVM2Item) assignment.value).typeObj;
} else if (assignment instanceof LocalRegAVM2Item) { //for..in
vtype = ((LocalRegAVM2Item)assignment).type;
vtype = ((LocalRegAVM2Item) assignment).type;
} else if (assignment instanceof GetSlotAVM2Item) { //for..in
vtype = ((GetSlotAVM2Item)assignment).slotType;
vtype = ((GetSlotAVM2Item) assignment).slotType;
} else if ((assignment.value instanceof SimpleValue) && ((SimpleValue) assignment.value).isSimpleValue()) {
vtype = assignment.value.returnType();
}
}
boolean isNull = false;
if (vtype.equals(new TypeItem(DottedChain.NULL))) {
vtype = TypeItem.UNBOUNDED;
}
if (declaredRegisters[reg] == null) {
if (declaredRegisters[reg] == null) {
declaredRegisters[reg] = new DeclarationAVM2Item(assignment, vtype);
if (assignment instanceof SetTypeAVM2Item) {
((SetTypeAVM2Item) assignment).setDeclaration(declaredRegisters[reg]);
}
declaredRegisters[reg].typeIsNull = isNull;
return declaredRegisters[reg];
}
if (declaredRegisters[reg].type == TypeItem.UNBOUNDED) {
if (declaredRegisters[reg].typeIsNull) {
declaredRegisters[reg].type = vtype;
declaredRegisters[reg].typeIsNull = isNull;
} else if (declaredRegisters[reg].type == TypeItem.UNBOUNDED) {
} else if (!declaredRegisters[reg].type.equals(vtype)) { //already declared with different type
declaredRegisters[reg].type = TypeItem.UNBOUNDED;
@@ -1896,7 +1905,7 @@ public class AVM2Code implements Cloneable {
Slot sl = new Slot(new NewActivationAVM2Item(null, null), propertyMultiName);
if (!paramNames.contains(propertyName)) {
if (traits.containsKey(propertyName) && !beginDeclaredSlotsNames.contains(propertyName)) {
hasPrevReference.setVal(true);
hasPrevReference.setVal(true);
}
}
}
@@ -1956,7 +1965,7 @@ public class AVM2Code implements Cloneable {
int reg = ((LocalRegAVM2Item) fi.expression.object).regIndex;
fi.expression.object = handleDeclareReg(minreg, fi.expression.object, declaredRegisters, declaredSlots, reg);
}
}
}
for (GraphTargetItem subItem : itemsOnLine) {
if (subItem instanceof SetLocalAVM2Item) {
@@ -1987,11 +1996,11 @@ public class AVM2Code implements Cloneable {
sp.setDeclaration(d);
declaredPropsDec.add(d);
declaredProperties.add(propName.resolvedMultinameName);
Slot sl = new Slot(new NewActivationAVM2Item(null, null), abc.constants.getMultiname(tsc.name_index));
declaredSlotsDec.add(d);
declaredSlots.add(sl);
if (subItem == currentItem) {
items.set(i, d);
} else {
@@ -2025,7 +2034,7 @@ public class AVM2Code implements Cloneable {
ssti.setDeclaration(d);
declaredSlotsDec.add(d);
declaredSlots.add(sl);
declaredPropsDec.add(d);
declaredProperties.add(slotPropertyName);
@@ -2088,10 +2097,10 @@ public class AVM2Code implements Cloneable {
localRegTypes.put(i + 1, AbcIndexing.multinameToType(abc.method_info.get(methodIndex).param_types[i], abc.constants));
}
ScopeStack prevScopeStack = (ScopeStack)scopeStack.clone();
try{
ScopeStack prevScopeStack = (ScopeStack) scopeStack.clone();
try {
list = AVM2Graph.translateViaGraph(null, callStack, abcIndex, path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, localRegTypes, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs, thisHasDefaultToPrimitive);
} catch(SecondPassException spe) {
} catch (SecondPassException spe) {
list = AVM2Graph.translateViaGraph(spe.getData(), callStack, abcIndex, path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, prevScopeStack, localRegNames, localRegTypes, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs, thisHasDefaultToPrimitive);
}
if (initTraits != null) {
@@ -2549,19 +2558,19 @@ public class AVM2Code implements Cloneable {
public int removeTraps(Trait trait, int methodInfo, MethodBody body, ABC abc, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException {
SWFDecompilerPlugin.fireAvm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body);
try ( Statistics s = new Statistics("AVM2DeobfuscatorGetSet")) {
try (Statistics s = new Statistics("AVM2DeobfuscatorGetSet")) {
new AVM2DeobfuscatorGetSet().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body);
}
try ( Statistics s = new Statistics("AVM2DeobfuscatorSimple")) {
try (Statistics s = new Statistics("AVM2DeobfuscatorSimple")) {
new AVM2DeobfuscatorSimpleOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body);
}
try ( Statistics s = new Statistics("AVM2DeobfuscatorRegisters")) {
try (Statistics s = new Statistics("AVM2DeobfuscatorRegisters")) {
new AVM2DeobfuscatorRegistersOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body);
}
try ( Statistics s = new Statistics("AVM2DeobfuscatorJumps")) {
try (Statistics s = new Statistics("AVM2DeobfuscatorJumps")) {
new AVM2DeobfuscatorJumps().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body);
}
try ( Statistics s = new Statistics("AVM2DeobfuscatorZeroJumpsNullPushes")) {
try (Statistics s = new Statistics("AVM2DeobfuscatorZeroJumpsNullPushes")) {
new AVM2DeobfuscatorZeroJumpsNullPushes().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body);
}
return 1;

View File

@@ -25,6 +25,7 @@ import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SimpleValue;
import com.jpexs.decompiler.graph.SourceGenerator;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.decompiler.graph.model.LocalData;
@@ -35,7 +36,7 @@ import java.util.Set;
*
* @author JPEXS
*/
public class NullAVM2Item extends AVM2Item {
public class NullAVM2Item extends AVM2Item implements SimpleValue {
public NullAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns) {
super(instruction, lineStartIns, PRECEDENCE_PRIMARY);
@@ -92,4 +93,9 @@ public class NullAVM2Item extends AVM2Item {
int hash = 3;
return hash;
}
@Override
public boolean isSimpleValue() {
return true;
}
}

View File

@@ -44,6 +44,8 @@ public class DeclarationAVM2Item extends AVM2Item {
public GraphTargetItem assignment;
public GraphTargetItem type;
public boolean typeIsNull = false;
public boolean showValue = true;

View File

@@ -348,6 +348,22 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
false);
}
@Test
public void testDeclarationInterface() {
decompileMethod("classic_air", "testDeclarationInterface", "var i:MyIFace = null;\r\n"
+ "var n:int = 2;\r\n"
+ "switch(n)\r\n"
+ "{\r\n"
+ "case 0:\r\n"
+ "i = new MyClass();\r\n"
+ "break;\r\n"
+ "case 1:\r\n"
+ "i = new MyClass2();\r\n"
+ "}\r\n"
+ "return i;\r\n",
false);
}
@Test
public void testDeclarations() {
decompileMethod("classic_air", "testDeclarations", "var vall:* = undefined;\r\n"

View File

@@ -347,6 +347,22 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes
false);
}
@Test
public void testDeclarationInterface() {
decompileMethod("classic", "testDeclarationInterface", "var i:MyIFace = null;\r\n"
+ "var n:int = 2;\r\n"
+ "switch(n)\r\n"
+ "{\r\n"
+ "case 0:\r\n"
+ "i = new MyClass();\r\n"
+ "break;\r\n"
+ "case 1:\r\n"
+ "i = new MyClass2();\r\n"
+ "}\r\n"
+ "return i;\r\n",
false);
}
@Test
public void testDeclarations() {
decompileMethod("classic", "testDeclarations", "var vall:* = undefined;\r\n"

View File

@@ -1,152 +1,153 @@
package
{
import flash.display.Sprite;
import flash.events.Event;
import tests.*;
import tests_classes.mypackage1.SetupMyPackage1;
import tests_classes.mypackage2.SetupMyPackage2;
import tests_classes.mypackage3.SetupMyPackage3;
import tests_classes.*;
import tests_edit.*;
/**
* ...
* @author JPEXS
*/
public class Main extends Sprite
{
TestActivationArguments;
TestArguments;
import flash.display.Sprite;
import flash.events.Event;
import tests.*;
import tests_classes.mypackage1.SetupMyPackage1;
import tests_classes.mypackage2.SetupMyPackage2;
import tests_classes.mypackage3.SetupMyPackage3;
import tests_classes.*;
import tests_edit.*;
/**
* ...
* @author JPEXS
*/
public class Main extends Sprite
{
TestActivationArguments;
TestArguments;
TestCallCall;
TestCallLocal;
TestCatchFinally;
TestChain2;
TestChainedAssignments;
TestCallLocal;
TestCatchFinally;
TestChain2;
TestChainedAssignments;
TestCollidingTry;
TestComplexExpressions;
TestContinueLevels;
TestConvert;
TestComma;
TestCompoundAssignments;
TestDecl2;
TestDeclarations;
TestDeobfuscation;
TestDefaultNotLastGrouped;
TestDotParent;
TestDoWhile;
TestDoWhile2;
TestDoWhile3;
TestDoWhile4;
TestExpressions;
TestFinallyZeroJump;
TestFor;
TestForAnd;
TestForBreak;
TestForContinue;
TestForEach;
TestForEachObjectArray;
TestForEachObjectAttribute;
TestForEachReturn;
TestForEachReturn2;
TestForGoto;
TestForIn;
TestForInIf;
TestForInReturn;
TestForInSwitch;
TestForXml;
TestGotos;
TestGotos2;
TestGotos3;
TestGotos4;
TestGotos5;
TestGotos6;
TestGotos7;
TestHello;
TestIf;
TestIfElse;
TestIfFinally;
TestIfInIf;
TestIfTry;
TestIgnoreAndOr;
TestContinueLevels;
TestConvert;
TestComma;
TestCompoundAssignments;
TestDecl2;
TestDeclarations;
TestDeclarationInterface;
TestDeobfuscation;
TestDefaultNotLastGrouped;
TestDotParent;
TestDoWhile;
TestDoWhile2;
TestDoWhile3;
TestDoWhile4;
TestExpressions;
TestFinallyZeroJump;
TestFor;
TestForAnd;
TestForBreak;
TestForContinue;
TestForEach;
TestForEachObjectArray;
TestForEachObjectAttribute;
TestForEachReturn;
TestForEachReturn2;
TestForGoto;
TestForIn;
TestForInIf;
TestForInReturn;
TestForInSwitch;
TestForXml;
TestGotos;
TestGotos2;
TestGotos3;
TestGotos4;
TestGotos5;
TestGotos6;
TestGotos7;
TestHello;
TestIf;
TestIfElse;
TestIfFinally;
TestIfInIf;
TestIfTry;
TestIgnoreAndOr;
TestImplicitCoerce;
TestImportedVar;
TestInc2;
TestIncDec;
TestInlineFunctions;
TestInlineFunctions2;
TestInnerFunctions;
TestInnerFunctionScope;
TestInnerIf;
TestInnerTry;
TestLogicalComputing;
TestManualConvert;
TestMissingDefault;
TestMultipleCondition;
TestNamedAnonFunctions;
TestNames;
TestNegate;
TestNumberCall;
TestOptionalParameters;
TestParamNames;
TestParamsCount;
TestPrecedence;
TestPrecedenceX;
TestProperty;
TestRegExp;
TestRest;
TestImportedVar;
TestInc2;
TestIncDec;
TestInlineFunctions;
TestInlineFunctions2;
TestInnerFunctions;
TestInnerFunctionScope;
TestInnerIf;
TestInnerTry;
TestLogicalComputing;
TestManualConvert;
TestMissingDefault;
TestMultipleCondition;
TestNamedAnonFunctions;
TestNames;
TestNegate;
TestNumberCall;
TestOptionalParameters;
TestParamNames;
TestParamsCount;
TestPrecedence;
TestPrecedenceX;
TestProperty;
TestRegExp;
TestRest;
TestSlots;
TestSlots2;
TestStrictEquals;
TestStringConcat;
TestStrings;
TestSwitch;
TestSlots2;
TestStrictEquals;
TestStringConcat;
TestStrings;
TestSwitch;
TestSwitchContinue;
TestSwitchComma;
TestSwitchDefault;
TestSwitchIf;
TestTernarOperator;
TestTry;
TestTryIf;
TestTryReturn;
TestTryReturn2;
TestSwitchComma;
TestSwitchDefault;
TestSwitchIf;
TestTernarOperator;
TestTry;
TestTryIf;
TestTryReturn;
TestTryReturn2;
TestUndefined;
TestUsagesTry;
TestVector;
TestVector2;
TestWhileAnd;
TestWhileBreak;
TestUsagesTry;
TestVector;
TestVector2;
TestWhileAnd;
TestWhileBreak;
TestWhileBreak2;
TestWhileContinue;
TestWhileTry;
TestWhileTry2;
TestXml;
SetupMyPackage1;
SetupMyPackage2;
SetupMyPackage3;
TestThisOutsideClass;
TestImports;
TestInitializer;
TestRegexpHilight;
TestPropertyCoerce;
TestUnaryMinus;
TestWhileContinue;
TestWhileTry;
TestWhileTry2;
TestXml;
SetupMyPackage1;
SetupMyPackage2;
SetupMyPackage3;
TestThisOutsideClass;
TestImports;
TestInitializer;
TestRegexpHilight;
TestPropertyCoerce;
TestUnaryMinus;
TestModifiers;
public function Main()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
}
}
public function Main()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
}
}
}

View File

@@ -0,0 +1,34 @@
package tests
{
public class TestDeclarationInterface
{
public function run(): MyIFace
{
var i:MyIFace = null;
var n:int = 2;
switch(n) {
case 0:
i = new MyClass();
break;
case 1:
i = new MyClass2();
break;
}
return i;
}
}
}
interface MyIFace {
}
class MyClass implements MyIFace {
}
class MyClass2 implements MyIFace {
}