How to catch and exception in a loaded SWF's global$init? - actionscript-3

My Flash program's loading a SWF that contains user code which has been compiled in real time. Because it's user code, it may throw exceptions. Unfortunately, I can't seem to catch the exceptions. This code doesn't work:
this._loader = new Loader();
this._loader.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, onUncaughtError);
this._loader.contentLoaderInfo.addEventListener(Event.COMPLETE, swfCompleteHandler);
this._loader.loadBytes(swfByteArray, loaderContext);
However, the debug player shows this in the unhandled exception dialog:
[Fault] exception, information=Error: Test error message
at global$init() [User_Code:3]
How do I catch an exception in global$init() of a loaded SWF? I've tried adding UNCAUGHT_ERROR event listeners to every loader and loaderInfo I can find... but none of them trigger when the exception is thrown from the loaded SWF's global$init(). Thanks in advance.

In cases where I could, I injected a try/catch into the user's code. For example, if the user code is simply:
trace("Hello");
My program modifies the code string to be:
try {
trace("Hello");
catch (Error error) { DoSomething(); }
However, this doesn't always work. For example, if the users' code is:
function output():void
{
throw new Error("Error!");
}
output();
Then the trick above doesn't work. Instead, I inject code like so:
startUserCode();
function output():void
{
throw new Error("Error!");
}
output();
endUserCode();
If endUserCode() doesn't get hit, I assume that an exception was thrown. I just don't know what exception. A nasty user could insert a random "return" into their code and endUserCode won't get hit but that's an edge case I decided to simply not handle.

Related

NetConnection unhandled NetStatusEvent

Occasionally I'm getting an unhanded NetStatusEvent when using NetConnection to connect to a Red5 server:
Error #2044: Unhandled NetStatusEvent:. level=error, code=NetConnection.Call.Failed
This is how I am connecting (the only place where NetConnection.connect() is called):
public function Connect(callBack:Function = null):void
{
if (IsConnected())
{
if (callBack != null)
{
callBack.call();
}
}
else // Not connected
{
netConnect.addEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void
{
// OnConnect called whenever there is a net status event
OnConnect(e, callBack);
netConnect.removeEventListener(NetStatusEvent.NET_STATUS, arguments.callee);
});
try
{
// Attempt to connect to Media Server
netConnect.connect(MEDIA_SERVER_URI, true);
}
catch(error:Error)
{
logger.LogError("NetConnection.connect threw an exception.", error);
}
}
}
I am adding an event listener for NetStatusEvent.NET_STATUS. How is it possible that sometimes my listener called?
You're removing your listener in your NetStatusEvent handler. You should keep it until the connection is closed. This is why NetStatusEvent is only handled once before its listener is removed. Any other than first event will throw that error.
So remove netConnect.removeEventListener(NetStatusEvent.NET_STATUS, arguments.callee);
NetConnection dispatches that event quite a lot, depending on what is happening. You have to handle the event until every time. For a list of possible values of the info property visit this Link. There's also a little example of how to handle the event at the end of the page.
You may see this if your client does not handle the onBWCheck or onBWDone methods. This will also happen if you have bandwidth detection turned on; turn it off on the server by changing this parameter in the red5.properties file and restart the server.
rtmp.bandwidth_detection=false
Blockquote
Just an additional piece of information. Dispatching NetStatusEvent objects with info.level = "error" will always throw an Unhandled Exception. Its a special use case. I, for example, wrap all of this functionality and change the level to "info" before re-dispatching the event.

How to handle security error and time out error of UrlLoader.load() in actionscript3?

I use UrlLoader.load() in my flash app.
And I'm handling UncaughtErrorEvent.UNCAUGHT_ERROR to stop the app when an uncaught exception occured.
UrlLoader.load() works when you are connecting the internet normally.
But if the connection to the internet was lost after your browser loaded the app,
SecurityError happens when UrlLoader.load() is called.
I can not catch the SecurityError by using try catch and UNCAUGHT_ERROR happens and it stops my app.
I don't want to stop the app when UrlLoader.load() failed because I'm just using UrlLoader.load() to log some unimportant information.
And I think timeout error also can be ocurred if it takes a long time to load.
And I also don't want to stop my app due to the time out error.
How can I solve those problems?
And are there more other type of errors which can be ocurred and stop my app?
The SecurityError exception is thrown when some type of security violation takes place.
Examples of security errors:
An unauthorized property access or method call is made across a security sandbox boundary.
An attempt was made to access a URL not permitted by the security sandbox.
A socket connection was attempted to an unauthorized port number, e.g. a port above 65535.
An attempt was made to access the user’s camera or microphone, and the request to access the device was denied by the user.
Lets say we have to load an swf from any external URL then:
// URL of the external movie content
var myRequest:URLRequest=new URLRequest("glow2.swf");
// Create a new Loader to load the swf files
var myLoader:Loader=new Loader();
// 1st level IO_ERROR input and output error checking
// Listen error events for the loading process
myLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioError);
function ioError(event:ErrorEvent):void
{
// Display error message to user in case of loading error.
output_txt.text = "Sorry that there is an IO error during the loading of an
external movie. The error is:" + "\n" + event;
}
function checkComplete(evt:MouseEvent)
{
// 2nd level SecurityError error checking
// Use the try-catch block
try
{
// Load the external movie into the Loader
myLoader.load(myRequest);
}
catch (error:SecurityError)
{
// catch the error here if any
// Display error message to user in case of loading error.
output_txt.text = "Sorry that there is a Security error during the
loading of an external movie. The error is:" + "\n" +
error;
}
}
movie1_btn.addEventListener(MouseEvent.CLICK, checkComplete);
// Listen when the loading of movie (glow.swf) is completed
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadMovie1);
function loadMovie1(myEvent:Event):void
{
// Display the Loader on the MainTimeline when the loading is completed
addChild(myLoader);
// Set display location of the Loader
myLoader.x = 200;
myLoader.y = 80;
}
Hope this will work for you.

