Author: Armin Rigo <[email protected]>
Branch: null_byte_after_str
Changeset: r85935:e043ee2bb479
Date: 2016-07-30 21:11 +0200
http://bitbucket.org/pypy/pypy/changeset/e043ee2bb479/

Log:    Introduce rffi.scoped_view_charp() and use it more; for now mainly
        in rffi.llexternal().

diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py
--- a/rpython/annotator/binaryop.py
+++ b/rpython/annotator/binaryop.py
@@ -201,8 +201,8 @@
         return SomeInteger(nonneg=int1.nonneg and int2.nonneg,
                            knowntype=knowntype)
 
-    or_ = xor = add = mul = _clone(union, [])
-    add_ovf = mul_ovf = _clone(union, [OverflowError])
+    or_ = xor = mul = _clone(union, [])
+    mul_ovf = _clone(union, [OverflowError])
     div = floordiv = mod = _clone(union, [ZeroDivisionError])
     div_ovf= floordiv_ovf = mod_ovf = _clone(union, [ZeroDivisionError, 
OverflowError])
 
@@ -214,6 +214,15 @@
     inplace_div = div
     inplace_truediv = truediv
 
+    def add((int1, int2)):
+        # propagate const-ness to help 'tup[j + 1]'
+        result = pair(int1, int2).union()
+        if int1.is_immutable_constant() and int2.is_immutable_constant():
+            result.const = int1.const + int2.const
+        return result
+    add.can_only_throw = []
+    add_ovf = _clone(add, [OverflowError])
+
     def sub((int1, int2)):
         knowntype = rarithmetic.compute_restype(int1.knowntype, int2.knowntype)
         return SomeInteger(knowntype=knowntype)
diff --git a/rpython/annotator/test/test_annrpython.py 
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -1004,6 +1004,15 @@
             a.build_types(f, [])
         # if you want to get a r_uint, you have to be explicit about it
 
+    def test_add_constant(self):
+        def f(a):
+            return a + 5
+        a = self.RPythonAnnotator()
+        s = annmodel.SomeInteger(nonneg=True)
+        s.const = 12
+        s = a.build_types(f, [s])
+        assert s.const == 17
+
     def test_add_different_ints(self):
         def f(a, b):
             return a + b
diff --git a/rpython/rlib/_os_support.py b/rpython/rlib/_os_support.py
--- a/rpython/rlib/_os_support.py
+++ b/rpython/rlib/_os_support.py
@@ -20,6 +20,7 @@
     charp2str = staticmethod(rffi.charp2str)
     charpsize2str = staticmethod(rffi.charpsize2str)
     scoped_str2charp = staticmethod(rffi.scoped_str2charp)
+    scoped_view_charp = staticmethod(rffi.scoped_view_charp)
     str2charp = staticmethod(rffi.str2charp)
     free_charp = staticmethod(rffi.free_charp)
     scoped_alloc_buffer = staticmethod(rffi.scoped_alloc_buffer)
@@ -55,6 +56,8 @@
     charpsize2str = staticmethod(rffi.wcharpsize2unicode)
     str2charp = staticmethod(rffi.unicode2wcharp)
     scoped_str2charp = staticmethod(rffi.scoped_unicode2wcharp)
+    scoped_view_charp = staticmethod(rffi.scoped_unicode2wcharp)
+    # ^^^ XXX there is no unicode variant of rffi.scoped_view_charp
     free_charp = staticmethod(rffi.free_wcharp)
     scoped_alloc_buffer = staticmethod(rffi.scoped_alloc_unicodebuffer)
 
diff --git a/rpython/rlib/rdtoa.py b/rpython/rlib/rdtoa.py
--- a/rpython/rlib/rdtoa.py
+++ b/rpython/rlib/rdtoa.py
@@ -56,22 +56,24 @@
         raise MemoryError
     end_ptr = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw')
     try:
