fix(devtools): avoid pause-on-caught-throw for raw VM DAP attach

DevTool::attach(HSQUIRRELVM) enabled sq_notifyallexceptions, so with
break-on-error the error hook paused at the throw site before catch /
reportError ran. That left a second pause hanging after one DAP continue
and flaked as SEGFAULT on Linux CI teardown
(devtools.dap.caughtErrorPausesAtReportSite). Keep notify-all only on
Runtime-bound attach (hook already capture-only there) and force-resume
in the test if the script thread is still paused.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
This commit is contained in:
Cursor Agentand西风逍遥游 committed 2026-09-12 04:12:16 +00:00
1 parent 90831eb6b8
commit 2fa181645c
2 files changed
+16 -1

No files matched your search

+9 -1
View File
@@ -135,6 +135,10 @@ void DevTool::attach(ssq::VM& vm, bool sampleLocals) { attach(vm.getHandle(), sa
void DevTool::attach(eve::Runtime& runtime, bool sampleLocals) {
attach(runtime.vm(), sampleLocals);
runtime_ = &runtime;
// Capture throw-site stacks for try/catch so reportError / lastScriptError
// can surface the original site (load.nut pattern). Safe here because the
// Runtime-bound error hook only stashes context and does not notify/pause.
sq_notifyallexceptions(runtime.handle(), SQTrue);
// Route Runtime-boundary errors into the slicer/report. The VM error hook
// only captures the stack when this Runtime sink is bound; this handler
// reports compile / reflect / unload failures and uncaught execute errors
@@ -182,7 +186,11 @@ void DevTool::attach(HSQUIRRELVM vm, bool sampleLocals) {
Debugger::instance().setPump([this]() { pumpWhilePaused(); });
sq_enabledebuginfo(vm_, SQTrue);
sq_notifyallexceptions(vm_, SQTrue);
// Do not enable sq_notifyallexceptions here. With notify-all + break-on-error,
// this hook would pause on every caught throw before script catch/reportError
// runs (double pause → hung script thread → flaky teardown SEGFAULT in
// devtools.dap.caughtErrorPausesAtReportSite). Runtime::installErrorHandler
// already turns notify-all on for production VMs; attach(Runtime&) keeps it.
sq_setnativedebughook(vm_, nativeDebugHook);
// Route uncaught script errors into the debugger (break-on-error aware).
sq_newclosure(vm_, runtimeErrorHook, 0);
+7
View File
@@ -869,6 +869,13 @@ TEST_CASE("devtools.dap.caughtErrorPausesAtReportSite") {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
dap.poll();
}
// If the script thread is still blocked in waitWhilePaused, force-resume
// before teardown so dap.stop()/detach cannot race a paused VM (SEGFAULT).
if (!scriptDone.load() && dbg.isPaused()) dbg.resume();
for (int i = 0; i < 100 && !scriptDone.load(); ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
dap.poll();
}
if (scriptThread.joinable()) {
if (scriptDone.load())
scriptThread.join();