rust-lang / rust-lang/rust-bindgen

Cannot call function that returns custom type when destructor is present.

Open
#2,864 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
5.3k
Forks
829
Avg merge
1d 1h
Merged PRs (30d)
15

Description

For reproduction see here.
When static Foo Foo::create_foo(int x) is called, throws signal: 11, SIGSEGV: invalid memory reference. But when the destructor is removed, it could work. Furthermore I confirm that when destructor is default, i.e. explicit ~Foo() = default, it also runs.

Input C/C++ Header
//// wrapper.h
#include "foo/foo.h"

//// foo.h
// #include <iostream>

class Foo {
    int x;
public:
    inline Foo(int x) : x(x) {
        // std::cerr << "Creating Foo at " << this << " with x = " << x << std::endl;
    }
    inline static Foo create_foo(int x) {
        // std::cerr << "Calling static create_foo with x = " << x << std::endl;
        return Foo(x);
    }
    inline ~Foo() {
        // std::cerr << "Destroying Foo at " << this << " with x = " << x << std::endl;
    }
};
Bindgen Invocation
// build.rs
use std::env;
use std::path::PathBuf;

fn main() {

    println!("cargo:rerun-if-changed=src/lib.rs");
    println!("cargo:rerun-if-changed=src/wrapper.hpp");
    println!("cargo:rerun-if-changed=../src");
    
    let mut cmake_config = cmake::Config::new("../");

    // we need to keep the inline functions for gcc
    cmake_config.define("CMAKE_CXX_FLAGS", "-fkeep-inline-functions");

    let out_dir = std::env::var("OUT_DIR").unwrap();

    println!("cargo:rustc-link-search=native={}", out_dir.clone() + "/lib");
    println!("cargo:rustc-link-lib=static=Foo");

    let bindings = bindgen::Builder::default()
        .clang_arg(format!("-I{}", out_dir.clone() + "/include"))
        .clang_args(&["-x", "c++"])
        .generate_inline_functions(true)
        .header("wrapper.h")
        .opaque_type("std::.*")
        .allowlist_type("Foo")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

// lib.rs
mod ffi {
    #![allow(non_upper_case_globals)]
    #![allow(non_camel_case_types)]
    #![allow(non_snake_case)]

    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_foo() {
        let foo = unsafe { ffi::Foo::create_foo(1234) };
    }
}

or

Actual Results
running 1 test
error: test failed, to rerun pass `--lib`

Caused by:
  process didn't exit successfully: `/data/lxq/test-bindgen/rustbind/target/debug/deps/rustbind-0ab6c7ac1c58af6f test_foo` (signal: 11, SIGSEGV: invalid memory reference)
Expected Results

Test should pass.

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 with the linked bindgen-bug-mw reproduction, especially build.rs, lib.rs, and the generated bindings.rs for Foo::create_foo. Run the test with the user’s header and compare the generated bindings when Foo has an explicit destructor versus a default or absent destructor. Done means the test passes without SIGSEGV for the reported custom return type.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, rust
Domain
devtools, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.