bug#63279: Segfault when printing a call-with-values stack frame in backtrace

"Thompson, David" <[email protected]>
Newsgroups gmane.lisp.guile.bugs
Message-ID <CAJ=RwfYZ7Tj_dpoF1a8LTkzrdtuK0jNy0zktjKX1=KKptvHwrA@mail.gmail.com>
Hello there,

Guile seems to segfault when trying to print certain backtraces with a
'call-with-values' stack frame.  Here's a minimal reproducer program:

(symbol? (call-with-values (lambda () (error 'oh-no)) list))

If you eval this at the REPL and enter ,bt in the debugger, Guile
should segfault.

Relevant gdb backtrace:

#0  0x00007ffff7f43397 in scm_is_values (x=<error reading variable:
ERROR: Cannot access memory at address 0x0>0x0) at
/tmp/guix-build-guile-3.0.9.drv-0/guile-3.0.9/libguile/values.h:30
#1  vm_regular_engine (thread=0x7ffff7401900) at
/tmp/guix-build-guile-3.0.9.drv-0/guile-3.0.9/libguile/vm-engine.c:974
#2  0x00007ffff7f50db5 in scm_call_n (proc=<optimized out>,
argv=<optimized out>, nargs=4) at
/tmp/guix-build-guile-3.0.9.drv-0/guile-3.0.9/libguile/vm.c:1615
#3  0x00007ffff7ebb674 in scm_call_4 (proc=<optimized out>,
arg1=<optimized out>, arg2=<optimized out>, arg3=<optimized out>,
arg4=<optimized out>) at
/tmp/guix-build-guile-3.0.9.drv-0/guile-3.0.9/libguile/eval.c:517
#4  0x00007ffff7eb801b in display_backtrace_body (a=0x7fffed68e6a0) at
/tmp/guix-build-guile-3.0.9.drv-0/guile-3.0.9/libguile/backtrace.c:239
#5  0x00007ffff7f62092 in scm_c_with_exception_handler.constprop.0
(type=#t, handler_data=handler_data@entry=0x7fffed68e630,
thunk_data=thunk_data@entry=0x7fffed68e630, thunk=<optimized out>,
handler=<optimized out>)
    at /tmp/guix-build-guile-3.0.9.drv-0/guile-3.0.9/libguile/exceptions.c:170

From what I can tell, in vm-engine.c, in the subr-call op,
'scm_apply_subr (sp, idx, FRAME_LOCALS_COUNT ())' is called and
returns an SCM object, which is stored in the local variable 'ret'.
Then 'scm_is_values (ret)' is called, and the segfault occurs due to a
null pointer dereference. At the time of the segfault, 'idx' is 1130,
corresponding to the 'frame-local-ref' subr. Makes sense since it's
the backtrace printer that crashes Guile.

It seems that the data stored in the stack frames for
'call-with-values' calls is incorrect and the backtrace printer wants
to display 3 arguments for the call when the procedure only accepts 2
arguments.  This can be clearly seen by running another small program
that happens to not segfault:

(call-with-values (lambda () (error 'oh-no)) list)

Check out the backtrace and you'll see a frame like this:

(_ #<procedure b34e28 at <unknown port>:8:18 ()> #<procedure list _> 1)

The first 2 arguments are as expected, but why is there a 1 at the end?

For another example that doesn't crash but has an even more clearly
messed up backtrace, try this:

(append '(a b c) (call-with-values (lambda () (error 'oh-no)) list))

You'll see a frame like this:

(_ #<procedure b39730 at <unknown port>:10:35 ()> #<procedure list _>
. #<unknown-type (0xb . 0x304) @ 0x7f50dd792050>)

At Spritely we've reproduced this issue on multiple machines with both
Guile 3.0.7 and 3.0.9.

- Dave
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.