-        ll_input = rffi.str2charp(input)
+        # note: don't use the class scoped_view_charp here, it
+        # break some tests because this function is used by the GC
+        ll_input, flag = rffi.get_nonmovingbuffer_final_null(input)
         try:
             result = dg_strtod(ll_input, end_ptr)
 
             endpos = (rffi.cast(lltype.Signed, end_ptr[0]) -
                       rffi.cast(lltype.Signed, ll_input))
-
-            if endpos == 0 or endpos < len(input):
-                raise ValueError("invalid input at position %d" % (endpos,))
-
-            return result
         finally:
-            rffi.free_charp(ll_input)
+            rffi.free_nonmovingbuffer(input, ll_input, flag)
     finally:
         lltype.free(end_ptr, flavor='raw')
 
+    if endpos == 0 or endpos < len(input):
+        raise ValueError("invalid input at position %d" % (endpos,))
+
+    return result
+
 lower_special_strings = ['inf', '+inf', '-inf', 'nan']
 upper_special_strings = ['INF', '+INF', '-INF', 'NAN']
 
diff --git a/rpython/rlib/rposix_environ.py b/rpython/rlib/rposix_environ.py
--- a/rpython/rlib/rposix_environ.py
+++ b/rpython/rlib/rposix_environ.py
@@ -163,7 +163,7 @@
         return result
 
     def getenv_llimpl(name):
-        with traits.scoped_str2charp(name) as l_name:
+        with traits.scoped_view_charp(name) as l_name:
             l_result = getenv(l_name)
             return traits.charp2str(l_result) if l_result else None
 
@@ -206,7 +206,7 @@
                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
     def unsetenv_llimpl(name):
-        with rffi.scoped_str2charp(name) as l_name:
+        with rffi.scoped_view_charp(name) as l_name:
             error = rffi.cast(lltype.Signed, os_unsetenv(l_name))
         if error:
             from rpython.rlib import rposix
diff --git a/rpython/rlib/rsocket.py b/rpython/rlib/rsocket.py
--- a/rpython/rlib/rsocket.py
+++ b/rpython/rlib/rsocket.py
@@ -963,7 +963,7 @@
         self.settimeout(timeout)
 
     def setsockopt(self, level, option, value):
-        with rffi.scoped_str2charp(value) as buf:
+        with rffi.scoped_view_charp(value) as buf:
             res = _c.socketsetsockopt(self.fd, level, option,
                                       rffi.cast(rffi.VOIDP, buf),
                                       len(value))
diff --git a/rpython/rtyper/lltypesystem/rffi.py 
b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -232,40 +232,36 @@
             call_external_function = jit.dont_look_inside(
                 call_external_function)
 
+    def _oops():
+        raise AssertionError("can't pass (any more) a unicode string"
+                             " directly to a VOIDP argument")
+    _oops._annspecialcase_ = 'specialize:memo'
+
     unrolling_arg_tps = unrolling_iterable(enumerate(args))
     def wrapper(*args):
         real_args = ()
+        # XXX 'to_free' leaks if an allocation fails with MemoryError
+        # and was not the first in this function
         to_free = ()
         for i, TARGET in unrolling_arg_tps:
             arg = args[i]
-            freeme = None
-            if TARGET == CCHARP:
+            if TARGET == CCHARP or TARGET is VOIDP:
                 if arg is None:
                     arg = lltype.nullptr(CCHARP.TO)   # None => (char*)NULL
-                    freeme = arg
+                    to_free = to_free + (arg, '\x04')
                 elif isinstance(arg, str):
-                    arg = str2charp(arg)
-                    # XXX leaks if a str2charp() fails with MemoryError
-                    # and was not the first in this function
-                    freeme = arg
+                    tup = get_nonmovingbuffer_final_null(arg)
+                    to_free = to_free + tup
+                    arg = tup[0]
+                elif isinstance(arg, unicode):
+                    _oops()
             elif TARGET == CWCHARP:
                 if arg is None:
                     arg = lltype.nullptr(CWCHARP.TO)   # None => (wchar_t*)NULL
