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

After quitting MacVim a vim process consuming 99.8% CPU is left #1423

Closed
6 tasks done
RStankov opened this issue Aug 11, 2023 · 8 comments · Fixed by #1427
Closed
6 tasks done

After quitting MacVim a vim process consuming 99.8% CPU is left #1423

RStankov opened this issue Aug 11, 2023 · 8 comments · Fixed by #1427

Comments

@RStankov
Copy link

RStankov commented Aug 11, 2023

Steps to reproduce

  1. Open Mac
  2. Do some work
  3. Cmd + W Cmd + Q

What happens

This happens some times.

Can't really catch when.

Usually I catch it by seeing the following in the terminal

Vim: Caught deadly signal SEGV

Then I open Activity Monitor and check for VIM

Screenshot 2023-08-11 at 13 36 07

I noticed this happening about ~3 weeks ago. Might have happen before that.

One week ago I added github-copilot to my vimrc, but this issue was happening before that

Expected behaviour

Close MacVim and all related issues.

Version of Vim and architecture

MacVim r177 (Vim 9.0.1677)

Environment

OS: 13.4.1 (c) (22F770820d)
Model: Mac Book Pro
Processor: Apple M1 Max

How MacVim was installed

Downloaded

Logs and stack traces

No response

Vim configuration where issue is reproducable

https://github.com/RStankov/config_files/blob/master/dot/vimrc

Issue has been tested with given configuration

  • by running MacVim.app from GUI macOS interface
  • by running vim/gvim/etc installed by MacVim
  • by running other versions of vim (e.g. /usr/bin/vim)

Issue has been tested with no configuration

  • by running mvim --clean (or gvim, supplied by MacVim distribution)
  • by running vim --clean (in terminal, supplied by MacVim distribution)
  • by running vim --clean (in terminal, other suppliers, e.g. /usr/bin/vim)
@ychin
Copy link
Member

ychin commented Aug 11, 2023

Huh that's not great. So basically Vim crashed and yet is using max CPU? One thing that's been on my TODO list is to expose crash logs better so it's easier for users to find them.

