From 80cce31b04d38ade5335feadc3342ad109c0f376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Tue, 22 Sep 2026 14:41:19 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3thread=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E7=88=B6=E5=8D=8F=E7=A8=8B=E6=98=A0=E5=B0=84?= =?UTF-8?q?=E6=96=B9=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit thread事件的处理搬到C之后,event.thread的参数约定和唯一的生产者(debugger.lua的setup_patch)不一致了:事件里的co是新协程,而hookmgr.gethost()是调用方(父协程),但映射仍按旧的C侧约定写成了coroutineTree[L] = co,方向反了。 而coroutineFrom/文档/native实现三处都要求child -> parent,且type == 1的擦除本来就用新协程当key,所以旧的写入方向自相矛盾。结果是拼不上父协程的栈,还可能拿到不在当前调用路径上的协程,和native结果构成环把CMD.stackTrace卡死。 同时把进入事件的updatehookmask目标改成新协程co,与native thread_hook更新被hook线程的行为对齐。 --- extension/script/backend/worker.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extension/script/backend/worker.lua b/extension/script/backend/worker.lua index ff7f45c2..12464a6a 100644 --- a/extension/script/backend/worker.lua +++ b/extension/script/backend/worker.lua @@ -945,10 +945,13 @@ end function event.thread(co, type) if not debuggeeReady() then return end + -- L是触发事件的协程,即co的调用方(父协程) local L = hookmgr.gethost() if co then if type == 0 then - coroutineTree[L] = co + coroutineTree[co] = L + hookmgr.updatehookmask(co) + return elseif type == 1 then coroutineTree[co] = nil end From 75f8e10982ed921c5350bf4feed78268cc1d023f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Tue, 22 Sep 2026 15:03:45 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20thread=E4=BA=8B=E4=BB=B6=E7=94=A8thr?= =?UTF-8?q?eadptr=E6=8A=8A=E5=8D=8F=E7=A8=8B=E8=BD=AC=E6=88=90=E5=9C=B0?= =?UTF-8?q?=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按review反馈:co是debugger.lua经rdebug.event传来的目标thread,copy_to_dbg_ref会把它变成一个新的worker侧refvalue userdata。它既不能当协程的标识(coroutineFrom插不到、退出事件也删不掉),更不能拿去调updatehookmask(会把载荷当lua_State*用)。 新增rdebug.threadptr,把线程转成调试目标中地址的lightuserdata;event.thread用它当key并传给updatehookmask。native函数缺失时跳过该事件,而不是把refvalue当成lua_State*。 --- docs/luadebug/visitor.lua | 8 ++++++++ extension/script/backend/worker.lua | 16 ++++++++++------ src/luadebug/rdebug_visitor.cpp | 10 ++++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/docs/luadebug/visitor.lua b/docs/luadebug/visitor.lua index 9472d700..a64bfe77 100644 --- a/docs/luadebug/visitor.lua +++ b/docs/luadebug/visitor.lua @@ -299,6 +299,14 @@ end function visitor.costatus(co) end +--- +---@param co refvalue +---@return lightuserdata? +---co不是thread返回nil,否则返回co在调试目标中的地址。该地址能作为协程的标识跨VM传递。 +--- +function visitor.threadptr(co) +end + --- ---@return integer ---等价于`collectgarbage "count"`。 diff --git a/extension/script/backend/worker.lua b/extension/script/backend/worker.lua index 12464a6a..83e1e468 100644 --- a/extension/script/backend/worker.lua +++ b/extension/script/backend/worker.lua @@ -948,12 +948,16 @@ function event.thread(co, type) -- L是触发事件的协程,即co的调用方(父协程) local L = hookmgr.gethost() if co then - if type == 0 then - coroutineTree[co] = L - hookmgr.updatehookmask(co) - return - elseif type == 1 then - coroutineTree[co] = nil + -- co是调试目标里的协程,转成地址才能在调试器侧标识它 + co = rdebug.threadptr and rdebug.threadptr(co) + if co then + if type == 0 then + coroutineTree[co] = L + hookmgr.updatehookmask(co) + return + elseif type == 1 then + coroutineTree[co] = nil + end end end hookmgr.updatehookmask(L) diff --git a/src/luadebug/rdebug_visitor.cpp b/src/luadebug/rdebug_visitor.cpp index 5168f7d7..96f96bfe 100644 --- a/src/luadebug/rdebug_visitor.cpp +++ b/src/luadebug/rdebug_visitor.cpp @@ -1247,6 +1247,15 @@ namespace luadebug::visitor { return 1; } + static int visitor_threadptr(luadbg_State* L, lua_State* hL, protected_area& area) { + if (!copy_from_dbg(L, hL, area, 1, LUADBG_TTHREAD)) { + return 0; + } + luadbg_pushlightuserdata(L, lua_tothread(hL, -1)); + lua_pop(hL, 1); + return 1; + } + static int visitor_gccount(luadbg_State* L, lua_State* hL, protected_area& area) { int k = lua_gc(hL, LUA_GCCOUNT, 0); int b = lua_gc(hL, LUA_GCCOUNTB, 0); @@ -1319,6 +1328,7 @@ namespace luadebug::visitor { { "watch", protected_call }, { "cleanwatch", protected_call }, { "costatus", protected_call }, + { "threadptr", protected_call }, { "gccount", protected_call }, { "cfunctioninfo", protected_call }, #if LUA_VERSION_NUM >= 503