rust-lang / rust-bindgen

Automatically generates Rust FFI bindings to C (and some C++) libraries.
https://rust-lang.github.io/rust-bindgen/
BSD 3-Clause "New" or "Revised" License
4.38k stars 689 forks source link

SIGSEGV running rust-bindgen on Objective-C headers #665

Open oluseyi opened 7 years ago

oluseyi commented 7 years ago

Input ~C/C++~ Objective-C Header

#import <Foundation/Foundation.h>
#import <NSWindow.h>
#import <NSTableView.h>

Bindgen Invocation

    let sdk_root = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk";

    let bindings = bindgen::Builder::default()
        .no_unstable_rust()
        .objc_extern_crate(true)
        .clang_arg("-x")
        .clang_arg("objective-c")
        .clang_arg(format!("-isysroot{}", sdk_root))
        .clang_arg("-mmacosx-version-min=10.10")
        .header("src/wrapper.h")
        .generate()
        .expect("Unable to generate bindings");

Invoked via cargo build with RUST_LOG=libbindgen and RUST_BACKTRACE=1.

Actual Results

oluseyi@Metroplex ~/S/cocoabind-rs> env RUST_LOG=libbindgen RUST_BACKTRACE=1 cargo build
   Compiling cocoabind-rs v0.1.0 (file:///Users/oluseyi/Source/cocoabind-rs)
error: failed to run custom build command for `cocoabind-rs v0.1.0 (file:///Users/oluseyi/Source/cocoabind-rs)`
process didn't exit successfully: `/Users/oluseyi/Source/cocoabind-rs/target/debug/build/cocoabind-rs-b444d464ed631d7a/build-script-build` (signal: 11, SIGSEGV: invalid memory reference)

Note: No stack trace generated!

Expected Results

At this point, simply successful execution without segfault and generation of bindings, even if incorrect.

oluseyi commented 7 years ago

Interestingly, changing the input header to only import framework umbrella headers while using the same invocation changes things:

Alternative Objective-C Header

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h> // both NSWindow and NSTableView are found in AppKit

Actual Results

oluseyi@Metroplex ~/S/cocoabind-rs> env RUST_LOG=libbindgen RUST_BACKTRACE=1 cargo build
   Compiling cocoabind-rs v0.1.0 (file:///Users/oluseyi/Source/cocoabind-rs)
error: failed to run custom build command for `cocoabind-rs v0.1.0 (file:///Users/oluseyi/Source/cocoabind-rs)`
process didn't exit successfully: `/Users/oluseyi/Source/cocoabind-rs/target/debug/build/cocoabind-rs-b444d464ed631d7a/build-script-build` (exit code: 101)
--- stderr
thread 'main' panicked at 'Invalid function sig: Continue', /Users/rustbuild/src/rust-buildbot/slave/stable-dist-rustc-mac/build/src/libcore/result.rs:868
stack backtrace:
   1:        0x107c81b3c - std::sys::imp::backtrace::tracing::imp::write::h21ca2762819c7ae8
   2:        0x107c8528e - std::panicking::default_hook::{{closure}}::h38f99a37d00bb19b
   3:        0x107c84f30 - std::panicking::default_hook::ha2186ee24b50729c
   4:        0x107c856e7 - std::panicking::rust_panic_with_hook::h979db19ee91d2a53
   5:        0x107c85594 - std::panicking::begin_panic::h6a69f5b54391c64d
   6:        0x107c854b2 - std::panicking::begin_panic_fmt::h9de2343580b3c2c4
   7:        0x107c85417 - rust_begin_unwind
   8:        0x107cadda0 - core::panicking::panic_fmt::haa2997386017a96f
   9:        0x1074dbc47 - core::result::unwrap_failed::hd4b9636c871e995c
  10:        0x10749987f - <core::result::Result<T, E>>::expect::hc3808a7201c3b02a
  11:        0x1075e0148 - bindgen::ir::objc::ObjCInterface::from_ty::{{closure}}::h23e91920790a5253
  12:        0x107599dd3 - bindgen::clang::visit_children::hb9435765c424748b
  13:        0x108e03c53 - _ZN5clang8cxcursor13CursorVisitor5VisitE8CXCursorb
  14:        0x108e057a4 - _ZN5clang8cxcursor13CursorVisitor23handleDeclForVisitationEPKNS_4DeclE
  15:        0x108e05849 - _ZN5clang8cxcursor13CursorVisitor16VisitDeclContextEPNS_11DeclContextE
  16:        0x108e074f5 - _ZN5clang8cxcursor13CursorVisitor22VisitObjCContainerDeclEPNS_17ObjCContainerDeclE
  17:        0x108e07bc2 - _ZN5clang8cxcursor13CursorVisitor22VisitObjCInterfaceDeclEPNS_17ObjCInterfaceDeclE
  18:        0x108e053b0 - _ZN5clang11declvisitor4BaseINS0_8make_ptrENS_8cxcursor13CursorVisitorEbE5VisitEPNS_4DeclE
  19:        0x108e0451d - _ZN5clang8cxcursor13CursorVisitor13VisitChildrenE8CXCursor
  20:        0x108e0e0bd - clang_visitChildren
  21:        0x107742fab - clang_sys::clang_visitChildren::h39a99caeaa290bcf
  22:        0x1075965c8 - bindgen::clang::Cursor::visit::hf458a3ad33e9fbe6
  23:        0x1075df51b - bindgen::ir::objc::ObjCInterface::from_ty::h2e82ec083166c00e
  24:        0x1075d5de9 - bindgen::ir::ty::Type::from_clang_ty::hf346cc68fd2c6cc1
  25:        0x1075c905c - <bindgen::ir::item::Item as bindgen::parse::ClangItemParser>::from_ty_with_id::hafaca2063af99fc4
  26:        0x1075c8184 - <bindgen::ir::item::Item as bindgen::parse::ClangItemParser>::from_ty::hb79ba4d7f2026786
  27:        0x1075c62a5 - <bindgen::ir::item::Item as bindgen::parse::ClangItemParser>::parse::h069918080bc479ca
  28:        0x1075e4b54 - bindgen::parse_one::h087e004499ab6029
  29:        0x1075e524c - bindgen::parse::{{closure}}::{{closure}}::h016504f7a21ebc44
  30:        0x10759a173 - bindgen::clang::visit_children::hcfa94b9af9a46465
  31:        0x108e03c53 - _ZN5clang8cxcursor13CursorVisitor5VisitE8CXCursorb
  32:        0x108e057a4 - _ZN5clang8cxcursor13CursorVisitor23handleDeclForVisitationEPKNS_4DeclE
  33:        0x108e05849 - _ZN5clang8cxcursor13CursorVisitor16VisitDeclContextEPNS_11DeclContextE
  34:        0x108e048cd - _ZN5clang8cxcursor13CursorVisitor13VisitChildrenE8CXCursor
  35:        0x108e0e0bd - clang_visitChildren
  36:        0x107742fab - clang_sys::clang_visitChildren::h39a99caeaa290bcf
  37:        0x107596504 - bindgen::clang::Cursor::visit::hef8bb37e2f4c9693
  38:        0x1075e529c - bindgen::parse::{{closure}}::h3db84f3a59f7ce32
  39:        0x1075b98c8 - bindgen::ir::context::BindgenContext::with_module::h2153d95a34634c8d
  40:        0x1075e5032 - bindgen::parse::hc085ed74066c82bd
  41:        0x1075e350c - bindgen::Bindings::generate::h48b6d40808caf41e
  42:        0x1075e239f - bindgen::Builder::generate::h03484a0dc6cdfda0
  43:        0x1073f3340 - build_script_build::main::h5b4468874f1dfcf4
  44:        0x107c8659a - __rust_maybe_catch_panic
  45:        0x107c85ab6 - std::rt::lang_start::hfc9882558f9403bf
  46:        0x1073f3509 - main

This looks to be running up against the incompleteness of the Objective-C support presently in rust-bindgen.

fitzgen commented 7 years ago

Thanks for the bug report!

svenknobloch commented 4 years ago

I've also been trying to use bindgen for AppKit and am running into the same issue (the 2nd one). I think I found the cause though.

In the AppKit header file, there is a property with the name operators:

.../MacOSX10.15.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSPredicateEditorRowTemplate.h:59:59
@property (nullable, readonly, copy) NSArray<NSNumber *> *operators;

In the function.rs the FunctionSig constructor checks against C++ operators (link) which matches the operators name and therefore throws an error and fails to parse.

I think a potential solution would be to improve the regex matching to include the symbols for C++ operators (+, =, etc.). I'm not too sure on what implications this would have on other codebases as I'm not too familiar with all the bindgen internals, but I can throw together a sample regex expression and make a PR if you think it's a valid solution.

svenknobloch commented 4 years ago

Alternatively another solution would just be to guard against only C++ functions using the kind to avoid a complex regex expression. Would guarding against CXCursor_CXXMethod capture all possible operators?

simlay commented 4 years ago

I've also been trying to use bindgen for AppKit and am running into the same issue (the 2nd one). I think I found the cause though.

@svenknobloch I think you'll be interested in #1750.

In the function.rs the FunctionSig constructor checks against C++ operators (link) which matches the operators name and therefore throws an error and fails to parse.

I tested this with the below test case and it looks like you're right.

To update the bug, here's the specific case:

input:

@interface Baz
@property (nullable, readonly) int *operators;
@end

Ran via: bindgen input.h -- -x objective-c

Expected output (based on recent master):

use objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
pub trait Baz {
    unsafe fn operators(self) -> *mut ::std::os::raw::c_int;
}
impl Baz for id {
    unsafe fn operators(self) -> *mut ::std::os::raw::c_int {
        msg_send!(self, foobar)
    }
}

Annoyingly enough blacklisting doesn't work. I'm guessing because it's at the parse tree phase rather than the generation.