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

@vue/shared generateCodeFrame can infinite loop, breaking a build process. #3987

Closed
DV8FromTheWorld opened this issue Jun 21, 2021 · 7 comments · Fixed by #3992
Closed

@vue/shared generateCodeFrame can infinite loop, breaking a build process. #3987

DV8FromTheWorld opened this issue Jun 21, 2021 · 7 comments · Fixed by #3992
Labels
🐞 bug Something isn't working scope: compiler

Comments

@DV8FromTheWorld
Copy link
Contributor

DV8FromTheWorld commented Jun 21, 2021

Version

3.1.1

Reproduction link

https://github.com/DV8FromTheWorld/vue3-sfc-compiler-bug-repro-template

Steps to reproduce

  1. Pull the repo and npm install it.
  2. Run npm run serve
  3. Observe how the build process gets stuck and never completes when it is handing the BrokenComponent.vue file.

What is expected?

The build should complete and generate warnings about using undecorated <template> elements in Vue3.

What is actually happening?

The build hangs forever due to an infinite loop when generating the code frame to display with the vue-migration compatibility warning.


I originally encountered this problem when transitioning my application from Vue 2.6 to @vue/compat: 3.1.1. The problem surfaced as a Webpack build that would never complete the compilation step. The Vue-loader would successfully separate the SFC into the specific template/script/style portions and pitch them, but when compiling the template (thus generating migration warnings) the system will get stuck.

In the screenshot below observe that the generateCodeFrame will infinite loop.
image

This will infinite loop because j >= lines.length will resolve to true and hit the continue statement without incrementing count any further.

It is possible that the culprit causing this problem is not so much the generateCodeFrame function itself but instead the function calculating the loc for the start and end of the <template> ... </template>. From my testing, the loc.*.column and loc.*.line for both loc.start and loc.end were accurate, however the loc.*.offset for both seemed to be off by 75 - 110 characters. The generateCodeFrame code uses offset as it's source of truth here and thus could be the problem here.

Additionally, another issue caused by this oddity with the offset is that the code frame actually generated has the ^^^^^^^ pointers multiple times in a very confusing fashion. This is caused by the count not exceeding end fast enough.
image

@posva
Copy link
Member

posva commented Jun 22, 2021

The provided reproduction gives this:Screenshot 2021-06-22 at 11 08 52 and it doesn't hang in an infinite loop.

The loop you showed still increments j when it continues but maybe end > count never changes, probably creating the infinite loop you saw

@posva posva closed this as completed Jun 22, 2021
@posva posva reopened this Jun 22, 2021
@DV8FromTheWorld
Copy link
Contributor Author

The loop indeed does increment j but yes, as mentioned before, the problem is that end > count never changes. You can see that the debugger is currently stopped in a state of infinite loop by comparing the values shown in the Scope tab on the right.

I just freshly pulled the repository, ran npm i, and npm run serve.
I was able to see the error still:

image

Gif showing it happen
vue-infinite-loop-example

@DV8FromTheWorld
Copy link
Contributor Author

I'm not sure what more information I can provide given that the repo does break for me.
What direction would you like to pursue for this?

@posva
Copy link
Member

posva commented Jun 22, 2021

make sure you update the dependencies then. I used yarn to install them

@DV8FromTheWorld
Copy link
Contributor Author

Cleared my node_modules, installed yarn, ran yarn install and yarn run serve.
Resulted in the same behavior.

Here is the generated yarn.lock file if you'd like to do a diff between it and your own.
https://gist.github.com/DV8FromTheWorld/8bd1dc6dc8288b86663630b44f466324

@DV8FromTheWorld
Copy link
Contributor Author

...I bet this has to do with the way the parser is consuming characters and adjusting offset. This probably is a difference between \n and \r\n given you are on unix and I am on windows.

@DV8FromTheWorld
Copy link
Contributor Author

Yeah, so the problem here is:
https://github.com/vuejs/vue-next/blob/master/packages/shared/src/codeframe.ts#L8

Basically, everything else in the parser deals with \n vs \r\n by using the .length property, thus getting 1 or 2 respectively.
This split treats \n and \r\n identically, so every time another line is processed, the count will deviate from offset by 1 additional character.

If there are enough lines in the file proceeding the piece of code that the generateCodeFrame is suppose to be generating a codeframe for and not enough content after the fragment to make up for the disparity then this will loop forever.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
🐞 bug Something isn't working scope: compiler
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants