English version
Accueil     À propos     Téléchargement     Ressources     Contactez-nous    

Ce site est rarement mis à jour. Pour les informations les plus récentes, rendez-vous sur le nouveau site OCaml à l'adresse ocaml.org.

Browse thread
[Caml-list] Problem with GC and custom blocks
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: 2003-03-25 (18:39)
From: Damien Doligez <Damien.Doligez@i...>
Subject: Re: [Caml-list] Problem with GC and custom blocks
On Tuesday, March 25, 2003, at 11:31 AM, Falk Hueffner wrote:

> I'm having trouble with the GC destroying my custom blocks, although
> it looks like I have properly protected them. Unfortunately, I cannot
> reproduce it with a small testcase.

You seem to misunderstand the purpose of the CAMLparam and CAMLlocal
macros.  The GC is not destroying your custom blocks, it is moving
them.  Because it is moving them, it has to update all pointers
to them.  Hence, it is the *pointers* (in fact, the local variables
that contain these pointers) that need to be "protected".

> static inline value alloc_graph(unsigned n,
> 				unsigned vertex_bits, unsigned edge_bits)
> {
>     value r = alloc_custom((struct custom_operations *) &graph_ops,
> 			   1 << 16, // huge value to trigger bug earlier
> 			   0, 1);
>     long *l = Data_custom_val(r);
>     for (int i = 0; i < 32/4; ++i)
> 	l[i] = 0xefbeadde;
>     dumpbytes(r, 32, __PRETTY_FUNCTION__);
>     return r;
> }

No problem here.  Note that alloc_graph calls an allocation function,
and thus may move blocks around.

> static inline value clone_graph(const struct graph *g)  {
>     dumpbytes(((char*) g)  - 4, 32, __PRETTY_FUNCTION__ " in");
>     value gv = alloc_graph(g->n, g->vertex_bits, g->edge_bits);
>     dumpbytes(((char*) g)  - 4, 32, __PRETTY_FUNCTION__ " post");
>     make_copy(Data_custom_val(gv), g);
>     dumpbytes(gv, 32, __PRETTY_FUNCTION__ " out");
>     return gv;
> }

Here, you have a problem if g is a pointer into the heap, because you
call alloc_graph, which may move heap blocks.

> // set_connected: graph -> int -> int -> graph
> value set_connected_c(value gv, value iv, value jv) {
>     fprintf(stderr, "protecting %p\n", gv);
>     CAMLparam3(gv, iv, jv);
>     dumpbytes(gv, 32, __PRETTY_FUNCTION__);
>     const struct graph *gin = Data_custom_val(gv);
>     ulong i = Long_val(iv);
>     ulong j = Long_val(jv);
>     CAMLlocal1(goutv);
>     goutv = clone_graph(gin);
>     struct graph *gout = Data_custom_val(goutv);
>     set_connected(gout, i, j);
>     dumpbytes(goutv, 32, __PRETTY_FUNCTION__ " out");
>     CAMLreturn(goutv);
> }

And here you trigger the problem by passing Data_custom_val(gv)
as argument to clone_graph.

What you should do is:
1. modify clone_graph to take a parameter of type "value"
2. protect this parameter with CAMLparam1

Even if another copy of the same address is protected in
"set_connected_c" under the name of "gv", you still need to protect
it under its new name in clone_graph, so the GC will be able to
update both copies when it moves the data.

Also, note that you cannot protect an infix pointer (a pointer
that points inside a block instead of pointing to its head).
That makes Data_custom_val rather error-prone and you should
avoid storing its result in a variable or passing it as argument
to functions that can allocate in the Caml heap.

> So 0x400c8fec gets mangled, although I protected it. Did I do
> something obvious wrong? Or are there any known bugs in the GC? Any
> other suggestions how to track this down? I'd be really grateful even 
> for
> a workaround...

Please let me know if this helps.

-- Damien

To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners