-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Resource-safe C interface: caml/fail.h
#12407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
As you documented, these exceptions encoded as values by or-ing them with 2 will crash the GC and, therefore, cannot survive an allocation. I think this is too dangerous to be exposed in the FFI. (We've had enough problems with Or perhaps you expose functions that return normal exception values (these could be useful in other situations, e.g. for other encodings of value-or-exception value) and let the caller use |
|
Taking a step back, this belongs to a project to fix the runtime wrt. async exceptions but also learn from it to improve the FFI (with C resource-management idioms in mind). Hence why making it non-internal. As a general goal,
This is not the first patch going in this direction, cf. So something like this at least is needed for users, not just for the runtime. You seem to be discussing the general direction, so it might be a good time to do it. We can explore better alternatives to the
I am curious to hear your thoughts for the general problems of exceptional return in the FFI rather than for |
Yes, I was thinking of this today when reviewing your |
|
I'm fine with using "exception-returning" style (return the exception describing the error instead of raising it on the spot) within the runtime system first: this has the potential to fix some nasty issues, and it will give us experience with this new approach, e.g. whether the current value-or-exception encoding is usable despite its limitations, or another representation is needed. But I think it's too early to change the public FFI in a way that hard-wires the current value-or-exception encoding. That's why I would much prefer expose functions that construct and return plain exception values, because they are just as useful as the functions that return value-or-exception encodings for the exceptions in question, but do not expose the encoding. |
|
I now have both implementations, the one embracing the I would like to mention that the concern about encoded exceptions was not raised during any of our previous discussions on the topic. Adding new public-facing Four years later, moving forward with this work is certainly not too early. We are no longer looking to experiment, because these non-raising variants are necessary for making the OCaml-Rust interoperability memory-safe. With the backwards-compatible proposition to move to a new alias for |
|
My naive understanding of the situation is the following:
Xavier objects to wider usage of the ugly encoding in (2). Could we instead explore (3), that is a proper type that is distinct from |
We already have such a type: As far as naming is concerned, the choice of the |
|
My understanding is that the types being discussed are for C code -- C callers and C callees -- so we do not need to allocate the result on the OCaml heap, we could for example use a C tagged union. We would actually get more type-safety this way, as we would have a more descriptive type than |
|
In #13013 I propose a |
|
@gasche proposes to implement separately the suggested approach in the fifth bullet point of my comment #12407 (comment). I think it goes in a right direction and I hope it will keep momentum. So I propose here a new version of this PR which introduces functions called |
gasche
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked at this and I think it is fine. (I like the commit factorizing shared code between fail_byt and fail_nat!) There will be some rebase work to be done on top of caml_result, unfortunately.
This introduces a new naming convention caml_exception_<foo> for the function constructing an exception value whose constructor is foo, as a variant of caml_raise_<foo>. Before we already had caml_exn_<foo> which is the exception constructor for that expression (without arguments), and so for constant exceptions caml_exn_foo and caml_exception_foo happen to be the same thing. This is very slightly awkward but I think it is overall fine and I don't have a better proposal to make, so I propose to go ahead.
runtime/caml/fail.h
Outdated
|
|
||
| /* Non-raising variants of the above functions. The exception is | ||
| returned as a normal value, which can be raised with [caml_raise], | ||
| typically after cleaning-up resources. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would make sense to also suggest Result_exception to return a caml_result instead of raising.
runtime/fail.c
Outdated
| CAMLno_asan | ||
| CAMLexport void caml_raise_constant(value tag) | ||
| #define Assert_is_tag(tag) \ | ||
| (CAMLassert(Is_block(tag) && Tag_val(tag) == Object_tag)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found the naming confusing because tag does not mean the same thing in Assert_is_tag / tag and in Tag_val / Object_tag. I understand that you are preserving the naming existing in the file, but I wonder if we could improve it to avoid the confusion. Other parts of the codebase (for example: lambda/translcore.ml:assert_failed) refer to this "tag" as a "slot", which is still unclear but at least does not conflict with the other meaning of "tag"; and then for extensible variants we call this the "extension constructor" which I find a much clearer name. I would find Assert_is_exn_constructor(constr) (or exn_constr) very clear -- and then constr or exn_constr as the variable name instead of tag below.
Simplification for subsequent commits.
Introduce variants of the functions that do not immediately raise the exception, allowing for resource cleanup. This is a preliminary change used to fix the error handling during the spawning of domains. Another motivating example is given at ocaml#7423: > caml_invalid_argument(str) is no return and does not free it's argument. So calling it with a string constructed dynamically will mean it'll never get freed. This led at the time to the introduction of [caml_invalid_argument_value] and [caml_failwith_value] that accept an OCaml string as argument, as a way to work around the lack of control on resource management. But this is a more general problem, for which the present commit gives a general solution in combination with caml_result.
|
I rebased and applied your suggestions. There was nothing special to be done wrt. the caml_result changes, so let me know if you thought of something specific. |
Dusting-off old commits, as a preliminary change to fix the error handling during the spawning of domains (#12269)...
This PR introduces
_exnvariants of the functions that do not immediately raise the exception, allowing for correct resource cleanup.Another motivating example is given at #7423:
This led at the time to the introduction of
caml_invalid_argument_valueandcaml_failwith_valuethat accept anOCaml string as argument, as a way to work around the lack of control on resource management. But this is a more general problem, for which the present commit gives a general solution that fits the rest of the resource-safe API.
This is best reviewed commit-per-commit.
cc @kayceesrk