summaryrefslogtreecommitdiff
path: root/sys/lib/python/test/crashers
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@localhost>2011-05-03 11:25:13 +0000
committercinap_lenrek <cinap_lenrek@localhost>2011-05-03 11:25:13 +0000
commit458120dd40db6b4df55a4e96b650e16798ef06a0 (patch)
tree8f82685be24fef97e715c6f5ca4c68d34d5074ee /sys/lib/python/test/crashers
parent3a742c699f6806c1145aea5149bf15de15a0afd7 (diff)
add hg and python
Diffstat (limited to 'sys/lib/python/test/crashers')
-rw-r--r--sys/lib/python/test/crashers/README20
-rw-r--r--sys/lib/python/test/crashers/bogus_code_obj.py19
-rw-r--r--sys/lib/python/test/crashers/borrowed_ref_1.py29
-rw-r--r--sys/lib/python/test/crashers/borrowed_ref_2.py38
-rw-r--r--sys/lib/python/test/crashers/dangerous_subclassing.py12
-rw-r--r--sys/lib/python/test/crashers/gc_inspection.py32
-rw-r--r--sys/lib/python/test/crashers/infinite_rec_1.py11
-rw-r--r--sys/lib/python/test/crashers/infinite_rec_2.py10
-rw-r--r--sys/lib/python/test/crashers/infinite_rec_4.py7
-rw-r--r--sys/lib/python/test/crashers/infinite_rec_5.py10
-rw-r--r--sys/lib/python/test/crashers/loosing_dict_ref.py21
-rw-r--r--sys/lib/python/test/crashers/modify_dict_attr.py19
-rw-r--r--sys/lib/python/test/crashers/nasty_eq_vs_dict.py47
-rw-r--r--sys/lib/python/test/crashers/recursion_limit_too_high.py16
-rw-r--r--sys/lib/python/test/crashers/recursive_call.py15
-rw-r--r--sys/lib/python/test/crashers/weakref_in_del.py17
16 files changed, 323 insertions, 0 deletions
diff --git a/sys/lib/python/test/crashers/README b/sys/lib/python/test/crashers/README
new file mode 100644
index 000000000..070c3f122
--- /dev/null
+++ b/sys/lib/python/test/crashers/README
@@ -0,0 +1,20 @@
+This directory only contains tests for outstanding bugs that cause
+the interpreter to segfault. Ideally this directory should always
+be empty. Sometimes it may not be easy to fix the underlying cause.
+
+Each test should fail when run from the command line:
+
+ ./python Lib/test/crashers/weakref_in_del.py
+
+Each test should have a link to the bug report:
+
+ # http://python.org/sf/BUG#
+
+Put as much info into a docstring or comments to help determine
+the cause of the failure. Particularly note if the cause is
+system or environment dependent and what the variables are.
+
+Once the crash is fixed, the test case should be moved into an appropriate
+test (even if it was originally from the test suite). This ensures the
+regression doesn't happen again. And if it does, it should be easier
+to track down.
diff --git a/sys/lib/python/test/crashers/bogus_code_obj.py b/sys/lib/python/test/crashers/bogus_code_obj.py
new file mode 100644
index 000000000..613ae518d
--- /dev/null
+++ b/sys/lib/python/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/sys/lib/python/test/crashers/borrowed_ref_1.py b/sys/lib/python/test/crashers/borrowed_ref_1.py
new file mode 100644
index 000000000..d16ede2e4
--- /dev/null
+++ b/sys/lib/python/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/sys/lib/python/test/crashers/borrowed_ref_2.py b/sys/lib/python/test/crashers/borrowed_ref_2.py
new file mode 100644
index 000000000..1a7b3ff75
--- /dev/null
+++ b/sys/lib/python/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/sys/lib/python/test/crashers/dangerous_subclassing.py b/sys/lib/python/test/crashers/dangerous_subclassing.py
new file mode 100644
index 000000000..0479952b2
--- /dev/null
+++ b/sys/lib/python/test/crashers/dangerous_subclassing.py
@@ -0,0 +1,12 @@
+
+# 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/sys/lib/python/test/crashers/gc_inspection.py b/sys/lib/python/test/crashers/gc_inspection.py
new file mode 100644
index 000000000..10caa7978
--- /dev/null
+++ b/sys/lib/python/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/sys/lib/python/test/crashers/infinite_rec_1.py b/sys/lib/python/test/crashers/infinite_rec_1.py
new file mode 100644
index 000000000..573a509b5
--- /dev/null
+++ b/sys/lib/python/test/crashers/infinite_rec_1.py
@@ -0,0 +1,11 @@
+
+# http://python.org/sf/1202533
+
+import new, operator
+
+class A:
+ pass
+A.__mul__ = new.instancemethod(operator.mul, None, A)
+
+if __name__ == '__main__':
+ A()*2 # segfault: infinite recursion in C
diff --git a/sys/lib/python/test/crashers/infinite_rec_2.py b/sys/lib/python/test/crashers/infinite_rec_2.py
new file mode 100644
index 000000000..5a14b33ea
--- /dev/null
+++ b/sys/lib/python/test/crashers/infinite_rec_2.py
@@ -0,0 +1,10 @@
+
+# http://python.org/sf/1202533
+
+class A(str):
+ __get__ = getattr
+
+if __name__ == '__main__':
+ a = A('a')
+ A.a = a
+ a.a # segfault: infinite recursion in C
diff --git a/sys/lib/python/test/crashers/infinite_rec_4.py b/sys/lib/python/test/crashers/infinite_rec_4.py
new file mode 100644
index 000000000..14f15208e
--- /dev/null
+++ b/sys/lib/python/test/crashers/infinite_rec_4.py
@@ -0,0 +1,7 @@
+
+# http://python.org/sf/1202533
+
+if __name__ == '__main__':
+ lst = [apply]
+ lst.append(lst)
+ apply(*lst) # segfault: infinite recursion in C
diff --git a/sys/lib/python/test/crashers/infinite_rec_5.py b/sys/lib/python/test/crashers/infinite_rec_5.py
new file mode 100644
index 000000000..18d296323
--- /dev/null
+++ b/sys/lib/python/test/crashers/infinite_rec_5.py
@@ -0,0 +1,10 @@
+
+# http://python.org/sf/1267884
+
+import types
+
+class C:
+ __str__ = types.InstanceType.__str__
+
+if __name__ == '__main__':
+ str(C()) # segfault: infinite recursion in C
diff --git a/sys/lib/python/test/crashers/loosing_dict_ref.py b/sys/lib/python/test/crashers/loosing_dict_ref.py
new file mode 100644
index 000000000..f44370b9a
--- /dev/null
+++ b/sys/lib/python/test/crashers/loosing_dict_ref.py
@@ -0,0 +1,21 @@
+
+# http://python.org/sf/1303614
+
+class Strange(object):
+ def __hash__(self):
+ return hash('hello')
+
+ def __eq__(self, other):
+ x.__dict__ = {} # the old x.__dict__ is deallocated
+ return False
+
+
+class X(object):
+ pass
+
+if __name__ == '__main__':
+ v = 123
+ x = X()
+ x.__dict__ = {Strange(): 42,
+ 'hello': v+456}
+ x.hello # segfault: the above dict is accessed after it's deallocated
diff --git a/sys/lib/python/test/crashers/modify_dict_attr.py b/sys/lib/python/test/crashers/modify_dict_attr.py
new file mode 100644
index 000000000..dfce467c8
--- /dev/null
+++ b/sys/lib/python/test/crashers/modify_dict_attr.py
@@ -0,0 +1,19 @@
+
+# http://python.org/sf/1303614
+
+class Y(object):
+ pass
+
+class type_with_modifiable_dict(Y, type):
+ pass
+
+class MyClass(object):
+ """This class has its __dict__ attribute completely exposed:
+ user code can read, reassign and even delete it.
+ """
+ __metaclass__ = type_with_modifiable_dict
+
+
+if __name__ == '__main__':
+ del MyClass.__dict__ # if we set tp_dict to NULL,
+ print MyClass # doing anything with MyClass segfaults
diff --git a/sys/lib/python/test/crashers/nasty_eq_vs_dict.py b/sys/lib/python/test/crashers/nasty_eq_vs_dict.py
new file mode 100644
index 000000000..3f3083da8
--- /dev/null
+++ b/sys/lib/python/test/crashers/nasty_eq_vs_dict.py
@@ -0,0 +1,47 @@
+# from http://mail.python.org/pipermail/python-dev/2001-June/015239.html
+
+# if you keep changing a dictionary while looking up a key, you can
+# provoke an infinite recursion in C
+
+# At the time neither Tim nor Michael could be bothered to think of a
+# way to fix it.
+
+class Yuck:
+ def __init__(self):
+ self.i = 0
+
+ def make_dangerous(self):
+ self.i = 1
+
+ def __hash__(self):
+ # direct to slot 4 in table of size 8; slot 12 when size 16
+ return 4 + 8
+
+ def __eq__(self, other):
+ if self.i == 0:
+ # leave dict alone
+ pass
+ elif self.i == 1:
+ # fiddle to 16 slots
+ self.__fill_dict(6)
+ self.i = 2
+ else:
+ # fiddle to 8 slots
+ self.__fill_dict(4)
+ self.i = 1
+
+ return 1
+
+ def __fill_dict(self, n):
+ self.i = 0
+ dict.clear()
+ for i in range(n):
+ dict[i] = i
+ dict[self] = "OK!"
+
+y = Yuck()
+dict = {y: "OK!"}
+
+z = Yuck()
+y.make_dangerous()
+print dict[z]
diff --git a/sys/lib/python/test/crashers/recursion_limit_too_high.py b/sys/lib/python/test/crashers/recursion_limit_too_high.py
new file mode 100644
index 000000000..1fa4d3254
--- /dev/null
+++ b/sys/lib/python/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/sys/lib/python/test/crashers/recursive_call.py b/sys/lib/python/test/crashers/recursive_call.py
new file mode 100644
index 000000000..31c896330
--- /dev/null
+++ b/sys/lib/python/test/crashers/recursive_call.py
@@ -0,0 +1,15 @@
+#!/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)
+f = lambda f:f(f)
+
+if __name__ == '__main__':
+ f(f)
diff --git a/sys/lib/python/test/crashers/weakref_in_del.py b/sys/lib/python/test/crashers/weakref_in_del.py
new file mode 100644
index 000000000..2e9b18683
--- /dev/null
+++ b/sys/lib/python/test/crashers/weakref_in_del.py
@@ -0,0 +1,17 @@
+import weakref
+
+# http://python.org/sf/1377858
+# Fixed for new-style classes in 2.5c1.
+
+ref = None
+
+def test_weakref_in_del():
+ class Target():
+ def __del__(self):
+ global ref
+ ref = weakref.ref(self)
+
+ w = Target()
+
+if __name__ == '__main__':
+ test_weakref_in_del()