# Python test set -- part 5, built-in exceptions
import copy
+import gc
import os
import sys
import unittest
next(i)
next(i)
+ def test_memory_error_subclasses(self):
+ # bpo-41654: MemoryError instances use a freelist of objects that are
+ # linked using the 'dict' attribute when they are inactive/dead.
+ # Subclasses of MemoryError should not participate in the freelist
+ # schema. This test creates a MemoryError object and keeps it alive
+ # (therefore advancing the freelist) and then it creates and destroys a
+ # subclass object. Finally, it checks that creating a new MemoryError
+ # succeeds, proving that the freelist is not corrupted.
+
+ class TestException(MemoryError):
+ pass
+
+ try:
+ raise MemoryError
+ except MemoryError as exc:
+ inst = exc
+
+ try:
+ raise TestException
+ except Exception:
+ pass
+
+ for _ in range(10):
+ try:
+ raise MemoryError
+ except MemoryError as exc:
+ pass
+
+ gc_collect()
class ImportErrorTests(unittest.TestCase):
{
PyBaseExceptionObject *self;
- if (type != (PyTypeObject *) PyExc_MemoryError)
+ /* If this is a subclass of MemoryError, don't use the freelist
+ * and just return a fresh object */
+ if (type != (PyTypeObject *) PyExc_MemoryError) {
return BaseException_new(type, args, kwds);
+ }
+
if (memerrors_freelist == NULL)
return BaseException_new(type, args, kwds);
/* Fetch object from freelist and revive it */
static void
MemoryError_dealloc(PyBaseExceptionObject *self)
{
- _PyObject_GC_UNTRACK(self);
BaseException_clear(self);
+
+ if (Py_TYPE(self) != PyExc_MemoryError) {
+ return Py_TYPE(self)->tp_free((PyObject *)self);
+ }
+
+ _PyObject_GC_UNTRACK(self);
+
if (memerrors_numfree >= MEMERRORS_SAVE)
Py_TYPE(self)->tp_free((PyObject *)self);
else {