From: Hendrik Tews <tews@tcs.inf.tu-dresden.de>
To: caml-list@inria.fr
Subject: catch / reraise exceptions in C, representation of exceptions
Date: Sat, 13 May 2006 00:42:53 +0200 [thread overview]
Message-ID: <17509.3949.971571.93976@ithif59.inf.tu-dresden.de> (raw)
Dear all,
I just finished some (C++) code that uses callbacks into ocaml
and catches and reraises some exceptions (raised in the
callbacks). For these matters the documentation ... aehm ... has
some space for improvements. Here are the things that I learned
the hard way (please correct if something is wrong), point 4
contains speculations and point 5 a question:
1. Users of caml_callback_exn must obey an additional garbage
collector harmony rule:
An exceptional value obtained from one of the
caml_callback_exn functions (that is one for which
Is_exception_result returns true) _must_ _not_ be contained in
a local or global root when calling one of the allocation
functions.
Because every value must be registered, it follows that you
either have to clear the exceptional value or replace it with
something else before the next allocation. Use the following
pattern, if you are unsure which code may perform allocations:
result = caml_callback_exn(...);
is_exception = Is_exception_result(result);
result = Extract_exception(result);
Extract_exception returns a non-exceptional value (not to be
confused with a value that represents an exception).
If you look at
#define Make_exception_result(v) ((v) | 2)
#define Is_exception_result(v) (((v) & 3) == 2)
#define Extract_exception(v) ((v) & ~3)
in caml/callback.h it is easy to understand why you get
segfaults sooner or later, if you don't obey the rule obove.
2. Exceptions (ie. results of Extract_exception) are represented
as blocks of size 1 plus the number of arguments of the
exception (ie, End_of_file has size 1, exception A of int *
int * string has size 4, and Match_failure has size 2 because
it is defined as exception Match_failore of (string * int *
int)).
The contents of the first field is the exception id, it
uniquely identifies the exception. Use the following pattern
to check if some specific exception occured:
result = caml_callback_exn(...);
if(Is_exception_result(result)){
result = Extract_exception(result); /* see rule above */
if(Field(result,0) == *caml_named_value("my_exception_id")){
/* exception registered under "my_exception" occured */
} else {
/* some other exception occured */
}
}
3. To reraise an unknown exception use caml_raise (with a
non-exceptional argument). For instance
result = caml_callback_exn(...);
if(Is_exception_result(result)){
result = Extract_exception(result); /* see rule above */
if(Field(result,0) == *caml_named_value("Not_found_id")){
/* catch Not_found */
....
}
else
caml_raise(result); /* reraise other exceptions */
}
To raise an exception with more than one argument, allocate a
block of the right size (see point 2), fill the exception id
in field 0 and the arguments in the remaining fields and use
caml_raise on this so created value.
4. It seems that an exception id is always a block of size one,
which contains (the value of) the string of the exception
name.
Is this true? Can one access the exception name that way or
are programs using this doomed to be broken in the future?
5. Question: Rule 1 says I should CAMLreturn at the end of my
function. But what if I raise an exception? Can I rely on the
ocaml runtime to unchain all my local roots, that is, is the
following safe:
void f(...){
CAMLparam(...);
CAMLlocal(...);
....
caml_raise_with_arg(...);
}
There is a CAMLnoreturn, but IMHO it doesn't make sense to put
it after caml_raise_with_arg.
Bye,
Hendrik
reply other threads:[~2006-05-12 22:42 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=17509.3949.971571.93976@ithif59.inf.tu-dresden.de \
--to=tews@tcs.inf.tu-dresden.de \
--cc=caml-list@inria.fr \
/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).