pugjs / pug

Pug – robust, elegant, feature rich template engine for Node.js
https://pugjs.org
21.66k stars 1.95k forks source link

Detect empty loop #1825

Open marcelaraujo opened 9 years ago

marcelaraujo commented 9 years ago

Hey, I found this bug when I have this template

FATAL ERROR: JS Allocation failed - process out of memory

https://gist.github.com/marcelaraujo/e4b35cb90a15699a5f8a

screen shot 2015-01-13 at 16 07 50

ForbesLindesay commented 9 years ago

That compiles to an infinite loop:

- var n = 0
ul
    while n < 20
    = n++

is approximately like writing:

buf.push('<ul>');
while (n < 20) {
}
buf.push(n++);
buf.push('</ul>');

You need to indent the code within the while statement:

- var n = 0
ul
    while n < 20
        = n++

This error is unfortunately impossible to statically detect in the most general case (it requires solving the halting problem). We could, however, do one of two things that would perhaps produce useful results:

  1. Error on totally empty while block, at least if the condition is side effect free
  2. Record the start time when rendering templates, then check current time - start time inside any loops (for, while, do {...} while etc.) so we could time out after something like 10 seconds.

The first might be possible to make a non-breaking change, but it is very limited. The second option is a definite breaking change, and it makes for very slow feedback.

marcelaraujo commented 9 years ago

Owwww

Is this an old known issue?

Hummmm.. I don't think that any of given solutions would be the best choice because we don't know how long the Jade will take to complete the compile process.

Is there not any regular expression could catch this case?

vendethiel commented 9 years ago

This isn't an issue, the code is just misindented.

ForbesLindesay commented 9 years ago

@marcelaraujo This is a known issue with all turing complete languages. Look up "The Halting Problem". It is one of the most famous computer science problems there is. It cannot be caught with a regular expression.

It would of course be possible to catch the specific case you illustrated (as I suggested in option 1) but it is not possible in the most general case. Consider the following example JavaScript program:

function foo() {
  return true;
}
var i = 0;
while (i % 2 === 0) {
  i++;
  if (foo()) i++;
}

As a human I can prove that that program never terminates. It gets stuck in an infinite loop. The only way to know that for a computer though, is to execute the program. We may sometimes be able to do clever tricks to spot cases where it will never finish, but it is not possible in all cases.

ForbesLindesay commented 9 years ago

We can apply https://github.com/ForbesLindesay/halting-problem to loops, which will catch a lot of the most common of these cases.