diff options
author | Armin Rigo <arigo@tunes.org> | 2007-05-02 19:23:31 +0000 |
---|---|---|
committer | Armin Rigo <arigo@tunes.org> | 2007-05-02 19:23:31 +0000 |
commit | 9790a2706573359e02fcfc5f18f9907467f4ec49 (patch) | |
tree | d953c06fbbb8325b8ed86e707ed17f0b43b870dd /Lib | |
parent | d83eb316dce49606041304afb6b68e85fb1794af (diff) | |
download | cpython-git-9790a2706573359e02fcfc5f18f9907467f4ec49.tar.gz |
Fix for #1303614 and #1174712:
- __dict__ descriptor abuse for subclasses of built-in types
- subclassing from both ModuleType and another built-in types
Thanks zseil for the patch.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/crashers/dangerous_subclassing.py | 12 | ||||
-rw-r--r-- | Lib/test/crashers/modify_dict_attr.py | 20 | ||||
-rw-r--r-- | Lib/test/test_descr.py | 80 |
3 files changed, 78 insertions, 34 deletions
diff --git a/Lib/test/crashers/dangerous_subclassing.py b/Lib/test/crashers/dangerous_subclassing.py deleted file mode 100644 index 0479952b2c..0000000000 --- a/Lib/test/crashers/dangerous_subclassing.py +++ /dev/null @@ -1,12 +0,0 @@ - -# http://python.org/sf/1174712 - -import types - -class X(types.ModuleType, str): - """Such a subclassing is incorrectly allowed -- - see the SF bug report for explanations""" - -if __name__ == '__main__': - X('name') # segfault: ModuleType.__init__() reads - # the dict at the wrong offset diff --git a/Lib/test/crashers/modify_dict_attr.py b/Lib/test/crashers/modify_dict_attr.py deleted file mode 100644 index 11c672106a..0000000000 --- a/Lib/test/crashers/modify_dict_attr.py +++ /dev/null @@ -1,20 +0,0 @@ - -# http://python.org/sf/1303614 - -class Y(object): - pass - -class type_with_modifiable_dict(type, Y): - pass - -class MyClass(object): - """This class has its __dict__ attribute indirectly - exposed via the __dict__ getter/setter of Y. - """ - __metaclass__ = type_with_modifiable_dict - - -if __name__ == '__main__': - dictattr = Y.__dict__['__dict__'] - dictattr.__delete__(MyClass) # if we set tp_dict to NULL, - print MyClass # doing anything with MyClass segfaults diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 53181ac135..57cef44097 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -3,6 +3,7 @@ from test.test_support import verify, vereq, verbose, TestFailed, TESTFN, get_original_stdout from copy import deepcopy import warnings +import types warnings.filterwarnings("ignore", r'complex divmod\(\), // and % are deprecated$', @@ -861,6 +862,16 @@ def pymods(): ("getattr", "foo"), ("delattr", "foo")]) + # http://python.org/sf/1174712 + try: + class Module(types.ModuleType, str): + pass + except TypeError: + pass + else: + raise TestFailed("inheriting from ModuleType and str at the " + "same time should fail") + def multi(): if verbose: print "Testing multiple inheritance..." class C(object): @@ -2907,8 +2918,73 @@ def setdict(): cant(a, []) cant(a, 1) del a.__dict__ # Deleting __dict__ is allowed - # Classes don't allow __dict__ assignment - cant(C, {}) + + class Base(object): + pass + def verify_dict_readonly(x): + """ + x has to be an instance of a class inheriting from Base. + """ + cant(x, {}) + try: + del x.__dict__ + except (AttributeError, TypeError): + pass + else: + raise TestFailed, "shouldn't allow del %r.__dict__" % x + dict_descr = Base.__dict__["__dict__"] + try: + dict_descr.__set__(x, {}) + except (AttributeError, TypeError): + pass + else: + raise TestFailed, "dict_descr allowed access to %r's dict" % x + + # Classes don't allow __dict__ assignment and have readonly dicts + class Meta1(type, Base): + pass + class Meta2(Base, type): + pass + class D(object): + __metaclass__ = Meta1 + class E(object): + __metaclass__ = Meta2 + for cls in C, D, E: + verify_dict_readonly(cls) + class_dict = cls.__dict__ + try: + class_dict["spam"] = "eggs" + except TypeError: + pass + else: + raise TestFailed, "%r's __dict__ can be modified" % cls + + # Modules also disallow __dict__ assignment + class Module1(types.ModuleType, Base): + pass + class Module2(Base, types.ModuleType): + pass + for ModuleType in Module1, Module2: + mod = ModuleType("spam") + verify_dict_readonly(mod) + mod.__dict__["spam"] = "eggs" + + # Exception's __dict__ can be replaced, but not deleted + class Exception1(Exception, Base): + pass + class Exception2(Base, Exception): + pass + for ExceptionType in Exception, Exception1, Exception2: + e = ExceptionType() + e.__dict__ = {"a": 1} + vereq(e.a, 1) + try: + del e.__dict__ + except (TypeError, AttributeError): + pass + else: + raise TestFaied, "%r's __dict__ can be deleted" % e + def pickles(): if verbose: |