classification
Title: documentation doesn't say that you can't handle C segfaults from python
Type: Stage: resolved
Components: Documentation Versions: Python 3.3
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: docs@python Nosy List: BreamoreBoy, Rhamphoryncus, belopolsky, docs@python, eric.araujo, georg.brandl, gvanrossum, poolie, python-dev, schmir, tebeka, terry.reedy, vstinner
Priority: normal Keywords: easy, patch

Created on 2007-09-27 17:05 by tebeka, last changed 2013-10-06 19:22 by python-dev. This issue is now closed.

Files
File name Uploaded Description Edit
20110822-1525-signal-doc.diff poolie, 2011-08-22 05:27 review
Messages (21)
msg56169 - (view) Author: Miki Tebeka (tebeka) * Date: 2007-09-27 17:05
The following code hangs Python:
#!/usr/bin/env python

import segfault
import signal
from os import _exit
from sys import stdout

def handler(signal, stackframe):
    print "OUCH"
    stdout.flush()
    _exit(1)

if __name__ == "__main__":
    from sys import argv

    signal.signal(signal.SIGSEGV, handler)
    segfault.segfault()

segfault is the following C module:
#include <Python.h>

static PyObject *
segfault(PyObject *self, PyObject *args)
{

    char *c;

    c = 0;
    *c = 'a';

    return Py_BuildValue("");
}

static PyMethodDef Methods[] = {
    { "segfault",  segfault, METH_VARARGS, "will segfault"},
    {NULL, NULL, 0, NULL}        /* Sentinel */
};

PyMODINIT_FUNC
initsegfault(void)
{
    Py_InitModule("segfault", Methods);
}
msg56192 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2007-09-28 18:31
Why is this a Python bug?
msg56194 - (view) Author: Miki Tebeka (tebeka) * Date: 2007-09-28 19:59
Because it hangs Python :)

I know, "while 1: pass" also hangs Python, however it'll nice
if this behaviour was documented or (IMO better) that Python will
raise an InvalidArgument exception on SIGSEGV (like it does for SIGKILL).
msg59842 - (view) Author: Ralf Schmitt (schmir) Date: 2008-01-12 22:25
If you replace your call segfault.segfault() with os.kill(os.getpid(),
signal.SIGSEGV) everything works as expected. The problem is that the
signal is just caught in the c handler (and a flag is set) and then the
program continues with the offending *c = 'a'; statement, which again
ends with a SIGSEGV and the handler being called.
The documentation explicitly states "Because the C signal handler always
returns, it makes little sense to catch synchronous errors like SIGFPE
or SIGSEGV."
I think raising that InvalidArgument exception is most probably the
right thing to do (or at least printing a warning). Those that really
want to handle SIGSEGV should do it from C anyway.
msg59844 - (view) Author: Adam Olsen (Rhamphoryncus) Date: 2008-01-12 23:20
The warning in the documentation should be strengthened.  Python simply
does not and cannot support synchronously-generated signals.

It is possible to send a normally synchronous signal asynchronously,
such as the os.kill() Ralf mentioned, so it's theoretically possible to
use custom handlers for them.  However, I can't think of any real use
cases, and having such a handler would be asking for trouble if a real
synchronously-generated signal was produced.  I guess that's an argument
for not allowing custom handlers. ;)

Suggested documentation:
"Because of the precarious nature of how synchronously-generated signals
must be handled, the signal module does not allow installing handlers
for them.  This includes SIGSEGV, SIGFPE, SIGBUS, SIGILL, SIGABRT..."

