[issue37997] Segfault when using pickle with exceptions and dynamic class inheritance

2019-09-09 Thread Gabriel C


Gabriel C  added the comment:

Some further investigation suggests this may have nothing to do with pickle at 
all.

Consider the following short example:
```
def CreateDynamicClass(basetype):
class DynamicClassImpl(basetype):
def __init__(self):
super(DynamicClassImpl, self).__init__()

return DynamicClassImpl()

# Comment out any of the following three lines and the test passes
dynamic_memerror = CreateDynamicClass(MemoryError)
memory_error = MemoryError("Test")
dynamic_memerror = CreateDynamicClass(MemoryError)

print(MemoryError("Test2"))
```

This reliably produces the following stack trace:
```
Traceback (most recent call last):
  File "test_min2.py", line 13, in 
print(MemoryError("Test2"))
TypeError: __init__() takes 1 positional argument but 2 were given
```
In addition it causes a bus error (signal 10) around 30% of the time when run 
on python 3.7.4 (macOS high sierra) and a segmentation fault around 10% of the 
time when run on python 3.5 (Ubuntu 16.04).

Now modify the short example as follows, inserting a dummy argument into the 
constructor of the dynamic exception type:
```
def CreateDynamicClass(basetype):
class DynamicClassImpl(basetype):
def __init__(self, dummy_arg):
if dummy_arg is not None:
raise AssertionError("Dynamic exception constructor called.")
super(DynamicClassImpl, self).__init__()

return DynamicClassImpl(None)

# Comment out any of the following three lines and the test passes
dynamic_memerror = CreateDynamicClass(MemoryError)
memory_error = MemoryError("Test")
dynamic_memerror = CreateDynamicClass(MemoryError)

print(MemoryError("Test2"))
```

This produces the following stack trace:
```
Traceback (most recent call last):
  File "test_min2.py", line 15, in 
print(MemoryError("Test2"))
  File "test_min2.py", line 5, in __init__
raise AssertionError("Dynamic exception constructor called.")
AssertionError: Dynamic exception constructor called.
```
showing that the user-defined type constructor is actually called when the 
MemoryError object is created.

--

___
Python tracker 
<https://bugs.python.org/issue37997>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue37997] Segfault when using pickle with exceptions and dynamic class inheritance

2019-08-31 Thread Gabriel C


New submission from Gabriel C :

The following results in a segfault on 3.7.4 (running on macOS high sierra) and 
3.5 (running on ubuntu 16.04). It does not happen in python 2.7.

The problem seems to involve two effects. The first is the creation of a class 
with a dynamic type that inherits from a MemoryError (but any exception will 
work). The second is pickling an instance of that MemoryError (note that the 
dynamic type is never pickled).

If a basic (non-exception) class is used instead of the MemoryError (see 
uncomment case 1), then the segfault does not occur in my testing. If the 
exception being pickled is a different type to the one used as the base class 
for the dynamic type, the segfault does not occur. 

Note that unpickling the MemoryError actually raises another exception, this 
raised exception (see uncomment case 2) is raised by the dynamic type class 
__init__ method. It seems that in trying to unpickle the MemoryError, pickle 
attempts to create an instance of the unrelated dynamic type instead. Examining 
the stack trace (uncomment case 3), shows the raised exception is indeed 
originating from attempting to unpickle the MemoryError.

The segfault does not happen immediately, but instead after several attempts. 
It can happen after as few as 5 attempts or as many as 100. 

```
import pickle

def CreateDynamicClass(basetype):
class DynamicClassImpl(basetype):
def __init__(self):
super(DynamicClassImpl, self).__init__()

return DynamicClassImpl()

class TestClass(object):
pass

N_attemps = 1000

pickle_list = []

def load_list():
for i in range(N_attemps):
test_exception = MemoryError("Test" + str(i))
#test_exception = TestClass() # Uncomment case 1
pickle_list.append(pickle.dumps(test_exception))
load_list()

def unload_list():
for i in range(N_attemps):
try:
test_object_instance = pickle.loads(pickle_list.pop())
test_dynamic_object = CreateDynamicClass(MemoryError)
#test_dynamic_object = CreateDynamicClass(TestClass) # Uncomment 
case 1
except Exception as e:
print("Exception at iteration {}: {}".format(i, e)) # Uncomment 
case 2
#raise # Uncomment case 3
pass
unload_list()
```

--
components: Library (Lib)
messages: 350932
nosy: gabrielc
priority: normal
severity: normal
status: open
title: Segfault when using pickle with exceptions and dynamic class inheritance
type: crash
versions: Python 3.5, Python 3.7

___
Python tracker 
<https://bugs.python.org/issue37997>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com