Subject: [clisp-list] bug report: 2.30 writes garbage to stdout

From: Scott Schwartz <[email-masked]>
Date: Sun Nov 10 12:00:01 2002

Friends,

Consider the following:
----------------------
bash% uname -a
Linux foo 2.2.19 #1 Wed Mar 20 19:41:41 EST 2002 i586 unknown

bash% clisp --version
GNU CLISP 2.30 (released 2002-09-15) (built 3245891238) (memory 3245895182)
Features: 
(CLOS LOOP COMPILER CLISP ANSI-CL COMMON-LISP LISP=CL INTERPRETER SOCKETS
 GENERIC-STREAMS LOGICAL-PATHNAMES SCREEN FFI UNICODE BASE-CHAR=CHARACTER PC386
 UNIX)

bash% cat foo.cl
(defun x () (x)) 
(x)

bash% clisp foo.cl 2>/dev/null </dev/zero  | head

*** - Lisp stack overflow. RESET

*** - READ from #<IO SYNONYM-STREAM *TERMINAL-IO*>: illegal character #\Null[1]> 

*** - READ from #<IO SYNONYM-STREAM *TERMINAL-IO*>: illegal character #\Null[3]> 

*** - READ from #<IO SYNONYM-STREAM *TERMINAL-IO*>: illegal character #\Null[5]> 

*** - READ from #<IO SYNONYM-STREAM *TERMINAL-IO*>: illegal character #\Null[7]> 

*** - READ from #<IO SYNONYM-STREAM *TERMINAL-IO*>: illegal character #\Null[9]> 

*** - READ from #<IO SYNONYM-STREAM *TERMINAL-IO*>: illegal character #\Null[11]> 

*** - READ from #<IO SYNONYM-STREAM *TERMINAL-IO*>: illegal character #\Null[13]> 

*** - READ from #<IO SYNONYM-STREAM *TERMINAL-IO*>: illegal character #\Null[15]> 
----------------------

This exhibits several horrible defects in clisp.  It should print an error
message (about stack overflow) to standard error and then simply exit.
Instead....

First, in a non-interactive setting, it jumps into an interactive
break loop.

Second, it writes garbage to standard output.  No runtime system can
ever be allowed to do that.

Third, the break loop reads from standard input.  No runtime system can
ever be allowed to do that.  Standard input and output are for the user's
program, and are generally connected to other programs by shell pipelines.

I'm not subscribed to clisp-list, so please cc any replies.

---

From: Sam Steingold <[email-masked]>
Date: Sun Nov 10 16:07:02 2002

> * In message <[email-masked]>
> * On the subject of "[clisp-list] bug report: 2.30 writes garbage to stdout"
> * Sent on Sun, 10 Nov 2002 14:59:28 -0500
> * Honorable Scott Schwartz <[email-masked]> writes:
>

why do you re-direct input to /dev/zero?!

> *** - READ from #<IO SYNONYM-STREAM *TERMINAL-IO*>: illegal character #\Null[1]>

of course: NULL (which is what is read from /dev/zero) is an illegal char.

> This exhibits several horrible defects in clisp.  It should print an
> error message (about stack overflow) to standard error and then simply
> exit.

well, this is what CLISP usually does.
stack overflow appears to be different.
please try the appended patch.

> ever be allowed to do that.

you gave a bad stdin.

> Third, the break loop reads from standard input.

where a break loop should read from?!

> I'm not subscribed to clisp-list, so please cc any replies.

I cannot guarantee that everyone who replies to your message will do
your bidding.  gmane.org is your friend.

--
Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
Every day above ground is a good day.

--- spvw.d.~1.204.~	2002-11-01 13:09:51.000000000 -0500
+++ spvw.d	2002-11-10 19:04:24.000000000 -0500
@@ -474,11 +474,17 @@
 # At overflow of one of the stacks:
 nonreturning_function(global, SP_ueber, (void)) {
   asciz_out(GETTEXTL(NLstring "*** - " "Program stack overflow. RESET"));
+  if (interactive_stream_p(Symbol_value(S(debug_io))))
   reset();
+  /* non-interactive session: quit */
+  else { asciz_out(NLstring); final_exitcode=1; quit(); }
 }
 nonreturning_function(global, STACK_ueber, (void)) {
   asciz_out(GETTEXTL(NLstring "*** - " "Lisp stack overflow. RESET"));
+  if (interactive_stream_p(Symbol_value(S(debug_io))))
   reset();
+  /* non-interactive session: quit */
+  else { asciz_out(NLstring); final_exitcode=1; quit(); }
 }
 
 # ----------------------------------------------------------------------------