-                    freeme = arg
+                    to_free = to_free + (arg,)
                 elif isinstance(arg, unicode):
                     arg = unicode2wcharp(arg)
-                    # XXX leaks if a unicode2wcharp() fails with MemoryError
-                    # and was not the first in this function
-                    freeme = arg
-            elif TARGET is VOIDP:
-                if arg is None:
-                    arg = lltype.nullptr(VOIDP.TO)
-                elif isinstance(arg, str):
-                    arg = str2charp(arg)
-                    freeme = arg
-                elif isinstance(arg, unicode):
-                    arg = unicode2wcharp(arg)
-                    freeme = arg
+                    to_free = to_free + (arg,)
             elif _isfunctype(TARGET) and not _isllptr(arg):
                 # XXX pass additional arguments
                 use_gil = invoke_around_handlers
@@ -283,11 +279,23 @@
                            or TARGET is lltype.Bool)):
                         arg = cast(TARGET, arg)
             real_args = real_args + (arg,)
-            to_free = to_free + (freeme,)
         res = call_external_function(*real_args)
+        j = 0
         for i, TARGET in unrolling_arg_tps:
-            if to_free[i]:
-                lltype.free(to_free[i], flavor='raw')
+            arg = args[i]
+            if TARGET == CCHARP or TARGET is VOIDP:
+                if arg is None:
+                    j = j + 2
+                elif isinstance(arg, str):
+                    free_nonmovingbuffer(arg, to_free[j], to_free[j+1])
+                    j = j + 2
+            elif TARGET == CWCHARP:
+                if arg is None:
+                    j = j + 1
+                elif isinstance(arg, unicode):
+                    free_wcharp(to_free[j])
+                    j = j + 1
+        assert j == len(to_free)
         if rarithmetic.r_int is not r_int:
             if result is INT:
                 return cast(lltype.Signed, res)
@@ -833,7 +841,7 @@
         if not rgc.can_move(data):
             flag = '\x04'
         else:
-            if rgc.pin(data):
+            if we_are_translated() and rgc.pin(data):
                 flag = '\x05'
             else:
                 buf = lltype.malloc(TYPEP.TO, count + (TYPEP is CCHARP),
@@ -1219,9 +1227,15 @@
     __enter__._always_inline_ = 'try'
     __exit__._always_inline_ = 'try'
 
-class scoped_nonmovingbuffer_final_null:
+class scoped_view_charp:
+    """Returns a 'char *' that (tries to) point inside the given RPython
+    string (which must not be None).  You can replace scoped_str2charp()
+    with scoped_view_charp() in all places that guarantee that the
+    content of the 'char[]' array will not be modified.
+    """
     def __init__(self, data):
         self.data = data
+    __init__._annenforceargs_ = [None, annmodel.SomeString(can_be_None=False)]
     def __enter__(self):
         self.buf, self.flag = get_nonmovingbuffer_final_null(self.data)
         return self.buf
diff --git a/rpython/rtyper/lltypesystem/test/test_rffi.py 
b/rpython/rtyper/lltypesystem/test/test_rffi.py
--- a/rpython/rtyper/lltypesystem/test/test_rffi.py
+++ b/rpython/rtyper/lltypesystem/test/test_rffi.py
@@ -836,9 +836,9 @@
         value = 0xAAAABBBBCCCCDDDD
         assert cast(rffi.__INT128_T, r_uint64(value)) == value
 
-def test_scoped_nonmovingbuffer_final_null():
+def test_scoped_view_charp():
     s = 'bar'
-    with scoped_nonmovingbuffer_final_null(s) as buf:
+    with scoped_view_charp(s) as buf:
         assert buf[0] == 'b'
         assert buf[1] == 'a'
         assert buf[2] == 'r'
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to