New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Website crash #20
Comments
There's not much I can do to prevent from an infinite loop crashing the browser in this instance - the only alternative I can see here to prevent the crash is running tests in a worker thread. I'll have a think at what else can be done but since the tests are run on the main thread then whatever code you run has the potential to crash the tab. It's the same as if you were to run the code from your console. |
How about something along these lines: class Loopless {
static loopLimit = 2500;
/* Format: [
* RegExp Object to match loop syntax,
* Array that is joined using a random number to replace the original loop
* ][]
*/
static regExps = [
[
/\s*?for\s*?\((.*?;.*?;[^\)]*?)\)\s*?\{(?!\nloop_)/,
[
';\nconst loop_',
' = loopless.next();\nfor ($1) {\nloop_',
'();\n'
]
],
// ... Other loop structures go here ...
];
constructor() {
this.loops = [];
}
// Called before a loop, returns a function to increment the loops personal counter
next() {
const id = loops.length;
this.loops.push(0);
return () => {
const count = this.loops[id]++;
if (count > Loopless.loopLimit) {
throw new Error('Infinite Loop Broken');
}
};
}
// Loops through each RegExp on our static property, then replaces loops as long as a match is found
loopify(string) {
let count = Loopless.regExps.length;
while(--count > -1) {
const [regExp, template] = Loopless.regExps[count];
while(regExp.test(string)) {
// random number in the variable name so that multiple loop counters can run simultaneously
const randomNumber = Math.random().toString().split('.')[1];
const replacer = template.join(randomNumber);
string = string.replace(regExp, replacer);
}
}
return string;
}
}
// Instanciate
const loopless = new Loopless();
// This is an example of a test input by the end-user
const testInputString = `for (let index = 0, incrLoop = loopless.next(); index < 3000; index++) {
incrLoop();
console.log('Loop #' + index + ' complete');
}`;
// This will be the modified input
const modifiedString = loopless.loopify(testInputString);
// Pass the modified input to the test runner rather than logging it.
console.log(modifiedString); Basically it injects an iteration counter into each loop and throws an error at some predetermined limit. Enable it by default and give users who want more precise results a button to disable it. I haven't looked through the repository to see how feasible implementation is. Just happened to see the issue and thought I'd contribute to your brainstorming :) |
@ChuckTerry Thank you for thinking about this and your contribution. I was thinking of something similar but to address the while loop in @joooKiwi 's example we could do similar to your code by extending with a conditional.. class Loopless {
constructor() {
this.loops = []
this.loopLimit = 1000
}
static loopRegExp = [
[
/(?<keyword>while)\s+\((?<condition>.+)\)\s*/,
(condition, id) => `
while (${condition} && safeWhile.next(${id}))
`
]
]
// Method for adding a new protection conditional to while loops in string
protect (string) {
for (const [regExp, tpl] of Loopless.loopRegExp) {
const [,,condition] = string.match(regExp)
const id = this.loops.length
this.loops.push(0)
string = string.replace(regExp, tpl(condition, id))
}
return string
}
// Run for each loop, if loopLimit reached then error
next (id) {
if (this.loops[id]++ >= this.loopLimit) {
throw new Error('prevented infinite loop')
return false
}
return true
}
}
const safeWhile = new Loopless()
const modifiedString = safeWhile.protect('let a = 1; while (a++ < 10000) {}')
// Example of protected while loop which would be run in a test
let a = 1; const someExistingCondition = () => a++ < 10000
while (someExistingCondition() && safeWhile.next(0)) {
// Will throw an error after loop limit is reached
} |
@rd13 Oh, that's even better! I hadn't considered a passive injection method into the loop initialization for solving this type of problem. |
I agree that having an option to enable it or disable it could be great since sometimes, a predetermined amount of iteration is not enough for some tests. So far, from my testing with loops, The rest of the loops are not a whole lot at risk if we follow a basic structure. |
While attempting to do a performance difference between different kind of loops (with at least 100,000 entries),
I've done a mistake in the loop. Making it an infinite loop.
But, for some reason, the application cannot recover from it
https://jsperf.app/pexuwo/1/preview
The code was something like
But with that, it was an infinite loop.
The text was updated successfully, but these errors were encountered: