Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/lgc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1624,16 +1624,24 @@ void luaC_inherit_thread(lua_State *L, lua_State *th)
{
int i;
GCheader *steal, *tmp;
thr_State *pt;

lua_lock(th);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double-locking th causes deadlock with existing callers

High Severity

The newly added lua_lock(th) inside luaC_inherit_thread double-locks th because at least two call sites already hold that lock. In reclaim_object (lgc.c), the caller does lua_lock(th) before calling luaC_inherit_thread(L, th). In lua_delrefthread (lapi.c), lua_lock(L) is called on the source thread which becomes the th parameter. If lua_lock is a non-recursive mutex, this will deadlock.

Additional Locations (1)

Fix in Cursor Fix in Web


if (th->heap == NULL) {
// already done
lua_unlock(th);
return;
}

pt = luaC_get_per_thread(L);

/* when a thread is reclaimed, the executing thread
* needs to steal its contents */
lock_all_threads();

block_collector(L, pt);

if (TEST_INHERIT_THREAD_DELAY_MS > 0) {
/* TR-1945: Both global trace and thread delref will grab
* the "all threads" lock. To induce false contention on that lock
Expand Down Expand Up @@ -1671,11 +1679,15 @@ void luaC_inherit_thread(lua_State *L, lua_State *th)
make_grey(L, steal);
}
TAILQ_REMOVE(&G(L)->all_heaps, th->heap, heaps);
unblock_collector(L, pt);

unlock_all_threads();

free(th->heap);
th->heap = NULL;

lua_unlock(th);

ck_pr_inc_32(&G(L)->need_global_trace);
}

Expand Down