reproduce_stack_overflow.py
text/x-python
Filename: reproduce_stack_overflow.py
Type: text/x-python
Part: 3
#!/usr/bin/env python3
# Reproduce stack overflow (SIGSEGV) in jsonb_plperl and jsonb_plpython3u.
import subprocess
import time
DEPTH = 100_000
PGLOG = "/home/eax/pginstall/data/logfile"
def psql(sql):
subprocess.run(["psql", "-c", sql], check=True, capture_output=True)
def run_test(label, query):
with open(PGLOG) as f:
f.seek(0, 2)
log_pos = f.tell()
print(f"{label} (depth={DEPTH}): ", end="", flush=True)
result = subprocess.run(["psql", "-c", query], capture_output=True)
time.sleep(2)
with open(PGLOG) as f:
f.seek(log_pos)
log = f.read()
if "signal 11" in log:
print("SIGSEGV")
for line in log.splitlines():
if "signal 11" in line or "DETAIL" in line:
print(" ", line.strip())
else:
output = result.stdout.decode().strip()
print(f"no crash:\n{output}")
if result.stderr:
print(result.stderr.decode().strip())
psql("CREATE EXTENSION IF NOT EXISTS jsonb_plpython3u CASCADE;")
psql("CREATE EXTENSION IF NOT EXISTS jsonb_plperl CASCADE;")
psql("""
CREATE OR REPLACE FUNCTION py_deep(n int) RETURNS jsonb
LANGUAGE plpython3u TRANSFORM FOR TYPE jsonb AS $$
d = 1
for i in range(n): d = {'x': d}
return d
$$;
""")
psql("""
CREATE OR REPLACE FUNCTION perl_deep(n int) RETURNS jsonb
LANGUAGE plperl TRANSFORM FOR TYPE jsonb AS $$
my $h = 1;
for my $i (1..$_[0]) { $h = {x => $h}; }
return $h;
$$;
""")
run_test("plpython3u", f"SELECT py_deep({DEPTH});")
# Wait for postmaster to restart the backend after the crash.
for _ in range(5):
result = subprocess.run(["psql", "-c", "SELECT 1;"], capture_output=True)
if result.returncode == 0:
break
time.sleep(2)
run_test("plperl ", f"SELECT perl_deep({DEPTH});")