HaxeFoundation / HaxeFoundation/haxe
[flash] Indirect calling of dynamic function containing anonymous function with local field access
- Dominant language
- Haxe
- Stars
- 6.9k
- Forks
- 715
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 11
Description
The following code will throw a runtime error at the invocation of `indirectCallToDynamicFunction`.
```haxe
package;
class DynamicFunctions
{
public static function main()
new DynamicFunctions();
var localVar = 0;
public function new() {
var indirectCallToDynamicFunction = dynamicFunction;
indirectCallToDynamicFunction(); //error here
}
public function runAnonymousFunction(func:()->Void)
func();
public dynamic function dynamicFunction() {
runAnonymousFunction(function() {
trace("localVar=" + localVar + ", called from dynamicFunction");
});
}
}
```
HXML:
```
-main DynamicFunctions
-debug
-swf dynamic.swf
```
The error:
```
TypeError: Error #1034: Type Coercion failed: cannot convert global@433f3e1 to DynamicFunctions.
at MethodInfo-1()[DynamicFunctions.hx:18]
at DynamicFunctions()[DynamicFunctions.hx:12]
at DynamicFunctions$/main()[DynamicFunctions.hx:6]
at boot_e198/init()[?:1]
at flash::Boot/start()[...\haxe\4.2.1-win64\std/flash/Boot.hx:70]
at boot_e198()[...\haxe\4.2.1-win64\std/flash/Boot.hx:40]
```
The decompiled swf looks like this
```as3
package
{
import haxe.Log;
public class DynamicFunctions
{
public var localVar:int;
public var dynamicFunction:Function;
public function DynamicFunctions()
{
if(!dynamicFunction)
{
dynamicFunction = function():void
{
var _gthis:DynamicFunctions = this; //this is the line that throws the error
runAnonymousFunction(function():void
{
Log.trace("localVar=" + _gthis.localVar + ", called from dynamicFunction",{
"fileName":"DynamicFunctions.hx",
"lineNumber":20,
"className":"DynamicFunctions",
"methodName":"dynamicFunction"
});
});
};
}
localVar = 0;
var indirectCallToDynamicFunction:Function = dynamicFunction;
indirectCallToDynamicFunction();
}
public static function main() : void
{
new DynamicFunctions();
}
public function runAnonymousFunction(func:Function) : void
{
func();
}
}
}
```
Here are the relevant opcodes generated at `indirectCallToDynamicFunction();`
```
getlocal1 //puts indirectCallToDynamicFunction onto the stack
getglobalscope //puts the global object onto the stack
call
```
According to the AVM2 Overview, the `call` instruction takes the first item on the stack to be the function, the second item to be the "this" value, and optionally a specified number of additional items to be used as parameters for the function call.
The stack has `indirectCallToDynamicFunction, global object` in it, so the global object will be taken as the "this" value, resulting in the type coercion error when this line of code is run in the called function:
```as3
var _gthis:DynamicFunctions = this;
```
Contributor guide
Assessment
This issue has not been assessed yet.