[Tarantool-patches] [PATCH 08/15] uuid: replace static_alloc with ffi stash

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Thu Mar 25 00:24:34 MSK 2021


static_alloc() appears not to be safe to use in Lua, because it
does not provide any ownership protection for the returned values.

The problem appears when something is allocated, then Lua GC
starts, and some __gc handlers might also use static_alloc(). In
Lua and in C - both lead to the buffer being corrupted in its
original usage place.

The patch is a part of activity of getting rid of static_alloc()
in Lua. It removes it from uuid Lua module and makes it use the
new FFI stash feature, which helps to cache frequently used and
heavy to allocate FFI values.

ffi.new() is not used, because

- It produces a new GC object;

- ffi.new('struct tt_uuid') costs around 300ns while FFI stash
  costs around 0.8ns (although it is magically fixed when
  ffi.new('struct tt_uuid[1]') is used);

- Without JIT ffi.new() costs about the same as the stash, ~280ns
  for small objects like tt_uuid.

The patch makes uuid perf a bit better in the places where
static_alloc() was used, because its cost was around 7ns for one
allocation.

(cherry picked from commit 5cbb69077ff9fe22224f94aeaa05d8da9ed9cb6e)
---
 src/lua/uuid.lua     | 24 +++++++++++++++++-------
 test/app/uuid.result |  2 +-
 2 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/src/lua/uuid.lua b/src/lua/uuid.lua
index 956ad6e36..46b35075a 100644
--- a/src/lua/uuid.lua
+++ b/src/lua/uuid.lua
@@ -1,6 +1,7 @@
 -- uuid.lua (internal file)
 
 local ffi = require("ffi")
+local buffer = require('buffer')
 local builtin = ffi.C
 
 ffi.cdef[[
@@ -33,7 +34,9 @@ extern const struct tt_uuid uuid_nil;
 local uuid_t = ffi.typeof('struct tt_uuid')
 local UUID_STR_LEN = 36
 local UUID_LEN = ffi.sizeof(uuid_t)
-local uuidbuf = ffi.new(uuid_t)
+local uuid_stash = buffer.ffi_stash_new(uuid_t)
+local uuid_stash_take = uuid_stash.take
+local uuid_stash_put = uuid_stash.put
 
 local uuid_tostring = function(uu)
     if not ffi.istype(uuid_t, uu) then
@@ -69,11 +72,12 @@ local uuid_tobin = function(uu, byteorder)
         return error('Usage: uuid:bin([byteorder])')
     end
     if need_bswap(byteorder) then
-        if uu ~= uuidbuf then
-            ffi.copy(uuidbuf, uu, UUID_LEN)
-        end
+        local uuidbuf = uuid_stash_take()
+        ffi.copy(uuidbuf, uu, UUID_LEN)
         builtin.tt_uuid_bswap(uuidbuf)
-        return ffi.string(ffi.cast('char *', uuidbuf), UUID_LEN)
+        uu = ffi.string(ffi.cast('char *', uuidbuf), UUID_LEN)
+        uuid_stash_put(uuidbuf)
+        return uu
     end
     return ffi.string(ffi.cast('char *', uu), UUID_LEN)
 end
@@ -114,12 +118,18 @@ local uuid_new = function()
 end
 
 local uuid_new_bin = function(byteorder)
+    local uuidbuf = uuid_stash_take()
     builtin.tt_uuid_create(uuidbuf)
-    return uuid_tobin(uuidbuf, byteorder)
+    local res = uuid_tobin(uuidbuf, byteorder)
+    uuid_stash_put(uuidbuf)
+    return res
 end
 local uuid_new_str = function()
+    local uuidbuf = uuid_stash_take()
     builtin.tt_uuid_create(uuidbuf)
-    return uuid_tostring(uuidbuf)
+    local res = uuid_tostring(uuidbuf)
+    uuid_stash_put(uuidbuf)
+    return res
 end
 
 local uuid_mt = {
diff --git a/test/app/uuid.result b/test/app/uuid.result
index 0713614c6..1da8b3e58 100644
--- a/test/app/uuid.result
+++ b/test/app/uuid.result
@@ -106,7 +106,7 @@ uu.node[5]
 -- invalid values
 uuid.fromstr(nil)
 ---
-- error: 'builtin/uuid.lua:47: fromstr(str)'
+- error: 'builtin/uuid.lua:50: fromstr(str)'
 ...
 uuid.fromstr('')
 ---
-- 
2.24.3 (Apple Git-128)



More information about the Tarantool-patches mailing list