[pypy-svn] r31114 - in pypy/dist/pypy/translator/c: . src test
arigo at codespeak.net
arigo at codespeak.net
Mon Aug 7 16:51:13 CEST 2006
Author: arigo
Date: Mon Aug 7 16:51:11 2006
New Revision: 31114
Modified:
pypy/dist/pypy/translator/c/funcgen.py
pypy/dist/pypy/translator/c/src/mem.h
pypy/dist/pypy/translator/c/test/test_exception.py
Log:
OP_MALLOC_VARSIZE bug, generates segfaults under some conditions when trying to allocate
very large arrays (just too large to fit in 32-bit).
Modified: pypy/dist/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/dist/pypy/translator/c/funcgen.py (original)
+++ pypy/dist/pypy/translator/c/funcgen.py Mon Aug 7 16:51:11 2006
@@ -525,12 +525,14 @@
eresult = self.expr(op.result)
if VARPART.OF is Void: # strange
esize = 'sizeof(%s)' % (cdecl(typename, ''),)
- result = ''
+ result = '{\n'
else:
itemtype = cdecl(itemtypename, '')
- result = 'OP_MAX_VARSIZE(%s, %s);\n' % (
+ result = 'IF_VARSIZE_OVERFLOW(%s, %s, %s)\nelse {\n' % (
elength,
- itemtype)
+ itemtype,
+ eresult)
+ tail = '\n}'
esize = 'sizeof(%s)-sizeof(%s)+%s*sizeof(%s)' % (
cdecl(typename, ''),
itemtype,
@@ -541,6 +543,7 @@
# ctypes Arrays have no length field
if not VARPART._hints.get('nolength', False):
result += '\nif(%s) %s->%s = %s;' % (eresult, eresult, lenfld, elength)
+ result += '\n}'
return result
def OP_RAW_MALLOC(self, op):
Modified: pypy/dist/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/mem.h (original)
+++ pypy/dist/pypy/translator/c/src/mem.h Mon Aug 7 16:51:11 2006
@@ -27,11 +27,13 @@
to compute the largest allowed number of items in the array. */
#define MAXIMUM_MALLOCABLE_SIZE (LONG_MAX-4096)
-#define OP_MAX_VARSIZE(numitems, itemtype) { \
+#define IF_VARSIZE_OVERFLOW(numitems, itemtype, r) \
if (((unsigned long)(numitems)) > \
- (MAXIMUM_MALLOCABLE_SIZE / sizeof(itemtype))) \
+ (MAXIMUM_MALLOCABLE_SIZE / sizeof(itemtype))) { \
FAIL_EXCEPTION(PyExc_MemoryError, "addr space overflow"); \
- }
+ r = NULL; \
+ }
+/* else { ...} -- generated by funcgen.py */
/* XXX hack to initialize the refcount of global structures: officially,
Modified: pypy/dist/pypy/translator/c/test/test_exception.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_exception.py (original)
+++ pypy/dist/pypy/translator/c/test/test_exception.py Mon Aug 7 16:51:11 2006
@@ -1,5 +1,7 @@
import py
+import sys
from pypy.translator.c.test import test_typed
+from pypy.rpython.lltypesystem import lltype
getcompiled = test_typed.TestTypedTestCase().getcompiled
@@ -76,6 +78,43 @@
else:
py.test.fail("f1(1) did not raise anything")
+def test_memoryerror():
+ # in rev 30717 this test causes a segfault on some Linux, but usually
+ # only after the test is run. It is caused by the following sequence
+ # of events in lltype.malloc(S, n): there is an OP_MAX_VARSIZE macro
+ # which figures out that the size asked for is too large and would
+ # cause a wrap-around, so it sets a MemoryError; but execution continues
+ # nevertheless and the next line is an OP_MALLOC instruction, which
+ # because of the wrap-around allocates for 's' an amount of bytes which
+ # falls precisely between 0 and offsetof(s, tail). It succeeds. Then
+ # the length field of s.tail is initialized - this overwrites random
+ # memory! And only then is the exception check performed, and the
+ # MemoryError is noticed.
+ A = lltype.Array(lltype.Signed)
+ S = lltype.GcStruct('S', ('a', lltype.Signed),
+ ('b', lltype.Signed),
+ ('c', lltype.Signed),
+ ('tail', A))
+ def g(n, tag):
+ s = lltype.malloc(S, n)
+ tag.a = 42
+ return s
+ def testfn(n=int):
+ tag = lltype.malloc(S, 0)
+ try:
+ s = g(n, tag)
+ result = s.tail[n//2]
+ except MemoryError:
+ result = 1000
+ return result + tag.a
+ f1 = getcompiled(testfn)
+ assert f1(10) == 42
+ assert f1(sys.maxint) == 1000
+ for i in range(20):
+ assert f1((sys.maxint+1) // 2 - i) == 1000
+ assert f1(sys.maxint // 2 - 16384) == 1000
+ assert f1(sys.maxint // 2 + 16384) == 1000
+
def test_assert():
def testfn(n=int):
assert n >= 0
More information about the Pypy-commit
mailing list