Socket error - sometimes?

so - I have this Socket (not XMLSocket, just Socket) client. I also have a custom PHP script on my server, that listens on port X. My client tries to connect to it.
Everything works fine, the security and communication, sync and whatever else. But - the Flash Player (AIR runtime actually) shoots an error when trying to connect, but ONLY when the server is not running... What? It is really weird - the error is actually handled by try catch (IOError), and even weirder, the line that is specified in the output as the error line is the line where I just CREATE the Socket...?
Hm...
Output:
Error #2044: Unhandled IOErrorEvent:. text=Error #2031: Socket Error.
at ---.server::Client()[---/server/Client.as:167]
at Function/<anonymous>()[---_fla.MainTimeline::frame1:430]
at Function/<anonymous>()
at Function/<anonymous>()[---_fla.MainTimeline::frame1:375]
Code:
try {
Sock = new Socket(); // THIS is line 167
} catch (e:IOError){
log("Could not connect!");
status = "disconnected";
}
It does not really matter - the server is supposed to be still online, the errors won't show up... But ignoring an error is not good.
One more thing: when I comment out the line where I actually connect using Sock.connect(...) - it does not throw the error, but it obviously does not work... Also, the connect part is also in try catch (IOError) block...
WHY does Flash say the problem is on line 167 when it is obviously elsewhere? And / or what can be the problem?
This might not seem obvious if you had not worked with Flash previously, but many Errors in the net api are asynchronous. Meaning, you cannot catch them with a catch block, because the error is not thrown when you execute the connect method, but at a later point.
In fact, the error message says you have an uncaught IOErrorEvent not an IOError.
This is covered here:
http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/net/Socket.html#connect()
Basically, you have to add a handler for the IOErrorEvent (adding one for SecurityErrorEvent is a good idea as well). Something like this:
private function connect():void {
socket = new Socket(host,port);
// handle asynchronous errors in these handlers
socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
try {
socket.connect();
} catch(ioError:IOError) {
// handle synchronous errors here
} catch(secError:SecurityError) {
// and here
}
}
private function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: " + event);
}
private function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
}
I came across a similar error. It was occurring because I had removed the handler ioErrorHandler (removeEventListener) before issuing a sock.close(). sock.close() can throw an IoErrorEvent.
Even though the ioErrorEvent was thrown by sock.close(), the debugger showed it as unhandled error at the line where the socket constructor was called.
Calling the removeEventListener() after the sock.close() solved the problem.
Hope this helps.
I got the error in the same situation with wizard, and fixed it by change the order of close and remove event listener.

Adobe Air, packaged install fails with my trace routine... how come?

I cobbled together some code from here and there for a trace I like... it generates an error to get a stack trace and picks out the traced routine name, I like that detail in the trace log.
Problem: it fails in an installed AIR file. I wonder why? I don't expect it to do anything as is... just, I'd prefer it not cause the program to fail!
tx
artie
enter code here
static public function XTRACE( ... traceArgs ):void {
try {
throw new Error(); // make a stack
} catch (e:Error) {
var stack:String = e.getStackTrace();
var frames:Array = stack.split("\n");
var myFrame:String = String(frames[2]);
myFrame = myFrame.replace("\t", "");
// "at " can be followed by some part of the package
// you don't want to see. E.g., if your code is all in
// com.foo.bar, you can put "at com.foo.bar." so as not
// to crowd the display
myFrame = myFrame.substr("at ".length);
myFrame = myFrame.substring(0, myFrame.indexOf("["));
var now:Date = new Date();
trace(new Date().toLocaleTimeString() + ":" + myFrame + ": " + traceArgs.join(" "));
}
}
In what way is your app failing?
1) Trace routines are for debugging, so your trace won't do anything in an installed app.
2) I'm not sure when you call this routine, but it seems weird that you have a routine that only throws an error. I think in this code the 'catch' is only going to get entered if there's an error throwing the error. Normally you would try to perform some useful action, and catch errors when something goes wrong.
Within the trace function your attempting to invoke the Date().toLocaleTimeString() statically before it becomes instantiated by the new keyword. Try the following instead:
trace((new Date()).toLocaleTimeString() + ":" + myFrame + ": " + traceArgs.join(" "));
thanks for your input Fergal. The XTRACE function works fine running with the debug player, and fails only when running with the release player. So I assume the code line I use must associate values in the right order... I settled on using a function I didn't know about before:
enter code here
static public function XTRACE( ... traceArgs ):void {
if ( Capabilities.isDebugger ) {
With that, XTRACE does nothing unless it is executing in a debug environment. So it works around the issue. I'll still use your brackets though, I like to make order of association obvious too ;-)
I realize you've probably grown old and forgot what flash is since you asked this question. But, you're getting an NPE because e.getStackTrace() returns null in the release player.
A couple other things:
You don't need to throw the error to get a stack trace; new Error().getStackTrace() works fine.
Since this is debug code, and the calling code probably isn't expecting errors, you should wrap the whole thing in a try catch.
The compiler won't resolve 'at '.length, so it will be called every time at runtime. Unless you're really paranoid, you can just hard code it to 3.
Both the substrs can be combined into 1
The now variable isn't used.

Unhandled Socket securityError even when (seemingly) handling it

I Have a problem where I occasionally (i.e. not always) see the below error popup from the Debug Flash Player after launching my app:
Error #2044: Unhandled securityError:. text=Error #2048: Security sandbox violation: http://example.com/myApp.swf cannot load data from localhost:4499.
at org.mydomain.mypackage::MyClassUsingSocket()
at MyMainApplicationClass$cinit()
at global$init()
at global$init()
at flash.system::ApplicationDomain/hasDefinition()
at mx.managers::SystemManager/getDefinitionByName()
at _MyMainApplicationClass_mx_managers_SystemManager/create()
at mx.managers::SystemManager/initializeTopLevelWindow()
at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::docFrameHandler()
I have some code in this app that tries to connect to localhost:4499 via a Socket, and this error occurs when the socket server is not running and listening for the connections, which is to be expected. What I don't understand, however, is why Flash Player is complaining about unhandled securityErrors when I have try/catch blocks to catch the SecurityErrors when trying to connect the socket (as well as listeners for the SecurityErrorEvents, which this error message doesn't seem to point to, though).
The constructor of the relevant class is below:
/**
* Constructor.
*/
public function MyClassUsingSocket(aHost:String = null, aPort:int = -1):void
{
super();
var hostToConnectTo:String = (aHost != null) ? aHost : DEFAULT_HOST;
var portToConnectTo:int = (aPort != -1) ? aPort : DEFAULT_PORT;
try
{
_out_socket = new Socket();
// note: the event handlers used below are private functions within the same class
_out_socket.addEventListener(Event.CONNECT, _socketConnectEventHandler, false,0,true);
_out_socket.addEventListener(IOErrorEvent.IO_ERROR, _socketIOErrorEventHandler, false,0,true);
_out_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _socketSecurityErrorEventHandler, false,0,true);
_out_socket.connect(hostToConnectTo, portToConnectTo);
}
catch(e:IOError)
{
enabled = false;
}
catch(e:SecurityError)
{
enabled = false;
}
}
Any ideas on why this might be occurring? What am I missing?
I too struggled with this for a couple of hours. The solution is to listen for SecurityErrorEvent.SECURITY_ERROR. Apparently the SecurityError is only raised if there isn't such an event handler.
I don't think the errors that show in the dialog box are synchronous. I'm almost certain that they are thrown outside of your code path (during an async network event), so catching them with a try-catch is impossible.
So you'd think that listening for the right event on the right dispatcher would catch the error? I've tried listening to the stage, root, the object (the socket), but nothing suppresses the error.
Yep, it's pretty horrendous. I've been looking for a way to catch these little critters for a while now. The only consolation is that I think it is suppressed in the release version of the player. Still, it's cryptic huh? Not much documentation either (that I've found).
This isn't really an answer. Sorry.
This may not be the issue but you're catching SecurityError and its throwing securityError. Maybe try lowercasing the s.
Shot in the dark: try catching a generic Error?
try
{
_out_socket = new Socket();
// note: the event handlers used below are private functions within the same class
_out_socket.addEventListener(Event.CONNECT, _socketConnectEventHandler, false,0,true);
_out_socket.addEventListener(IOErrorEvent.IO_ERROR, _socketIOErrorEventHandler, false,0,true);
_out_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _socketSecurityErrorEventHandler, false,0,true);
_out_socket.connect(hostToConnectTo, portToConnectTo);
}
catch(e:IOError)
{
enabled = false;
}
catch(e:SecurityError)
{
enabled = false;
}
catch( e:Error )
{
trace( e );
}