rust-lang / rust-lang/rust-bindgen

Segmentation Fault in C++ operator caused by argument being NULL

Open
#2,222 6 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

Input C/C++ Header
class RAK_DLL_EXPORT RakPeer : public RakPeerInterface, public RNS2EventHandler
{
public:
	/// \brief Sends a block of data to the specified system that you are connected to.
	/// 
	/// Same as the above version, but takes a BitStream as input.
	/// \param[in] bitStream Bitstream to send
	/// \param[in] priority Priority level to send on.  See PacketPriority.h
	/// \param[in] reliability How reliably to send this data.  See PacketPriority.h
	/// \param[in] orderingChannel Channel to order the messages on, when using ordered or sequenced messages. Messages are only ordered relative to other messages on the same stream.
	/// \param[in] systemIdentifier System Address or RakNetGUID to send this packet to, or in the case of broadcasting, the address not to send it to.  Use UNASSIGNED_SYSTEM_ADDRESS to specify none.
	/// \param[in] broadcast True to send this packet to all connected systems. If true, then systemAddress specifies who not to send the packet to.
	/// \param[in] forceReceipt If 0, will automatically determine the receipt number to return. If non-zero, will return what you give it.
	/// \return 0 on bad input. Otherwise a number that identifies this message. If \a reliability is a type that returns a receipt, on a later call to Receive() you will get ID_SND_RECEIPT_ACKED or ID_SND_RECEIPT_LOSS with bytes 1-4 inclusive containing this number
	/// \note COMMON MISTAKE: When writing the first byte, bitStream->Write((unsigned char) ID_MY_TYPE) be sure it is casted to a byte, and you are not writing a 4 byte enumeration.
	uint32_t Send( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, uint32_t forceReceiptNumber=0 );
}
Bindgen Invocation
    let bindings = bindgen::Builder::default()
        .header("wrapper.hpp")
        .enable_cxx_namespaces()
        .layout_tests(false)
        .generate_inline_functions(true)

        .allowlist_type("Rak.*")
        .allowlist_type("DefaultMessageIDTypes")
        .allowlist_type("UNASSIGNED.*")
        .allowlist_function(".*Undefined.*")

        .blocklist_function(".*BitStream_Write1")

        .generate()
        .expect("Unable to generate bindings");
Actual Results

Test crashes with

Signal: SIGSEGV (signal SIGSEGV: invalid address (fault address: 0x0))

Debugger stack at time of crash:

