Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functions returning structs do not work #3

Open
meerik opened this issue Jan 16, 2017 · 12 comments
Open

Functions returning structs do not work #3

meerik opened this issue Jan 16, 2017 · 12 comments

Comments

@meerik
Copy link

meerik commented Jan 16, 2017

Structs defined in c++, such as b2Vec2 seem to cause many problems when they are passed over the FFI by-value. I think the reason is different calling conventions for C vs C++.
It seems like functions returning structs as-value or taking structs as input argument as-value cause problems. Take Body::world_point() as example, it does not work and return undefined data or some times crash. (All other demos from the testbed work because they never use any such function).

It is implemented as follows:

pub fn world_point(&self, local: &Vec2) -> Vec2 {
        unsafe { ffi::Body_get_world_point(self.ptr(), local) }
    }
b2Vec2 Body_get_world_point(const b2Body* self, const b2Vec2* local) {
    return self->GetWorldPoint(*local);
}

Here the argument "local" will point to garbage no matter how you call the funcition and the program crashes. This is because the return value is a b2Vec2 as-value and b2Vec2 is compiled as struct/class by c++ code while the function Body_get_world_point is treated as C-code.

@Bastacyclop
Copy link
Owner

@meerik Thanks for the detailed issue,
convention issues between C and C++ would surprise me since I'm using extern "C" so I would at least expect a warning if the result is not C compatible. Although I don't know the details and there may be no checks at all, so it is very possible, are you confident in your explanation ?

This code works fine for me, I guess it doesn't work for you ?

use wrapped2d::b2;
use wrapped2d::user_data::NoUserData;

#[test]
fn get_world_point() {
    let gravity = b2::Vec2 { x: 0., y: -10. };
    let mut world = b2::World::<NoUserData>::new(&gravity);

    let mut ground_body_def = b2::BodyDef::new();
    ground_body_def.position = b2::Vec2 { x: 0., y: -10. };
    let ground_handle = world.create_body(&ground_body_def);
    {
        let mut ground = world.body_mut(ground_handle);

        let ground_box = b2::PolygonShape::new_box(50., 10.);
        ground.create_fast_fixture(&ground_box, 0.);
        assert_eq!(ground.world_point(&b2::Vec2 { x: 5., y: 0. }),
                   b2::Vec2 { x: 5., y: -10. });
    }
}
> rustc --print cfg
debug_assertions
target_arch="x86_64"
target_endian="little"
target_env="gnu"
target_family="unix"
target_feature="sse"
target_feature="sse2"
target_has_atomic="16"
target_has_atomic="32"
target_has_atomic="64"
target_has_atomic="8"
target_has_atomic="ptr"
target_os="linux"
target_pointer_width="64"
target_thread_local
target_vendor="unknown"
unix

@meerik
Copy link
Author

meerik commented Jan 16, 2017

Thank you for the quick reply.
Your test works on Ubuntu with GCC but not on Windows with MSVC.


---- tests::get_world_point stdout ----
	thread 'tests::get_world_point' panicked at 'assertion failed: `(left == right)` (left: `Vec2 { x: -0.00000000000000029138696, y: 0.000000000000000000000000000000000000000000912 }`, right: `Vec2 { x: 5, y: -10 }`)', src\lib.rs:22
rustc --print cfg
target_os="windows"
target_family="windows"
target_arch="x86_64"
target_endian="little"
target_pointer_width="64"
target_env="msvc"
windows
debug_assertions

@Bastacyclop
Copy link
Owner

Maybe the problem comes from the use of gcc in build_frontend ?

@retep998
Copy link

This may be a case of rust-lang/rfcs#1342, especially since it specifically does not work on Windows.

@Bastacyclop
Copy link
Owner

@retep998 Thanks for the info!

@norru
Copy link
Contributor

norru commented Jan 29, 2017

I've seen this too in VS 2015, msvc toolchain.

Quite a few other related issues too. 1) stdc++ cannot be linked in MSVC 2) no luck with 64 bit build, link.exe laments a 32/64 bit mismatch with one of the deps. I'll investigate and post separate issues.

@retep998
Copy link

stdc++ cannot be linked in MSVC

Statically linking together MSVC and MinGW code is not supported at all whatsoever and will almost always break.

@norru
Copy link
Contributor

norru commented Jan 29, 2017

Yep, I am building with the MSVC toolchain, but rust_box2d causes the linker to attempt to include stdc++ anyway.

@retep998
Copy link

Hmmm, it uses the gcc crate to build things, and that should know how to handle MSVC just fine. I'll investigate more later perhaps.

@norru
Copy link
Contributor

norru commented Jan 29, 2017

This may have something to do with it (in lib.rs)

#[link(name = "stdc++")] extern "C" {}

EDIT: removing the line above from lib.rs actually fixes the problem in MSVC - I haven't tried other toolchains/platforms though. That may require a #[cfg(...)] annotation for other platforms.

I'll move to another thread though, I've hijacked this enough :)

@retep998
Copy link

@norru Since this uses the gcc crate to handle building and linking the C++, that automatically handles linking the C++ standard library. https://github.com/alexcrichton/gcc-rs/blob/master/src/lib.rs#L950-L963 So definitely removing that #[link(name = "stdc++")] is the right thing to do.

@Bastacyclop
Copy link
Owner

For information, the latter has been done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants