Skip to content
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

Infinite loop in vue-template-compiler #10547

Open
oguimbal opened this issue Sep 22, 2019 · 15 comments · May be fixed by #10553
Open

Infinite loop in vue-template-compiler #10547

oguimbal opened this issue Sep 22, 2019 · 15 comments · May be fixed by #10553

Comments

@oguimbal
Copy link

Version

2.6.10

Reproduction link

https://github.com/oguimbal/vuebug

Steps to reproduce

git clone git@github.com:oguimbal/vuebug.git
npm i
npm start

Wait a couple of seconds, and your compilation process will be frozen.

If you attach a debugger to the node process, you will see the infinite loop in generateCodeFrame() method of vue-template-compiler:

bug

What is expected?

I would expect the compiler not to freeze

What is actually happening?

The compiler is freezing

@posva
Copy link
Member

posva commented Sep 22, 2019

Hey, in order to check we need a boiled down repro without any extra dependency (like storybook). Ping me when you get a boiled down repro so I can get a look

@posva posva closed this as completed Sep 22, 2019
@oguimbal
Copy link
Author

oguimbal commented Sep 22, 2019

@posva No problem...

https://github.com/oguimbal/vuebug-simple

git clone git@github.com:oguimbal/vuebug-simple.git
cd vuebug-simple
npm i
code .

Then hit F5 (if using vscode, otherwise npm start) => freeze.

nb: I know that i forgot to include pug loader ... but thats the point, it freezes without error.

[edit] NB: The tight loop is in generateCodeFrame(), where line 16-17 seems fishy to me

@posva
Copy link
Member

posva commented Sep 23, 2019

It shows an error instead of freezing:

ERROR in ./bug.vue?vue&type=template&id=20e40a56&lang=pug& (./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./bug.vue?vue&type=template&id=20e40a56&lang=pug&)
Module Error (from ./node_modules/vue-loader/lib/loaders/templateLoader.js):
(Emitted value instead of an instance of Error)

  Errors compiling template:

  Component template requires a root element, rather than just text.

  1  |
     |
  2  |  div Whatever
     |  ^^^^^^^^^^^^
  3  |

 @ ./bug.vue?vue&type=template&id=20e40a56&lang=pug& 1:0-202 1:0-202
 @ ./bug.vue
 @ ./main.js

The error comes from vue-loader though. It could maybe display a warning if the specified lang does not contain a rule in the webpack config but at the same time the need of using pre processors is explained on the very first paragraph

@oguimbal
Copy link
Author

Not on my machine oO' (see screenshot as "proof")

However, if you look at this , it is kind of obvious that this loop can never finish in some circumstances.

For me, with my repo, it gets called that way:

generateCodeFrame(`
div Whatever
`, 2, 16)

Which freezes: https://codesandbox.io/embed/xenodochial-roentgen-5dbbq

image

@oguimbal
Copy link
Author

@posva I know know if you dont believe me or if you dont have the time to look at it, but I think it is probably due to the fact that I'm on Windows and you might not: My line breaks are \r\n instead of \n ...

Thus generateCodeFrame() gets called with "16" as length in the example above (which should be 14 without \r's)

The split const lines = source.split(/\r?\n/); removes those two caracters.

But the line count += lineLength + 1; does not take them into account (only adds 1 line return character), and there is no check that gets execution out of this infinite loop.

Anyway I wont bother you further with that, the problem is solved for me anyway :)

@posva
Copy link
Member

posva commented Sep 24, 2019

I see, you should use LF ending. It can be enforced through eslint via linebreak-style.
Let me check a bit more about this

@posva
Copy link
Member

posva commented Sep 24, 2019

Even when using CRLF endings in the bug.vue file (on osx), I get the same error as before, no infinite loop 🤔

@sodatea
Copy link
Member

sodatea commented Sep 24, 2019

I just reproduced this issue… The repository URL in OP is different from the one in the screenshot. The correct one is https://github.com/oguimbal/vuebug-simple
After cloning this repo & change the line endings I can reproduce the frozen output bug.

@sodatea
Copy link
Member

sodatea commented Sep 24, 2019

So… I believe this is a bug. PR's welcome.

@sodatea
Copy link
Member

sodatea commented Sep 24, 2019

Well I have found the culprit 😂

end: number = source.length

This line.
There're many warnings that do not provide the end position.
For those warnings, end is calculated by source.length. However, in the following for-loop, count is incremented by lineLength + 1, which is incorrect if the line ends with CRLF. Thus the infinite loop.

Also, this only happens when the template does not have an indentation because otherwise Vue would have normalized the template source during de-indentation

@sodatea
Copy link
Member

sodatea commented Sep 24, 2019

The fix is as simple as

end: number = source.replace(/\r\n/g, '\n').length
@oguimbal
Copy link
Author

Created a pull request that should fix it.

Just a suggestion that is a bit more agnostic about wether if this funciton input has CR in source.
( @sodatea fix would work, but only if caller does not provide the end argument).

Plus it breaks out of the loop if j >= lines.length ... if i'm correct, there is no good reason to stick in the loop in this case :)

@caiwang1993
Copy link

哈哈

@webwhy
Copy link

webwhy commented Nov 18, 2019

xx

@parthibd
Copy link

Any updates on this ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment