From patchwork Mon May 18 19:18:38 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 135230 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 165814BB24F5 for ; Mon, 18 May 2026 19:19:14 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 165814BB24F5 X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-wm1-f52.google.com (mail-wm1-f52.google.com [209.85.128.52]) by sourceware.org (Postfix) with ESMTPS id C2F4D4BB1C24 for ; Mon, 18 May 2026 19:18:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C2F4D4BB1C24 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=palves.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org C2F4D4BB1C24 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=209.85.128.52 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1779131921; cv=none; b=g1NB8DwzfBk0EExiTYCEbsdMEIRVHv2DWqLuxskzh7n3y28aLApbfUOXeV9o6TxqCwFhTmXsKbq2Dr1KvK3JNEQcGyXubBkI21++e1E9mmGOwAY6OUJpoBUmO83XostMyYMZop3Avv3qFZ6ByIOBUEqFSKsaJES2yIwaCEiyNSk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1779131921; c=relaxed/simple; bh=J6RJbehd3yfexxRRFm9cwx7HB7jRYfRvZ9hg1+/THZw=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=nRpk4cuk+hs1kzOEH/nAXxypfLA+D9odUOTpYcCP/eQ8ZwRH5eit3MDyoMxMD6CyIlGU/yqFYJkzYxGfmxw/+xk7VDpw/Z15UsGUFri7MH4JxshNgENl5eDvAJDPXCAD9AkX2Uqmn8ZayD47fKuiFgALhx0wr09iDd1p2gt9doQ= ARC-Authentication-Results: i=1; sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C2F4D4BB1C24 Received: by mail-wm1-f52.google.com with SMTP id 5b1f17b1804b1-48fde648a71so19301845e9.0 for ; Mon, 18 May 2026 12:18:41 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779131920; x=1779736720; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=ZdpCfb4Ecjpp8l1oV6EkUBG5HbcjwWXKM2BdSKuCPdY=; b=UIMs4mMXxK6+bEG9a3PTdDL05C4CY6MQWf956IrWc8VqTd3OKfMuj+KzAduJVuG+aK dladNK5tEcS/Pue9PW6t88OPvYnqRYWXIfCe8W8a7vCAifyZ/yaAyGwI9FKssz9xRUOt ZV6DgOebjxA13YtBCcxpQGyPOcibEs5iVqBoMiFpI7jyru+KroTGSPPXBcZW3W+igBmg bKTzI/n4c+MAFMz4Hmq+d10tmvkvFUakc9tZrylCEkEaLiBGzYkGUh7RhGqWLvoL3EHr S7NX9XYBnfNfOXLW1tqW/0/ebtFW2uj5az1UiYVxXgi4JUt3lYZq6ZnYVDE/F2J+wbPO lArA== X-Gm-Message-State: AOJu0YzLQrsYVeONe8HDx7hp9agkyDLkPpC8QwHEXoIo0sugg5nciwiA 2jmRZ/GsJVvZrU5SkQxb28FXI9yltfaG6fAHMeMbydtkobc17drCJ/s4edGrqg== X-Gm-Gg: Acq92OEIQfLSKEWZEHd3xexk8LM6+QJJS8MNr9MOKENFB6UTIwPGXTi74gXPB6LkeZH F1Hkqib2eD6dd7NMDxZUKtja6fUZmOkGlhFD3k0eDYi6unrvxy3oCkY8GRWRbSI+cb/rh9FIdmI qmZ30pYBP6sWM5U5CkkqqUC8o/19Km7yXq10C3cboKcJs7jWORwWB661XpRKR7093twr8cesyM9 b2+SbPUG0bQx+HL++Z+gjZFnY9CbOWf8cWKED1X0j+YlEGvWHbB5TO5EdEwn03g21GDlPzB+jER 91QFl1B+U7QwVoexpOccAg+CLBW5ZTQtgHnSMHz5ngzFFvWIcTzKAzYWw9dAvcxugSfI2NVqeL/ hN+qEkfzXT4etWW3cPbewk9QUPlQ6wuGEELtHavujc+upuxzidHcKpYaqpbo5gRmEXuYWEtqvdj kcydnH1AtVrpQokaL1/SpVbQ== X-Received: by 2002:a05:600c:5010:b0:486:faa8:9e4 with SMTP id 5b1f17b1804b1-48fe5388407mr241257035e9.12.1779131919761; Mon, 18 May 2026 12:18:39 -0700 (PDT) Received: from localhost ([2001:8a0:fae3:2600:55b5:d85a:dc79:9161]) by smtp.gmail.com with UTF8SMTPSA id 5b1f17b1804b1-48fea52a0bfsm134015305e9.0.2026.05.18.12.18.39 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 18 May 2026 12:18:39 -0700 (PDT) From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH] Sync thread state after infcalls with "set unwind-on-* on" (PR gdb/34148) Date: Mon, 18 May 2026 20:18:38 +0100 Message-ID: <20260518191838.1301993-1-pedro@palves.net> X-Mailer: git-send-email 2.53.0 MIME-Version: 1.0 X-Spam-Status: No, score=-8.8 required=5.0 tests=BAYES_00, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_PBL, SPF_HELO_NONE, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org Commit 519774805a1 ("Don't pretend infcalls don't set the inferior running (PR gdb/34082)") removed the special case in proceed that skipped set_state(THREAD_RUNNING) for infcalls. That fixed gdb.threads/hand-call-new-thread.exp, but introduced a regression in gdb.compile/compile.exp: ... set unwind-on-signal on (gdb) PASS: gdb.compile/compile.exp: set unwind-on-signal on compile code *(volatile int *) 0 = 0; The program being debugged received signal SIGSEGV, Segmentation fault while in a function called from GDB. GDB has restored the context to what it was before the call. To change this behavior use "set unwind-on-signal off". Evaluation of the expression containing the function (_gdb_expr) will be abandoned. (gdb) PASS: gdb.compile/compile.exp: compile code segfault second break 132 Breakpoint 2 at 0x555555555262: file .../compile.c, line 132. (gdb) continue Cannot execute this command while the selected thread is running. (gdb) FAIL: gdb.compile/compile.exp: continue to breakpoint: break-here The "compile code" command before the FAIL is an infcall under the hood. That hits SIGSEGV with "set unwind-on-signal on" in effect, so GDB unwinds and abandons the call. After that, "continue" is rejected because the thread is still marked THREAD_RUNNING from the proceed that started the infcall. When an infcall is unwound due to a signal, timeout, or terminating exception, call_thread_fsm::should_notify_stop returns false, and so normal_stop is not called from fetch_inferior_event. normal_stop is what would normally call finish_thread_state to sync the public thread state back to THREAD_STOPPED. run_inferior_call has a fallback finish_thread_state call for that purpose, but it is gated on stop_stack_dummy == STOP_STACK_DUMMY, which is only true for successful calls. Before the commit mentioned above, proceed never marked an infcall's thread as THREAD_RUNNING, so the missing RUNNING => STOPPED transition was harmless. The old comment in infcall.c about the finish_thread_state call claimed "If the infcall does NOT succeed, normal_stop will have already finished the thread states", but that was already incorrect for the unwind paths. It just happened to not matter. Fix this by dropping the STOP_STACK_DUMMY guard and updating the comment to describe the actual rule: sync regardless of how the call ended. The !was_running check is kept since it is there to exclude the in-cond-eval case, where the thread is meant to stay marked running. finish_thread_state is idempotent, so the call is harmless on paths where normal_stop also ran. Extend gdb.base/unwindonsignal.exp to exercise the "set unwind-on-signal on" path without having to rely on the "compile code" feature. Without the fix, the test fails like so: info threads Id Target Id Frame * 1 Thread 0x7ffff7f8f740 (LWP 239019) "unwindonsignal" (running) (gdb) FAIL: gdb.base/unwindonsignal.exp: thread is stopped continue Cannot execute this command while the selected thread is running. (gdb) FAIL: gdb.base/unwindonsignal.exp: continue until exit at after unwound infcall Similarly, extend gdb.cp/gdb2495.exp for "set unwind-on-terminating-exception on", and gdb.base/infcall-timeout.exp for "set unwind-on-timeout on". Both would fail without the code fix, too. With the fix, gdb.compile/compile.exp now passes cleanly. Tested on x86_64-unknown-linux-gnu. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34148 Change-Id: Idef0dcd4dd751b501869c58b752f77d4dadb6c72 commit-id: 1a8b36d4 --- gdb/infcall.c | 23 ++++++++++++++-------- gdb/testsuite/gdb.base/infcall-timeout.exp | 13 ++++++++++++ gdb/testsuite/gdb.base/unwindonsignal.exp | 10 ++++++++++ gdb/testsuite/gdb.cp/gdb2495.exp | 6 ++++++ 4 files changed, 44 insertions(+), 8 deletions(-) base-commit: f6c1ca239d932db39a6f19d9bd343f4f4fddba76 diff --git a/gdb/infcall.c b/gdb/infcall.c index 8b26f541de6..e6b24ff5310 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -918,12 +918,20 @@ run_inferior_call (std::unique_ptr sm, current_ui->register_file_handler (); } - /* If the infcall does NOT succeed, normal_stop will have already - finished the thread states. However, on success, normal_stop - defers here, so that we can set back the thread states to what - they were before the call. Note that we must also finish the - state of new threads that might have spawned while the call was - running. The main cases to handle are: + /* Sync the user/frontend thread states from the internal thread + states. proceed marked threads in resume_ptid as THREAD_RUNNING + for this infcall; we must now sync them back, regardless of how + the call ended. For the success path and for the unwind paths + (unwind-on-{signal,timeout,terminating-exception}), + call_thread_fsm::should_notify_stop returns false and normal_stop + is skipped -- this call is the canonical place to do the sync. + For other failure paths normal_stop does run and has already + finished the thread state; finish_thread_state is idempotent, so + calling it again here is harmless. Note that we must also finish + the state of new threads that might have spawned while the call + was running. + + The main cases to handle are: - "(gdb) print foo ()", or any other command that evaluates an expression at the prompt. (The thread was marked stopped before.) @@ -934,8 +942,7 @@ run_inferior_call (std::unique_ptr sm, evaluates true and thus we'll present a user-visible stop is decided elsewhere. */ if (!was_running - && call_thread_ptid == inferior_ptid - && stop_stack_dummy == STOP_STACK_DUMMY) + && call_thread_ptid == inferior_ptid) finish_thread_state (call_thread->inf->process_target (), user_visible_resume_ptid (0)); diff --git a/gdb/testsuite/gdb.base/infcall-timeout.exp b/gdb/testsuite/gdb.base/infcall-timeout.exp index 37aa6c0ef54..99d29624337 100644 --- a/gdb/testsuite/gdb.base/infcall-timeout.exp +++ b/gdb/testsuite/gdb.base/infcall-timeout.exp @@ -86,6 +86,19 @@ proc run_test { target_async target_non_stop non_stop unwind } { gdb_test "bt" \ ".* function_that_never_returns .*.*" } + + # After the infcall, the thread should be stopped. Regression + # test for PR gdb/34148. + if {$non_stop} { + # Check the main thread only, in case we have system-spawned + # threads. + set thread_filter "1" + } else { + set thread_filter "" + } + gdb_test "info threads -running $thread_filter" \ + "No threads matched\\." \ + "thread is stopped" } foreach_with_prefix target_async { "on" "off" } { diff --git a/gdb/testsuite/gdb.base/unwindonsignal.exp b/gdb/testsuite/gdb.base/unwindonsignal.exp index aed8ef6f4c7..2ae8cc4a6dd 100644 --- a/gdb/testsuite/gdb.base/unwindonsignal.exp +++ b/gdb/testsuite/gdb.base/unwindonsignal.exp @@ -86,3 +86,13 @@ gdb_test_multiple "maint print dummy-frames" \ pass $gdb_test_name } } + +# After the unwound infcall, the thread should be stopped, and a +# subsequent resumption command should be accepted. Regression test +# for PR gdb/34148. + +gdb_test "info threads -running" \ + "No threads matched\\." \ + "thread is stopped" + +gdb_continue_to_end "after unwound infcall" diff --git a/gdb/testsuite/gdb.cp/gdb2495.exp b/gdb/testsuite/gdb.cp/gdb2495.exp index aa5a2a16e43..60396494161 100644 --- a/gdb/testsuite/gdb.cp/gdb2495.exp +++ b/gdb/testsuite/gdb.cp/gdb2495.exp @@ -64,6 +64,12 @@ gdb_test "p exceptions.throw_function()" \ "The program being debugged entered a std::terminate call, .*" \ "call a function that raises an exception without a handler." +# Make sure that the thread is stopped. Regression test for PR +# gdb/34148. +gdb_test "info threads -running" \ + "No threads matched\\." \ + "thread is stopped" + # Make sure that after rewinding we are back at the call parent. gdb_test "bt" \ "#0 main.*" \