Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Support C++ exceptions without undefined behaviour #1208

Copy link
Copy link
Open
@Ekleog

Description

@Ekleog
Issue body actions

Bindgen currently does not (cannot) support C++ exceptions, because C++ won't be able to unwind correctly into the rust code.

An idea to support this would be to emit a C++ wrapper for the C++ functions (see #1172 (comment) for the design idea). Emitting a C++ wrapper for functions would also allow to (by making it extern "C") remove all of bindgen's code for mangling C++ functions and make supporting new C++ compilers much easier.

A C++ wrapper function could look like this (syntax untested esp. the union one, and there are tricks with non-copyable return types, I can never remember the correct syntax for moving c++ stuff):

// Original function
ret_t fun(arg_t arg) {
    // ...
}

// Wrapper function
struct XXX_bindgen_result_ret_t {
    enum { OK, ERROR, UNKNOWN_ERROR } tag;
    union {
        ret_t ok;
        char * error_msg;
    } value;

    static XXX_bindgen_result_ret_t make_ok(ret_t r) {
        XXX_bindgen_result_ret_t ret;
        ret.tag = OK;
        ret.value.ok = r;
        return ret;
    }
    static XXX_bindgen_result_ret_t make_err(char * s) {
        XXX_bindgen_result_ret_t ret;
        ret.tag = ERROR;
        ret.value.error_msg = s;
        return ret;
    }
    static XXX_bindgen_result_ret_t make_unknown_error() {
        XXX_bindgen_result_ret_t ret;
        ret.tag = UNKNOWN_ERROR;
        return ret;
    }
};

extern "C"
XXX_bindgen_result_ret_t XXX_bindgen_function_fun(arg_t arg) {
    try {
        return XXX_bindgen_result_ret_t::make_ok(original_cpp_function(arg));
    } catch (exception e) {
        return XXX_bindgen_result_ret_t::make_err(e.message());
    } catch (...) {
        return XXX_bindgen_result_ret_t::make_unknown_error();
    }
}

Basically, with this C++ wrapper, bindgen takes control of the way FFI is performed, and can almost ignore the fact that it's a C++ compiler on which it's running.

The drawbacks are:

  • A (single) additional function call at each FFI call
  • Requirement to build an additional C++ file in addition to building rust code
  • This requirement is a backward-incompatible change if it's not hidden behind a flag (and I guess if exceptions are supported it should be by opt-out and not opt-in, unless not opting in also means not allowing C++, given it's such an easy way to trigger UB and exceptions are way too rarely documented)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.