[pypy-commit] pypy null_byte_after_str: rffi.scoped_nonmovingbuffer_final_null

arigo pypy.commits at gmail.com
Fri Jul 29 14:10:02 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: null_byte_after_str
Changeset: r85915:4496557d38d9
Date: 2016-07-29 19:25 +0200
http://bitbucket.org/pypy/pypy/changeset/4496557d38d9/

Log:	rffi.scoped_nonmovingbuffer_final_null

diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -1279,7 +1279,7 @@
     """
     from rpython.rtyper.lltypesystem import rffi
     PSTR = lltype.typeOf(s)
-    _check_final_null_char(PSTR)
+    assert has_final_null_char(PSTR) == 1
     n = llmemory.offsetof(PSTR.TO, 'chars')
     n += llmemory.itemoffsetof(PSTR.TO.chars, 0)
     n = llmemory.raw_malloc_usage(n)
@@ -1289,5 +1289,5 @@
     ptr[n] = '\x00'
 
 @specialize.memo()
-def _check_final_null_char(PSTR):
-    assert PSTR.TO.chars._hints.get('extra_item_after_alloc', 0) == 1
+def has_final_null_char(PSTR):
+    return PSTR.TO.chars._hints.get('extra_item_after_alloc', 0)
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
@@ -819,6 +819,11 @@
         First bool returned indicates if 'data' was pinned. Second bool returned
         indicates if we did a raw alloc because pinning failed. Both bools
         should never be true at the same time.
+
+        For strings (not unicodes), the len()th character of the resulting
+        raw buffer is available, but not initialized.  Use
+        get_nonmovingbuffer_final_null() instead of get_nonmovingbuffer()
+        to get a regular null-terminated "char *".
         """
 
         lldata = llstrtype(data)
@@ -829,6 +834,7 @@
             if rgc.pin(data):
                 pinned = True
             else:
+                count += has_final_null_char(TYPEP)
                 buf = lltype.malloc(TYPEP.TO, count, flavor='raw')
                 copy_string_to_raw(lldata, buf, 0, count)
                 return buf, pinned, True
@@ -846,6 +852,14 @@
     get_nonmovingbuffer._always_inline_ = 'try' # get rid of the returned tuple
     get_nonmovingbuffer._annenforceargs_ = [strtype]
 
+    @jit.dont_look_inside
+    def get_nonmovingbuffer_final_null(data):
+        buf, is_pinned, is_raw = get_nonmovingbuffer(data)
+        buf[len(data)] = lastchar
+        return buf, is_pinned, is_raw
+    get_nonmovingbuffer_final_null._always_inline_ = 'try'
+    get_nonmovingbuffer_final_null._annenforceargs_ = [strtype]
+
     # (str, char*, bool, bool) -> None
     # Can't inline this because of the raw address manipulation.
     @jit.dont_look_inside
@@ -947,18 +961,19 @@
 
     return (str2charp, free_charp, charp2str,
             get_nonmovingbuffer, free_nonmovingbuffer,
+            get_nonmovingbuffer_final_null,
             alloc_buffer, str_from_buffer, keep_buffer_alive_until_here,
             charp2strn, charpsize2str, str2chararray, str2rawmem,
             )
 
 (str2charp, free_charp, charp2str,
- get_nonmovingbuffer, free_nonmovingbuffer,
+ get_nonmovingbuffer, free_nonmovingbuffer, get_nonmovingbuffer_final_null,
  alloc_buffer, str_from_buffer, keep_buffer_alive_until_here,
  charp2strn, charpsize2str, str2chararray, str2rawmem,
  ) = make_string_mappings(str)
 
 (unicode2wcharp, free_wcharp, wcharp2unicode,
- get_nonmoving_unicodebuffer, free_nonmoving_unicodebuffer,
+ get_nonmoving_unicodebuffer, free_nonmoving_unicodebuffer, __not_usable,
  alloc_unicodebuffer, unicode_from_buffer, keep_unicodebuffer_alive_until_here,
  wcharp2unicoden, wcharpsize2unicode, unicode2wchararray, unicode2rawmem,
  ) = make_string_mappings(unicode)
@@ -1202,6 +1217,19 @@
     __enter__._always_inline_ = 'try'
     __exit__._always_inline_ = 'try'
 
+class scoped_nonmovingbuffer_final_null:
+    def __init__(self, data):
+        self.data = data
+    def __enter__(self):
+        self.buf, self.pinned, self.is_raw = (
+            get_nonmovingbuffer_final_null(self.data))
+        return self.buf
+    def __exit__(self, *args):
+        free_nonmovingbuffer(self.data, self.buf, self.pinned, self.is_raw)
+    __init__._always_inline_ = 'try'
+    __enter__._always_inline_ = 'try'
+    __exit__._always_inline_ = 'try'
+
 class scoped_nonmoving_unicodebuffer:
     def __init__(self, data):
         self.data = data
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
@@ -835,3 +835,11 @@
     if hasattr(rffi, '__INT128_T'):
         value = 0xAAAABBBBCCCCDDDD
         assert cast(rffi.__INT128_T, r_uint64(value)) == value
+
+def test_scoped_nonmovingbuffer_final_null():
+    s = 'bar'
+    with scoped_nonmovingbuffer_final_null(s) as buf:
+        assert buf[0] == 'b'
+        assert buf[1] == 'a'
+        assert buf[2] == 'r'
+        assert buf[3] == '\x00'


More information about the pypy-commit mailing list