RakNet::RakNetGUID::operator!=(const RakNet::RakNetGUID &) const RakNetTypes.cpp:762
RakNet::RakPeer::IsLoopbackAddress(const RakNet::AddressOrGUID &, bool) const RakPeer.cpp:4008
RakNet::RakPeer::Send(const RakNet::BitStream *, PacketPriority, PacketReliability, char, RakNet::AddressOrGUID, bool, unsigned int) RakPeer.cpp:1391
chat_example lib.rs:75
chat_client lib.rs:127
{closure#0} lib.rs:126
call_once<raknet::tests::chat_client::{closure_env#0}, ()> function.rs:230
[Inlined] core::ops::function::FnOnce::call_once function.rs:230
__rust_begin_short_backtrace<fn()> lib.rs:573
[Inlined] _$LT$alloc..boxed..Box$LT$F$C$A$GT$$u20$as$u20$core..ops..function..FnOnce$LT$Args$GT$$GT$::call_once boxed.rs:1861
[Inlined] _$LT$core..panic..unwind_safe..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$$LP$$RP$$GT$$GT$::call_once unwind_safe.rs:271
[Inlined] std::panicking::try::do_call panicking.rs:492
[Inlined] std::panicking::try panicking.rs:456
[Inlined] std::panic::catch_unwind panic.rs:137
[Inlined] test::run_test_in_process lib.rs:596
{closure#0} lib.rs:490
[Inlined] test::run_test::run_test_inner::_$u7b$$u7b$closure$u7d$$u7d$ lib.rs:517
__rust_begin_short_backtrace<test::run_test::run_test_inner::{closure_env#1}, ()> backtrace.rs:122
[Inlined] std::thread::Builder::spawn_unchecked_::_$u7b$$u7b$closure$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$ mod.rs:498
[Inlined] _$LT$core..panic..unwind_safe..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$$LP$$RP$$GT$$GT$::call_once unwind_safe.rs:271
[Inlined] std::panicking::try::do_call panicking.rs:492
[Inlined] std::panicking::try panicking.rs:456
[Inlined] std::panic::catch_unwind panic.rs:137
[Inlined] std::thread::Builder::spawn_unchecked_::_$u7b$$u7b$closure$u7d$$u7d$ mod.rs:497
call_once<std::thread::{impl#0}::spawn_unchecked_::{closure_env#1}<test::run_test::run_test_inner::{closure_env#1}, ()>, ()> function.rs:230
[Inlined] _$LT$alloc..boxed..Box$LT$F$C$A$GT$$u20$as$u20$core..ops..function..FnOnce$LT$Args$GT$$GT$::call_once boxed.rs:1861
[Inlined] _$LT$alloc..boxed..Box$LT$F$C$A$GT$$u20$as$u20$core..ops..function..FnOnce$LT$Args$GT$$GT$::call_once boxed.rs:1861
thread_start thread.rs:108
<unknown> 0x00007fb5da3e354d
__clone 0x00007fb5da468874

By looking at the debugger results, it seems the Send function is called with a NULL systemIdentifier even though it is instantiated and called in rust with this:

let system_identifier = AddressOrGUID::new2(&(*packet).systemAddress);

RakPeer_Send1(peer as *mut c_void, &bsOut as *const BitStream, PacketPriority_HIGH_PRIORITY, PacketReliability_RELIABLE_ORDERED, 0, system_identifier, false, 0);

The debugger also shows that all the other arguments are non-null and valid in the Send function.

I have tried other ways to instantiate the system_identifier but everything ends up with the same result, and I was able to verify that the system_identifier variable is valid on the rust side using the debugger.

Here are the generated bindings for some of the functions used:

#[link_name = "\u{1}_ZN6RakNet7RakPeer4SendEPKNS_9BitStreamE14PacketPriority17PacketReliabilitycNS_13AddressOrGUIDEbj"]
            pub fn RakPeer_Send1(
                this: *mut ::std::os::raw::c_void,
                bitStream: *const root::RakNet::BitStream,
                priority: root::PacketPriority,
                reliability: root::PacketReliability,
                orderingChannel: ::std::os::raw::c_char,
                systemIdentifier: root::RakNet::AddressOrGUID,
                broadcast: bool,
                forceReceiptNumber: u32,
            ) -> u32;

// I use new2 in this example but I also tried new3 and new4
#[inline]
            pub unsafe fn new() -> Self {
                let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
                AddressOrGUID_AddressOrGUID(__bindgen_tmp.as_mut_ptr());
                __bindgen_tmp.assume_init()
            }
            #[inline]
            pub unsafe fn new1(input: *const root::RakNet::AddressOrGUID) -> Self {
                let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
                AddressOrGUID_AddressOrGUID1(__bindgen_tmp.as_mut_ptr(), input);
                __bindgen_tmp.assume_init()
            }
            #[inline]
            pub unsafe fn new2(input: *const root::RakNet::SystemAddress) -> Self {
                let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
                AddressOrGUID_AddressOrGUID2(__bindgen_tmp.as_mut_ptr(), input);
                __bindgen_tmp.assume_init()
            }
            #[inline]
            pub unsafe fn new3(packet: *mut root::RakNet::Packet) -> Self {
                let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
                AddressOrGUID_AddressOrGUID3(__bindgen_tmp.as_mut_ptr(), packet);
                __bindgen_tmp.assume_init()
            }
            #[inline]
            pub unsafe fn new4(input: *const root::RakNet::RakNetGUID) -> Self {
                let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
                AddressOrGUID_AddressOrGUID4(__bindgen_tmp.as_mut_ptr(), input);
                __bindgen_tmp.assume_init()
            }
Expected Results

The send function is called with valid arguments and doesn't crash

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 generated RakPeer_Send1 declaration and the C++ RakPeer::Send signature, then trace the call from chat_example lib.rs:75 through chat_client lib.rs:127. Compare the AddressOrGUID constructors with the debugger stack in RakPeer.cpp:1391 and RakNetTypes.cpp:762; done means the reproduced send call no longer crashes and its arguments remain valid across the binding boundary.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.