diff options
Diffstat (limited to 'Lib/test/crashers')
-rw-r--r-- | Lib/test/crashers/bogus_code_obj.py | 19 | ||||
-rw-r--r-- | Lib/test/crashers/borrowed_ref_1.py | 29 | ||||
-rw-r--r-- | Lib/test/crashers/borrowed_ref_2.py | 38 | ||||
-rw-r--r-- | Lib/test/crashers/coerce.py | 9 | ||||
-rw-r--r-- | Lib/test/crashers/gc_inspection.py | 32 | ||||
-rw-r--r-- | Lib/test/crashers/infinite_rec_3.py | 9 | ||||
-rw-r--r-- | Lib/test/crashers/recursion_limit_too_high.py | 16 | ||||
-rw-r--r-- | Lib/test/crashers/recursive_call.py | 5 | ||||
-rw-r--r-- | Lib/test/crashers/xml_parsers.py | 56 |
9 files changed, 139 insertions, 74 deletions
diff --git a/Lib/test/crashers/bogus_code_obj.py b/Lib/test/crashers/bogus_code_obj.py new file mode 100644 index 0000000..613ae51 --- /dev/null +++ b/Lib/test/crashers/bogus_code_obj.py @@ -0,0 +1,19 @@ +""" +Broken bytecode objects can easily crash the interpreter. + +This is not going to be fixed. It is generally agreed that there is no +point in writing a bytecode verifier and putting it in CPython just for +this. Moreover, a verifier is bound to accept only a subset of all safe +bytecodes, so it could lead to unnecessary breakage. + +For security purposes, "restricted" interpreters are not going to let +the user build or load random bytecodes anyway. Otherwise, this is a +"won't fix" case. + +""" + +import types + +co = types.CodeType(0, 0, 0, 0, '\x04\x71\x00\x00', (), + (), (), '', '', 1, '') +exec co diff --git a/Lib/test/crashers/borrowed_ref_1.py b/Lib/test/crashers/borrowed_ref_1.py new file mode 100644 index 0000000..d16ede2 --- /dev/null +++ b/Lib/test/crashers/borrowed_ref_1.py @@ -0,0 +1,29 @@ +""" +_PyType_Lookup() returns a borrowed reference. +This attacks the call in dictobject.c. +""" + +class A(object): + pass + +class B(object): + def __del__(self): + print 'hi' + del D.__missing__ + +class D(dict): + class __missing__: + def __init__(self, *args): + pass + + +d = D() +a = A() +a.cycle = a +a.other = B() +del a + +prev = None +while 1: + d[5] + prev = (prev,) diff --git a/Lib/test/crashers/borrowed_ref_2.py b/Lib/test/crashers/borrowed_ref_2.py new file mode 100644 index 0000000..1a7b3ff --- /dev/null +++ b/Lib/test/crashers/borrowed_ref_2.py @@ -0,0 +1,38 @@ +""" +_PyType_Lookup() returns a borrowed reference. +This attacks PyObject_GenericSetAttr(). + +NB. on my machine this crashes in 2.5 debug but not release. +""" + +class A(object): + pass + +class B(object): + def __del__(self): + print "hi" + del C.d + +class D(object): + def __set__(self, obj, value): + self.hello = 42 + +class C(object): + d = D() + + def g(): + pass + + +c = C() +a = A() +a.cycle = a +a.other = B() + +lst = [None] * 1000000 +i = 0 +del a +while 1: + c.d = 42 # segfaults in PyMethod_New(im_func=D.__set__, im_self=d) + lst[i] = c.g # consume the free list of instancemethod objects + i += 1 diff --git a/Lib/test/crashers/coerce.py b/Lib/test/crashers/coerce.py deleted file mode 100644 index 574956b..0000000 --- a/Lib/test/crashers/coerce.py +++ /dev/null @@ -1,9 +0,0 @@ - -# http://python.org/sf/992017 - -class foo: - def __coerce__(self, other): - return other, self - -if __name__ == '__main__': - foo()+1 # segfault: infinite recursion in C diff --git a/Lib/test/crashers/gc_inspection.py b/Lib/test/crashers/gc_inspection.py new file mode 100644 index 0000000..10caa79 --- /dev/null +++ b/Lib/test/crashers/gc_inspection.py @@ -0,0 +1,32 @@ +""" +gc.get_referrers() can be used to see objects before they are fully built. + +Note that this is only an example. There are many ways to crash Python +by using gc.get_referrers(), as well as many extension modules (even +when they are using perfectly documented patterns to build objects). + +Identifying and removing all places that expose to the GC a +partially-built object is a long-term project. A patch was proposed on +SF specifically for this example but I consider fixing just this single +example a bit pointless (#1517042). + +A fix would include a whole-scale code review, possibly with an API +change to decouple object creation and GC registration, and according +fixes to the documentation for extension module writers. It's unlikely +to happen, though. So this is currently classified as +"gc.get_referrers() is dangerous, use only for debugging". +""" + +import gc + + +def g(): + marker = object() + yield marker + # now the marker is in the tuple being constructed + [tup] = [x for x in gc.get_referrers(marker) if type(x) is tuple] + print tup + print tup[1] + + +tuple(g()) diff --git a/Lib/test/crashers/infinite_rec_3.py b/Lib/test/crashers/infinite_rec_3.py deleted file mode 100644 index 0b04e4c..0000000 --- a/Lib/test/crashers/infinite_rec_3.py +++ /dev/null @@ -1,9 +0,0 @@ - -# http://python.org/sf/1202533 - -class A(object): - pass -A.__call__ = A() - -if __name__ == '__main__': - A()() # segfault: infinite recursion in C diff --git a/Lib/test/crashers/recursion_limit_too_high.py b/Lib/test/crashers/recursion_limit_too_high.py new file mode 100644 index 0000000..1fa4d32 --- /dev/null +++ b/Lib/test/crashers/recursion_limit_too_high.py @@ -0,0 +1,16 @@ +# The following example may crash or not depending on the platform. +# E.g. on 32-bit Intel Linux in a "standard" configuration it seems to +# crash on Python 2.5 (but not 2.4 nor 2.3). On Windows the import +# eventually fails to find the module, possibly because we run out of +# file handles. + +# The point of this example is to show that sys.setrecursionlimit() is a +# hack, and not a robust solution. This example simply exercices a path +# where it takes many C-level recursions, consuming a lot of stack +# space, for each Python-level recursion. So 1000 times this amount of +# stack space may be too much for standard platforms already. + +import sys +if 'recursion_limit_too_high' in sys.modules: + del sys.modules['recursion_limit_too_high'] +import recursion_limit_too_high diff --git a/Lib/test/crashers/recursive_call.py b/Lib/test/crashers/recursive_call.py index 0776479..31c8963 100644 --- a/Lib/test/crashers/recursive_call.py +++ b/Lib/test/crashers/recursive_call.py @@ -1,6 +1,11 @@ #!/usr/bin/env python # No bug report AFAIK, mail on python-dev on 2006-01-10 + +# This is a "won't fix" case. It is known that setting a high enough +# recursion limit crashes by overflowing the stack. Unless this is +# redesigned somehow, it won't go away. + import sys sys.setrecursionlimit(1 << 30) diff --git a/Lib/test/crashers/xml_parsers.py b/Lib/test/crashers/xml_parsers.py deleted file mode 100644 index e6b5727..0000000 --- a/Lib/test/crashers/xml_parsers.py +++ /dev/null @@ -1,56 +0,0 @@ -from xml.parsers import expat - -# http://python.org/sf/1296433 - -def test_parse_only_xml_data(): - # - xml = "<?xml version='1.0' encoding='iso8859'?><s>%s</s>" % ('a' * 1025) - # this one doesn't crash - #xml = "<?xml version='1.0'?><s>%s</s>" % ('a' * 10000) - - def handler(text): - raise Exception - - parser = expat.ParserCreate() - parser.CharacterDataHandler = handler - - try: - parser.Parse(xml) - except: - pass - -if __name__ == '__main__': - test_parse_only_xml_data() - -# Invalid read of size 4 -# at 0x43F936: PyObject_Free (obmalloc.c:735) -# by 0x45A7C7: unicode_dealloc (unicodeobject.c:246) -# by 0x1299021D: PyUnknownEncodingHandler (pyexpat.c:1314) -# by 0x12993A66: processXmlDecl (xmlparse.c:3330) -# by 0x12999211: doProlog (xmlparse.c:3678) -# by 0x1299C3F0: prologInitProcessor (xmlparse.c:3550) -# by 0x12991EA3: XML_ParseBuffer (xmlparse.c:1562) -# by 0x1298F8EC: xmlparse_Parse (pyexpat.c:895) -# by 0x47B3A1: PyEval_EvalFrameEx (ceval.c:3565) -# by 0x47CCAC: PyEval_EvalCodeEx (ceval.c:2739) -# by 0x47CDE1: PyEval_EvalCode (ceval.c:490) -# by 0x499820: PyRun_SimpleFileExFlags (pythonrun.c:1198) -# by 0x4117F1: Py_Main (main.c:492) -# by 0x12476D1F: __libc_start_main (in /lib/libc-2.3.5.so) -# by 0x410DC9: (within /home/neal/build/python/svn/clean/python) -# Address 0x12704020 is 264 bytes inside a block of size 592 free'd -# at 0x11B1BA8A: free (vg_replace_malloc.c:235) -# by 0x124B5F18: (within /lib/libc-2.3.5.so) -# by 0x48DE43: find_module (import.c:1320) -# by 0x48E997: import_submodule (import.c:2249) -# by 0x48EC15: load_next (import.c:2083) -# by 0x48F091: import_module_ex (import.c:1914) -# by 0x48F385: PyImport_ImportModuleEx (import.c:1955) -# by 0x46D070: builtin___import__ (bltinmodule.c:44) -# by 0x4186CF: PyObject_Call (abstract.c:1777) -# by 0x474E9B: PyEval_CallObjectWithKeywords (ceval.c:3432) -# by 0x47928E: PyEval_EvalFrameEx (ceval.c:2038) -# by 0x47CCAC: PyEval_EvalCodeEx (ceval.c:2739) -# by 0x47CDE1: PyEval_EvalCode (ceval.c:490) -# by 0x48D0F7: PyImport_ExecCodeModuleEx (import.c:635) -# by 0x48D4F4: load_source_module (import.c:913) |