libc的stat函数和LuaJIT

我今天一整天都在排查LuaJIT出现的一个神秘问题。libc中的stat函数在其stat缓冲区中返回错误值。

LuaJIT脚本:

-- sys/types.h中的定义
 typedef uint32_t      mode_t;
 typedef uint64_t      dev_t;
 typedef uint64_t      ino_t;
 typedef unsigned int  nlink_t;
 typedef int           pid_t;
 typedef unsigned int  id_t;
 typedef unsigned int  uid_t;
 typedef unsigned int  gid_t;
 typedef int64_t       off_t;
 typedef long          blksize_t;
 typedef int64_t       blkcnt_t;
 typedef uint64_t      fsblkcnt_t;
 typedef uint64_t      fsfilcnt_t;

-- sys/stat.h中的定义
  struct stat {
   dev_t      st_dev;         /* 设备 */
   ino_t      st_ino; /* 文件序列号 */
   nlink_t    st_nlink;     /* 链接数 */
   mode_t     st_mode; /* 文件模式 */
   uid_t      st_uid; /* 文件所有者的用户ID */
   gid_t      st_gid; /* 该文件的用户组ID */
   int        __pad0;
   dev_t      st_rdev; /* 如果是设备,则为设备号 */
   off_t      st_size;     /* 文件大小(以字节为单位) */
   blksize_t  st_blksize; /* I/O的最佳块大小 */
   blkcnt_t   st_blocks; /* 分配的512字节块数 */
   /* __USE_XOPEN2K8 */
   struct timespec st_atim; /* 上次访问时间 */
   struct timespec st_mtim; /* 上次修改时间 */
   struct timespec st_ctim; /* 上次状态更改时间 */
   long   __unused[3];
  };
  /* luajit调用此函数 */
  int __xstat(int ver, const char *path, struct stat *buf);

-- lua stat函数部分
stat = function(path, buf) return ffi.C.__xstat(_STAT_VER, path, buf) end;

上述内容来自我的系统C头文件。现在LuaJIT调用如下所示:

local buf = ffi.new("struct stat[1]")
local res = stat('main.c', buf)
ffi.cdef [[
 int printf(const char *fmt, ...);
]]
ffi.C.printf("size: %lu, ino: %lu, mode: %d\n", buf[0].st_size, buf[0].st_ino, buf[0].st_mode);

在Luajit邮件列表中,有人友好地建议在ffi.new中使用struct stat[1]

更新

的想法是调用Linux的__xtat。添加了声明。

__xstat的方法来自https://github.com/Wiladams/LJIT2libc。否则,C头文件中的定义对我来说太多了。

输出在st_mode区域之前都是正常的。该区域的值为零。我用C语言进行了测试,一切都很好。因此,问题是LuaJIT的stat给出了错误结果。请建议我该怎么做。我花了一整天来解决这个问题。

点赞
用户8339821
用户8339821

我在 ffi.cdef 类型声明中犯了一些错误。幸运的是,在 luajit 邮件列表的用户的帮助下,这个问题已经得到解决。简单来说:

  1. 通过 clang -E <some_c_file>.c 命令在包含 #include <sys/stat.h>C 源文件上进行操作,获得输出。
  2. 建立合适的 struct stat 定义。
  3. 我的系统 stat 函数有太多级别的宏垃圾。最终,stat 函数调用 __xstat。对我来说,调用 stat 函数的唯一合理方式是使用 syscall
  4. 要注意 Lua print 函数不知道 cdata 类型。而 printf 不知道 Lua 类型。但是 luajit 提供了一个很好且易于理解的方法,可以将常见的数据类型相互转换。
2020-02-12 14:00:54