Ocaml:使用包含C指针的自定义块时GC上的段错误

时间:2017-01-30 14:34:09

标签: binding garbage-collection ocaml

我正在尝试在C库和Ocaml程序之间创建绑定。我在与Gc接口时遇到了问题。 我制作了一个小程序来复制我的问题。  目标是将在C程序中分配的custom_block传递给Ocaml中的主程序,并将C结构上的指针包含在内。 然后,我试图在清理之前使用它(只是在示例中打印一个值)(我强制调用GC)。

在ocaml下面的主程序中,我可以对该行进行注释" my_print_block"或者" Gc.compact()"并且一切正常。指针的地址是正确的,我可以打印该值并调用析构函数来释放C分配的指针。 但是当两者被激活时,我会遇到分段错误。

Mail.ml

type ptr

external create_block:  String.t -> ptr  = "create_block"
external print_block:  ptr -> unit       = "print_block"

let my_print_block x :unit =
  print_block x;
  ()

let main () =
        let z  = create_block "2.4" in
        let _  = my_print_block z in
        let () = Gc.compact () in
        ()

let _ = main ()

Interface.c

#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>
#include <caml/custom.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct foo
{
        float x;
};

void local_destroy(value v)
{
        struct foo* p = *((struct foo**)Data_custom_val(v));
        printf( "freeing p now (%p)\n with *p=%f \n", p, p->x  );
        fflush(stdout);
        free(p);
}

static struct custom_operations ops = {
        "ufpa custom_operations",
        local_destroy,
        custom_compare_default,     //default function, should not be used
        custom_hash_default,        //default function, should not be used
        custom_serialize_default,   //default function, should not be used
        custom_deserialize_default, //default function, should not be used
        custom_compare_ext_default  //default function, should not be used
};

void print_block(value type_str)
{
        CAMLparam1(type_str);
        struct foo* p =  *( (struct foo**)Data_custom_val(type_str));
        printf("value float = %f\n", p->x);
}
CAMLprim value create_block(value type_str)
{
        CAMLparam1(type_str);
        //retrieving str and creating a float value
        char* fval = String_val(type_str);
        float val  = atof(fval);

        //creating and allocating a custom_block
        CAMLlocal1(res);
        res = alloc_custom(&ops, sizeof(struct foo*), 10, 100);

        //creating and allocating a struct pointer
        struct foo* ptr = malloc(sizeof(struct foo));
        printf("allocating : %p\n", ptr);
        ptr->x = val;

        //copying the pointer itself in the custom block
        memcpy(Data_custom_val(res), &ptr, sizeof(struct foo*));
        CAMLreturn(res);
}

生成文件

main.native: interface.c main.ml
        rm -rf _build
        rm -f  main.native main.byte
        ocamlbuild -cflags -g interface.o
        ocamlbuild -lflag -custom -cflags -g -lflags -g main.byte -lflags interface.o
        #ocamlbuild -cflags -g -lflags -g main.native -lflags interface.o

使用ocamldebug,程序似乎在my_print_block上崩溃,但我无法从跟踪中提取更多感觉。

使用gdb,错误位于Gc

#0  0x000000000040433d in caml_oldify_one ()
#1  0x0000000000406060 in caml_oldify_local_roots ()
#2  0x000000000040470f in caml_empty_minor_heap ()
#3  0x00000000004141ca in caml_gc_compaction ()
#4  0x000000000041bfd0 in caml_interprete ()
#5  0x000000000041df48 in caml_main ()
#6  0x000000000040234c in main ()

我已经看过几个例子,我在https://caml.inria.fr/pub/docs/manual-ocaml/intfc.html阅读了有关C绑定的文档,但我无法弄清楚我做错了什么。我使用的是ocaml version4.04.0 + flambda

感谢您的帮助

1 个答案:

答案 0 :(得分:3)

您的<html><body bgcolor="white"> <h1>Dissociation</h1> <p><b>Artist: </b>Dillinger Escape Plan</p> <table> <tr bgcolor="linen"> <td>Limerent Death</td> <td>4:06</td> </tr> <tr bgcolor="linen"> <td>Symptom Of Terminal Illness</td> <td>4:03</td> </tr> <tr bgcolor="linen"> <td>Wanting Not So Much To As To</td> <td>5:23</td> </tr> </table> </body></html> 函数使用print_block,因此它应该以{{1​​}}返回。我不确定这是你的问题,这只是我注意到的事情。但这可能是问题所在。