Commit 5adfac2c authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #5322: Fixed setting __new__ to a PyCFunction inside Python code.

Original patch by Andreas Stührk.
parent 028ace1c
...@@ -7,6 +7,7 @@ import pickle ...@@ -7,6 +7,7 @@ import pickle
import sys import sys
import types import types
import unittest import unittest
import warnings
import weakref import weakref
from copy import deepcopy from copy import deepcopy
...@@ -1661,6 +1662,75 @@ order (MRO) for bases """ ...@@ -1661,6 +1662,75 @@ order (MRO) for bases """
self.assertEqual(b.foo, 3) self.assertEqual(b.foo, 3)
self.assertEqual(b.__class__, D) self.assertEqual(b.__class__, D)
def test_bad_new(self):
self.assertRaises(TypeError, object.__new__)
self.assertRaises(TypeError, object.__new__, '')
self.assertRaises(TypeError, list.__new__, object)
self.assertRaises(TypeError, object.__new__, list)
class C(object):
__new__ = list.__new__
self.assertRaises(TypeError, C)
class C(list):
__new__ = object.__new__
self.assertRaises(TypeError, C)
def test_object_new(self):
class A(object):
pass
object.__new__(A)
self.assertRaises(TypeError, object.__new__, A, 5)
object.__init__(A())
self.assertRaises(TypeError, object.__init__, A(), 5)
class A(object):
def __init__(self, foo):
self.foo = foo
object.__new__(A)
object.__new__(A, 5)
object.__init__(A(3))
self.assertRaises(TypeError, object.__init__, A(3), 5)
class A(object):
def __new__(cls, foo):
return object.__new__(cls)
object.__new__(A)
self.assertRaises(TypeError, object.__new__, A, 5)
object.__init__(A(3))
object.__init__(A(3), 5)
class A(object):
def __new__(cls, foo):
return object.__new__(cls)
def __init__(self, foo):
self.foo = foo
object.__new__(A)
self.assertRaises(TypeError, object.__new__, A, 5)
object.__init__(A(3))
self.assertRaises(TypeError, object.__init__, A(3), 5)
def test_restored_object_new(self):
class A(object):
def __new__(cls, *args, **kwargs):
raise AssertionError
self.assertRaises(AssertionError, A)
class B(A):
__new__ = object.__new__
def __init__(self, foo):
self.foo = foo
with warnings.catch_warnings():
warnings.simplefilter('error', DeprecationWarning)
b = B(3)
self.assertEqual(b.foo, 3)
self.assertEqual(b.__class__, B)
del B.__new__
self.assertRaises(AssertionError, B)
del A.__new__
with warnings.catch_warnings():
warnings.simplefilter('error', DeprecationWarning)
b = B(3)
self.assertEqual(b.foo, 3)
self.assertEqual(b.__class__, B)
def test_altmro(self): def test_altmro(self):
# Testing mro() and overriding it... # Testing mro() and overriding it...
class A(object): class A(object):
...@@ -3522,6 +3592,24 @@ order (MRO) for bases """ ...@@ -3522,6 +3592,24 @@ order (MRO) for bases """
self.assertIsInstance(d, D) self.assertIsInstance(d, D)
self.assertEqual(d.foo, 1) self.assertEqual(d.foo, 1)
class C(object):
@staticmethod
def __new__(*args):
return args
self.assertEqual(C(1, 2), (C, 1, 2))
class D(C):
pass
self.assertEqual(D(1, 2), (D, 1, 2))
class C(object):
@classmethod
def __new__(*args):
return args
self.assertEqual(C(1, 2), (C, C, 1, 2))
class D(C):
pass
self.assertEqual(D(1, 2), (D, D, 1, 2))
def test_imul_bug(self): def test_imul_bug(self):
# Testing for __imul__ problems... # Testing for __imul__ problems...
# SF bug 544647 # SF bug 544647
......
...@@ -10,6 +10,9 @@ Release date: TBA ...@@ -10,6 +10,9 @@ Release date: TBA
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #5322: Fixed setting __new__ to a PyCFunction inside Python code.
Original patch by Andreas Stührk.
- Issue #28648: Fixed crash in Py_DecodeLocale() in debug build on Mac OS X - Issue #28648: Fixed crash in Py_DecodeLocale() in debug build on Mac OS X
when decode astral characters. Patch by Xiang Zhang. when decode astral characters. Patch by Xiang Zhang.
......
...@@ -6798,7 +6798,34 @@ update_one_slot(PyTypeObject *type, slotdef *p) ...@@ -6798,7 +6798,34 @@ update_one_slot(PyTypeObject *type, slotdef *p)
sanity checks and constructing a new argument sanity checks and constructing a new argument
list. Cut all that nonsense short -- this speeds list. Cut all that nonsense short -- this speeds
up instance creation tremendously. */ up instance creation tremendously. */
specific = (void *)type->tp_new; PyObject *self = PyCFunction_GET_SELF(descr);
if (!self || !PyType_Check(self)) {
/* This should never happen because
tp_new_wrapper expects a type for self.
Use slot_tp_new which will call
tp_new_wrapper which will raise an
exception. */
specific = (void *)slot_tp_new;
}
else {
PyTypeObject *staticbase;
specific = ((PyTypeObject *)self)->tp_new;
/* Check that the user does not do anything
silly and unsafe like object.__new__(dict).
To do this, we check that the most derived
base that's not a heap type is this type. */
staticbase = type->tp_base;
while (staticbase &&
(staticbase->tp_flags & Py_TPFLAGS_HEAPTYPE))
staticbase = staticbase->tp_base;
if (staticbase &&
staticbase->tp_new != specific)
/* Seems to be unsafe, better use
slot_tp_new which will call
tp_new_wrapper which will raise an
exception if it is unsafe. */
specific = (void *)slot_tp_new;
}
/* XXX I'm not 100% sure that there isn't a hole /* XXX I'm not 100% sure that there isn't a hole
in this reasoning that requires additional in this reasoning that requires additional
sanity checks. I'll buy the first person to sanity checks. I'll buy the first person to
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment