Skip to content

Calls from C to Rust get miscompiled on Windows 64 #24427

Closed
@vosen

Description

@vosen
Contributor

Rust code:

#[repr(C)]
pub struct Data {
    bar: u64,
    baz: u64,
}

#[no_mangle]
pub extern fn foo(a1: Data,
                  a2: Data,
                  a3: Data,
                  a4: Data,
                  a5: Data) {
    println!("{:}", a1.bar);
    println!("{:}", a2.bar);
    println!("{:}", a3.bar);
    println!("{:}", a4.bar);
    println!("{:}", a5.bar);
}


extern {
    fn c_main();
}

fn main() {
    unsafe { c_main() };
}

C code:

#include <stdint.h>

typedef struct data {
    uint64_t bar;
    uint64_t baz;
} data;
void foo(data a1,
         data a2,
         data a3,
         data a4,
         data a5);

void c_main(void) {
    data a1;
    a1.bar = 1;
    data a2;
    a2.bar = 2;
    data a3;
    a3.bar = 3;
    data a4;
    a4.bar = 4;
    data a5;
    a5.bar = 5;
    foo(a1, a2, a3, a4, a5);
}

Expected output:

1
2
3
4
5

Actual output:

1
2
3
4
2357776

I couldn't reproduce it with larger number of smaller arguments (eg. passing ten u64s), couldn't reproduce it on 32 bits either. Changing debug/optimization options has no effect.
Works correctly when calling C from C (eg. using this code).
It originally manifested on another 64 bit machine, but I don't have access to it at the moment, though I can get its enviroment too.

LLVM IR: here
Assembly: here
Gcc version: 4.9.2 x86_64-pc-msys (verbose output)
Rust version:

rustc 1.0.0-nightly (6790b0e51 2015-04-11) (built 2015-04-12)
binary: rustc
commit-hash: 6790b0e51967b1487728d155e0800a1ed03a30d3
commit-date: 2015-04-11
build-date: 2015-04-12
host: x86_64-pc-windows-gnu
release: 1.0.0-nightly

Compiled and ran with gcc main.c -c -o libcmain.a && rustc main.rs -l cmain -L. && main.exe

Activity

vadimcn

vadimcn commented on Apr 16, 2015

@vadimcn
Contributor

Looks like there a slight misunderstanding about the calling convention between GCC and LLVM.
GCC passes a pointer to a5, whereas LLVM expects a5 to be by-value. Changing the last line of foo() to this ↓ produces the expected result.

    unsafe {
        let x5: *const Data = std::mem::transmute(a5.bar);
        println!("{:}", (*x5).bar);
    }

The IR generated by rustc looks correct... unless I am missing some implication of the byval attribute.

define void @foo(%Data* byval, %Data* byval, %Data* byval, 
                 %Data* byval, %Data* byval) unnamed_addr {

Hmm... LLVM codegen bug?

retep998

retep998 commented on Apr 17, 2015

@retep998
Member

You forgot to specify the calling convention for your Rust function, so it is using the rust call convention which is different from the C calling convention.
Once you've set the calling convention from both sides to ensure they match up, if it still doesn't work, then you have an actual bug.

vosen

vosen commented on Apr 17, 2015

@vosen
ContributorAuthor

No, looking at the --pretty=expanded output, function convention correctly defaults to pub extern "win64" fn foo(...).
Also, I forgot to mention in the original post, but, I've tried every calling convention mentioned in the FFI part of the book.

retep998

retep998 commented on Apr 17, 2015

@retep998
Member

Okay, I tested this locally, made sure the calling conventions match up, and yet I can still reproduce this issue.

pravic

pravic commented on Apr 8, 2016

@pravic
Contributor

This also was fixed by #29012, btw.

alexcrichton

alexcrichton commented on Apr 8, 2016

@alexcrichton
Member

Yay!

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    O-windowsOperating system: Windows

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @alexcrichton@retep998@pravic@vosen@sfackler

        Issue actions

          Calls from C to Rust get miscompiled on Windows 64 · Issue #24427 · rust-lang/rust