I haven't been able to find a canonical list if synchronously-generated
signals.  Furthermore, I've seen conflicting claims about SIGABRT.
msg59908 - (view) Author: Ralf Schmitt (schmir) Date: 2008-01-14 19:10
Should I work on a patch, which makes signal.signal raise an Exception
for SIGSEGV, SIGBUS, SIGFPE,...?
msg59910 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2008-01-14 19:13
I'm not sure what the point of that would be.  Somebody might want to
send these asynchronously (using kill) which we might legitimately want
to catch.  Also you don't know which other synchronous signals a
platform might define.  I think at best a doc update on the relative
uselessness of handlers for synchronous signals (with examples) is all
we need.
msg59912 - (view) Author: Ralf Schmitt (schmir) Date: 2008-01-14 19:30
Those who want to legitimately catch SIGSEGV will end up with an
uninterruptible python process using 100 % CPU on a real segmentation fault.
But, then I can live with the current behaviour.
msg59913 - (view) Author: Adam Olsen (Rhamphoryncus) Date: 2008-01-14 19:32
In essence, it's a weakness of the POSIX API that it doesn't distinguish
synchronous from asynchronous signals.

The consequences of either approach seem minor though.  I cannot imagine
a sane use case for catching SIGSEGV, but documentation changes should
be sufficient anyway.

Suggested wording, if you take the documentation-only approach:
"Because of the precarious nature of how synchronously-generated signals
must be handled, it is impossible to handle them correctly from python.
 You should never install handlers for synchronously-generated signals,
such as SIGSEGV and SIGFPE."
msg76995 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2008-12-05 09:42
The docs already say 
"Because the C signal handler always returns, it makes little sense to
catch synchronous errors like :const:`SIGFPE` or :const:`SIGSEGV`."

Should this still be reworded or promoted to a warning?
msg77045 - (view) Author: Adam Olsen (Rhamphoryncus) Date: 2008-12-05 17:51
I'm in favour of just the doc change now.  It's less work and we don't
really need to disable that usage.
msg107988 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2010-06-17 02:27
From the comments, it seems like this should be changed to a doc issue.

Given that I do not know a 'synchronous' from an 'asynchronous' signal, I would want an expanded list if I were using this module.

Strengthening 'little sense' to 'do not do it' makes sense, at least for 2.7 and 3.2.
msg116778 - (view) Author: Mark Lawrence (BreamoreBoy) * Date: 2010-09-18 13:50
There are several suggestions inline as how how the docs should be changed.
msg127681 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2011-02-01 04:27
The consensus is that this is not a crash (and not even a bug).  I am not sure what is the proper type for doc enhancement, but is certainly should not show up in a search for crashers.
msg142670 - (view) Author: Martin Pool (poolie) Date: 2011-08-22 05:11
The documentation for this can now point to the faulthandler module (in Python 3).
msg142675 - (view) Author: Martin Pool (poolie) Date: 2011-08-22 05:27
This patch tries to improve the documentation a bit more to address the issue that confused tebeka and to advertise faulthandler.  Could someone review or apply it?
msg143236 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2011-08-30 21:56
> def handler(signal, stackframe):
>     print "OUCH"
>     stdout.flush()
>     _exit(1)

What do you want to do on a SIGSEGV? On a real fault, you cannot rely on  Python internal state, you cannot use any Python object. To handle a real SIGSEGV fault, you have to implement a signal handler using only *signal safe* functions.... in C.

See faulthandler_fatal_error() function:
https://github.com/haypo/faulthandler/blob/master/faulthandler.c#L257

> The documentation for this can now point to the faulthandler module
> (in Python 3).

For your information, faulthandler is available for Python older than 3.3 as a third party module:
http://pypi.python.org/pypi/faulthandler

> segfault is the following C module:

For tests, you can use ctypes.string_at(0) to read a word from NULL.

--

faulthandler installs a signal handler for SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals:
http://docs.python.org/dev/library/faulthandler.html
msg143244 - (view) Author: Martin Pool (poolie) Date: 2011-08-31 00:52
On 31 August 2011 07:56, STINNER Victor <report@bugs.python.org> wrote:
>
> STINNER Victor <victor.stinner@haypocalc.com> added the comment:
>
>> def handler(signal, stackframe):
>>     print "OUCH"
>>     stdout.flush()
>>     _exit(1)
>
> What do you want to do on a SIGSEGV? On a real fault, you cannot rely on  Python internal state, you cannot use any Python object. To handle a real SIGSEGV fault, you have to implement a signal handler using only *signal safe* functions.... in C.

