msg56761 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-25 23:07 |
Python 3.0a1 on Linux and MacOS X 10.4.10 exits differently than Python
2.4 and 2.5.
With previous Python binaries the destructor** function of any pre-
loaded shared library is called prior to exit. With Python 3.0a1 it is
not, neither when exiting Python from the command line with Ctrl-D nor
when using exit().
A workaround is to install a SIGABRT signal handler from the library and
exit Python with os.abort().
Python 3.0a1 was built from source using the standard build sequence
without any ./configure options except --prefix.
---
**) defined with GNU __attribute__((destructor)). The shared library is
loaded through environment variable LD_PRELOAD on Linux and
DYLD_INSERT_LIBRARIES on MacOS X.
|
msg56779 - (view) |
Author: Neal Norwitz (nnorwitz) * |
Date: 2007-10-26 06:28 |
Thanks for testing 3.0.
Do you have any idea why they are no longer called? I don't recall any
changes related to this area. Can you try to debug further?
|
msg56792 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-26 15:28 |
Here is one thought, maybe 3.0a calls _exit() while 2.x uses exit() to
terminate. With _exit() any functions installed with atexit() or
on_exit() are *not* called.
That would explain the difference but only if destructor functions are
installed with atexit() or on_exit(). I do not know whether that.
|
msg56793 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-26 15:30 |
Sorry, premature submit. I will try using atexit() and report what
happens there.
|
msg56796 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-26 17:18 |
Using atexit() to install the destructor function does not help. The
function in not called when 3.0a1 exits, but with 2.5.1 it is. Same
behavior on Linux and MacOS X.
Btw, that would mean that any C extension which uses atexit() directly
may be affected by this issue.
Running python with the debugger shows that 3.0a1 and 2.5.1 both exit
thru exit() and not _exit(). A breakpoint at _exit is hit, but the call
originates from exit and not anywhere in the python binary.
There is a new atexitmodule.c in 3.0a1 which did not exits in 2.5.1.
But that is handling the atexit functionality at the Python level and
not C.
This man page <http://linux.die.net/man/3/atexit> mentions that all
registered atexit functions are removed after a fork+exec. But
breakpoints set at fork, fork1, forkpty and vfork are never hit by
3.0a1.
That is as far as I got.
|
msg56802 - (view) |
Author: Guido van Rossum (gvanrossum) * |
Date: 2007-10-26 17:47 |
Can you provide a very small shared library that demonstrates this
problem? (E.g. you could start by modifying Modules/xxmodule.c, adding a
'destructor' function.)
|
msg56810 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-26 19:10 |
Yes, I will make a small library. But first, here is another piece of
evidence.
As I mentioned, using std atexit does not work on 3.0a1. But
surprisingly, the destructor function is not called either when
installed with Py_AtExit on 3.0a1. On 2.5.1 it is.
There must something in Py_Terminate or Py_Finalize which is different
in 3.0a1.
|
msg56818 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-26 20:03 |
Attached is a simple test case which demonstrates the problem on Linux
and MacOS X. It is not an xxmodule example, though and hope this is OK.
See the comments for build steps and example output with 3 different
Python builds on both platforms.
If you need another test case which uses Py_AtExit, let me know.
|
msg56820 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-26 20:22 |
Here is the same file with an #if to use to Py_AtExit or destructor case.
Please us this one instead of the earlier one.
|
msg56821 - (view) |
Author: Guido van Rossum (gvanrossum) * |
Date: 2007-10-26 20:30 |
> Here is the same file with an #if to use to Py_AtExit or destructor case.
> Please us this one instead of the earlier one.
>
> Added file: http://bugs.python.org/file8622/dlibtest.c
I can build it just fine on Ubuntu dapper, but I can't run it. The
command given in the comment fails immediately:
$ env LD_PRELOAD dlibtest.so ~/p3/python
env: LD_PRELOAD: No such file or directory
$
When I modify it slightly I get another error:
$ env LD_PRELOAD=dlibtest.so ~/p3/python
ERROR: ld.so: object 'dlibtest.so' from LD_PRELOAD cannot be preloaded: ignored.
Python 3.0a1+ (py3k, Oct 26 2007, 12:30:11)
[GCC 4.0.3 (Ubuntu 4.0.3-1ubuntu5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> ^D
$
|
msg56823 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-26 21:02 |
My fault, sorry. The command line to run should be
env LD_PRELOAD=./dlibtest.so ...
i.e. with '=' sign and no spaces. And the library file may have to be
an absolute path.
|
msg56824 - (view) |
Author: Guido van Rossum (gvanrossum) * |
Date: 2007-10-26 21:16 |
OK, confirmed. But no insignt in what happened yet... Do you know where
the atexit stuff happens in 2.5?
|
msg56825 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-26 21:30 |
The Py_AtExit function is in Python/pythonrun.c. The calls to all
installed C functions are made in call_ll_exitfuncs, also in
pythonrun.c. The call to call_ll_exitfuncs is at the very end of
Py_Finalize also in pythonrun.c.
I am just getting down there now and Py_Finalize is called and reaches
the call to PyGrammar_RemoveAccelerators a few lines higher. But
call_ll_exitfuncs is not called, as far as I can tell.
|
msg56826 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-26 21:38 |
One more thing. Stepping with the debugger thru Py_Finalize looks exactly
the same for 2.5.1 and 3.0a1 in the last part of that function.
|
msg56827 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-26 22:20 |
I put a bunch of printf's in the Py_Finalize function of 2.5.1 and
3.0a1.
All those show up when 2.5.1 exists including the call to
call_ll_exitfuncs.
But in 3.0a1 only a few show up and the last one is just before the call
to PyImport_Cleanup near line 393. It looks like that call never
returns. That call never returns, it seems.
|
msg56831 - (view) |
Author: Neal Norwitz (nnorwitz) * |
Date: 2007-10-26 23:28 |
Maybe that's because site and io get cleaned up and then there is some
fatal error that can't be printed?
|
msg56832 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-26 23:55 |
This is quite bizarre and difficult to reproduce. With gdb, 3.0a1 does
get to the very end of Py_Finalize, but without gdb it doesn't.
Also, the call to static function call_all_exitfuncs is inlined, its
while loop is shown inside Py_Finalize on MacOS X. On Linux that is not
visible, probably due to differences in gcc/gdb, 4.0.1 or MacOS X and
3.4.6 on Linux.
|
msg56834 - (view) |
Author: Neal Norwitz (nnorwitz) * |
Date: 2007-10-27 00:01 |
I suggest you configure --with-pydebug. That will disable
optimization, enable debugging symbols and will make it easier to
develop. Note that a debug version runs much slower due to asserts()
and other internal changes. Otherwise, it should work the same.
On Oct 26, 2007 4:55 PM, Jean Brouwers <report@bugs.python.org> wrote:
>
> Jean Brouwers added the comment:
>
> This is quite bizarre and difficult to reproduce. With gdb, 3.0a1 does
> get to the very end of Py_Finalize, but without gdb it doesn't.
>
> Also, the call to static function call_all_exitfuncs is inlined, its
> while loop is shown inside Py_Finalize on MacOS X. On Linux that is not
> visible, probably due to differences in gcc/gdb, 4.0.1 or MacOS X and
> 3.4.6 on Linux.
>
>
> __________________________________
> Tracker <report@bugs.python.org>
> <http://bugs.python.org/issue1329>
> __________________________________
>
|
msg56835 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-27 00:09 |
OK, I try that.
|
msg56838 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-27 00:28 |
The 3.0a1 build --with-pydebug behaves the same as before (on Linux). The
problem does occur without gdb but not with gdb.
|
msg56840 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-27 01:49 |
It looks like the problem may indeed just be that I/O is being shut down
somewhere inside PyImport_Cleanup. I am modifying the test case to
demonstrate that and will submit that version as soon as it runs.
|
msg56844 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-27 06:03 |
Attached is an updated dlibtest.c file. It prints a message in the con-
/destructor functions and if that fails it calls _exit(9).
Compile and run it as before and check the exit status. If the latter
is 9 or 011, a printf error occurred indicating e.g. that stdout was
closed or something similar.
This version can also be used with gdb, either by pre-loading the
dlibtest.so library within gdb or before invoking gdb. To preload the
library within gdb (on Linux) use
gdb .../python
(gdb) set environment LD_PRELOAD ./dlibtest.so
(gdb) run
.....
or to preload before gdb use
setenv LD_PRELOAD ./dlibtest.so
gdb .../python
(gdb) run
.....
Lastly, my previous observations about this issue were clearly a "trompe
d'oeil", especially my statement that PyImport_Cleanup never returned.
The missing print statements *after* the PyImport_Cleanup call are
simply due to printf errors, and nothing else ;-)
|
msg56845 - (view) |
Author: Neal Norwitz (nnorwitz) * |
Date: 2007-10-27 06:20 |
When I run with the attached patch, I see the message:
*** dtor called in python ...
Is that the behavior you expect?
|
msg56854 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-27 15:12 |
Yes, that is the expected behavior in this case.
|
msg56856 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-27 16:41 |
One final comment as confirmation. If the messages are written to a file,
other than stdout and stderr, they do appear in unpatched 3.0a1 and 3.0a1
behaves as expected. The root cause of the problem was the closed stdout.
|
msg56857 - (view) |
Author: Guido van Rossum (gvanrossum) * |
Date: 2007-10-27 17:04 |
So is there even a bug? Arguably you shouldn't be writing anything that
late in the life of a shared library.
|
msg56859 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-27 18:48 |
It is quite common to pre-load libraries into existing binaries e.g. for
profiling Typically, those write to stdout or stderr only if the option
for an output file is not used. That is how I happened to run into the
issue the other day.
For a while, the initial symptoms looked like the different exit
behavior in 3.0a1 might be a serious problem. It was not obvious that
stdout and -err might have been closed and caused the difference. All
the Python 2.x versions never closed stdout and -err.
Therefore, 3.0 should probably not do that either. But that is really
your call.
|
msg56882 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-28 15:31 |
One more argument. Without a fix, 3.0 would not even print a C debug
message from a destructor function nor from any function installed with
atexit or Py_AtExit. The dlibtest shows that for 2 of these 3.
|
msg56885 - (view) |
Author: Christian Heimes (christian.heimes) * |
Date: 2007-10-28 17:03 |
Can you try this patch, please? It has the same effect as the other
patch from Neal but it doesn't loose ref counts. I've patched the
dealloc function of _FileIO to keep fd 1 and fd 2 open.
Index: Modules/_fileio.c
===================================================================
--- Modules/_fileio.c (Revision 58699)
+++ Modules/_fileio.c (Arbeitskopie)
@@ -270,7 +270,8 @@
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
- if (self->fd >= 0) {
+ /* Don't close stdout and stderr */
+ if (self->fd == 0 || self->fd > 2) {
errno = internal_close(self);
if (errno < 0) {
#ifdef HAVE_STRERROR
|
msg56886 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-28 17:44 |
I could not try Neal's patch since it does not seem to apply to the
3.0a1 source I have. But the Modules/_fileio.c patch works just fine on
my Linux and MacOS X. Here is the Linux result:
$ env LD_PRELOAD=./dlibtest4.so ~/Python-3dbg/python
*** ctor called in python ...
*** atexit OK in python ...
Python 3.0a1 (py3k, Oct 28 2007, 10:23:59)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
[36000 refs]
[21985 refs]
*** dtor called in python ...
$
Most interesting is that this Python build --with-pydebug now prints 2
lines in [..] brackets on exit. That 2nd line, [21985 refs] never
showed up before!
Also, attached is another version of my test case renamed to dlibtest4.
It includes 4 different use cases. More details inside.
|
msg56890 - (view) |
Author: Jean Brouwers (MrJean1) |
Date: 2007-10-28 19:08 |
Perhaps, the proper behavior is the following.
After calling all functions/methods installed at the Python level with
atexit.register and all C functions installed with Py_AtExit, the
objects sys.stdin, sys.stdout and sys.stderr are destroyed.
However, the C level files stdin, stdout and stderr are *never* closed
by Python. Those will be closed (like any other open file) after all
functions installed with atexit or defined as destructors have been
called.
|
msg56897 - (view) |
Author: Guido van Rossum (gvanrossum) * |
Date: 2007-10-29 00:57 |
Right. I think the right solution is to add an option to _FileIO that
says "don't close the filedescriptor when close() is called". This
option should only be allowed when the "filename" argument is an
integer file descriptor. It should be passed when stdin/out/err are
created. It may also be helpful in some other places?!
|
msg56898 - (view) |
Author: Christian Heimes (christian.heimes) * |
Date: 2007-10-29 09:03 |
Here you go, Guido!
|
msg56944 - (view) |
Author: Guido van Rossum (gvanrossum) * |
Date: 2007-10-30 00:42 |
Thanks!! Code review:
Shouldn't closefd be passed as 1 in import.c?
I don't see the point of distinguishing between -1 and +1. The block
"if (closefd < 0) { closefd = 1; }" looks rather silly.
In io.py, you should document that closefd must not be False when a
filename is given.
I think in _fileio.c, you can insist that the closefd argument is an int
(a bool will work anyway, as bool is a subclass of int).
I don't think we should warn when trying to close an unclosable fd; it
should really just be a no-op. Also, if you are going to call
PyErr_WarnEx(), you should test its return value (it can raise an
exception!).
Please don't add trailing whitespace.
|
msg56957 - (view) |
Author: Christian Heimes (christian.heimes) * |
Date: 2007-10-30 06:33 |
Guido van Rossum wrote:
> Shouldn't closefd be passed as 1 in import.c?
>
> I don't see the point of distinguishing between -1 and +1. The block
> "if (closefd < 0) { closefd = 1; }" looks rather silly.
I used -1 as default to keep it consistent with buffer=-1. I figured out
that I can go with "closefd != 0 means close it".
> In io.py, you should document that closefd must not be False when a
> filename is given.
Done
> I think in _fileio.c, you can insist that the closefd argument is an int
> (a bool will work anyway, as bool is a subclass of int).
Thanks, it makes the code a bit easier.
> I don't think we should warn when trying to close an unclosable fd; it
> should really just be a no-op. Also, if you are going to call
> PyErr_WarnEx(), you should test its return value (it can raise an
> exception!).
I think we should keep the warning. The warning made me aware of a minor
bug in quopri.
> Please don't add trailing whitespace.
I've reconfigured my editor to remove trailing spaces.
I've attached a combined patch for closefd and preliminary stderr.
Christian
|
msg56963 - (view) |
Author: Guido van Rossum (gvanrossum) * |
Date: 2007-10-30 17:19 |
OK, thanks. The closefd part is good, but the stderrprinter part has a
problem. On Linux, in a non-debug build, this has the odd side effect
of subtracting one from sys.maxunicode. In a debug build, it dies like
this:
$ ./python -S
python: Modules/gcmodule.c:336: visit_reachable: Assertion `gc_refs > 0
|| gc_refs == (-3) || gc_refs == (-2)' failed.
Aborted
$
If I comment out the PySys_SetObject() call everything seems fine, but I
suspect that the problem is actually in the creation of the stdprinter
object.
|
msg56964 - (view) |
Author: Guido van Rossum (gvanrossum) * |
Date: 2007-10-30 17:28 |
I've checked the closefd patch (which minor changes) into the py3k branch.
Committed revision 58711.
Please take the stdprinter patch to the original issue (bug 1352).
|
msg56969 - (view) |
Author: Christian Heimes (christian.heimes) * |
Date: 2007-10-30 18:06 |
Guido van Rossum wrote:
> Guido van Rossum added the comment:
>
> OK, thanks. The closefd part is good, but the stderrprinter part has a
> problem. On Linux, in a non-debug build, this has the odd side effect
> of subtracting one from sys.maxunicode. In a debug build, it dies like
> this:
>
> $ ./python -S
> python: Modules/gcmodule.c:336: visit_reachable: Assertion `gc_refs > 0
> || gc_refs == (-3) || gc_refs == (-2)' failed.
> Aborted
> $
>
> If I comment out the PySys_SetObject() call everything seems fine, but I
> suspect that the problem is actually in the creation of the stdprinter
> object.
I may have found the problem. I forgot th remove Py_TPFLAGS_HAVE_GC from
tp_flags. It's a relict from my first implementation.
$ ./python
Fatal Python error: Py_Initialize: can't initialize sys standard streams
Traceback (most recent call last):
File "/home/heimes/dev/python/py3k/Lib/io.py", line 22, in <module>
test
NameError: name 'test' is not defined
Aborted
$ vi Lib/io.py
$ ./python -S
Python 3.0a1+ (py3k:58715M, Oct 30 2007, 19:02:47)
[GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
>>> import sys
[33116 refs]
>>> sys.maxunicode
1114111
[33127 refs]
>>>
[33128 refs]
[23233 refs]
$ python2.5 -c "import sys; print sys.maxunicode"
1114111
|
msg56975 - (view) |
Author: Guido van Rossum (gvanrossum) * |
Date: 2007-10-30 18:37 |
Thanks, I've closed issue 1352 too now.
|
|
Date |
User |
Action |
Args |
2022-04-11 14:56:27 | admin | set | github: 45670 |
2007-10-30 18:37:53 | gvanrossum | set | messages:
+ msg56975 |
2007-10-30 18:10:01 | christian.heimes | set | files:
+ py3k_preliminary_stderr3.patch |
2007-10-30 18:06:44 | christian.heimes | set | messages:
+ msg56969 |
2007-10-30 17:28:37 | gvanrossum | set | status: open -> closed resolution: accepted messages:
+ msg56964 |
2007-10-30 17:19:01 | gvanrossum | set | messages:
+ msg56963 |
2007-10-30 06:33:20 | christian.heimes | set | files:
+ py3k_combined_preliminary_closefd.patch messages:
+ msg56957 |
2007-10-30 00:42:26 | gvanrossum | set | priority: high messages:
+ msg56944 |
2007-10-29 20:23:52 | gvanrossum | set | assignee: gvanrossum |
2007-10-29 09:03:33 | christian.heimes | set | files:
+ py3k_closefd.patch messages:
+ msg56898 |
2007-10-29 00:57:23 | gvanrossum | set | messages:
+ msg56897 |
2007-10-28 19:08:08 | MrJean1 | set | messages:
+ msg56890 |
2007-10-28 17:44:21 | MrJean1 | set | files:
+ dlibtest4.c messages:
+ msg56886 |
2007-10-28 17:03:58 | christian.heimes | set | nosy:
+ christian.heimes messages:
+ msg56885 |
2007-10-28 15:31:17 | MrJean1 | set | messages:
+ msg56882 |
2007-10-27 18:48:10 | MrJean1 | set | messages:
+ msg56859 |
2007-10-27 17:04:41 | gvanrossum | set | messages:
+ msg56857 |
2007-10-27 16:41:20 | MrJean1 | set | messages:
+ msg56856 |
2007-10-27 15:12:54 | MrJean1 | set | messages:
+ msg56854 |
2007-10-27 06:20:09 | nnorwitz | set | files:
+ stdout-close.patch messages:
+ msg56845 |
2007-10-27 06:03:49 | MrJean1 | set | files:
+ dlibtest.c messages:
+ msg56844 |
2007-10-27 01:49:40 | MrJean1 | set | messages:
+ msg56840 |
2007-10-27 00:28:18 | MrJean1 | set | messages:
+ msg56838 |
2007-10-27 00:09:02 | MrJean1 | set | messages:
+ msg56835 |
2007-10-27 00:01:32 | nnorwitz | set | messages:
+ msg56834 |
2007-10-26 23:55:07 | MrJean1 | set | messages:
+ msg56832 |
2007-10-26 23:28:13 | nnorwitz | set | messages:
+ msg56831 |
2007-10-26 22:20:20 | MrJean1 | set | messages:
+ msg56827 |
2007-10-26 21:38:42 | MrJean1 | set | messages:
+ msg56826 |
2007-10-26 21:30:45 | MrJean1 | set | messages:
+ msg56825 |
2007-10-26 21:16:34 | gvanrossum | set | messages:
+ msg56824 |
2007-10-26 21:15:56 | gvanrossum | set | files:
- dlibtest.c |
2007-10-26 21:02:18 | MrJean1 | set | messages:
+ msg56823 |
2007-10-26 20:30:11 | gvanrossum | set | messages:
+ msg56821 |
2007-10-26 20:22:44 | MrJean1 | set | files:
+ dlibtest.c messages:
+ msg56820 |
2007-10-26 20:03:50 | MrJean1 | set | files:
+ dlibtest.c messages:
+ msg56818 |
2007-10-26 19:10:13 | MrJean1 | set | messages:
+ msg56810 |
2007-10-26 17:47:53 | gvanrossum | set | nosy:
+ gvanrossum messages:
+ msg56802 |
2007-10-26 17:18:28 | MrJean1 | set | messages:
+ msg56796 |
2007-10-26 15:30:26 | MrJean1 | set | messages:
+ msg56793 |
2007-10-26 15:28:31 | MrJean1 | set | messages:
+ msg56792 |
2007-10-26 06:28:16 | nnorwitz | set | nosy:
+ nnorwitz messages:
+ msg56779 |
2007-10-25 23:07:47 | MrJean1 | create | |