From: Vladislav Shpilevoy via Tarantool-patches <tarantool-patches@dev.tarantool.org> To: tarantool-patches@dev.tarantool.org, gorcunov@gmail.com, sergepetrenko@tarantool.org Subject: [Tarantool-patches] [PATCH 10/16] uri: replace static_alloc with ffi stash and ibuf Date: Sat, 20 Mar 2021 01:42:32 +0100 [thread overview] Message-ID: <bf6a7bfc0b589cbd7fd91ab7d0a88224bd92d9ef.1616200860.git.v.shpilevoy@tarantool.org> (raw) In-Reply-To: <cover.1616200860.git.v.shpilevoy@tarantool.org> 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 uri Lua module and makes it use the new FFI stash feature, which helps to cache frequently used and heavy to allocate FFI values. In one place static_alloc() was used for an actual buffer - it was replaced with cord_ibuf which is equally fast when preallocated. ffi.new() for temporary struct uri is not used, because - It produces a new GC object; - ffi.new('struct uri') costs around 20ns while FFI stash costs around 0.8ns. The hack with 'struct uri[1]' does not help because size of uri is > 128 bytes; - Without JIT ffi.new() costs about the same as the stash, not better as well; The patch makes uri perf a bit better in the places where static_alloc() was used, because its cost was around 7ns for one allocation. --- src/lua/uri.lua | 21 ++++++-- test/app-tap/gh-5632-gc-buf-reuse.test.lua | 60 +++++++++++++++++++++- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/lua/uri.lua b/src/lua/uri.lua index e08e20675..98f4e02ec 100644 --- a/src/lua/uri.lua +++ b/src/lua/uri.lua @@ -1,7 +1,7 @@ -- uri.lua (internal file) local ffi = require('ffi') -local static_alloc = require('buffer').static_alloc +local buffer = require('buffer') ffi.cdef[[ struct uri { @@ -32,13 +32,19 @@ uri_format(char *str, size_t len, struct uri *uri, bool write_password); ]] local builtin = ffi.C; +local uri_stash = buffer.ffi_stash_new('struct uri') +local uri_stash_take = uri_stash.take +local uri_stash_put = uri_stash.put +local cord_ibuf_take = buffer.internal.cord_ibuf_take +local cord_ibuf_put = buffer.internal.cord_ibuf_put local function parse(str) if str == nil then error("Usage: uri.parse(string)") end - local uribuf = static_alloc('struct uri') + local uribuf = uri_stash_take() if builtin.uri_parse(uribuf, str) ~= 0 then + uri_stash_put(uribuf) return nil end local result = {} @@ -55,11 +61,12 @@ local function parse(str) elseif uribuf.host_hint == 3 then result.unix = result.service end + uri_stash_put(uribuf) return result end local function format(uri, write_password) - local uribuf = static_alloc('struct uri') + local uribuf = uri_stash_take() uribuf.scheme = uri.scheme uribuf.scheme_len = string.len(uri.scheme or '') uribuf.login = uri.login @@ -76,9 +83,13 @@ local function format(uri, write_password) uribuf.query_len = string.len(uri.query or '') uribuf.fragment = uri.fragment uribuf.fragment_len = string.len(uri.fragment or '') - local str = static_alloc('char', 1024) + local ibuf = cord_ibuf_take() + local str = ibuf:alloc(1024) local len = builtin.uri_format(str, 1024, uribuf, write_password and 1 or 0) - return ffi.string(str, len) + uri_stash_put(uribuf) + str = ffi.string(str, len) + cord_ibuf_put(ibuf) + return str end return { diff --git a/test/app-tap/gh-5632-gc-buf-reuse.test.lua b/test/app-tap/gh-5632-gc-buf-reuse.test.lua index 8fe662d3f..bfa86615f 100755 --- a/test/app-tap/gh-5632-gc-buf-reuse.test.lua +++ b/test/app-tap/gh-5632-gc-buf-reuse.test.lua @@ -10,6 +10,7 @@ local tap = require('tap') local ffi = require('ffi') local uuid = require('uuid') +local uri = require('uri') local function test_uuid(test) test:plan(1) @@ -42,8 +43,65 @@ local function test_uuid(test) test:ok(is_success, 'uuid in gc') end +local function test_uri(test) + test:plan(1) + + local gc_count = 100 + local iter_count = 1000 + local port = 1 + local ip = 1 + local login = 1 + local pass = 1 + local is_success = true + + local function uri_parse() + local loc_ip = ip + local loc_port = port + local loc_pass = pass + local loc_login = login + + ip = ip + 1 + port = port + 1 + pass = pass + 1 + login = login + 1 + if port > 60000 then + port = 1 + end + if ip > 255 then + ip = 1 + end + + loc_ip = string.format('127.0.0.%s', loc_ip) + loc_port = tostring(loc_port) + loc_pass = string.format('password%s', loc_pass) + loc_login = string.format('login%s', loc_login) + local host = string.format('%s:%s@%s:%s', loc_login, loc_pass, + loc_ip, loc_port) + local u = uri.parse(host) + if u.host ~= loc_ip or u.login ~= loc_login or u.service ~= loc_port or + u.password ~= loc_pass then + is_success = false + assert(false) + end + end + + local function create_gc() + for i = 1, gc_count do + ffi.gc(ffi.new('char[1]'), uri_parse) + end + end + + for i = 1, iter_count do + create_gc() + uri_parse() + end + + test:ok(is_success, 'uri in gc') +end + local test = tap.test('gh-5632-gc-buf-reuse') -test:plan(1) +test:plan(2) test:test('uuid in __gc', test_uuid) +test:test('uri in __gc', test_uri) os.exit(test:check() and 0 or 1) -- 2.24.3 (Apple Git-128)
next prev parent reply other threads:[~2021-03-20 0:43 UTC|newest] Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-03-20 0:42 [Tarantool-patches] [PATCH 00/16] Cord buffer, static alloc, and Lua GC bug Vladislav Shpilevoy via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 01/16] fio: don't use shared buffer in pread() Vladislav Shpilevoy via Tarantool-patches 2021-03-22 7:19 ` Cyrill Gorcunov via Tarantool-patches 2021-03-20 0:42 ` Vladislav Shpilevoy via Tarantool-patches [this message] 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 11/16] buffer: remove static_alloc() from Lua Vladislav Shpilevoy via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 12/16] lua: use lua_pushfstring() instead of tt_sprintf() Vladislav Shpilevoy via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 13/16] sio: rework sio_strfaddr() Vladislav Shpilevoy via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 14/16] sio: increase SERVICE_NAME_MAXLEN size Vladislav Shpilevoy via Tarantool-patches 2021-03-21 21:58 ` Cyrill Gorcunov via Tarantool-patches 2021-03-22 22:32 ` Vladislav Shpilevoy via Tarantool-patches 2021-03-23 6:56 ` Cyrill Gorcunov via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 15/16] sio: introduce and use sio_snprintf() Vladislav Shpilevoy via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 16/16] buffer: remove Lua registers Vladislav Shpilevoy via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 02/16] test: don't use IBUF_SHARED in the tests Vladislav Shpilevoy via Tarantool-patches 2021-03-22 7:35 ` Cyrill Gorcunov via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 03/16] tuple: pass global ibuf explicitly where possible Vladislav Shpilevoy via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 04/16] iconv: take errno before reseting the context Vladislav Shpilevoy via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 05/16] cord_buf: introduce cord_buf API Vladislav Shpilevoy via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 06/16] cord_buf: introduce ownership management Vladislav Shpilevoy via Tarantool-patches 2021-03-22 16:48 ` Serge Petrenko via Tarantool-patches 2021-03-22 22:32 ` Vladislav Shpilevoy via Tarantool-patches 2021-03-23 7:46 ` Serge Petrenko via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 07/16] buffer: implement ffi stash Vladislav Shpilevoy via Tarantool-patches 2021-03-23 0:29 ` Vladislav Shpilevoy via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 08/16] uuid: replace static_alloc with " Vladislav Shpilevoy via Tarantool-patches 2021-03-20 0:42 ` [Tarantool-patches] [PATCH 09/16] uuid: drop tt_uuid_str() from Lua Vladislav Shpilevoy via Tarantool-patches 2021-03-21 16:38 ` [Tarantool-patches] [PATCH 00/16] Cord buffer, static alloc, and Lua GC bug Vladislav Shpilevoy via Tarantool-patches 2021-03-22 7:52 ` Cyrill Gorcunov via Tarantool-patches 2021-03-22 7:56 ` Konstantin Osipov via Tarantool-patches 2021-03-22 17:17 ` Serge Petrenko via Tarantool-patches 2021-03-23 23:45 ` Vladislav Shpilevoy via Tarantool-patches 2021-03-24 13:28 ` Kirill Yukhin via Tarantool-patches
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=bf6a7bfc0b589cbd7fd91ab7d0a88224bd92d9ef.1616200860.git.v.shpilevoy@tarantool.org \ --to=tarantool-patches@dev.tarantool.org \ --cc=gorcunov@gmail.com \ --cc=sergepetrenko@tarantool.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH 10/16] uri: replace static_alloc with ffi stash and ibuf' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox