summaryrefslogtreecommitdiffstats
path: root/Lib/test/crashers
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/crashers')
-rw-r--r--Lib/test/crashers/bogus_code_obj.py19
-rw-r--r--Lib/test/crashers/borrowed_ref_1.py29
-rw-r--r--Lib/test/crashers/borrowed_ref_2.py38
-rw-r--r--Lib/test/crashers/coerce.py9
-rw-r--r--Lib/test/crashers/gc_inspection.py32
-rw-r--r--Lib/test/crashers/infinite_rec_3.py9
-rw-r--r--Lib/test/crashers/recursion_limit_too_high.py16
-rw-r--r--Lib/test/crashers/recursive_call.py5
-rw-r--r--Lib/test/crashers/xml_parsers.py56
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)