Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
d92f0406
Commit
d92f0406
authored
Jul 17, 2010
by
Alexander Belopolsky
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #5180: Fixed a bug that prevented loading 2.x pickles in 3.x
python when they contain instances of old-style classes.
parent
bbda0c5f
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
91 additions
and
40 deletions
+91
-40
Lib/pickle.py
Lib/pickle.py
+5
-16
Lib/test/pickletester.py
Lib/test/pickletester.py
+69
-0
Misc/NEWS
Misc/NEWS
+3
-0
Modules/_pickle.c
Modules/_pickle.c
+14
-24
No files found.
Lib/pickle.py
View file @
d92f0406
...
...
@@ -1034,19 +1034,15 @@ class _Unpickler:
def
_instantiate
(
self
,
klass
,
k
):
args
=
tuple
(
self
.
stack
[
k
+
1
:])
del
self
.
stack
[
k
:]
instantiated
=
False
if
(
not
args
and
isinstance
(
klass
,
type
)
and
not
hasattr
(
klass
,
"__getinitargs__"
)):
value
=
_EmptyClass
()
value
.
__class__
=
klass
instantiated
=
True
if
not
instantiated
:
if
(
args
or
not
isinstance
(
klass
,
type
)
or
hasattr
(
klass
,
"__getinitargs__"
)):
try
:
value
=
klass
(
*
args
)
except
TypeError
as
err
:
raise
TypeError
(
"in constructor for %s: %s"
%
(
klass
.
__name__
,
str
(
err
)),
sys
.
exc_info
()[
2
])
else
:
value
=
klass
.
__new__
(
klass
)
self
.
append
(
value
)
def
load_inst
(
self
):
...
...
@@ -1239,14 +1235,7 @@ class _Unpickler:
raise
_Stop
(
value
)
dispatch
[
STOP
[
0
]]
=
load_stop
# Helper class for load_inst/load_obj
class
_EmptyClass
:
pass
# Encode/decode longs in linear time.
import
binascii
as
_binascii
# Encode/decode longs.
def
encode_long
(
x
):
r"""Encode a long to a two's complement little-endian binary string.
...
...
Lib/test/pickletester.py
View file @
d92f0406
...
...
@@ -65,9 +65,21 @@ class C:
def
__eq__
(
self
,
other
):
return
self
.
__dict__
==
other
.
__dict__
class
D
(
C
):
def
__init__
(
self
,
arg
):
pass
class
E
(
C
):
def
__getinitargs__
(
self
):
return
()
import
__main__
__main__
.
C
=
C
C
.
__module__
=
"__main__"
__main__
.
D
=
D
D
.
__module__
=
"__main__"
__main__
.
E
=
E
E
.
__module__
=
"__main__"
class
myint
(
int
):
def
__init__
(
self
,
x
):
...
...
@@ -425,6 +437,63 @@ class AbstractPickleTests(unittest.TestCase):
def
test_load_from_data2
(
self
):
self
.
assertEqual
(
self
.
_testdata
,
self
.
loads
(
DATA2
))
def
test_load_classic_instance
(
self
):
# See issue5180. Test loading 2.x pickles that
# contain an instance of old style class.
for
X
,
args
in
[(
C
,
()),
(
D
,
(
'x'
,)),
(
E
,
())]:
xname
=
X
.
__name__
.
encode
(
'ascii'
)
# Protocol 0 (text mode pickle):
"""
0: ( MARK
1: i INST '__main__ X' (MARK at 0)
15: p PUT 0
18: ( MARK
19: d DICT (MARK at 18)
20: p PUT 1
23: b BUILD
24: . STOP
"""
pickle0
=
(
b"(i__main__
\
n
"
b"X
\
n
"
b"p0
\
n
"
b"(dp1
\
n
b."
).
replace
(
b'X'
,
xname
)
self
.
assertEqual
(
X
(
*
args
),
self
.
loads
(
pickle0
))
# Protocol 1 (binary mode pickle)
"""
0: ( MARK
1: c GLOBAL '__main__ X'
15: q BINPUT 0
17: o OBJ (MARK at 0)
18: q BINPUT 1
20: } EMPTY_DICT
21: q BINPUT 2
23: b BUILD
24: . STOP
"""
pickle1
=
(
b'(c__main__
\
n
'
b'X
\
n
'
b'q
\
x00
oq
\
x01
}q
\
x02
b.'
).
replace
(
b'X'
,
xname
)
self
.
assertEqual
(
X
(
*
args
),
self
.
loads
(
pickle1
))
# Protocol 2 (pickle2 = b'\x80\x02' + pickle1)
"""
0:
\
x80
PROTO 2
2: ( MARK
3: c GLOBAL '__main__ X'
17: q BINPUT 0
19: o OBJ (MARK at 2)
20: q BINPUT 1
22: } EMPTY_DICT
23: q BINPUT 2
25: b BUILD
26: . STOP
"""
pickle2
=
(
b'
\
x80
\
x02
(c__main__
\
n
'
b'X
\
n
'
b'q
\
x00
oq
\
x01
}q
\
x02
b.'
).
replace
(
b'X'
,
xname
)
self
.
assertEqual
(
X
(
*
args
),
self
.
loads
(
pickle2
))
# There are gratuitous differences between pickles produced by
# pickle and cPickle, largely because cPickle starts PUT indices at
# 1 and pickle starts them at 0. See XXX comment in cPickle's put2() --
...
...
Misc/NEWS
View file @
d92f0406
...
...
@@ -1429,6 +1429,9 @@ Library
Extension Modules
-----------------
- Issue #5180: Fixed a bug that prevented loading 2.x pickles in 3.x
python when they contain instances of old-style classes.
- Issue #9165: Add new functions math.isfinite and cmath.isfinite, to
accompany existing isinf and isnan functions.
...
...
Modules/_pickle.c
View file @
d92f0406
...
...
@@ -3466,29 +3466,19 @@ load_dict(UnpicklerObject *self)
static
PyObject
*
instantiate
(
PyObject
*
cls
,
PyObject
*
args
)
{
PyObject
*
r
=
NULL
;
/* XXX: The pickle.py module does not create instances this way when the
args tuple is empty. See Unpickler._instantiate(). */
if
((
r
=
PyObject_CallObject
(
cls
,
args
)))
return
r
;
/* XXX: Is this still nescessary? */
{
PyObject
*
tp
,
*
v
,
*
tb
,
*
tmp_value
;
PyErr_Fetch
(
&
tp
,
&
v
,
&
tb
);
tmp_value
=
v
;
/* NULL occurs when there was a KeyboardInterrupt */
if
(
tmp_value
==
NULL
)
tmp_value
=
Py_None
;
if
((
r
=
PyTuple_Pack
(
3
,
tmp_value
,
cls
,
args
)))
{
Py_XDECREF
(
v
);
v
=
r
;
}
PyErr_Restore
(
tp
,
v
,
tb
);
PyObject
*
result
=
NULL
;
/* Caller must assure args are a tuple. Normally, args come from
Pdata_poptuple which packs objects from the top of the stack
into a newly created tuple. */
assert
(
PyTuple_Check
(
args
));
if
(
Py_SIZE
(
args
)
>
0
||
!
PyType_Check
(
cls
)
||
PyObject_HasAttrString
(
cls
,
"__getinitargs__"
))
{
result
=
PyObject_CallObject
(
cls
,
args
);
}
return
NULL
;
else
{
result
=
PyObject_CallMethod
(
cls
,
"__new__"
,
"O"
,
cls
);
}
return
result
;
}
static
int
...
...
@@ -3547,7 +3537,7 @@ load_inst(UnpicklerObject *self)
if
(
len
<
2
)
return
bad_readline
();
class_name
=
PyUnicode_DecodeASCII
(
s
,
len
-
1
,
"strict"
);
if
(
class_name
=
=
NULL
)
{
if
(
class_name
!
=
NULL
)
{
cls
=
find_class
(
self
,
module_name
,
class_name
);
Py_DECREF
(
class_name
);
}
...
...
@@ -4276,7 +4266,7 @@ load_reduce(UnpicklerObject *self)
return
-
1
;
PDATA_POP
(
self
->
stack
,
callable
);
if
(
callable
)
{
obj
=
instantiate
(
callable
,
argtup
);
obj
=
PyObject_CallObject
(
callable
,
argtup
);
Py_DECREF
(
callable
);
}
Py_DECREF
(
argtup
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment