caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Gerd Stolpmann <info@gerd-stolpmann.de>
To: "Neuhaeusser, Martin" <martin.neuhaeusser@siemens.com>
Cc: "caml-list@inria.fr" <caml-list@inria.fr>
Subject: Re: [Caml-list] The OCaml garbage collector, finalisers, and the right way of disposing native pointers in C bindings
Date: Tue, 12 Jan 2016 11:33:00 +0100	[thread overview]
Message-ID: <1452594780.13126.63.camel@e130.lan.sumadev.de> (raw)
In-Reply-To: <965631B03C670145ABB9F693E51622530D0D763B@DENBGAT9EK5MSX.ww902.siemens.net>

[-- Attachment #1: Type: text/plain, Size: 3469 bytes --]

Dealing with naked pointers from OCaml is notoriously difficult. As you
found out, you have no good ways of controlling GC cycles, and to limit
bad effects of that. Also, there is a dangling pointer problem -
essentially the naked pointer can be mistaken as heap pointer between
the time the memory has been freed and the naked pointer is set to null.
Note that this aspect is practically impossible to do right from OCaml
code, and even in a C function it is easy to get wrong, resulting in
random crashes that occur infrequently.

For these reasons naked pointers are strongly discouraged. The way to go
is to wrap pointers into custom blocks
(http://caml.inria.fr/pub/docs/manual-ocaml/intfc.html#sec458), and to
do all pointer management in C.

Gerd

Am Dienstag, den 12.01.2016, 09:12 +0000 schrieb Neuhaeusser, Martin:
> Dear all,
> 
> during our work on some SMT solver bindings, a couple of question came up regarding the behavior of the OCaml garbage collector (see also https://github.com/Z3Prover/z3/issues/411). Assume we have defined a record type containing a native pointer to some object from an external C-DLL:
> 
> type ocaml_record = {
>   native_ptr np;
>   [... some more fields ...]
> }
> 
> When creating an ocaml_record, we register a finalizer that makes the C library dispose the data belonging to the native pointer once the GC collects the OCaml record value:
> 
> let f ocaml_record = NativeLib.dispose ocaml_record.np
> 
> let create [...] =
>   let new_ocaml_record = { ... } in
>   Gc.finalise f new_ocaml_record;
>   new_ocaml_record
> 
> When calling one of the C-stubs, we pass the native pointer from the OCaml record value:
> 
> let get_native_pointer ocaml_record = ocaml_record.np
> 
> NativeLib.native_function (get_native_pointer ocaml_record)
> 
> However, this has the problem that if ocaml_record has become otherwise unreachable, the GC might collect ocaml_record directly after evaluating (get_native_pointer ocaml_record), triggering the finalizer which disposes the data pointed at by ocaml_record.native_ptr. The successive call to NativeLib.native_function (i.e. the C-stub) results in a segfault, as it tries to access data that has previously been freed by the finalizer.
> 
> I assume this is a common problem in writing interfaces to C libraries. If so, is there a preferred way how to tackle it?
> Two approaches that came to my mind are
> 
> 1. One could design the C-stubs such that they accept values of type ocaml_record and extract the native pointer within the C stub. In the C-stubs, the GC must not collect an item that has been "pinned" by the CAMLparamX macros, right?
> 2. One could invent some function that takes an ocaml_record, but does nothing with it and whose calls do not get optimized away by the compiler... Evaluating such a function after the call to NativeLib.native_function would prevent the GC from collecting ocaml_record. However, this feels like a very ugly hack. 
> 
> Are there any better ideas? Any help and suggestions are highly appreciated.
> 
> Best,
> Martin
> 

-- 
------------------------------------------------------------
Gerd Stolpmann, Darmstadt, Germany    gerd@gerd-stolpmann.de
My OCaml site:          http://www.camlcity.org
Contact details:        http://www.camlcity.org/contact.html
Company homepage:       http://www.gerd-stolpmann.de
------------------------------------------------------------


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

  parent reply	other threads:[~2016-01-12 10:33 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-12  9:12 Neuhaeusser, Martin
2016-01-12  9:37 ` Kim Nguyễn
2016-01-12 10:33 ` Gerd Stolpmann [this message]
2016-01-12 13:06 ` Richard W.M. Jones

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1452594780.13126.63.camel@e130.lan.sumadev.de \
    --to=info@gerd-stolpmann.de \
    --cc=caml-list@inria.fr \
    --cc=martin.neuhaeusser@siemens.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).