rust-lang / rust-lang/rust-bindgen

Support C++ exceptions without undefined behaviour

Open
#1,208 4 comments 9 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-C++ E-hard enhancement help wanted
Dominant language
Rust
Stars
5.3k
Forks
829
Avg merge
1d 1h
Merged PRs (30d)
15

Description

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 https://github.com/rust-lang-nursery/rust-bindgen/issues/1172#issuecomment-354831001 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)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the proposed C++ wrapper design in this issue and the linked rust-bindgen issue 1172. Work out how wrapper generation, exception-to-result handling, and the additional C++ build requirement would fit together; done means C++ exceptions cannot unwind into Rust and the design's compatibility trade-offs are resolved.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, rust
Domain
compilers, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.