Well, strictly speaking, it is very hard or impossible to write C code
that's guaranteed to be safe after an unexpected segv too; who knows
what might have caused it.  The odds are probably better that it will work in
in C than in Python.  At any rate I think it's agreed that the
original code is not supported and it's just the docs that need to
change.

So what do you think of
<http://bugs.python.org/file22989/20110822-1525-signal-doc.diff> ?
msg143253 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2011-08-31 12:02
Le mercredi 31 août 2011 02:52:01, vous avez écrit :
> > What do you want to do on a SIGSEGV? On a real fault, you cannot rely on
> >  Python internal state, you cannot use any Python object. To handle a
> > real SIGSEGV fault, you have to implement a signal handler using only
> > *signal safe* functions.... in C.
> 
> Well, strictly speaking, it is very hard or impossible to write C code
> that's guaranteed to be safe after an unexpected segv too

It is possible if you only use signal safe functions. I think that no Python 
function is signal safe :-)
msg199111 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2013-10-06 19:21
I see not much to be done here, except from committing Martin's patch updated to the current trunk.
msg199112 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2013-10-06 19:22
New changeset b4444d16e333 by Georg Brandl in branch '3.3':
Closes #1215: document better why it is not a good idea to catch e.g. SIGSEGV and refer to faulthandler.
http://hg.python.org/cpython/rev/b4444d16e333
History
Date User Action Args
2013-10-06 19:22:43python-devsetstatus: open -> closed

nosy: + python-dev
messages: + msg199112

resolution: fixed
stage: resolved
2013-10-06 19:21:21georg.brandlsetmessages: + msg199111
2011-08-31 12:02:31vstinnersetmessages: + msg143253
2011-08-31 00:52:00pooliesetmessages: + msg143244
2011-08-30 21:56:02vstinnersetmessages: + msg143236
2011-08-30 16:05:28eric.araujosetnosy: + vstinner, eric.araujo

versions: + Python 3.3, - Python 2.6, Python 3.1, Python 2.7, Python 3.2
2011-08-22 05:27:06pooliesetfiles: + 20110822-1525-signal-doc.diff
keywords: + patch
messages: + msg142675
2011-08-22 05:15:01pooliesettitle: Python hang when catching a segfault -> documentation doesn't say that you can't handle C segfaults from python
2011-08-22 05:11:14pooliesetnosy: + poolie
messages: + msg142670
2011-02-01 04:27:04belopolskysetnosy: + belopolsky
messages: + msg127681

components: - Interpreter Core
type: crash ->
2010-09-18 13:50:35BreamoreBoysetassignee: docs@python

messages: + msg116778
nosy: + docs@python, BreamoreBoy
2010-06-17 02:27:19terry.reedysetnosy: + terry.reedy

messages: + msg107988
versions: + Python 2.6, Python 3.1, Python 2.7, Python 3.2, - Python 2.5
2008-12-05 17:51:37Rhamphoryncussetmessages: + msg77045
2008-12-05 09:42:13georg.brandlsetnosy: + georg.brandl
messages: + msg76995
2008-01-20 20:05:19christian.heimessetpriority: normal
keywords: + easy
components: + Documentation
2008-01-14 19:32:45Rhamphoryncussetmessages: + msg59913
2008-01-14 19:30:52schmirsetmessages: + msg59912
2008-01-14 19:13:08gvanrossumsetmessages: + msg59910
2008-01-14 19:10:04schmirsetmessages: + msg59908
2008-01-12 23:20:23Rhamphoryncussetnosy: + Rhamphoryncus
messages: + msg59844
2008-01-12 22:25:37schmirsetnosy: + schmir
messages: + msg59842
2007-09-28 19:59:03tebekasetmessages: + msg56194
2007-09-28 18:31:17gvanrossumsetnosy: + gvanrossum
messages: + msg56192
2007-09-27 17:05:24tebekacreate