From 8a28aa8b1c9302422eab93e7565e85747ed2670e Mon Sep 17 00:00:00 2001 From: Maria <marianneliash@gmail.com> Date: Thu, 12 Sep 2019 16:55:53 +0300 Subject: [PATCH] lua: keeping the pointer type in msgpackffi.decode() Method decode_unchecked returns two values - the one that has been decoded and a pointer to the new position within the buffer given as a parameter. The type of returned pointer used to be cdata<unsigned char *> and it was not possible to assign returned value to buf.rpos due to the following error: > cannot convert 'const unsigned char *' to 'char *' The patch fixes this by making decode_unchecked method return either cdata<char *> or cdata<const char *> depending on the given parameter. Closes #3926 (cherry picked from commit 84bcba52a84852870726e1a4d19b3768c0bde7a7) --- src/lua/msgpackffi.lua | 12 +++++---- test/app-tap/msgpackffi.test.lua | 42 +++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/lua/msgpackffi.lua b/src/lua/msgpackffi.lua index 63d9b33b7c..051011dd9f 100644 --- a/src/lua/msgpackffi.lua +++ b/src/lua/msgpackffi.lua @@ -9,7 +9,7 @@ local uint8_ptr_t = ffi.typeof('uint8_t *') local uint16_ptr_t = ffi.typeof('uint16_t *') local uint32_ptr_t = ffi.typeof('uint32_t *') local uint64_ptr_t = ffi.typeof('uint64_t *') -local const_char_ptr_t = ffi.typeof('const char *') +local char_ptr_t = ffi.typeof('char *') ffi.cdef([[ char * @@ -564,17 +564,19 @@ end local function decode_unchecked(str, offset) if type(str) == "string" then offset = check_offset(offset, #str) - local buf = ffi.cast(const_char_ptr_t, str) + local buf = ffi.cast(char_ptr_t, str) bufp[0] = buf + offset - 1 local r = decode_r(bufp) return r, bufp[0] - buf + 1 - elseif ffi.istype(const_char_ptr_t, str) then + elseif ffi.istype(char_ptr_t, str) then + -- Note: ffi.istype() ignores the const qualifier, so both + -- (char *) and (const char *) buffers are valid. bufp[0] = str local r = decode_r(bufp) - return r, bufp[0] + return r, ffi.cast(ffi.typeof(str), bufp[0]) else error("msgpackffi.decode_unchecked(str, offset) -> res, new_offset | ".. - "msgpackffi.decode_unchecked(const char *buf) -> res, new_buf") + "msgpackffi.decode_unchecked([const] char *buf) -> res, new_buf") end end diff --git a/test/app-tap/msgpackffi.test.lua b/test/app-tap/msgpackffi.test.lua index e82c7401ac..bb9826580a 100755 --- a/test/app-tap/msgpackffi.test.lua +++ b/test/app-tap/msgpackffi.test.lua @@ -4,6 +4,7 @@ package.path = "lua/?.lua;"..package.path local tap = require('tap') local common = require('serializer_test') +local ffi = require('ffi') local function is_map(s) local b = string.byte(string.sub(s, 1, 1)) @@ -115,9 +116,48 @@ local function test_other(test, s) encode_max_depth = max_depth}) end +-- gh-3926: Ensure that a returned pointer has the same cdata type +-- as passed argument. +local function test_decode_buffer(test, s) + local cases = { + { + 'decode_unchecked(cdata<const char *>)', + data = ffi.cast('const char *', '\x93\x01\x02\x03'), + exp_res = {1, 2, 3}, + exp_rewind = 4, + }, + { + 'decode_unchecked(cdata<char *>)', + data = ffi.cast('char *', '\x93\x01\x02\x03'), + exp_res = {1, 2, 3}, + exp_rewind = 4, + }, + } + + test:plan(#cases) + + for _, case in ipairs(cases) do + test:test(case[1], function(test) + test:plan(4) + local res, res_buf = s.decode_unchecked(case.data) + test:is_deeply(res, case.exp_res, 'verify result') + local rewind = res_buf - case.data + test:is(rewind, case.exp_rewind, 'verify resulting buffer') + -- test:iscdata() is not sufficient here, because it + -- ignores 'const' qualifier (because of using + -- ffi.istype()). + test:is(type(res_buf), 'cdata', 'verify resulting buffer type') + local data_ctype = tostring(ffi.typeof(case.data)) + local res_buf_ctype = tostring(ffi.typeof(res_buf)) + test:is(res_buf_ctype, data_ctype, 'verify resulting buffer ctype') + end) + end +end + + tap.test("msgpackffi", function(test) local serializer = require('msgpackffi') - test:plan(9) + test:plan(10) test:test("unsigned", common.test_unsigned, serializer) test:test("signed", common.test_signed, serializer) test:test("double", common.test_double, serializer) -- GitLab