Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save FrostyX/73379ff510cd7acf897925199575299e to your computer and use it in GitHub Desktop.

Select an option

Save FrostyX/73379ff510cd7acf897925199575299e to your computer and use it in GitHub Desktop.
Resalloc subprocess timeout reproducer
#!/usr/bin/python3 -u
import time
print("LINE1")
print("LINE2")
time.sleep(99999)
print("LINE3")
print("LINE4")
#!/usr/bin/python3
print("PREFIX LINE1")
print("PREFIX LINE2")
print("PREFIX LINE3")
print("PREFIX LINE4")
#!/usr/bin/python3
import time
time.sleep(99999)
#!/usr/bin/python3 -u
import sys
sys.stdout.write("No newline at the end")
#!/usr/bin/python3
print("LINE1")
print("LINE2")
print("LINE3")
print("LINE4")
#!/usr/bin/python3 -u
import sys
sys.stdout.write("LINE1\n")
sys.stderr.write("LINE2\n")
sys.stdout.write("LINE3\n")
sys.stderr.write("LINE4\n")
import os
import select
import subprocess
import time
def run_command():
timeout=5
stdout_written = 0
stdout_stopped = False
catch_stdout_bytes = 5120
catch_stdout_lines_securely = True
command = ["./resalloc-timeout-reproducer-ok"]
command = ["./resalloc-timeout-reproducer-no-bytes"]
command = ["./resalloc-timeout-reproducer-no-eof"]
command = ["./resalloc-timeout-reproducer-no-bytes-hang-forever"]
command = ["./resalloc-timeout-reproducer-hang-after-output"]
command = ["./resalloc-timeout-reproducer-multiple-words"]
command = ["./resalloc-timeout-reproducer-stderr"]
with subprocess.Popen(command, stdout=subprocess.PIPE) as sp:
captured_string = b""
deadline = time.monotonic() + timeout
buffer = b""
while True:
# How many seconds are left before we want to timeout
remaining = deadline - time.monotonic()
if remaining <= 0:
sp.kill()
break
# Either we get a readable file descriptors back or we get nothing
# because the `select` timeouted on `read`
ready, _, _ = select.select([sp.stdout], [], [], remaining)
if not ready:
sp.kill()
break
chunk = os.read(sp.stdout.fileno(), 4096)
eof = chunk == b''
# We successfully read a chunk of data
if not eof:
buffer += chunk
# We encountered EOF but we still have unprocessed bytes
elif buffer:
# Treat partial line as a complete line
# TODO do we want this or rather discard the incomplete line?
buffer += b'\n'
# We encountered EOF and we already processed everything
else:
break
# Process all complete lines from buffer
while b'\n' in buffer:
line, buffer = buffer.split(b'\n', 1)
line += b'\n'
# Write to the log.
# logfile.write(line)
# logfile.flush()
if stdout_stopped:
continue
if stdout_written + len(line) > catch_stdout_bytes:
if stdout_written == 0 and not catch_stdout_lines_securely:
# Even the first line is too long for this buffer. Catch at
# least part of it.
line = line[:catch_stdout_bytes]
captured_string += line
stdout_stopped = True
if not catch_stdout_lines_securely:
captured_string += b"<< trimmed >>\n"
continue
stdout_written += len(line)
captured_string += line
# This is to handle EOF after processing a partial line
if eof:
break
return {
'status': sp.wait(),
'stdout': captured_string,
}
if __name__ == "__main__":
result = run_command()
print(f"STATUS: {result["status"]}")
print(f"STDOUT: {result["stdout"]}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment