Browse thread
Wrapping OCaml function returning a variant
[
Home
]
[ Index:
by date
|
by threads
]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
| Date: | -- (:) |
| From: | Xavier Leroy <Xavier.Leroy@i...> |
| Subject: | Re: [Caml-list] Wrapping OCaml function returning a variant |
> I came up with this. Is it sound?
Not quite.
> char *morph(char *code, char** error, int *line, int *start, int *end)
> {
> static value *closure = NULL;
> value v;
> char *res;
>
> if (closure == NULL)
> closure = caml_named_value("morph");
>
> v = callback(*closure, caml_copy_string(code));
Here, caml_copy_string could trigger a GC and move the closure pointed
to by closure, so the value of *closure could become invalid.
You need to order the computations explicitly:
value vcode;
if (closure == NULL)
closure = caml_named_value("morph");
vcode = caml_copy_string(code);
v = callback(*closure, vcode);
> switch (Long_val(v)) {
v is not a constant constructor, but a constructor with arguments.
So, its representation is not an integer, but a pointer to a block.
You want to discriminate on the tag of this block.
switch (Tag_val(v)) {
> case 0: /* success */
> res = String_val(Field(v, 0));
> *error = NULL;
> case 1: /* error */
> res = NULL;
> *error = String_val(Field(v, 0));
> *line = Int_val(Field(v, 1));
> *start = Int_val(Field(v, 2));
> *end = Int_val(Field(v, 3));
> }
The next GC can move the strings obtained by String_val, making
invalid the pointer you return or store in *error. Take a copy immediately:
switch (Tag_val(v)) {
case 0: /* success */
res = strdup(String_val(Field(v, 0)));
*error = NULL;
case 1: /* error */
res = NULL;
*error = strdup(String_val(Field(v, 0)));
*line = Int_val(Field(v, 1));
*start = Int_val(Field(v, 2));
*end = Int_val(Field(v, 3));
}
Hope this helps,
- Xavier Leroy