Added Python (Thanks to Beholder) - it fails to build properly using my build system,
so there's a precompiled binary included, with a hack in Android.mk to make it work on NDK r4b
This commit is contained in:
20
project/jni/python/src/Lib/test/crashers/README
Normal file
20
project/jni/python/src/Lib/test/crashers/README
Normal file
@@ -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.
|
||||
19
project/jni/python/src/Lib/test/crashers/bogus_code_obj.py
Normal file
19
project/jni/python/src/Lib/test/crashers/bogus_code_obj.py
Normal file
@@ -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
|
||||
@@ -0,0 +1,47 @@
|
||||
"""
|
||||
The regular expression engine in '_sre' can segfault when interpreting
|
||||
bogus bytecode.
|
||||
|
||||
It is unclear whether this is a real bug or a "won't fix" case like
|
||||
bogus_code_obj.py, because it requires bytecode that is built by hand,
|
||||
as opposed to compiled by 're' from a string-source regexp. The
|
||||
difference with bogus_code_obj, though, is that the only existing regexp
|
||||
compiler is written in Python, so that the C code has no choice but
|
||||
accept arbitrary bytecode from Python-level.
|
||||
|
||||
The test below builds and runs random bytecodes until 'match' crashes
|
||||
Python. I have not investigated why exactly segfaults occur nor how
|
||||
hard they would be to fix. Here are a few examples of 'code' that
|
||||
segfault for me:
|
||||
|
||||
[21, 50814, 8, 29, 16]
|
||||
[21, 3967, 26, 10, 23, 54113]
|
||||
[29, 23, 0, 2, 5]
|
||||
[31, 64351, 0, 28, 3, 22281, 20, 4463, 9, 25, 59154, 15245, 2,
|
||||
16343, 3, 11600, 24380, 10, 37556, 10, 31, 15, 31]
|
||||
|
||||
Here is also a 'code' that triggers an infinite uninterruptible loop:
|
||||
|
||||
[29, 1, 8, 21, 1, 43083, 6]
|
||||
|
||||
"""
|
||||
|
||||
import _sre, random
|
||||
|
||||
def pick():
|
||||
n = random.randrange(-65536, 65536)
|
||||
if n < 0:
|
||||
n &= 31
|
||||
return n
|
||||
|
||||
ss = ["", "world", "x" * 500]
|
||||
|
||||
while 1:
|
||||
code = [pick() for i in range(random.randrange(5, 25))]
|
||||
print code
|
||||
pat = _sre.compile(None, 0, code)
|
||||
for s in ss:
|
||||
try:
|
||||
pat.match(s)
|
||||
except RuntimeError:
|
||||
pass
|
||||
29
project/jni/python/src/Lib/test/crashers/borrowed_ref_1.py
Normal file
29
project/jni/python/src/Lib/test/crashers/borrowed_ref_1.py
Normal file
@@ -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,)
|
||||
38
project/jni/python/src/Lib/test/crashers/borrowed_ref_2.py
Normal file
38
project/jni/python/src/Lib/test/crashers/borrowed_ref_2.py
Normal file
@@ -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
|
||||
32
project/jni/python/src/Lib/test/crashers/gc_inspection.py
Normal file
32
project/jni/python/src/Lib/test/crashers/gc_inspection.py
Normal file
@@ -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())
|
||||
16
project/jni/python/src/Lib/test/crashers/infinite_loop_re.py
Normal file
16
project/jni/python/src/Lib/test/crashers/infinite_loop_re.py
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
# This was taken from http://python.org/sf/1541697
|
||||
# It's not technically a crasher. It may not even truly be infinite,
|
||||
# however, I haven't waited a long time to see the result. It takes
|
||||
# 100% of CPU while running this and should be fixed.
|
||||
|
||||
import re
|
||||
starttag = re.compile(r'<[a-zA-Z][-_.:a-zA-Z0-9]*\s*('
|
||||
r'\s*([a-zA-Z_][-:.a-zA-Z_0-9]*)(\s*=\s*'
|
||||
r'(\'[^\']*\'|"[^"]*"|[-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~@]'
|
||||
r'[][\-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~\'"@]*(?=[\s>/<])))?'
|
||||
r')*\s*/?\s*(?=[<>])')
|
||||
|
||||
if __name__ == '__main__':
|
||||
foo = '<table cellspacing="0" cellpadding="0" style="border-collapse'
|
||||
starttag.match(foo)
|
||||
53
project/jni/python/src/Lib/test/crashers/iter.py
Normal file
53
project/jni/python/src/Lib/test/crashers/iter.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# Calls to PyIter_Next, or direct calls to tp_iternext, on an object
|
||||
# which might no longer be an iterable because its 'next' method was
|
||||
# removed. These are all variants of Issue3720.
|
||||
|
||||
"""
|
||||
Run this script with an argument between 1 and <N> to test for
|
||||
different crashes.
|
||||
"""
|
||||
N = 8
|
||||
|
||||
import sys
|
||||
|
||||
class Foo(object):
|
||||
def __iter__(self):
|
||||
return self
|
||||
def next(self):
|
||||
del Foo.next
|
||||
return (1, 2)
|
||||
|
||||
def case1():
|
||||
list(enumerate(Foo()))
|
||||
|
||||
def case2():
|
||||
x, y = Foo()
|
||||
|
||||
def case3():
|
||||
filter(None, Foo())
|
||||
|
||||
def case4():
|
||||
map(None, Foo(), Foo())
|
||||
|
||||
def case5():
|
||||
max(Foo())
|
||||
|
||||
def case6():
|
||||
sum(Foo(), ())
|
||||
|
||||
def case7():
|
||||
dict(Foo())
|
||||
|
||||
def case8():
|
||||
sys.stdout.writelines(Foo())
|
||||
|
||||
# etc...
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print __doc__.replace('<N>', str(N))
|
||||
else:
|
||||
n = int(sys.argv[1])
|
||||
func = globals()['case%d' % n]
|
||||
func()
|
||||
35
project/jni/python/src/Lib/test/crashers/loosing_mro_ref.py
Normal file
35
project/jni/python/src/Lib/test/crashers/loosing_mro_ref.py
Normal file
@@ -0,0 +1,35 @@
|
||||
"""
|
||||
There is a way to put keys of any type in a type's dictionary.
|
||||
I think this allows various kinds of crashes, but so far I have only
|
||||
found a convoluted attack of _PyType_Lookup(), which uses the mro of the
|
||||
type without holding a strong reference to it. Probably works with
|
||||
super.__getattribute__() too, which uses the same kind of code.
|
||||
"""
|
||||
|
||||
class MyKey(object):
|
||||
def __hash__(self):
|
||||
return hash('mykey')
|
||||
|
||||
def __cmp__(self, other):
|
||||
# the following line decrefs the previous X.__mro__
|
||||
X.__bases__ = (Base2,)
|
||||
# trash all tuples of length 3, to make sure that the items of
|
||||
# the previous X.__mro__ are really garbage
|
||||
z = []
|
||||
for i in range(1000):
|
||||
z.append((i, None, None))
|
||||
return -1
|
||||
|
||||
|
||||
class Base(object):
|
||||
mykey = 'from Base'
|
||||
|
||||
class Base2(object):
|
||||
mykey = 'from Base2'
|
||||
|
||||
# you can't add a non-string key to X.__dict__, but it can be
|
||||
# there from the beginning :-)
|
||||
X = type('X', (Base,), {MyKey(): 5})
|
||||
|
||||
print X.mykey
|
||||
# I get a segfault, or a slightly wrong assertion error in a debug build.
|
||||
@@ -0,0 +1,14 @@
|
||||
# f.close() is not thread-safe: calling it at the same time as another
|
||||
# operation (or another close) on the same file, but done from another
|
||||
# thread, causes crashes. The issue is more complicated than it seems,
|
||||
# witness the discussions in:
|
||||
#
|
||||
# http://bugs.python.org/issue595601
|
||||
# http://bugs.python.org/issue815646
|
||||
|
||||
import thread
|
||||
|
||||
while 1:
|
||||
f = open("multithreaded_close.tmp", "w")
|
||||
thread.start_new_thread(f.close, ())
|
||||
f.close()
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
# The cycle GC collector can be executed when any GC-tracked object is
|
||||
# allocated, e.g. during a call to PyList_New(), PyDict_New(), ...
|
||||
# Moreover, it can invoke arbitrary Python code via a weakref callback.
|
||||
# This means that there are many places in the source where an arbitrary
|
||||
# mutation could unexpectedly occur.
|
||||
|
||||
# The example below shows list_slice() not expecting the call to
|
||||
# PyList_New to mutate the input list. (Of course there are many
|
||||
# more examples like this one.)
|
||||
|
||||
|
||||
import weakref
|
||||
|
||||
class A(object):
|
||||
pass
|
||||
|
||||
def callback(x):
|
||||
del lst[:]
|
||||
|
||||
|
||||
keepalive = []
|
||||
|
||||
for i in range(100):
|
||||
lst = [str(i)]
|
||||
a = A()
|
||||
a.cycle = a
|
||||
keepalive.append(weakref.ref(a, callback))
|
||||
del a
|
||||
while lst:
|
||||
keepalive.append(lst[:])
|
||||
47
project/jni/python/src/Lib/test/crashers/nasty_eq_vs_dict.py
Normal file
47
project/jni/python/src/Lib/test/crashers/nasty_eq_vs_dict.py
Normal file
@@ -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]
|
||||
@@ -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
|
||||
15
project/jni/python/src/Lib/test/crashers/recursive_call.py
Normal file
15
project/jni/python/src/Lib/test/crashers/recursive_call.py
Normal file
@@ -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)
|
||||
Reference in New Issue
Block a user