Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 12 additions & 15 deletions dill/_dill.py
Original file line number Diff line number Diff line change
Expand Up @@ -1032,23 +1032,20 @@ def _create_capsule(pointer, name, context, destructor):
return capsule

def _getattr(objclass, name, repr_str):
# hack to grab the reference directly
try: #XXX: works only for __builtin__ ?
attr = repr_str.split("'")[3]
return eval(attr+'.__dict__["'+name+'"]')
except Exception:
try:
attr = objclass.__dict__
if type(attr) is DictProxyType:
if sys.hexversion > 0x30f00a0 and name in ('__weakref__','__dict__'):
attr = _dictproxy_helper.__dict__[name]
else:
attr = attr[name]
# grab the descriptor directly off its owning class; repr_str is kept
# for backward compatibility with existing pickles but is not evaluated
try:
attr = objclass.__dict__
if type(attr) is DictProxyType:
if sys.hexversion > 0x30f00a0 and name in ('__weakref__','__dict__'):
attr = _dictproxy_helper.__dict__[name]
else:
attr = getattr(objclass,name)
except (AttributeError, KeyError):
attr = attr[name]
else:
attr = getattr(objclass,name)
return attr
except (AttributeError, KeyError):
attr = getattr(objclass,name)
return attr

def _get_attr(self, name):
# stop recursive pickling
Expand Down
16 changes: 16 additions & 0 deletions dill/tests/test_selected.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,21 @@ def test_class_descriptors():
assert ok
if verbose: print ("")

# descriptors are restored via dill._dill._getattr; the attribute name
# carried in the pickle must be looked up, never evaluated as code
def test_descriptor_getattr():
from dill._dill import _getattr
for i in (int.__dict__['real'], str.__dict__['__len__']):
assert dill.copy(i) is i
# a crafted name that would run code if passed to eval() must instead be
# treated as a plain (missing) lookup key
name = '__doc__"].count("zz") or setattr(__import__("dill"), "_pwned", True) or object.__dict__["__doc__'
try:
_getattr(object, name, "x'x'x'object'x")
except (AttributeError, KeyError):
pass
assert not getattr(dill, "_pwned", False)

# (__main__) class instance for new-style classes
def test_class():
o = _d()
Expand Down Expand Up @@ -118,4 +133,5 @@ def test_typing():
test_dict_contents()
test_class()
test_class_descriptors()
test_descriptor_getattr()
test_typing()