cffi函数调用挂起

时间:2015-03-12 00:11:19

标签: common-lisp sbcl cffi

我想使用Common Lisp中的stat(2)

我已经定义了stat函数使用的结构:

(cffi:defctype mode_t :unsigned-int)
(cffi:defctype ino_t :unsigned-int)
(cffi:defctype dev_t :int)
(cffi:defctype nlink_t :int)
(cffi:defctype uid_t :unsigned-int)
(cffi:defctype gid_t :unsigned-int)
(cffi:defctype off_t :int)
(cffi:defctype time_t :long)
(cffi:defctype blksize_t :unsigned-int)
(cffi:defctype blkcnt_t :int)

(cffi:defcstruct stat
  (st_dev dev_t)
  (st_ino ino_t)
  (st_mode mode_t)
  (st_nlink nlink_t)
  (st_uid uid_t)
  (st_gid gid_t)
  (st_rdev dev_t)
  (st_size off_t)
  (st_atime time_t)
  (st_mtime time_t)
  (st_ctime time_t)
  (st_blksize blksize_t)
  (st_blocks blkcnt_t))

功能本身:

(cffi:defcfun "stat" :int
  (path :string)
  (buf (:pointer (:struct stat))))

我试着像这样称呼它:

(cffi:with-foreign-object (buf '(:pointer (:struct stat)))
  (stat "/home/florian/tmp/msg.txt" buf)
  (cffi:with-foreign-slots ((st_mode) buf (:struct stat))
    st_mode))

史莱姆刚挂了。没有错误,REPL输入也没有回来。

2 个答案:

答案 0 :(得分:3)

如果你查看你的*inferior-lisp*缓冲区,你会发现由于一些严重的内存损坏,SBCL已经进入了它的低级调试器。

struct stat的具体布局在很大程度上取决于您拥有的架构。在我的64位Ubuntu 14.04上,以下似乎长度为144个字节,而您的定义只有52个字节长 - 难怪尝试写入它会导致内存损坏。

尝试为结构编写defcstruct表单可能是一个坏主意,操作系统可以以任何方式自由定义结构。代码可以在您的计算机上运行,​​但如果他们使用不同的操作系统或处理器体系结构,可能不会在其他人的系统上运行 - 但如果您确实需要在系统上运行它,最简单的方法可能是写一个简短的C程序,转储屏幕上所有字段的大小和偏移量,然后从那里构建。

如果您需要编写在多个不同系统上运行且使用stat的代码,一个很好的选择是自己在C中编写一个简单的代理模块,并使用一个定义良好的常量接口来调用{ {1}}代表你。这是我多次使用的方法,在C端保持外来物的安全,只在FFI上传递真正需要的数据。

对于更强大的CFFI定义,还有SWIG

答案 1 :(得分:2)

@ jlahd的回答帮助我找到了正确的解决方案。

找到正确的结构后,我的调用代码仍然是错误的。这是最终的代码:

(cffi:with-foreign-object (buf '(:struct stat))
  (stat "/home/florian/tmp/msg.txt" buf)
  (cffi:with-foreign-slots ((st_mode) buf (:struct stat))
    st_mode))

请注意,对于'(:struct stat)外国类型,它使用'(:pointer (:struct stat))代替buf


我是如何得到正确的结构的?我想记录下来。

以下是我使用的最终cffi结构:

(cffi:defcstruct (stat :size 144)
  (st_mode :unsigned-int :offset 24))

以下是我用来查找stat结构及其成员的大小和偏移量的C程序:

#include <stddef.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char* argv[])
{
    struct stat foo;
    printf("stat sizeof: %zu\n", sizeof(struct stat));
    printf("st_mode sizeof: %zu\n", sizeof(foo.st_mode));
    printf("st_mode offset: %zu\n", offsetof(struct stat, st_mode));
}

在我的电脑上,这给了我这个:

$ gcc stat.c
$ ./a.out
stat sizeof: 144
st_mode sizeof: 4
st_mode offset: 24

然后我可以检查:unsigned-int的大小是4个字节:

CL-USER> (cffi:foreign-type-size :unsigned-int)
4

检查我的cffi结构的大小:

CL-USER> (cffi:foreign-type-size '(:struct stat))
144

哪个与C中的sizeof(struct stat)匹配。