Search code examples
luaffiluajit

Segmentation fault while using ffi to convert lua strings to C strings


I met a strange problem whne tying to convert a Lua string to C char arry.

local str = "1234567890abcdef"
local ffi = require "ffi"
ffi.cdef[[
    int printf(const char *fmt, ...);
]]
print(#str)
print(str)
local cstr = ffi.new("unsigned char[?]", #str, str)

run this code get:

[root@origin ~]# luajit test.lua 
16
1234567890abcdef
Segmentation fault

I know ffi.new("unsigned char[?]", #str+1, str) will solve this, but I dont know why.

I don't think it is the \0 problem because I found some strange point.

  • if str is not 16 bytes, this will not happen.
  • if I delete ffi.cdef which I didn't use , this will not happen.
  • if I put ffi.cdef behind the ffi.new ,this will not happen .

    [root@origin ~]# luajit test.lua
    17
    1234567890abcdefg
    // this is the result that I only append a 'g' to `str`.
    

I tried on Luajit 2.0.5 and Luajit 2.1.0-beta3 with default compiler arguments.

So, is there anyone knows how this happen, thanks.


Solution

  • It is exactly because of string size is 17 but array allocated only for 16 bytes. https://github.com/LuaJIT/LuaJIT/blob/0c0e7b168ea147866835954267c151ef789f64fb/src/lj_cconv.c#L582 is the code that copies string to resulting array. As you can see, if target is array and its size is smaller than string length, it shrinks string; however your type is VLA (variable-length array), and for VLA size is not specified (it is 2**32-1, actually, which is way bigger than 17).

    "I don't get error if" is not an argument here - you stomp memory that is used for something else. Sometimes stomping extra byte with 0 is not fatal (e.g. due to alignment this byte wasn't used anyway, or just happened to be 0 already) or doesn't result in hard crash - it doesn't make it correct.