使用 ffi 将 lua 字符串转换为 C 字符串时出现段错误

我在将 Lua 字符串转换为 C 字符数组时遇到了奇怪的问题。

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)

运行这段代码会得到:

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

我知道 ffi.new("unsigned char[?]", #str+1, str) 可以解决这个问题,但我不知道为什么。

我不认为这是由于 \0 问题,因为我发现了一些奇怪的点。

  • 如果 str 不是 16 个字节,这种情况就不会发生。

  • 如果我删除我没有使用的 ffi.cdef,这种情况也不会发生。

  • 如果我将 ffi.cdef 放在 ffi.new 后面,这种情况也不会发生。

    [root@origin ~]# luajit test.lua
    17
    1234567890abcdefg
    // 这是我只向 `str` 添加了一个 'g' 的结果。
    

我在 Luajit 2.0.5 和 Luajit 2.1.0-beta3 中使用了默认编译器参数进行了尝试。

因此,有人知道为什么会出现这种情况吗?谢谢。

点赞
用户744720
用户744720

正是因为字符串大小为17,但数组只为16个字节分配了空间。 [https://github.com/LuaJIT/LuaJIT/blob/0c0e7b168ea147866835954267c151ef789f64fb/src/lj\_cconv.c#L582]https://github.com/LuaJIT/LuaJIT/blob/0c0e7b168ea147866835954267c151ef789f64fb/src/lj_cconv.c#L582)是将字符串复制到结果数组中的代码。正如您所见,如果目标是数组且其大小小于字符串长度,则缩小字符串; 然而,您的类型为VLA(可变长度数组),对于VLA,大小未指定(实际上为“2 ** 32-1”,比17大得多)。

“我不会出现错误”在这里不是一个论点-您会践踏用于其他事物的内存。有时用0碾压额外的字节并不致命(例如,由于对齐,此字节未被使用,或者恰好已经为0)或不会导致硬崩溃-但这并不意味着它是正确的。

2017-11-03 06:47:46