I posted some instructions at this comment before (#1407 (comment)). Basically you can directly find them in Console.app, or ~/Library/Logs/DiagnosticReports. If you see it again (or if it's recent), feel free to see if you find the crash log. I would be interested to see where it's crashing. Thanks.

@RStankov
Copy link
Author

@ychin Here is the DiagnosticReports

Vim-2023-08-15-120214_ips.txt

I also had the following in the terminal:

2023-08-15 12:02:14.182 Vim[68081:14883398] *** -[NSMachPort handlePortMessage:]: dropping incoming DO message because the connection is invalid                                         [main]
2023-08-15 12:02:14.233 Vim[68081:14883398] *** Terminating app due to uncaught exception 'NSInvalidReceivePortException', reason: 'connection is invalid'
*** First throw call stack:
(
	0   CoreFoundation                      0x000000018df57154 __exceptionPreprocess + 176
	1   libobjc.A.dylib                     0x000000018da764d4 objc_exception_throw + 60
	2   Foundation                          0x000000018eefe60c -[NSConnection sendInvocation:internal:] + 2116
	3   CoreFoundation                      0x000000018debee30 ___forwarding___ + 976
	4   CoreFoundation                      0x000000018debe9a0 _CF_forwarding_prep_0 + 96
	5   Foundation                          0x000000018eefdb1c -[NSConnection rootProxy] + 56
	6   Vim                                 0x00000001023f5364 -[MMBackend serverList] + 52
	7   Vim                                 0x00000001023efb38 serverGetVimNames + 24
	8   Vim                                 0x0000000102197eb8 f_serverlist + 20
	9   Vim                                 0x00000001021d0704 call_internal_func + 268
	10  Vim                                 0x000000010239e1c0 call_func + 1836
	11  Vim                                 0x000000010239d978 get_func_tv + 508
	12  Vim                                 0x00000001021cd480 eval_func + 248
	13  Vim                                 0x00000001021ccf60 eval9 + 1176
	14  Vim                                 0x00000001021ce698 eval8 + 292
	15  Vim                                 0x00000001021ce244 eval7 + 52
	16  Vim                                 0x00000001021cdd40 eval6 + 76
	17  Vim                                 0x00000001021cdae0 eval5 + 48
	18  Vim                                 0x00000001021cd838 eval4 + 56
	19  Vim                                 0x00000001021cd52c eval3 + 48
	20  Vim                                 0x00000001021c4614 eval1 + 52
	21  Vim                                 0x000000010239d68c get_func_arguments + 232
	22  Vim                                 0x000000010239d814 get_func_tv + 152
	23  Vim                                 0x00000001021cd480 eval_func + 248
	24  Vim                                 0x00000001021ccf60 eval9 + 1176
	25  Vim                                 0x00000001021ce698 eval8 + 292
	26  Vim                                 0x00000001021ce244 eval7 + 52
	27  Vim                                 0x00000001021cdd40 eval6 + 76
	28  Vim                                 0x00000001021cdae0 eval5 + 48
	29  Vim                                 0x00000001021cd838 eval4 + 56
	30  Vim                                 0x00000001021cd52c eval3 + 48
	31  Vim                                 0x00000001021c4614 eval1 + 52
	32  Vim                                 0x000000010239d68c get_func_arguments + 232
	33  Vim                                 0x000000010239d814 get_func_tv + 152
	34  Vim                                 0x00000001021cd480 eval_func + 248
	35  Vim                                 0x00000001021ccf60 eval9 + 1176
	36  Vim                                 0x00000001021ce698 eval8 + 292
	37  Vim                                 0x00000001021ce244 eval7 + 52
	38  Vim                                 0x00000001021cdd40 eval6 + 76
	39  Vim                                 0x00000001021cdae0 eval5 + 48
	40  Vim                                 0x00000001021cd838 eval4 + 56
	41  Vim                                 0x00000001021cd724 eval3 + 552
	42  Vim                                 0x00000001021c4614 eval1 + 52
	43  Vim                                 0x00000001021cd04c eval9 + 1412
	44  Vim                                 0x00000001021ce698 eval8 + 292
	45  Vim                                 0x00000001021ce244 eval7 + 52
	46  Vim                                 0x00000001021cdd40 eval6 + 76
	47  Vim                                 0x00000001021cdae0 eval5 + 48
	48  Vim                                 0x00000001021cd838 eval4 + 56
	49  Vim                                 0x00000001021cd724 eval3 + 552
	50  Vim                                 0x00000001021c4614 eval1 + 52
	51  Vim                                 0x00000001021c81c0 eval0_retarg + 100
	52  Vim                                 0x00000001021c3e00 eval_to_bool + 228
	53  Vim                                 0x0000000102200014 ex_if + 272
	54  Vim                                 0x00000001021f2984 do_cmdline + 11312
	55  Vim                                 0x000000010239f9fc call_user_func_check + 2288
	56  Vim                                 0x000000010239e180 call_func + 1772
	57  Vim                                 0x000000010239d978 get_func_tv + 508
	58  Vim                                 0x00000001023a5d00 ex_call + 684
	59  Vim                                 0x00000001021f2984 do_cmdline + 11312
	60  Vim                                 0x000000010217cd3c apply_autocmds_group + 1792
	61  Vim                                 0x000000010245119c getout + 524
	62  Vim                                 0x00000001023f8c94 -[MMBackend(Private) connectionDidDie:] + 296
	63  CoreFoundation                      0x000000018ded3180 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 148
	64  CoreFoundation                      0x000000018df6eeec ___CFXRegistrationPost_block_invoke + 88
	65  CoreFoundation                      0x000000018df6ee34 _CFXRegistrationPost + 440
	66  CoreFoundation                      0x000000018dea44cc _CFXNotificationPost + 704
	67  Foundation                          0x000000018ee028f4 -[NSNotificationCenter postNotificationName:object:userInfo:] + 88
	68  Foundation                          0x000000018f30deb8 -[NSConnection invalidate] + 340
	69  CoreFoundation                      0x000000018ded3180 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 148
	70  CoreFoundation                      0x000000018df6eeec ___CFXRegistrationPost_block_invoke + 88
	71  CoreFoundation                      0x000000018df6ee34 _CFXRegistrationPost + 440
	72  CoreFoundation                      0x000000018dea44cc _CFXNotificationPost + 704
	73  Foundation                          0x000000018ee028f4 -[NSNotificationCenter postNotificationName:object:userInfo:] + 88
	74  Foundation                          0x000000018ee55dd8 _NSPortDeathNotify + 60
	75  CoreFoundation                      0x000000018df5c54c ____CFMachPortChecker_block_invoke + 92
	76  libdispatch.dylib                   0x000000018dc4e874 _dispatch_call_block_and_release + 32
	77  libdispatch.dylib                   0x000000018dc50400 _dispatch_client_callout + 20
	78  libdispatch.dylib                   0x000000018dc5ebf8 _dispatch_main_queue_drain + 928
	79  libdispatch.dylib                   0x000000018dc5e848 _dispatch_main_queue_callback_4CF + 44
	80  CoreFoundation                      0x000000018df1fc54 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
	81  CoreFoundation                      0x000000018dedd3d4 __CFRunLoopRun + 1992
	82  CoreFoundation                      0x000000018dedc4b8 CFRunLoopRunSpecific + 612
	83  Vim                                 0x00000001023f240c -[MMBackend waitForInput:] + 316
	84  Vim                                 0x00000001023ec474 gui_mch_wait_for_chars + 84
	85  Vim                                 0x0000000102392578 ui_wait_for_chars_or_timer + 280
	86  Vim                                 0x0000000102392158 inchar_loop + 312
	87  Vim                                 0x00000001023e903c gui_wait_for_chars_buf + 140
	88  Vim                                 0x0000000102391f98 ui_inchar + 268
	89  Vim                                 0x0000000102222278 inchar + 676
	90  Vim                                 0x0000000102227030 vgetorpeek + 4124
	91  Vim                                 0x00000001022259a4 vgetc + 268
	92  Vim                                 0x0000000102227e24 safe_vgetc + 12
	93  Vim                                 0x000000010227e580 normal_cmd + 324
	94  Vim                                 0x000000010245155c main_loop + 640
	95  Vim                                 0x0000000102450e84 vim_main2 + 3756
	96  Vim                                 0x000000010244fc7c main + 7116
	97  dyld                                0x000000018daa7f28 start + 2236
)
libc++abi: terminating due to uncaught exception of type NSException
Vim: Caught deadly signal ABRT
Vim: Finished.

@ychin
Copy link
Member

ychin commented Aug 15, 2023

Oh interesting. That helps a lot! I just happen to be looking at that part of the code for unrelated reasons. Thanks for the logs.

@ychin ychin added this to the Release 178 milestone Aug 15, 2023
@ychin
Copy link
Member

ychin commented Aug 16, 2023

After some initial investigation, this is a weird confluence of factors due to how the IPC mechanism works (which is quite outdated and needs to be replaced in #1157). In particular, during shutdown, an autocmd triggers a serverlist() call in your configs, which ends up calling the invalidated connection since it's been shutdown. It only happens sometimes because usually shutdown is done cleanly.

I will submit a fix, but for now, if this bugs you, you could identify which plugin/config is calling serverlist() when BufWinLeave is triggered and disable that and I think it would alleviate the issue. You will still see a "dropping incoming DO message" message on terminal but it should at least shut down cleanly.

@ychin
Copy link
Member

ychin commented Aug 17, 2023

Actually are you sure you were doing Cmd-W when that happened? Or do you think you could be hitting Cmd-Q instead? It's fine if you don't remember, but it's just that the callstack makes me believe that was a Cmd-Q instead, although I'm still not sure.

@RStankov
Copy link
Author

Thanks.

I think in this case I did cmd + Q.

@RStankov
Copy link
Author

Actually when I observed more carefully most of the time the issue happens is when Cmd + Q is clicked. 🙄

What usually happens is I Cmd + Q and then work on something else. There I do Cmd + W and then notice the error and Activity Log, I wrongly associated this with Cmd + W. Sorry for misleading

@ychin
Copy link
Member

ychin commented Aug 21, 2023

Cool, thanks. There are actually a fair bit of issues with the current way that MacVim is structured as it's vulnerable to zombie orphaned Vim processes if something went wrong, so I'm trying to prioritize fixing the immediate issue first. I think the Cmd + Q one is easy to identify and fix so that's good to hear.

ychin added a commit to ychin/macvim that referenced this issue Sep 9, 2023
Currently, when quitting MacVim using Cmd-Q, if an autocmd queries
serverlist() during shutdown (e.g.  VimLeavePre), there's a potential
that Vim will crash and then stuck in a spinloop and never gets killed
by the parent process.

The reason is somehwat complicated. MMAppController tells Vim to quit
but has a hard-coded timer before terminating the connection. If Vim
takes too long to respond somehow, it will see a "connectionDidDie"
message where it will be forced to quit. The serverlist() IPC API call
isn't properly guarding against an invalid connection and if an autocmd
triggers that call during this time, it will throw an exception and
crash.

Usually if Vim crashes, it should terminate cleanly, but couple things
cause this to not work properly:
- Vim's signal handler `deathtrap` tries to exit cleanly, and invoke all
  deferred functions. These are added to the stack when we enter a new
  autocmd.
- The ObjC exception is thrown inside a CFRunLoop (which is what called
  connectionDidDie) and CFRunLoop silently handles the exception before
  re-throwing it which triggers the actual abort signal to be caught by
  Vim's signal handler, but at this time, the deferred functions data
  structure is messed up as the stack is already gone since the first
  exception unwound it. This leads to a bogus memory state and lead to
  an infinite loop in `invoke_all_defer`.

MacVim also doesn't have a solid mechanism to shut down zombie processes
right now (it depends on Vim cleaning up after itself), so after MacVim
quits, the now-orphaned Vim process stuck consuming 100% CPU.

The fix is to simply guard against this and make sure we clean up the
connection properly when we detected it died, and to be more defensive
and make sure the serverlist call properly guard against invalid states
and exceptions.

Not tackling the other issues for now. There are some unfortunate
interactions here with an unwound exception causing invoke_all_defer()
to not work, but we just need to make sure to guard potential places
with try/catch blocks, as invoke_all_defer() is still useful. Also,
proper zombie process killing will be done at a later time, as we will
soon tackle removing Distributed Objects/NSConnection and revamp the
entire IPC stack anyway.

Fix macvim-dev#1423
ychin added a commit to ychin/macvim that referenced this issue Sep 9, 2023
Currently, when quitting MacVim using Cmd-Q, if an autocmd queries
serverlist() during shutdown (e.g.  VimLeavePre), there's a potential
that Vim will crash and then stuck in a spinloop and never gets killed
by the parent process.

The reason is somehwat complicated. MMAppController tells Vim to quit
but has a hard-coded timer before terminating the connection. If Vim
takes too long to respond somehow, it will see a "connectionDidDie"
message where it will be forced to quit. The serverlist() IPC API call
isn't properly guarding against an invalid connection and if an autocmd
triggers that call during this time, it will throw an exception and
crash.

Usually if Vim crashes, it should terminate cleanly, but couple things
cause this to not work properly:
- Vim's signal handler `deathtrap` tries to exit cleanly when a signal
  is detected, and it tries to call all deferred functions (added by
  :defer in Vimscript). The list of functions are allocated on the stack
  rather than the heap.
- The ObjC exception is thrown inside a CFRunLoop (which is what called
  connectionDidDie) and CFRunLoop silently handles the exception before
  re-throwing it which triggers the actual abort signal to be caught by
  Vim's signal handler, but at this time, the deferred functions data
  structure is messed up as the stack is already gone since the first
  exception unwound it. This leads to a bogus memory state and lead to
  an infinite loop in `invoke_all_defer`.

MacVim also doesn't have a solid mechanism to shut down zombie processes
right now (it depends on Vim cleaning up after itself), so after MacVim
quits, the now-orphaned Vim process stuck consuming 100% CPU.

The fix is to simply guard against this and make sure we clean up the
connection properly when we detected it died, and to be more defensive
and make sure the serverlist call properly guard against invalid states
and exceptions.

Not tackling the other issues for now. There are some unfortunate
interactions here with an unwound exception causing invoke_all_defer()
to not work, but we just need to make sure to guard potential places
with try/catch blocks, as invoke_all_defer() is still useful. Also,
proper zombie process killing will be done at a later time, as we will
soon tackle removing Distributed Objects/NSConnection and revamp the
entire IPC stack anyway.

Fix macvim-dev#1423
ychin added a commit to ychin/macvim that referenced this issue Sep 9, 2023
Currently, when quitting MacVim using Cmd-Q, if an autocmd queries
serverlist() during shutdown (e.g.  VimLeavePre), there's a potential
that Vim will crash and then stuck in a spinloop and never gets killed
by the parent process.

The reason is somehwat complicated. MMAppController tells Vim to quit
but has a hard-coded timer before terminating the connection. If Vim
takes too long to respond somehow, it will see a "connectionDidDie"
message where it will be forced to quit. The serverlist() IPC API call
isn't properly guarding against an invalid connection and if an autocmd
triggers that call during this time, it will throw an exception and
crash.

Usually if Vim crashes, it should terminate cleanly, but couple things
cause this to not work properly:
- Vim's signal handler `deathtrap` tries to exit cleanly when a signal
  is detected, and it tries to call all deferred functions (added by
  :defer in Vimscript). The list of functions are allocated on the stack
  rather than the heap.
- The ObjC exception is thrown inside a CFRunLoop (which is what called
  connectionDidDie) and CFRunLoop silently handles the exception before
  re-throwing it which triggers the actual abort signal to be caught by
  Vim's signal handler, but at this time, the deferred functions data
  structure is messed up as the stack is already gone since the first
  exception unwound it. This leads to a bogus memory state and lead to
  an infinite loop in `invoke_all_defer`.

MacVim also doesn't have a solid mechanism to shut down zombie processes
right now (it depends on Vim cleaning up after itself), so after MacVim
quits, the now-orphaned Vim process stuck consuming 100% CPU.

The fix is to simply guard against this and make sure we clean up the
connection properly when we detected it died, and to be more defensive
and make sure the serverlist call properly guard against invalid states
and exceptions.

Not tackling the other issues for now. There are some unfortunate
interactions here with an unwound exception causing invoke_all_defer()
to not work, but we just need to make sure to guard potential places
with try/catch blocks, as invoke_all_defer() is still useful. Also,
proper zombie process killing will be done at a later time, as we will
soon tackle removing Distributed Objects/NSConnection and revamp the
entire IPC stack anyway.

Fix macvim-dev#1423
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants