[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