---

From: Scott Schwartz <[email-masked]>
Date: Sun Nov 10 17:49:03 2002

| > * In message <[email-masked]>
| > * On the subject of "[clisp-list] bug report: 2.30 writes garbage to stdout"
| > * Sent on Sun, 10 Nov 2002 14:59:28 -0500
| > * Honorable Scott Schwartz <[email-masked]> writes:
| >
| > bash% clisp foo.cl 2>/dev/null </dev/zero  | head
| 
| why do you re-direct input to /dev/zero?!

Just to provide you with a minimal example.
Any piped input would do as well.

In general 
1) standard input is not a tty.
2) standard input is not a user.
3) standard input is not plain text.

write

  cat /bin/clisp | clisp foo.cl 2>/dev/null | wc

if you prefer.  

| > *** - Lisp stack overflow. RESET
| >
| > *** - READ from #<IO SYNONYM-STREAM *TERMINAL-IO*>: illegal character #\Null[1]>
| 
| of course: NULL (which is what is read from /dev/zero) is an illegal char.

It should not be reading *any* characters!  There should be *no* break
loop in this situation!

That to the side, ASCII NUL is *not* an illegal character.  It's perfectly
valid, just like any other.

And what's this "*terminal-io*" stuff?  There is no terminal, and no user,
in the example I gave.

| well, this is what CLISP usually does.
| stack overflow appears to be different.
| please try the appended patch.
 
It looks wrong to me.

That still unconditionally spews garbage 
	"*** - " "Program stack overflow. RESET"
to stdout.  How many other places does that happen?

What does clisp think an interactive stream is, and why is that relevent?
You might want your debugger to be talking over a socket, right?

Why is debug_io open at all?  In general there is no file descriptor that
it could possibly be connected to.  Inside of a special development repl
is the only time this could make sense.

| > Second, it writes garbage to standard output.  No runtime system can
| > ever be allowed to do that.
| 
| you gave a bad stdin.

No I didn't!  The initial "*** - Lisp stack overflow. RESET" message was
printed to stdout without reading anything from stdin.  That's totally
unsolicited, and totally erroneous.

In any case, "you gave bad stdin" is no excuse.  The runtime system is
not allowed to write garbage down my pipes!  That's what standard error
is for!

| > Third, the break loop reads from standard input.
| 
| where a break loop should read from?!

It can't.  The concept doesn't make sense, unless you are talking to a
user in a user-requested debugging situation.  In general, every open
file descriptor is connected to another program, with no user in sight.

If you run clisp with the (hypothetical) --interactive-development flag,
then you can have your debugger read from (user specified) somewhere.
(Maybe /dev/tty, maybe /dev/stdin, maybe something else.)  Otherwise,
don't touch anything.  There is no console.  There is no user.  Just exit.

It's like those times when you see DOS-based Kiosks and other
non-interactive appliances with "keyboard error, strike any key to
continue" messages on the display.

---

From: Sam Steingold <[email-masked]>
Date: Mon Nov 11 06:17:05 2002

> * In message <[email-masked]>
> * On the subject of "Re: [clisp-list] bug report: 2.30 writes garbage to stdout "
> * Sent on 10 Nov 2002 20:48:18 -0500

that was a bug, it has been fixed.

> That to the side, ASCII NUL is *not* an illegal character.  It's
> perfectly valid, just like any other.

wrong. please see CLHS.

> to stdout.

A lot of CLISP low-level stuff is a hold-over from the Amiga days where
probably there was no difference between stdout and stderr.
At any rate, making asciz_out() print to stderr instead of stdout is
probably not a very good idea.

Patches are welcome.

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
Diplomacy is the art of saying "nice doggy" until you can find a rock.