msg69532 - (view) |
Author: Darryl Dixon (esrever_otua) |
Date: 2008-07-11 04:54 |
In at least Python 2.4, using cPickle.Pickler to try and pickle a nested
chain of objects more than about 2590 objects deep causes the Python
interpreter to segfault. This doesn't seem to happen when using the pure
Python pickle module.
It is not memory related (witness that the pure Python module can
achieve depths much greater than this just fine), and does not seem to
be directly related to system architecture (happens on both i386 and on
x86_64 (32bit and 64bit)).
Sample interpreter session to replicate:
>>> # Let's cause cPickle to segfault:
>>> from cPickle import Pickler as cPickler
>>> class rec:
... child = None
... def __init__(self, counter):
... if counter > 0:
... self.child = rec(counter-1)
...
>>> import sys
>>> sys.setrecursionlimit(10000)
>>> mychain = rec(2600)
>>> from cStringIO import StringIO
>>> stream = StringIO()
>>> p = cPickler(stream, 1)
>>> res = p.dump(mychain)
Segmentation fault
And now the same steps again using the pure Python Pickler:
>>> import sys
>>> from pickle import Pickler as pPickler
>>> from cStringIO import StringIO
>>> class rec:
... child = None
... def __init__(self, counter):
... if counter > 0:
... self.child = rec(counter-1)
...
>>> sys.setrecursionlimit(20000)
>>> mychain = rec(2600)
>>> stream = StringIO()
>>> p = pPickler(stream, 1)
>>> p.dump(mychain)
>>> len(stream.getvalue())
48676
>>>
|
msg69534 - (view) |
Author: Martin v. Löwis (loewis) * |
Date: 2008-07-11 06:49 |
Can you try this for a newer version? For 2.4, such problems will not be
fixed anymore.
|
msg69585 - (view) |
Author: Darryl Dixon (esrever_otua) |
Date: 2008-07-12 12:37 |
Happens with Python 2.5.2 on 64bit also:
Python 2.5.2 (r252:60911, Apr 21 2008, 11:17:30)
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> platform.architecture()
('64bit', '')
>>> from cPickle import Pickler
>>> class rec:
... child = None
... def __init__(self, counter):
... if counter > 0:
... self.child = rec(counter-1)
...
>>> import sys
>>> sys.setrecursionlimit(10000)
>>> mychain = rec(2600)
>>> from cStringIO import StringIO
>>> stream = StringIO()
>>> p = Pickler(stream, 1)
>>> res = p.dump(mychain)
Segmentation fault
|
msg69756 - (view) |
Author: Darryl Dixon (esrever_otua) |
Date: 2008-07-16 03:27 |
Hmm, looks like this dup's 2702... Funny how two people find the same
thing within a short window of each other *sighs* so looks like it's
probably fixed. I'll test /trunk against the failing testcase below and
make sure all is OK.
D
|
msg69759 - (view) |
Author: Darryl Dixon (esrever_otua) |
Date: 2008-07-16 04:07 |
No, I've just tested /trunk, including r64595, and the Segmentation
fault is still present, eg:
Python 2.6b1+ (trunk:64998, Jul 16 2008, 15:50:22)
[GCC 4.1.1 20070105 (Red Hat 4.1.1-52)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.setrecursionlimit(40000)
>>> class rec(object):
... child = None
... def __init__(self, counter):
... if counter > 0:
... self.child = rec(counter-1)
...
>>> mychain = rec(2600)
>>> from cPickle import Pickler
>>> from cStringIO import StringIO
>>> stream = StringIO()
>>> p = Pickler(stream, 1)
>>> p.dump(mychain)
Segmentation fault
|
msg69803 - (view) |
Author: Facundo Batista (facundobatista) * |
Date: 2008-07-16 17:01 |
Confirmed in...
Python 2.6b1+ (trunk:65017M, Jul 16 2008, 13:37:00)
[GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
...with a more simple case:
"""
import sys, cPickle
sys.setrecursionlimit(10405)
class rec(object):
child = None
def __init__(self, counter):
if counter > 0:
self.child = rec(counter-1)
mychain = rec(2600)
cPickle.dumps(mychain)
"""
Note that if we put the recursion limit in 10405 we get a segfault, but
if we put it 10404, we get a "RuntimeError: maximum recursion depth
exceeded".
Considering that 10400 is exactly 2600 * 4, maybe this is a useful hint.
Another behaviour I got: With a recursion limit big big enough, doing
rec(1670) works ok, and rec(1671) segfaults.
And a very nasty one:
I put rec(1671) to see in which recursion limit we have the conversion
of RecursionLimit to SegFault. Testing, I tried with recursion limit in
6700, and sometimes it worked ok, and sometimes it segfaulted. Yes,
*sometimes*, :(
|
msg69842 - (view) |
Author: Darryl Dixon (esrever_otua) |
Date: 2008-07-16 21:39 |
That is a very interesting observation (x4), especially in light of #3373
Unfortunately I don't really have the (p|g)db -foo to debug either of
these properly :(
|
msg71656 - (view) |
Author: Antoine Pitrou (pitrou) * |
Date: 2008-08-21 16:24 |
Well, the standard recursion limit is precisely there to guard against
segfaults when blowing up the C stack, so if you make the recursion
limit much larger, it's quite normal to get segfaults.
Therefore, I don't think this is a real bug.
|
msg71722 - (view) |
Author: Darryl Dixon (esrever_otua) |
Date: 2008-08-22 04:18 |
Well, it's definitely a bug, or inconsistency, if you like, between
cPickle and pickle.
My gut says that probably there is some fault in cPickle that is causing
this. When pickle.py can recurse to 10,000+ and cPickle segfaults at
2600 on a 64bit machine, something smells wrong.
Especially as there have been other, similar, *fixable* bugs already in
cPickle (cf #2702). Unfortunately I can only report the problem, I do
not have the expertise to debug.
regards,
D
|
msg71733 - (view) |
Author: Antoine Pitrou (pitrou) * |
Date: 2008-08-22 09:23 |
> Well, it's definitely a bug, or inconsistency, if you like, between
> cPickle and pickle.
There is clearly a problem with cPickle stack consumption and a new bug has been
opened for this in #3640.
What I don't agree with is your argument that pickle and cPickle should have the
same recursion limits - it's just "foolish consistency" to ask for identical
behaviour on such a low-level and implementation-dependent issue.
|
msg87936 - (view) |
Author: Antoine Pitrou (pitrou) * |
Date: 2009-05-16 21:23 |
Now that #3640 has been fixed, this bug is probably fixed too (at least
in trunk and py3k).
|
|
Date |
User |
Action |
Args |
2022-04-11 14:56:36 | admin | set | github: 47588 |
2010-08-03 20:46:31 | terry.reedy | set | status: open -> closed resolution: fixed |
2009-05-16 21:23:59 | pitrou | set | messages:
+ msg87936 |
2009-05-16 20:35:06 | ajaksu2 | set | priority: normal dependencies:
+ test_cpickle crash on AMD64 Windows build versions:
+ Python 2.6, - Python 2.4 |
2008-08-22 09:23:45 | pitrou | set | messages:
+ msg71733 |
2008-08-22 04:18:08 | esrever_otua | set | messages:
+ msg71722 |
2008-08-21 16:24:20 | pitrou | set | nosy:
+ pitrou messages:
+ msg71656 |
2008-07-16 21:39:59 | esrever_otua | set | messages:
+ msg69842 |
2008-07-16 18:45:41 | jcea | set | nosy:
+ jcea |
2008-07-16 17:01:08 | facundobatista | set | nosy:
+ facundobatista messages:
+ msg69803 |
2008-07-16 04:07:55 | esrever_otua | set | messages:
+ msg69759 |
2008-07-16 03:27:05 | esrever_otua | set | messages:
+ msg69756 |
2008-07-12 12:37:09 | esrever_otua | set | messages:
+ msg69585 versions:
+ Python 2.5 |
2008-07-11 06:49:03 | loewis | set | nosy:
+ loewis messages:
+ msg69534 |
2008-07-11 04:54:21 | esrever_otua | create | |