AS3 Keyword / Name Qualifier Operator (::) Bug Exploit/Trick

Sometime last year, I ran into an ActionScript compiler bug involving the name qualifier operator and certain keywords / future reserved words where one could use one of a select group of keywords along with that operator to cause unexpected compiler behavior (something similar happens with use namespace). It actually crashed the Flex/Java version of ASC, but it failed silently with the Flash IDE’s ASC. Anyway, my bug ended up being somewhat misfiled, so I’m working to correct that. Here it is, though: http://bugs.adobe.com/jira/browse/SDK-18148

Recently I have been playing around with side-effects of that bug, and I found a couple things that you can do that are actually pretty neat that I thought some people might find interesting or useful.

First up, it turns out that you can access properties of the (or a) global object fairly quickly using the weird syntax that I ran into:

// here's my normal way to access a global from most contexts
var glob:Object = function(){ return function(){ return this }() }();
trace(glob); // [object global]
glob.prop = 'val';

// here's the shortcut for property access
trace(virtual::['prop']); // val

In addition to virtual, you can also use intrinsic, native, public, dynamic, override, or final. Note the strange mix of keywords and what Adobe calls future reserved words.

Anyway, you can use most everything that you’d normally use a global variable for, except for things like reference passing and iteration, since I still haven’t found a way to use this trick to get a reference to the actual global object like you can using the unbound function call approach. Of course, the usual complaints about globals being a shady practice still apply here. It just seems to me that this way is quite a bit more lightweight than the usual static property of some class, like Global.obj.prop = 'someGloballyAccessibleValue', since you don’t have to create a separate file or use more than a couple of characters per access.

The second interesting use case that I’ve found so far is that you can use the broken name qualifier in an unbound function to access the scope that would have been bound had the function been bound, like what happens with methods. In other words, you can basically nullify the effects of Function#call or Function#apply when you prefix your property accesses with the broken form of the name qualifier.

Here’s an example where I create functions with and without a bound scope in a class and then compare the results of a property access:

// in my tester .fla file
var c:C = new C();
c.boundMethod.call(root, 'name'); // someC someC
c.unboundMethod.call(root, 'name'); // root1 someC

// in the class file
package {
	public class C {
		public var name:String = 'someC';
		
		public function boundMethod(propName:String):void {
			trace(this[propName], intrinsic::[propName]);
		}
		
		public var unboundMethod:Function = function(propName:String):void {
			trace(this[propName], intrinsic::[propName]);
		}
	}
}

The cool thing is that in the call where the function is being called with root as the specified scope, the exploit allows you to dynamically access properties of the scope in which the function was defined without having to explicitly store a reference to that object first. It’s kind of like having two different values for this in the same scope, which is good since it gives you more flexibility without taking anything from you and without specific/explicit preparation.


Now that I’ve mentioned the cool things about it, I’ll just note some other things that you might notice when using code like the above.

If you use the AS3 namespace, you’ll get a runtime error from attempting to access what appears to be a different than usual global object. Maybe it’s a meta-global object, since there are almost certainly different global objects for each SWF. Anyway, an example :

AS3::['prop']; // ReferenceError: Error #1081: Property prop not found on global and there is no default value.

If you use the private namespace, you can see that ASC really chokes:

trace(this.private::arguments); // ReferenceError: Error #1069: Property ::arguments not found on MainTimeline and there is no default value.

For some reason, ASC decides that the name qualifier operator is no longer an operator and treats it noparse[/noparse] as a string. I’m considering filing a separate ASC bug for this one since it’s a bit different. Edit: It’s here: http://bugs.adobe.com/jira/browse/ASC-3794

Anyway, let me know what you think! (-: