views:

261

answers:

5

On a page, something like jsFiddle, that executes user inputed Javascript, is there a way to stop / disrupt "problem" scripts running in an iframe?

The major class of problem scripts would be infinite loops, I think. Browsers deal with multiple alerts quite well, but a script like, ​for (var i = 0; ++i; i < 100) { /* do stuff */ }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ will go forever.

How can I either detect and not run, or run and stop, say after 10 seconds of running, a script?

Removing the iframe is fine, but I only want to remove it if the script is still running after 10 seconds, but I don't want to remove it if the script has stopped running.


Here is how I imagine the page will work. If you have a better solution, let me know...

The input page contains a textarea and a blank iframe. The user enters their script into the textarea, and when ready they click on run. Then (backstage) a separate page is created that contains the user script in executable form on an HTML page. The src of the iframe is set to the page with the executable code. This all happens dynamically without a page refresh.

A: 

I think this would largely depend on the script and how browsers handle scripts in iframes.

Let's say there's a while(true) in the iframe.

The browser may either lock up, or crash the tab (like what Chrome does), or it might lock up the iframe. If it locks up or crashes the tab, there's nothing you can do with JS itself to prevent it, other than attempting static analysis on the script to find possibly problematic statements (Static analysis to find problematic scripts like that would never be foolproof)

Assuming the browser only locks up the iframe or does something else while still allowing the scripts in the main page to do things, removing the iframe after a certain period of time is an option.

The browser might also display the "Script is slow" popup. In this case, it will most likely either completely shut down all scripts in the entire tab or just in the iframe. If just the iframe, the other scripts in the tab could still clean up after it after the predefined period of time.

Another alternative would be to pre-evaluate the script in a separate runtime where you can detect things like that yourself. You could run the script in, say, Rhino, and determine if it takes too long to process, or something similar.

Jani Hartikainen
+1  A: 

If one script freezes on a page, other scripts will not continue to run. Therefore, there is no way to detect if another script has stopped running, without using a custom plugin or something. Browsers do not use multithreading in that way.

SimpleCoder
what about using try-catch statements?
Tom Brito
try-catch can catch errors, but they will do nothing to stop infinite loops.
SimpleCoder
+1  A: 

You could set a timeout in the main window which stops / deletes the script after 10 seconds. Then you just have to clear the timeout when the script has finished (just add a line like this to the iframe script: window.frames[0].clearTimeout(window.frames[0].timeoutName) -- I don't know if it works, but it should)

elektronikLexikon
Would this work if the script in the iframe was while(1); for example? I always thought setTimeout had to wait for the first opportunity(no other scripts running) after its timeout time. So if the script never gave a chance for setTimeout to run the browser would hang. With the iframe I am not sure though.
Bishnu
+2  A: 

I haven't used this jsandbox script, but it appears to have what you want.

fudgey
This or a similar approach should work because it uses HTML5 web workers, which run in parallel to the main page. As SimpleCoder said, many browsers run a single thread for all JavaScript, so JavaScript on the page would not be running if the JavaScript in the iframe is running in a tight loop.
Annie
I'm going to go with this answer. Thanks for the suggestion. It does look like a promising avenue to go down. I didn't have time to test it yet, but this seems like it is the most promising solution.
Peter Ajtai
A: 

I don't know if this would work exactly, you might be able to get something like this to work with a little bit of tinkering. I take it that you are taking in text JavaScript and then evaling it, right? You could parse or maybe even just use regex to replace all of the for, for..in, while, and function declaration's call with the function call then some logic that calls your code and figures out if it has been running for 10 secs. If it has it will either return; or break; or something. The code would likely freak out afterward and probably start throwing errors, but at least the script would stop.

Bishnu
I don't think I'd `eval()` the code. I would create a file that contains an executable version of the code (w PHP through an AJAX call), and then I would set the `src` of the `iframe` to that file.
Peter Ajtai
The above could still be done on the server side
Bishnu