luv icon indicating copy to clipboard operation
luv copied to clipboard

It's possible for Luv to call into Lua with an unusable state (i.e. during lua_close)

Open squeek502 opened this issue 6 years ago • 1 comments

See #414 and #436.

This is a more general problem than I thought. There are two things here:

  1. It's possible for Lua to be called out to during lua_close due to how handles work in Libuv. One example is in #414 where if there is a shutdown req on a stream handle during gc, then that gets called during uv_close of that handle (which can be during loop_gc). This can be triggered in other ways as well (like a close callback being called during loop_gc)
  2. We aren't handling handle closing properly/safely. In our handle_gc function, we free the handle memory if it's closing, but that is not safe to do, because in Libuv CLOSING and CLOSED are separate states (there can still be pending things on a closing handle like the flag UV_HANDLE_ENDGAME_QUEUED). It's only safe to free a handle once the callback from uv_close is called.

https://github.com/luvit/luv/blob/ab4a9ad98f4afc290fb5885e7b72d6127044fc18/src/handle.c#L116-L127

Running the code below will cause Luv to free the handle during GC and then Libuv will try to access it (because of UV_HANDLE_ENDGAME_QUEUED), causing an assert/crash/undefined behaviour (tested on Windows, different platforms have different closing procedures, so not sure if it happens everywhere):

local uv = require('luv')

local test = uv.new_pipe(false)
uv.close(test)
-- during loop_gc, test is marked as closing so luv frees its uv_handle_t memory,
-- but Libuv was not actually done with the handle and tries to access that memory
-- while the loop is walking the handles and closing them so that the loop can be closed

Note that adding a uv.run() at the end of the script fixes this specific case.


I'm not quite sure how to fix either of these. I'll need to do more research and maybe check into how Node handles this sort of thing if possible (Node might be different though since Luv gives direct access to uv_run and I don't think Node does?).

squeek502 avatar Nov 03 '19 06:11 squeek502

Partially addressed by https://github.com/luvit/luv/pull/654. See https://github.com/luvit/luv/pull/654#pullrequestreview-1576122356 for what's left to do for this issue.

squeek502 avatar Aug 14 '23 10:08 squeek502