aboutsummaryrefslogtreecommitdiffstats
path: root/tools/ocaml/libs/mmap
diff options
context:
space:
mode:
authorZheng Li <dev@zheng.li>2011-10-06 17:45:43 +0100
committerZheng Li <dev@zheng.li>2011-10-06 17:45:43 +0100
commitc9e3fb65ae60f2719acdb11ce648620b1d6c6ce4 (patch)
treef2291082119fed3972f513dfc7af7204dfe1a003 /tools/ocaml/libs/mmap
parent8d7a87b20e43fa82feed36abd41abf4f02444c73 (diff)
downloadxen-c9e3fb65ae60f2719acdb11ce648620b1d6c6ce4.tar.gz
xen-c9e3fb65ae60f2719acdb11ce648620b1d6c6ce4.tar.bz2
xen-c9e3fb65ae60f2719acdb11ce648620b1d6c6ce4.zip
tools: ocaml: Fix invalid memory access in OCaml mmap library
Fix invalid memory access in OCaml mmap library (to play nicely with the GC) This was a bug reported by Roberto Di Cosmo. When he tried to reuse the mmap library for his own project, Mmap.read occasionally got different result when reading from the same map. This turned out to be a bug in the binding, where a C pointer was created pointing to a OCaml value, and the OCaml value was subsequently moved around by the GC after memory allocation and hence invalidated the C pointer. This patch removes the indirection of C pointer and uses OCaml macro to access values directly. Only Mmap.read function had this problem. The other functions, despite having the same code style, didn't have memory allocation involved hence wouldn't intrigue such an error. I've changed all of them to the safer style for future proof. Directly casting OCaml value's *data block* (rather than the value itself) as a C pointer is not a common practice either, but I'll leave it as it is. The bug hadn't occured on XenServer because XenServer didn't make use of the Mmap.read function (except in one place for debugging). In XenServer, most mmap operations were going through another pair of separately implemented functions (Xs_ring.read/write). Signed-off-by: Zheng Li <dev@zheng.li> Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
Diffstat (limited to 'tools/ocaml/libs/mmap')
-rw-r--r--tools/ocaml/libs/mmap/mmap_stubs.c24
1 files changed, 9 insertions, 15 deletions
diff --git a/tools/ocaml/libs/mmap/mmap_stubs.c b/tools/ocaml/libs/mmap/mmap_stubs.c
index e32cef6c4f..322700f96e 100644
--- a/tools/ocaml/libs/mmap/mmap_stubs.c
+++ b/tools/ocaml/libs/mmap/mmap_stubs.c
@@ -71,12 +71,10 @@ CAMLprim value stub_mmap_init(value fd, value pflag, value mflag,
CAMLprim value stub_mmap_final(value interface)
{
CAMLparam1(interface);
- struct mmap_interface *intf;
- intf = GET_C_STRUCT(interface);
- if (intf->addr != MAP_FAILED)
- munmap(intf->addr, intf->len);
- intf->addr = MAP_FAILED;
+ if (GET_C_STRUCT(interface)->addr != MAP_FAILED)
+ munmap(GET_C_STRUCT(interface)->addr, GET_C_STRUCT(interface)->len);
+ GET_C_STRUCT(interface)->addr = MAP_FAILED;
CAMLreturn(Val_unit);
}
@@ -85,21 +83,19 @@ CAMLprim value stub_mmap_read(value interface, value start, value len)
{
CAMLparam3(interface, start, len);
CAMLlocal1(data);
- struct mmap_interface *intf;
int c_start;
int c_len;
c_start = Int_val(start);
c_len = Int_val(len);
- intf = GET_C_STRUCT(interface);
- if (c_start > intf->len)
+ if (c_start > GET_C_STRUCT(interface)->len)
caml_invalid_argument("start invalid");
- if (c_start + c_len > intf->len)
+ if (c_start + c_len > GET_C_STRUCT(interface)->len)
caml_invalid_argument("len invalid");
data = caml_alloc_string(c_len);
- memcpy((char *) data, intf->addr + c_start, c_len);
+ memcpy((char *) data, GET_C_STRUCT(interface)->addr + c_start, c_len);
CAMLreturn(data);
}
@@ -108,20 +104,18 @@ CAMLprim value stub_mmap_write(value interface, value data,
value start, value len)
{
CAMLparam4(interface, data, start, len);
- struct mmap_interface *intf;
int c_start;
int c_len;
c_start = Int_val(start);
c_len = Int_val(len);
- intf = GET_C_STRUCT(interface);
- if (c_start > intf->len)
+ if (c_start > GET_C_STRUCT(interface)->len)
caml_invalid_argument("start invalid");
- if (c_start + c_len > intf->len)
+ if (c_start + c_len > GET_C_STRUCT(interface)->len)
caml_invalid_argument("len invalid");
- memcpy(intf->addr + c_start, (char *) data, c_len);
+ memcpy(GET_C_STRUCT(interface)->addr + c_start, (char *) data, c_len);
CAMLreturn(Val_unit);
}