Summary

chicken.base#implicit-exit-handler reporting segmentation violation with non-default heap size

Metadata

Attachments

Description

I was experimenting with the "Man-or-boy" test (http://rosettacode.org/wiki/Man_or_boy_test) using Chicken Scheme; my variant looks like this:

 vjo@glaucus/pts/11:chicken/man_or_boy % cat test.scm
 (import (chicken process-context)
         (chicken fixnum))
 
 (define (A k x1 x2 x3 x4 x5)
   (let
       ([+ fx+]
        [- fx-]
        [<= fx<=])
     (define (B)
       (set! k (- k 1))
       (A k B x1 x2 x3 x4))
     (if (<= k 0)
         (+ (x4) (x5))
         (B))))
 
 (define k (let ([args (command-line-arguments)])
             (if (> (length args) 0)
                 (string->number (car args))
                 10)))
 (print (A k
           (lambda () 1)
           (lambda () -1)
           (lambda () -1)
           (lambda () 1)
           (lambda () 0)))

This compiles fine, and runs great with the default heap size up to a value of k=27:

 vjo@glaucus/pts/11:chicken/man_or_boy % csc -O4 test.scm
 vjo@glaucus/pts/11:chicken/man_or_boy % time ./test 26
 -21051458
 ./test 26  25.20s user 1.31s system 99% cpu 26.577 total
 vjo@glaucus/pts/11:chicken/man_or_boy % time ./test 27
 -46750171
 ./test 27  101.91s user 4.42s system 99% cpu 1:46.66 total

At k=28, however, we run out of heap, with the default settings:

 vjo@glaucus/pts/11:chicken/man_or_boy % time ./test 28
 [panic] out of memory - heap has reached its maximum size - execution terminated
 
 ...more...
 test.scm:14: B
 test.scm:11: A
 test.scm:14: B
 test.scm:11: A
 test.scm:13: x4
 test.scm:11: A
 test.scm:14: B
 test.scm:11: A
 test.scm:14: B
 test.scm:11: A
 test.scm:13: x4
 test.scm:11: A
 test.scm:14: B
 test.scm:11: A
 test.scm:14: B
 test.scm:11: A  <--
 ./test 28  22.39s user 3.79s system 99% cpu 26.282 total

No problem, say I; let me re-compile with an increased heap. That works well - and the code gives back the correct answer - but, I now encounter the bug I wish to report:

 vjo@glaucus/pts/11:chicken/man_or_boy % csc -O4 -heap-size 4096M test.scm
 vjo@glaucus/pts/11:chicken/man_or_boy % time ./test 28
 -103821058
 
 Error: segmentation violation
 
         Call history:
 
         test.scm:13: x5
         test.scm:11: A
         test.scm:13: x4
         test.scm:13: x5
         test.scm:13: x5
         test.scm:11: A
         test.scm:13: x4
         test.scm:11: A
         test.scm:13: x4
         test.scm:13: x5
         test.scm:13: x5
         test.scm:11: A
         test.scm:13: x4
         test.scm:13: x5
         test.scm:20: chicken.base#print
         chicken.base#implicit-exit-handler              <--
 ./test 28  90.91s user 1.71s system 99% cpu 1:32.65 total

It *appears* that the implicit-exit-handler triggers a segmentation violation for any binary compiled with a non-default heap size specified; as an illustrative example, here is the same code compiled with two different heap sizes and executed using k=26. The first shows what happens with an insufficient heap size, the second shows what happens when the heap size is *just barely* sufficient, but non-default value:

 vjo@glaucus/pts/11:chicken/man_or_boy % csc -O4 -heap-size 928M test.scm
 vjo@glaucus/pts/11:chicken/man_or_boy % time ./test 26
 [panic] out of memory - heap full - execution terminated
 
 ...more...
 test.scm:14: B
 test.scm:11: A
 test.scm:14: B
 test.scm:11: A
 test.scm:13: x4
 test.scm:11: A
 test.scm:14: B
 test.scm:11: A
 test.scm:14: B
 test.scm:11: A
 test.scm:13: x4
 test.scm:11: A
 test.scm:14: B
 test.scm:11: A
 test.scm:14: B
 test.scm:11: A  <--
 ./test 26  5.01s user 0.44s system 99% cpu 5.471 total
 
 vjo@glaucus/pts/11:chicken/man_or_boy % csc -O4 -heap-size 929M test.scm
 vjo@glaucus/pts/11:chicken/man_or_boy % time ./test 26
 -21051458
 
 Error: segmentation violation
 
         Call history:
 
         test.scm:13: x5
         test.scm:13: x5
         test.scm:11: A
         test.scm:13: x4
         test.scm:11: A
         test.scm:13: x4
         test.scm:11: A
         test.scm:13: x4
         test.scm:13: x5
         test.scm:13: x5
         test.scm:13: x5
         test.scm:11: A
         test.scm:13: x4
         test.scm:13: x5
         test.scm:20: chicken.base#print
         chicken.base#implicit-exit-handler              <--
 ./test 26  25.87s user 0.73s system 99% cpu 26.620 total

The versions of all software involved have been determined below:

 vjo@glaucus/pts/11:chicken/man_or_boy % csc -O4 -kv test.scm          
 '/usr/bin/chicken' 'test.scm' -output-file 'test.c' -optimize-level 4 -verbose
 'x86_64-linux-gnu-gcc' 'test.c' -o 'test.o' -c  -fno-strict-aliasing -fwrapv
 -DHAVE_CHICKEN_CONFIG_H -DC_ENABLE_PTABLES -g -O2
 -fdebug-prefix-map=/build/chicken-8b5V5S/chicken-5.1.0=. -fstack-protector-strong -Wformat
 -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -I/usr/include/chicken
 'x86_64-linux-gnu-gcc' 'test.o' -o 'test' -L/usr/lib -Wl,-R/usr/lib -lchicken -lm -ldl
 
 vjo@glaucus/pts/11:chicken/man_or_boy % x86_64-linux-gnu-gcc --version
 x86_64-linux-gnu-gcc (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008
 Copyright (C) 2019 Free Software Foundation, Inc.
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 vjo@glaucus/pts/11:chicken/man_or_boy % csc -version                  
 CHICKEN
 (c) 2008-2019, The CHICKEN Team
 (c) 2000-2007, Felix L. Winkelmann
 Version 5.1.0 (rev 8e62f718)
 linux-unix-gnu-x86-64 [ 64bit dload ptables ]

Changes and comments

[2021-01-15 04:20:16 UTC] vjorlikowski attached test.scm (description=Man-or-boy test file source)

[2021-01-15 08:51:59 UTC] sjamaan changed milestone from someday to 5.3

[2021-01-15 10:25:59 UTC] sjamaan wrote:

NOTE: This only happens when compiling with `-maximum-heap-size`. When passing `-:hm` at runtime, I could not reproduce this issue.

[2021-01-15 10:52:06 UTC] sjamaan wrote:

This looks like some sort of corruption in the GC, as the pointer to the continuation of `cleanup-before-exit` seems to be broken.

[2021-01-15 11:54:58 UTC] sjamaan wrote:

Possibly there's a bug in the `reintern` option of `C_set_or_change_heap_size`, as that differs between `-:h` and `-heap-size`

[2021-01-16 13:03:40 UTC] megane wrote:

Just compiling an empty program with -heap-size gives the same result.

[2021-01-17 19:43:00 UTC] sjamaan wrote:

It looks like when `C_set_or_change_heap_size` is invoked with `reinit=1`, it only recreates the symbol table, but the termination continuation is still allocated on the old heap which is now in freed memory. This was allocated by `CHICKEN_initialize`.

I tried to copy that bit into the `if(reintern) ...` block of `C_set_or_change_heap_size` so that the termination continuation is pointing into the correct heap, but that didn't seem to fix the situation. I also tried resetting the temporary stack before doing this, but that didn't help either. I guess by the time the toplevel is called, the continuation pointer that's passed to it is still pointing into the old heap.

I think we need to longjump back and re-invoke the toplevel. But then it needs to know that it shouldn't try to resize the heap *again*. Or somehow we must do something with the termination continuation. Maybe not allocate it on the heap?

Possibly instead treat the heap reallocation as a reallocating GC?

[2021-04-18 11:22:20 UTC] felix changed milestone from 5.3 to 5.4

[2021-04-21 14:15:54 UTC] megane wrote:

Patch posted https://lists.nongnu.org/archive/html/chicken-hackers/2021-03/msg00009.html

[2023-11-06 22:17:27 UTC] felix changed milestone from 5.4 to 6.0.0

[2023-11-14 18:48:38 UTC] felix changed milestone from 6.0.0 to someday