segfault on erroneous program
Closed this issue · 14 comments
This program contains an undefined variable reference, and passes 2 arguments to a function expecting 1. It should not segfault:
$ eisl
Easy-ISLisp Ver2.32
> (defun fact (x) (if (< x 1) 1 (* x (fact (- x 10)A))))
FACT
> (fact 30)
Segmentation fault: 11
I couldn't reproduce it in my environment(Linux Ubuntu on WSL). Please tell me your OS.
$ eisl
Easy-ISLisp Ver2.32
> (defun fact (x) (if (< x 1) 1 (* x (fact (- x 10)A))))
FACT
> (fact 30)
Unbound variable at EVAL A
debug mode ?(help)
>>
Same macOS system Darwin despina 20.6.0 Darwin Kernel Version 20.6.0: Tue Oct 12 18:33:42 PDT 2021; root:xnu-7195.141.8~1/RELEASE_X86_64 x86_64 i386 iMac17,1 Darwin
I'm also unable to reproduce, on a slightly later version of macOS. :-(
23:46[pjb@despina org.xquartz:0 ~ 41Gi]$ eisl
Easy-ISLisp Ver2.32
> A
Segmentation fault: 11
~
23:46[pjb@despina org.xquartz:0 ~ 41Gi]$ eisl
Easy-ISLisp Ver2.32
> (let ((b 42)) (list a b))
Segmentation fault: 11
Perhaps we could catch all those signals, or use an atexit function, to dump the stack frames? https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
Both of your later examples behaved differently for me (i.e. signalled "unbound variable" error rather than crash) too, sorry.
Dumping stack frames on error exit is a good suggestion. It is certainly a good idea for debug builds. I'll look into it, so far as I can keep the code portable to POSIX rather than Linux-specific. To compensate for this lack I do the following in my workflow at present, but that may not be obvious:
- Build using the "DEBUG=1" make flag (see here)
- Set a breakpoint on
abort()
- Run under lldb (or gdb)
Ok, compiling with DEBUG=1, we get:
00:47[pjb@despina org.xquartz:0 eisl 41Gi]$ PREFIX=/usr/local make clean install OPSYS=macos DEBUG=1
rm -f *.o cii/src/except.o cii/src/fmt.o cii/src/str.o cii/src/text.o cii/src/memchk.o cii/src/assert.o nana/src/I.o eisl edlis
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c main.c -o main.o
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c function.c -o function.o
function.c:4715:1: warning: non-void function does not return a value [-Wreturn-type]
}
^
function.c:4960:10: warning: variable 'pexist' is used uninitialized whenever 'while' loop exits because its condition is false [-Wsometimes-uninitialized]
while (!nullp(body)) {
^~~~~~~~~~~~
function.c:5007:6: note: uninitialized use occurs here
if (pexist == 0 && qexist == 0)
^~~~~~
function.c:4960:10: note: remove the condition if it is always true
while (!nullp(body)) {
^~~~~~~~~~~~
1
function.c:4928:27: note: initialize the variable 'pexist' to silence this warning
pexist,
^
= 0
2 warnings generated.
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c extension.c -o extension.o
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c syntax.c -o syntax.o
syntax.c:477:6: warning: variable 'var' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
if (functionp(car(arg1)) || genericp(car(arg1))) {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
syntax.c:485:51: note: uninitialized use occurs here
list2(cadr(arg1), list2(makesym("QUOTE"), var))));
^~~
syntax.c:477:2: note: remove the 'if' if its condition is always true
if (functionp(car(arg1)) || genericp(car(arg1))) {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
syntax.c:431:24: note: initialize the variable 'var' to silence this warning
var,
^
= 0
1 warning generated.
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c data.c -o data.o
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c gbc.c -o gbc.o
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c cell.c -o cell.o
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c error.c -o error.o
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c bignum.c -o bignum.o
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c compute.c -o compute.o
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c edit.c -o edit.o
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c syn_highlight.c -o syn_highlight.o
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c long.c -o long.o
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c cii/src/except.c -o cii/src/except.o
cii/src/except.c:1:13: warning: unused variable 'rcsid' [-Wunused-variable]
static char rcsid[] = "$Id$" "\n$Id$";
^
1 warning generated.
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c cii/src/fmt.c -o cii/src/fmt.o
cii/src/fmt.c:23:23: warning: unused parameter 'code' [-Wunused-parameter]
static void cvt_s(int code, va_list_box *box,
^
cii/src/fmt.c:31:23: warning: unused parameter 'code' [-Wunused-parameter]
static void cvt_d(int code, va_list_box *box,
^
cii/src/fmt.c:52:23: warning: unused parameter 'code' [-Wunused-parameter]
static void cvt_u(int code, va_list_box *box,
^
cii/src/fmt.c:64:23: warning: unused parameter 'code' [-Wunused-parameter]
static void cvt_o(int code, va_list_box *box,
^
cii/src/fmt.c:76:23: warning: unused parameter 'code' [-Wunused-parameter]
static void cvt_x(int code, va_list_box *box,
^
cii/src/fmt.c:88:23: warning: unused parameter 'code' [-Wunused-parameter]
static void cvt_p(int code, va_list_box *box,
^
cii/src/fmt.c:101:23: warning: unused parameter 'code' [-Wunused-parameter]
static void cvt_c(int code, va_list_box *box,
^
cii/src/fmt.c:103:40: warning: unused parameter 'precision' [-Wunused-parameter]
unsigned char flags[], int width, int precision) {
^
cii/src/fmt.c:1:13: warning: unused variable 'rcsid' [-Wunused-variable]
static char rcsid[] = "$Id$";
^
9 warnings generated.
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c cii/src/str.c -o cii/src/str.o
cii/src/str.c:273:18: warning: unused parameter 'code' [-Wunused-parameter]
void Str_fmt(int code, va_list_box *box,
^
cii/src/str.c:1:13: warning: unused variable 'rcsid' [-Wunused-variable]
static char rcsid[] = "$Id$";
^
2 warnings generated.
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c cii/src/text.c -o cii/src/text.o
cii/src/text.c:38:35: warning: adding 'char' to a string pointer does not append to the string [-Wstring-plus-char]
const T Text_ucase = { 26, cset + 'A' };
~~~~~^~~~~
cii/src/text.c:38:35: note: use array indexing to silence this warning
const T Text_ucase = { 26, cset + 'A' };
^
& [ ]
cii/src/text.c:39:35: warning: adding 'char' to a string pointer does not append to the string [-Wstring-plus-char]
const T Text_lcase = { 26, cset + 'a' };
~~~~~^~~~~
cii/src/text.c:39:35: note: use array indexing to silence this warning
const T Text_lcase = { 26, cset + 'a' };
^
& [ ]
cii/src/text.c:40:35: warning: adding 'char' to a string pointer does not append to the string [-Wstring-plus-char]
const T Text_digits = { 10, cset + '0' };
~~~~~^~~~~
cii/src/text.c:40:35: note: use array indexing to silence this warning
const T Text_digits = { 10, cset + '0' };
^
& [ ]
cii/src/text.c:387:19: warning: unused parameter 'code' [-Wunused-parameter]
void Text_fmt(int code, va_list_box *box,
^
cii/src/text.c:1:20: warning: unused variable 'rcsid' [-Wunused-variable]
static const char *rcsid = "$Id$";
^
5 warnings generated.
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c cii/src/memchk.c -o cii/src/memchk.o
cii/src/memchk.c:35:49: warning: missing field 'link' initializer [-Wmissing-field-initializers]
static struct descriptor freelist = { &freelist };
^
cii/src/memchk.c:45:7: warning: variable 'bp' is used uninitialized whenever '||' condition is true [-Wsometimes-uninitialized]
if (((unsigned long)ptr)%(sizeof (union align)) != 0
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cii/src/memchk.c:48:3: note: uninitialized use occurs here
bp->free = freelist.free;
^~
cii/src/memchk.c:45:7: note: remove the '||' if its condition is always false
if (((unsigned long)ptr)%(sizeof (union align)) != 0
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cii/src/memchk.c:44:24: note: initialize the variable 'bp' to silence this warning
struct descriptor *bp;
^
= NULL
cii/src/memchk.c:58:6: warning: variable 'bp' is used uninitialized whenever '||' condition is true [-Wsometimes-uninitialized]
if (((unsigned long)ptr)%(sizeof (union align)) != 0
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cii/src/memchk.c:63:12: note: uninitialized use occurs here
nbytes < bp->size ? nbytes : bp->size);
^~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/secure/_string.h:63:33: note: expanded from macro 'memcpy'
__builtin___memcpy_chk (dest, __VA_ARGS__, __darwin_obsz0 (dest))
^~~~~~~~~~~
cii/src/memchk.c:58:6: note: remove the '||' if its condition is always false
if (((unsigned long)ptr)%(sizeof (union align)) != 0
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cii/src/memchk.c:54:23: note: initialize the variable 'bp' to silence this warning
struct descriptor *bp;
^
= NULL
cii/src/memchk.c:119:8: warning: variable 'newptr' is used uninitialized whenever '||' condition is true [-Wsometimes-uninitialized]
if ((ptr = malloc(nbytes + NALLOC)) == NULL
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cii/src/memchk.c:128:4: note: uninitialized use occurs here
newptr->free = freelist.free;
^~~~~~
cii/src/memchk.c:119:8: note: remove the '||' if its condition is always false
if ((ptr = malloc(nbytes + NALLOC)) == NULL
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cii/src/memchk.c:118:29: note: initialize the variable 'newptr' to silence this warning
struct descriptor *newptr;
^
= NULL
cii/src/memchk.c:1:13: warning: unused variable 'rcsid' [-Wunused-variable]
static char rcsid[] = "$Id$";
^
5 warnings generated.
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c cii/src/assert.c -o cii/src/assert.o
cii/src/assert.c:1:13: warning: unused variable 'rcsid' [-Wunused-variable]
static char rcsid[] = "$Id$";
^
1 warning generated.
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c nana/src/I.c -o nana/src/I.o
cc -fsanitize=undefined main.o function.o extension.o syntax.o data.o gbc.o cell.o error.o bignum.o compute.o edit.o syn_highlight.o long.o cii/src/except.o cii/src/fmt.o cii/src/str.o cii/src/text.o cii/src/memchk.o cii/src/assert.o nana/src/I.o -o eisl -lncurses
cc -Icii/include -Wall -Wextra -D_FORTIFY_SOURCE=2 -I/usr/include/ncurses -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 -Inana/src -O0 -g -DEIFFEL_DOEND -DEIFFEL_CHECK=CHECK_ENSURE -fsanitize=undefined -std=c17 -c edlis.c
cc -fsanitize=undefined edlis.o syn_highlight.o cii/src/except.o cii/src/fmt.o cii/src/str.o cii/src/text.o cii/src/memchk.o cii/src/assert.o -o edlis -lncurses
install -m755 eisl /usr/local/bin/
install -m755 edlis /usr/local/bin/
/usr/local/src/eisl
00:47[pjb@despina org.xquartz:0 eisl 41Gi]$ eisl
Easy-ISLisp Ver2.32
> A
error.c:20:17: runtime error: member access within null pointer of type 'TERMINAL' (aka 'struct term')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior error.c:20:17 in
error.c:20:17: runtime error: member access within null pointer of type 'TERMTYPE' (aka 'struct termtype')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior error.c:20:17 in
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==72103==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000020 (pc 0x000109a58f7e bp 0x7ffee61f7d40 sp 0x7ffee61f7d10 T3060754)
==72103==The signal is caused by a READ memory access.
==72103==Hint: address points to the zero page.
#0 0x109a58f7e in ESCERRFRED error.c:20
#1 0x109a586d6 in signal_condition error.c:646
#2 0x109a5496c in error error.c:87
#3 0x109a09a0b in eval main.c:1520
#4 0x109a09034 in main main.c:306
#5 0x7fff204d3f3c in start+0x0 (libdyld.dylib:x86_64+0x15f3c)
==72103==Register values:
rax = 0x0000000000000020 rbx = 0x00000000000000d5 rcx = 0x0000000000000001 rdx = 0x000000000000003f
rdi = 0x00007ffee61f7841 rsi = 0x0000000000000000 rbp = 0x00007ffee61f7d40 rsp = 0x00007ffee61f7d10
r8 = 0x00000001302b2000 r9 = 0x00007ffee61f6fe0 r10 = 0x0000000000000000 r11 = 0x0000000000000202
r12 = 0x0000000000000000 r13 = 0x0000000000000000 r14 = 0x0000000000000000 r15 = 0x0000000000000000
UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV error.c:20 in ESCERRFRED
==72103==ABORTING
Abort trap: 6
/usr/local/src/eisl
00:47[pjb@despina org.xquartz:0 eisl 41Gi]$ eisl
Easy-ISLisp Ver2.32
> (+ 1 2)
3
>
So it seems to be a problem with the terminal output, in case of error; in the normal case, the value is printed ok.
That's a useful test failure log, thanks.
Indeed it does seem to be connected to the terminal output. I usually use Terminal.app but tried xterm under XQuartz to reproduce this. I still failed though.
TERMINAL and TERMTYPE look like terminfo/curses data structures. And ESCERRFRED is a function to switch the foreground colour to red for an error mesage. The error message for "unbound variable" I see when running under xterm is red. Maybe there is some omission in the error handling for the curses code? My $TERM environment variable is "xterm", just in case yours is different. In particular, the fact that TERMINAL and TERMTYPE seem to be NULL should have been caught at initialisation and reverted to the "no fancy terminal" code path, but I'll double-check the error-handling there.
Thanks again for helping with this. I know from $DAYJOB how useless defect reports like "your software doesn't work" are, so it's refreshing that you repeated the test and attached logs, etc.
The previous test was performed in emacs M-x shell RET, so with TERM=emacs
and indeed, even in an xterm, if TERM is set to emacs, it fails similarly. I guess any TERM value that is not in the database will give the same behavior. In those cases, a good fallback is TERM=dumb
xterm -hold -e bash -c 'export TERM=emacs ; eisl'
Easy-ISLisp Ver2.32
> A
error.c:20:17: runtime error: member access within null pointer of type 'TERMINAL' (aka 'struct term')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior error.c:20:17 in
error.c:20:17: runtime error: member access within null pointer of type 'TERMTYPE' (aka 'struct termtype')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior error.c:20:17 in
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==84248==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000020 (pc 0x000102435f7e bp 0x7ffeed81ae90 sp 0x7ffeed81ae60 T3234496)
==84248==The signal is caused by a READ memory access.
==84248==Hint: address points to the zero page.
#0 0x102435f7e in ESCERRFRED error.c:20
#1 0x1024356d6 in signal_condition error.c:646
#2 0x10243196c in error error.c:87
#3 0x1023e6a0b in eval main.c:1520
#4 0x1023e6034 in main main.c:306
#5 0x7fff204d3f3c in start+0x0 (libdyld.dylib:x86_64+0x15f3c)
==84248==Register values:
rax = 0x0000000000000020 rbx = 0x00000000000000d5 rcx = 0x0000000000000001 rdx = 0x000000000000003f
rdi = 0x00007ffeed81a991 rsi = 0x0000000000000000 rbp = 0x00007ffeed81ae90 rsp = 0x00007ffeed81ae60
r8 = 0x0000000128c94000 r9 = 0x00007ffeed81a130 r10 = 0x0000000000000000 r11 = 0x0000000000000202
r12 = 0x0000000000000000 r13 = 0x0000000000000000 r14 = 0x0000000000000000 r15 = 0x0000000000000000
UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV error.c:20 in ESCERRFRED
==84248==ABORTING
bash: line 1: 84248 Abort trap: 6 eisl
Thank you for the error report. I am very busy with work now. I will think about it when I have time. Wait a minuet.
I still don't understand the problem well. Maybe the problem is using escape sequences. The error is displayed in red. It may work if you remove the terminal color specification in error.c.
Please test ver2.33.
$ eisl -r
Easy-ISLisp Ver2.33
> (defun fact (x) (if (< x 1) 1 (* x (fact (- x 10)A))))
FACT
> (fact 30)
Unbound variable at EVAL A
debug mode ?(help)
>>
Yay! It works!
/usr/local/src/eisl
13:21[pjb@despina org.xquartz:0 eisl 42Gi]$ eisl
Easy-ISLisp Ver2.33
> a
Unbound variable at EVAL A
debug mode ?(help)
>>?
? help
:a abort
:b backtrace
:d dynamic environment
:e environment
:i identify examining symbol
:q quit
:r room
:s stepper ON/OFF
other S exps eval
>>:b
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
(DEFGENERIC CREATE (x :REST y) (:METHOD (x :REST y) (LET ((obj (CREATE* x NIL))) (INITIALIZE-OBJECT obj y) obj)))
(DEFGENERIC* INITIALIZE-OBJECT (x y) (:METHOD (x y) (INITIALIZE-OBJECT* x y)))
(DEFGENERIC* REPORT-CONDITION (x y) NIL)
>>:q
Easy-ISLisp Ver2.33
>
Now that I understand the problem, Sasagawa's fix looks perfect.
Just in case you're interested, I use islisp-mode rather than "M-x shell" to run eisl under Emacs.