diff --git a/src/scripts/frame.js b/src/scripts/frame.js index d44470c0..5db8b46b 100644 --- a/src/scripts/frame.js +++ b/src/scripts/frame.js @@ -1,3 +1,8 @@ +import infiniteLoopDetector from './makeitsafe.js'; +console.log(infiniteLoopDetector); +let infDetector = infiniteLoopDetector.infiniteLoopDetector; +console.log(infDetector); + // Defaults in case a game doesn't load. var code = "console.error('Nothing to run!!')"; let image_lookup = {}; @@ -82,9 +87,15 @@ let meta = { } console.dispatchEvent("evaluate", item); }; + + code = infDetector.wrap(code) try { eval(code); } catch (e) { + if (e.type === 'InfiniteLoopError') { + console.err('infinite loop detected') + } + var err = e.constructor(e.message); let trace = e.stack.split("\n")[1].split(":"); err.lineNumber = trace[trace.length - 2]; diff --git a/src/scripts/makeitsafe.js b/src/scripts/makeitsafe.js new file mode 100644 index 00000000..06b41618 --- /dev/null +++ b/src/scripts/makeitsafe.js @@ -0,0 +1,49 @@ +// TODO: Clean up. Not really wriotten for modules and a bit of a hack as is. +// Imports should be better, also may as well make this a proper javascript +// class opposed to whatever this is. + +var infiniteLoopDetector = (function() { + var map = {} + + // define an InfiniteLoopError class + function InfiniteLoopError(msg, type) { + Error.call(this ,msg) + this.type = 'InfiniteLoopError' + } + + function infiniteLoopDetector(id) { + if (id in map) { // Not the first execution, it can be optimized here, the performance is too low + if (Date.now() - map[id] > 1000) { + delete map[id] + throw new Error('Loop running too long!', 'InfiniteLoopError') + } + } else { // First run, record the time the loop started. All the judgments that are not first run are written in the previous if because the above will be executed more times + map[id] = Date.now() + } + } + + infiniteLoopDetector.wrap = function(codeStr) { + if (typeof codeStr !== 'string') { + throw new Error('Can only wrap code represented by string, not any other thing at the time! If you want to wrap a function, convert it to string first.') + } + // Replaces potential infite loop areas with a bit of guard code that makes + // and makes sure that the loop doesn't exceed some value of execution time. + // + // this is not a strong regex, but enough to use at the time + let response = codeStr.replace(/for *\(.*\{|while *\(.*\{|do *\{/g, function(loopHead) { + var id = parseInt(Math.random() * Number.MAX_SAFE_INTEGER) + return `infDetector(${id});${loopHead}infDetector(${id});` + }); + // console.log(response); + return response; + } + infiniteLoopDetector.unwrap = function(codeStr) { + return codeStr.replace(/infiniteLoopDetector\([0-9]*?\);/g, '') + } + + return infiniteLoopDetector +}()) + +module.exports.infiniteLoopDetector = infiniteLoopDetector; + +// todo: copied from https://github.com/xieranmaya/infinite-loop-detector/blob/master/infinite-loop-detector.js