From 8807cd53beb12ff9a022a9fa355e989e31fcc871 Mon Sep 17 00:00:00 2001 From: Marc Hartmayer Date: Tue, 9 Dec 2025 09:57:48 +0000 Subject: [PATCH] mitogen: first_stage: Break the while loop in case of EOF The current implementation can cause an infinite loop, leading to a process that hangs and consumes 100% CPU. This occurs because the EOF condition is not handled properly, resulting in repeated select(...) and read(...) calls. The fix is to properly handle the EOF condition and break out of the loop when it occurs. -SSH command size: 822 +SSH command size: 838 Preamble (mitogen.core + econtext) size: 18226 (17.80KiB) -mitogen.parent 99062 96.7KiB 51235 50.0KiB 51.7% 12936 12.6KiB 13.1% +mitogen.parent 99240 96.9KiB 51244 50.0KiB 51.6% 12956 12.7KiB 13.1% Fixes: https://github.com/mitogen-hq/mitogen/issues/1348 Signed-off-by: Marc Hartmayer --- docs/changelog.rst | 1 + mitogen/parent.py | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index af756f37..6d35b7b2 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -27,6 +27,7 @@ In progress (unreleased) * :gh:issue:`1354` docs: Document Ansible 13 (ansible-core 2.20) support * :gh:issue:`1354` :mod:`mitogen`: Clarify error message when a module request would be refused by allow or deny listing +* :gh:issue:`1348` :mod:`mitogen`: Fix hanging process with 100% CPU usage v0.3.35 (2025-12-01) diff --git a/mitogen/parent.py b/mitogen/parent.py index 9da5d58a..97681653 100644 --- a/mitogen/parent.py +++ b/mitogen/parent.py @@ -1436,11 +1436,16 @@ class Connection(object): os.environ['ARGV0']=sys.executable os.execl(sys.executable,sys.executable+'(mitogen:%s)'%sys.argv[2]) os.write(1,'MITO000\n'.encode()) + # Size of the compressed core source to be read + n=int(sys.argv[3]) # Read `len(compressed preamble)` bytes sent by our Mitogen parent. # `select()` handles non-blocking stdin (e.g. sudo + log_output). # `C` accumulates compressed bytes. C=''.encode() - while int(sys.argv[3])-len(C)and select.select([0],[],[]):C+=os.read(0,int(sys.argv[3])-len(C)) + # data chunk + V='V' + # Stop looping if no more data is needed or EOF is detected (empty bytes). + while n-len(C) and V:select.select([0],[],[]);V=os.read(0,n-len(C));C+=V # Raises `zlib.error` if compressed preamble is truncated or invalid C=zlib.decompress(C) f=os.fdopen(W,'wb',0)