Control-C on Unix misbehaviour?

flight at mathi.uni-heidelberg.de flight at mathi.uni-heidelberg.de
Mon Oct 18 09:47:52 EDT 1999


This is a thing I noticed some time ago and was about to enter into the
Python Bug Database. It's been recorded in the Debian Bug Tracking system
since some time:

- Debian Bug#24605: python-base: signal handling problems
  (http://www.debian.org/Bugs/db/24/24605.html)
- Debian Bug#45929: python: ^C acts as ^D instead of raising a
  KeyboardInterrupt exception while working within the interactive interpreter.
  (http://www.debian.org/Bugs/db/45/45929.html)

I'll add a few more data points here for different Linux flavors, all of
them running on i386 machines:

(A) Debian GNU/Linux 2.1: python 1.5.1-7, libreadlineg2 2.1-12,
          libc6 2.0.7.19981211
(B) Debian GNU/Linux 2.1 like above, but running python 1.5.2-5slink-1.
(C) Debian potato: python 1.5.2-6, libreadlineg2 2.1-13.6,
          libc6 2.1.2-5
(D) SuSE Linux 6.1: python-1.5.1-44, libc-99.4.4-0, no readline module
          (Like Debian 2.1, SuSE 6.1 is running libc6 2.0.7)
(E) SuSE Linux 6.1: like above, but running Debian's python 1.5.2-6 package.


First test: "python" and pressing Control-C twice
-------------------------------------------------
On (C), python will be aborted after the first Control-C.

On (A), (B) and (D), "KeyboardInterrupt" after the first Control-C, no reaction 
at all after the second Control-C (Control-C won't work in this session
after the first).

On (E), nothing happens after the first Control-C, but if I press enter,
I get
  Traceback (innermost last):
    File "<stdin>", line 0, in ?
    KeyboardInterrupt
On the second and any subsequent Control-C, I get an "KeyboardInterrupt"
immediately.


Second test: like first, but after installing an empty, dummy readline.so
-------------------------------------------------------------------------
On (A), (D), I get a message
  Traceback (innermost last):
    File "<stdin>", line 0, in ?
    KeyboardInterrupt
after each Control-C, but only after pressing enter.

On (E), the same reaction as with the first test.

(B) and (C) now behave like (E), too.


python -c "raw_input()", ff, Control-C twice
--------------------------------------------
(A), (D): Back in shell after first Control-C, but only after I press enter:
ff
Traceback (innermost last):
  File "<string>", line 1, in ?
  KeyboardInterrupt

(B), (C), (E): back in shell after second Control-C:
ffTraceback (innermost last):
  File "<string>", line 1, in ?
  KeyboardInterrupt


python -c "import readline; raw_input()", ff, Control-C twice
-------------------------------------------------------------
(A), (B), (C): back in shell

[not applicable for (D) and (E)]

>  
> > If Ctrl-C does kill the interpreter, it's a platform-specific bug.  Start
> > your exciting search by trying:
> > 
> > >>> import signal
> > >>> signal.default_int_handler()
> > 
> > Hoping for something like:
> > 
> > Traceback (innermost last):
> >   File "<stdin>", line 1, in ?
> > KeyboardInterrupt
> > >>>
> > 
> > and still in the interpreter shell.

Works like expected on all five configurations.

> 
> No, that all works. The execution is never getting to the handler. I
> can do this:
> 
> >>> import signal
> >>> def f():
> ...  print "hello"
> ...
> >>> signal.signal(signal.SIGINT,f)
> <built-in function default_int_handler>
> >>> ^C - and back we go to bash
> 
> I get the same behaviour if I use `kill' from another xterm, so it
> looks as if the signal's getting deleivered correctly.
> 
> possibly relavent info:
> 
> python 1.5.2 (both from redhat 6.1 & a fairly recent cvs)
> readline-2.2.1-5 (according rpm -q readline)
> 
> running under gdb yields different behaviour (oh good!) - hitting
> control-C drops you into __libc_read where the stack looks a bit like
> this:

gdb python, run and Control-C
-----------------------------

(A) and (B): Program received signal SIGINT, Interrupt.
#0  0x400a2a44 in   ()
#1  0x40037810 in   ()
#2  0x400ff72a in rl_getc ()
#3  0x400ff6b5 in rl_read_key ()
#4  0x400ea760 in readline_internal_char ()
#5  0x400ea8a5 in readline_internal_char ()
#6  0x400ea8ed in readline_internal_char ()
#7  0x400ea4a0 in readline ()
#8  0x4000d2c9 in   ()
...
#17 0x804f31a in   ()
#18 0x804ed40 in main ()

(C): Program received signal SIGINT, Interrupt.
#0  0x401471a4 in read () from /lib/libc.so.6
#1  0x40097ffc in __libc_internal_tsd_get () from /lib/libpthread.so.0
#2  0x401b51a7 in rl_getc () from /lib/libreadline.so.2
#3  0x401b5152 in rl_read_key () from /lib/libreadline.so.2
#4  0x401a1e1b in readline_internal_char () from /lib/libreadline.so.2
#5  0x401a1f35 in readline_internal_char () from /lib/libreadline.so.2
#6  0x401a1f69 in readline_internal_char () from /lib/libreadline.so.2
#7  0x401a1b76 in readline () from /lib/libreadline.so.2
#8  0x40014554 in _init () from /usr/lib/python1.5/lib-dynload/readline.so
#9  0x4004eb71 in PyOS_Readline () from /usr/lib/libpython1.5.so.0.0
#10 0x40065c4a in PyTokenizer_Free () from /usr/lib/libpython1.5.so.0.0
#11 0x4006652a in PyTokenizer_Get () from /usr/lib/libpython1.5.so.0.0
#12 0x400503fb in PyParser_ParseFile () from /usr/lib/libpython1.5.so.0.0
#13 0x400502a5 in PyParser_ParseFile () from /usr/lib/libpython1.5.so.0.0
#14 0x4005a843 in PyRun_InteractiveOne () from /usr/lib/libpython1.5.so.0.0
#15 0x4005a743 in PyRun_InteractiveLoop () from /usr/lib/libpython1.5.so.0.0
#16 0x4005a67a in PyRun_AnyFile () from /usr/lib/libpython1.5.so.0.0
#17 0x4004b444 in Py_Main () from /usr/lib/libpython1.5.so.0.0
#18 0x8048724 in main ()
#19 0x400ce78a in __libc_start_main () from /lib/libc.so.6


[gdb not available on (D) and (E)]

> #0  0x40113db4 in __libc_read () from /lib/libc.so.6
> #1  0x40052a7c in __DTOR_END__ () from /lib/libpthread.so.0
> #2  0x4002f422 in rl_getc () from /usr/lib/libreadline.so.3
> #3  0x4002f3e2 in rl_read_key () from /usr/lib/libreadline.so.3
> #4  0x40021aa5 in readline_internal_char () from /usr/lib/libreadline.so.3
> #5  0x40021b7b in readline_internal_charloop () from /usr/lib/libreadline.so.3
> #6  0x40021baa in readline_internal () from /usr/lib/libreadline.so.3
> #7  0x40021888 in readline () from /usr/lib/libreadline.so.3
> #8  0x8085d85 in call_readline (prompt=0x811be9c ">>> ") at ./readline.c:288
> #9  0x8052689 in PyOS_Readline (prompt=0x811be9c ">>> ") at myreadline.c:148
> #10 0x805184b in tok_nextc (tok=0x8140e70) at tokenizer.c:216
> ...
> 
> single stepping a few times through source-absent libc files leaves me
> back at the Python interpreter's prompt.

Same behavior here.


No need to say that with the readline module loaded behavior for Control-C
(SIGINT) is different depending if you're on the Python command line or if
you're running a Python statement.


The problem is indeed related to the readline module, but then, it seems to
depend on libc6 as well! At least I get different effects with the same
Python version running on systems with a roughly identical libreadline, but
different libc6 versions.

	Gregor





More information about the Python-list mailing list