Your message dated Tue, 30 Jun 2026 14:41:42 +0000
with message-id <[email protected]>
and subject line Bug#1140806: fixed in pycurl 7.47.0-1
has caused the Debian Bug report #1140806,
regarding python3-pycurl: WebSocket test deadlock under libcurl 8.21.0 (lazy
PONG + read-only select)
to be marked as done.
This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.
(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)
--
1140806: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1140806
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: python3-pycurl
Version: 7.46.0-1
Severity: important
Tags: upstream
User: [email protected]
Usertags: autopkgtest
Control: affects -1 + curl
Dear Maintainer,
While investigating the autopkgtest regression blocking the migration
of vsftpd (3.0.5-1) to testing, I discovered that the newly introduced
WebSocket test case in pycurl consistently deadlocks and fails under
libcurl >= 8.21.0 inside autopkgtest (LXC) environments:
tests/test_websocket.py::test_default_mode_autopongs_server_ping
Correlation with libcurl 8.21.0:
- PASS: Runs against libcurl 8.20.0 (from testing) pass 100% of the time.
- FAIL: Runs against libcurl 8.21.0 (from unstable, including rc3) fail 100% of
the time.
This regression was triggered by the upstream security fix for
CVE-2026-11586 in curl 8.21.0.
Root Cause & Deadlock Mechanism:
1. The PycURL Test Loop
In tests/test_websocket.py, the helper _recv catches
BlockingIOError and calls _wait_readable, which polls the
socket only for readability:
r, _, _ = select.select([fd], [], [], timeout) # Empty write list
2. curl 8.21.0 "Lazy PONG" (CVE-2026-11586)
To prevent memory exhaustion, upstream commit 849317ff5c5a5e13f50ec3d0
removed the immediate flush from ws_enc_add_cntrl() and made
PONG sending lazy. The PONG frame is now merely buffered in
ws->pending to be flushed during subsequent I/O.
3. The Deadlock
In non-blocking mode, when curl_ws_recv() consumes the incoming
PING frame from the socket receive buffer, no application-layer data
(TEXT or BINARY) is yet available to return. Consequently,
curl_ws_recv() naturally returns CURLE_AGAIN (raising
BlockingIOError in Python) to yield control.
Crucially, under curl 8.21.0's new "lazy PONG" design, the generated
PONG frame is only buffered in ws->pending and has not yet been
flushed to the socket.
Because the PycURL test loop immediately suspends in a read-only
select() upon receiving BlockingIOError, the client blocks
forever waiting for readability. The server, waiting for the PONG,
sends no further data. Since the client is blocked in select(),
it never invokes any subsequent libcurl API to drive the write
queue, leaving the PONG permanently trapped in ws->pending.
4. The Latent Bug in PycURL's I/O Loop
In non-blocking mode with CONNECT_ONLY, the application has the
obligation to drive the outbound write queue (either by polling
for write-readiness or invoking subsequent libcurl APIs to flush
pending output). The pycurl test helper _wait_readable violates
this by only polling for readability. This latent bug was exposed
by libcurl's new lazy PONG design. While alternative options like
CURLWS_NOAUTOPONG (CURLOPT_WS_OPTIONS) exist, the default mode
requires a robust non-blocking drive.
[Why Increasing Timeout is Ineffective]
Increasing the client-side timeout (even to 60.0s) does not resolve
the deadlock. The mock server's underlying websockets library has
a hardcoded 10.0-second close_timeout:
# websockets/asyncio/connection.py
class Connection:
def __init__(..., close_timeout: float | None = 10, ...):
After exactly 10.0 seconds of waiting for the PONG, the server
forcefully closes the TCP connection (sending a FIN packet). This
wakes the client's select(), which then calls ws_recv() and
immediately fails with CURLE_GOT_NOTHING (52, "Server returned
nothing").
Execution trace obtained by adding print debug messages to the
client-side execution path (60s timeout):
=== PHASE 3: The Deadlock (PING received, PONG trapped) ===
[DEBUG CLIENT] ws_recv raised BlockingIOError at 0.000798s
[DEBUG CLIENT] Entering _wait_readable (remaining=59.493937s) at 0.001020s
[DEBUG CLIENT] Exited _wait_readable at 10.008510s # Trapped
for exactly 10.0s until server FIN
[DEBUG CLIENT] Calling ws_recv at 10.008932s
FAILED (pycurl.error: 52, 'Server returned nothing')
strace of pytest running the websocket test case:
18:12:26.595986 recvfrom(11, ..., 65535, 0, ...) = -1 EAGAIN # Read-side
yield, socket is empty
18:12:26.596821 pselect6(12, [11], NULL, NULL, ...) <unfinished ...> #
Read-only select (writefds is NULL)
...
[10.0-second silence: PONG remains trapped in ws->pending, zero outbound
writes on fd 11]
...
18:12:36.603624 close(12) <unfinished ...> # Server close_timeout (10s)
expires, sending FIN
18:12:36.603798 <... pselect6 resumed> = 1 (in [11]) # Woken by TCP FIN
18:12:36.604703 recvfrom(11, "", 65535, ...) = 0 # Connection closed
(EOF), raising CURLE_GOT_NOTHING
[Proposed Temporary Workaround]
Since a complete fix requires upstream architectural refactoring of
the non-blocking I/O loop, marking this test as xfail is proposed
as a temporary workaround to unblock package migrations in Debian.
diff --git a/tests/test_websocket.py b/tests/test_websocket.py
index d9268f7..0b764db 100644
--- a/tests/test_websocket.py
+++ b/tests/test_websocket.py
@@ -381,6 +381,7 @@ def test_ws_recv_would_block(wscurl, ws_app):
assert exc_info.value.errno == errno.EAGAIN
[email protected](run=False, reason="flaky deadlock on non-blocking
auto-PONG without write-ready drive")
def test_default_mode_autopongs_server_ping(wscurl, ws_app):
wscurl.setopt(pycurl.URL, ws_app + "/ping-and-report-pong")
wscurl.setopt(pycurl.CONNECT_ONLY, 2)
Thanks,
Keng-Yu Lin
--- End Message ---
--- Begin Message ---
Source: pycurl
Source-Version: 7.47.0-1
Done: Scott Talbert <[email protected]>
We believe that the bug you reported is fixed in the latest version of
pycurl, which is due to be installed in the Debian FTP archive.
A summary of the changes between this version and the previous one is
attached.
Thank you for reporting the bug, which will now be closed. If you
have further comments please address them to [email protected],
and the maintainer will reopen the bug report if appropriate.
Debian distribution maintenance software
pp.
Scott Talbert <[email protected]> (supplier of updated pycurl package)
(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing [email protected])
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Format: 1.8
Date: Mon, 29 Jun 2026 15:37:32 -0400
Source: pycurl
Architecture: source
Version: 7.47.0-1
Distribution: unstable
Urgency: medium
Maintainer: Debian Python Team <[email protected]>
Changed-By: Scott Talbert <[email protected]>
Closes: 1140806
Changes:
pycurl (7.47.0-1) unstable; urgency=medium
.
* Update to new upstream release 7.47.0 (Closes: #1140806)
Checksums-Sha1:
5c8ceb87b4bf5f7b1e8e79b72743f04ede1dc3b8 2786 pycurl_7.47.0-1.dsc
1901857fec3a0b34b614483b442fb9b22b406c02 216768 pycurl_7.47.0.orig.tar.xz
9cb64e962ee777ed1ae859aaa58cb0187cce3f3e 11364 pycurl_7.47.0-1.debian.tar.xz
480e695ed71bbabc04c2990d632b9ad0ab57ff0b 11970 pycurl_7.47.0-1_amd64.buildinfo
Checksums-Sha256:
ae3a7d3f0663fed35c6604f5bf12f65c6fa59a67a1a6f360770952cebbe5a7e9 2786
pycurl_7.47.0-1.dsc
8f5404e39b359b850ab92e6b13f7b2e16a1000d2f77668a14547cbae82830c61 216768
pycurl_7.47.0.orig.tar.xz
eab482dc58c0816e2300e2b8909eaeb897a87aabf4522c09eaf5a3f51968953f 11364
pycurl_7.47.0-1.debian.tar.xz
643629d206055bcd13180f9fa9de4f3b5b907c5164211f4bf63d0bcdb3e5865f 11970
pycurl_7.47.0-1_amd64.buildinfo
Files:
6c300f955b07880045215f4029795ece 2786 python optional pycurl_7.47.0-1.dsc
ea4eca914a4403de0ab59f7585b88a18 216768 python optional
pycurl_7.47.0.orig.tar.xz
584211bfbf3fa5411431e9497fdef014 11364 python optional
pycurl_7.47.0-1.debian.tar.xz
7ffecfbd3443a3d00b4b002dd71d8ba3 11970 python optional
pycurl_7.47.0-1_amd64.buildinfo
-----BEGIN PGP SIGNATURE-----
iQJDBAEBCgAtFiEEbnQ09Yl9Q7F/zVe3U9W8ZLUjeKIFAmpDzA8PHHN3dEB0ZWNo
aWUubmV0AAoJEFPVvGS1I3iiEKgP/j/yYx4aGBfeSNa3hrdM69L48+Kz3YJwEjlK
Kcv0VqivUaghe9T4HE2y9rcQMQ1SE/6joeB4WCr8UKzzYXmaX/bvIDuurLN1mAfw
ABOxaoZEUt2ojVlM3RsvQ9CIV5ejmlpW8N5o5LhMDOIW2D/Yf5srWeFh+ChyTnX0
uaX3ctGaahlERutzWb+FpTF8WeQwKS33iarCjDktuCJo/mZqpYZp89IVWfAG9vdY
RWIdkt+WlUWo5YGoR2Dtbs+VtsTpYh/AHY8jQHTu/J6YagYIfL6E18nqA/pwE8GN
A/KWw2bl7IhTlitE6On+mTzxec9dAym+MOmic8jSipa1CxRv+etemFNDdLy6hAQ7
WBlJqEIz2sviH7Y0COm9Up6bEdm2iA9WVSAIqX2EniXtW7V8mlK6J3ORpYMXBhjC
tcQSNPwLMCDkuAaGZrrXHF/zgOR4VgF/IhOLnxjYr+s6BXag7CiyCwp49gQwwCsw
U2JEgN9pfeOoBHx0TABXD8IunNiq6Kat4iZDHmjm9ACRxxtkdtCfd7WSv2gQ9KTv
2LvVCH9JhFPmN0SpFxzHfYIEwox84fUagPCVEr3wkAf3lT46FNPpbiwGIBf5tB+8
jUnklEdKzFtDac9enV8oRQedXxEyaCMfX2KIRXJ5GJVfGOgEAFJNNx+hgt3Opbh+
/XcK6WyP
=RGmp
-----END PGP SIGNATURE-----
pgpNyAICHF5Z8.pgp
Description: PGP signature
--- End Message ---