Version française
Home     About     Download     Resources     Contact us    
Browse thread
Bigarrays and temporar C pointers
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Daniel_Bünzli <daniel.buenzli@e...>
Subject: Bigarrays and temporar C pointers
Hello,

Suppose that I have a C library which allows me to access data via a 
temporar pointer with the following interface  :

> void *map(void);  /* Returns a valid pointer to data */
> int map_size(void);  /* Returns the size of the data in bytes. */
> void unmap(void);  /* Invalidates the last pointer returned by map. */

Mapping data to a pointer must only be done for a short period of time: 
map, get size, process data, and unmap.

I would like to be able to process data in ocaml with bigarrays. To do 
so I provide the ocaml function `map'. This function maps the pointer, 
pass it as a bigarray to a user callback to process the data and then 
unmaps the pointer.

> open Bigarray;;
>
> type ('a, 'b) data = ('a, 'b, c_layout) Array1.t
>
> val map : ('a, b) kind -> (('a, 'b) data -> unit) -> unit

Map is implemented as follow (C primitives are at the end of the mail),

> external _map_ptr : ('a, 'b) kind -> ('a, 'b) data = "stub_map_ptr"
> external _unmap_ptr : ('a, 'b) data -> unit = "stub_unmap_ptr"
>
> let map k f =
>   let a = _map_ptr k in
>   f a;
>   _unmap_ptr a

My problem is that the provided bigarray may escape the scope of the 
user callback (e.g. by setting a global reference to the bigarray) 
potentially allowing the user to access data at an invalid pointer 
position after the pointer was invalidated.

In fact for the bigarray itself it is not a problem, I set its 
dimension to zero when I unmap it in _unmap_ptr (see the C 
implementation below) so access outside the user callback raise 
exceptions. However, according to my experiments and wandering in the 
implementation of bigarray this doesn't work if the user extracts a 
subarray with Array1.sub and sets it to a global variable.

Is there a solution to make that completely safe or I can only warn the 
user that he should not to try to escape data from the callback ?

Thanks for your help,

Daniel


The implementation of the C primitives :

> extern int bigarray_element_size[]; /* bigarray_stubs.c */
>
> CAMLprim value stub_map_ptr (value kind)
> {
>   void *p = map ();
>   long dim = map_size () / bigarray_element_size[Int_val (kind)];
>   int flag = Int_val (kind) | BIGARRAY_C_LAYOUT | BIGARRAY_EXTERNAL;
>   return alloc_bigarray(flag, 1, p, &dim);
> }
>
> CAMLprim value stub_unmap_ptr (value b)
> {
>   struct caml_bigarray *arr = Bigarray_val(b);
>   arr->data = NULL;
>   arr->dim[0] = 0;
>   unmap();
>   return Val_unit;
> }