This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git

commit 2ffca2d99f80d86eaf6f704141b3ed68d31ec15a
Author: Andrew Stitcher <[email protected]>
AuthorDate: Tue Oct 6 17:03:21 2026 -0400

    PROTON-2986: Don't crash closing a listener that never listened
    
    Both libuv and win_iocp proactors would crash if you close a listener that
    was never added to the proactor, because they would try to access the NULL
    proactor on closing.
    
    Added a test to ensure there is no regression in this behaviour.
    
    Assisted-By: Claude Opus 5 <[email protected]>
---
 c/src/proactor/libuv.c      | 5 ++++-
 c/src/proactor/win_iocp.cpp | 3 +++
 c/tests/proactor_test.cpp   | 9 +++++++++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/c/src/proactor/libuv.c b/c/src/proactor/libuv.c
index 59cd1c653..c12e1d4d8 100644
--- a/c/src/proactor/libuv.c
+++ b/c/src/proactor/libuv.c
@@ -1367,7 +1367,10 @@ pn_listener_t *pn_listener(void) {
 void pn_listener_close(pn_listener_t* l) {
   /* May be called from any thread */
   uv_mutex_lock(&l->lock);
-  listener_close_lh(l);
+  /* Don't crash if we never passed it to a proactor */
+  if (l->work.proactor) {
+    listener_close_lh(l);
+  }
   uv_mutex_unlock(&l->lock);
 }
 
diff --git a/c/src/proactor/win_iocp.cpp b/c/src/proactor/win_iocp.cpp
index 85d5821c5..d64ab0cb7 100644
--- a/c/src/proactor/win_iocp.cpp
+++ b/c/src/proactor/win_iocp.cpp
@@ -3160,6 +3160,9 @@ static void listener_begin_close(pn_listener_t* l) {
 
 void pn_listener_close(pn_listener_t* l) {
   csguard g(&l->context.cslock);
+  /* Don't crash if we never passed it to a proactor */
+  if (!l->context.proactor)
+    return;
   listener_begin_close(l);
   wakeup(&l->psockets[0]);
 }
diff --git a/c/tests/proactor_test.cpp b/c/tests/proactor_test.cpp
index 8c1e4c9d7..8a32f654f 100644
--- a/c/tests/proactor_test.cpp
+++ b/c/tests/proactor_test.cpp
@@ -194,6 +194,15 @@ TEST_CASE("proactor_connect_close_before_open") {
   REQUIRE(h.proactor_inactive_);
 }
 
+/* Close a listener that was never passed to pn_proactor_listen(). Thread 
safety
+   is the only documented precondition, so this must not crash. */
+TEST_CASE("proactor_listener_close_before_listen") {
+  pn_listener_t *l = pn_listener();
+  REQUIRE(l != nullptr);
+  pn_listener_close(l);
+  pn_listener_free(l);
+}
+
 /* Failing name lookup - connect to invalid hostname. */
 TEST_CASE("proactor_name_lookup_fails") {
   common_handler h;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to