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

derive(Debug) on struct containing array that is too big for derive(Debug) #372

Closed
fitzgen opened this issue Dec 29, 2016 · 17 comments
Closed
Assignees

Comments

@fitzgen
Copy link
Member

fitzgen commented Dec 29, 2016

$ ./target/debug/bindgen --enable-cxx-namespaces test.hpp > test.rs 

Here is test.hpp (really really nasty):

template <typename a, int b> class c { a e[b]; };
class d;
template <typename g, g f> class C { c<d, f> h; };
class i {
  i *j;
  i *k;
  bool l;
};
class d {
  i m;
};
enum n { o, p, q, r, s, t, b, ae, e, ag, ah, ai };
class F {
  C<n, ai> w;
};

Here is the generated test.rs bindings:

/* automatically generated by rust-bindgen */

pub mod root {
    #[allow(unused_imports)]
    use self::super::root;
    #[repr(C)]
    #[derive(Debug, Copy)]
    pub struct d {
        pub m: root::i,
    }
    #[test]
    fn bindgen_test_layout_d() {
        assert_eq!(::std::mem::size_of::<d>() , 24usize);
        assert_eq!(::std::mem::align_of::<d>() , 8usize);
    }
    impl Clone for d {
        fn clone(&self) -> Self { *self }
    }
    #[repr(C)]
    #[derive(Debug, Copy)]
    pub struct i {
        pub j: *mut root::i,
        pub k: *mut root::i,
        pub l: bool,
    }
    #[test]
    fn bindgen_test_layout_i() {
        assert_eq!(::std::mem::size_of::<i>() , 24usize);
        assert_eq!(::std::mem::align_of::<i>() , 8usize);
    }
    impl Clone for i {
        fn clone(&self) -> Self { *self }
    }
    #[repr(u32)]
    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
    pub enum n {
        o = 0,
        p = 1,
        q = 2,
        r = 3,
        s = 4,
        t = 5,
        b = 6,
        ae = 7,
        e = 8,
        ag = 9,
        ah = 10,
        ai = 11,
    }
    #[repr(C)]
    #[derive(Debug, Copy)]
    pub struct F {
        pub w: [u64; 33usize],
    }
    #[test]
    fn bindgen_test_layout_F() {
        assert_eq!(::std::mem::size_of::<F>() , 264usize);
        assert_eq!(::std::mem::align_of::<F>() , 8usize);
    }
    impl Clone for F {
        fn clone(&self) -> Self { *self }
    }
}

And when we try to compile the bindings, we get this error:

$ rustc --crate-type lib test.rs 
error[E0277]: the trait bound `[u64; 33]: std::fmt::Debug` is not satisfied
  --> js.rs:53:9
   |
53 |         pub w: [u64; 33usize],
   |         ^^^^^^^^^^^^^^^^^^^^^ the trait `std::fmt::Debug` is not implemented for `[u64; 33]`
   |
   = note: `[u64; 33]` cannot be formatted using `:?`; if it is defined in your crate, add `#[derive(Debug)]` or manually implement it
   = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[u64; 33]`
   = note: required for the cast to the object type `std::fmt::Debug`

error: aborting due to previous error
@emilio
Copy link
Contributor

emilio commented Dec 29, 2016

This is a nasty consequence of us trying to do the best we can to guarantee correct layout.

When we find a type with non-type template parameters, we generate a blob of memory. Of course, we don't check that with can_derive_debug.

We should. We can go safe and just return false if the type had any non-type template parameters, or we can factor out the logic from BlobTyBuilder, and check the layout of the type to see if it'd generate a valid array.

We should probably do the same for can_derive_copy.

@emilio
Copy link
Contributor

emilio commented Dec 29, 2016

@fitzgen do yo want to tackle or mentor this bug?

@fitzgen
Copy link
Member Author

fitzgen commented Dec 29, 2016

I can take it.

@fitzgen fitzgen self-assigned this Dec 29, 2016
@emilio emilio added the bug label Dec 29, 2016
@64
Copy link

64 commented Jun 28, 2017

I'm still getting this error while trying to run bindgen on uv.h:

error[E0277]: the trait bound `[u8; 40]: std::fmt::Debug` is not satisfied
     --> c:\code\rust\libuv-test\target\debug\build\libuv-test-9b56431e6ab39041\out/bindings.rs:75085:5
      |
75085 |     pub __bindgen_padding_0: [u8; 40usize],
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::fmt::Debug` is not implemented for `[u8; 40]`
      |
      = note: `[u8; 40]` cannot be formatted using `:?`; if it is defined in your crate, add `#[derive(Debug)]` or manually implement it
      = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[u8; 40]`
      = note: required for the cast to the object type `std::fmt::Debug`

error: aborting due to previous error

I'm using bindgen version 0.26.2 on windows. Any ideas?

@emilio
Copy link
Contributor

emilio commented Jul 4, 2017

That's a different issue, and it deserves another bug, I think. That's when generating padding for a struct, which is a different case.

I can file as soon as I arrive home.

@tomwhoiscontrary
Copy link

I'm getting some relative of this. I am translating some reasonably big C++ class, and i tried making it opaque to make my life easier:

#[repr(C)]
#[derive(Debug)]
pub struct OsiClpSolverInterface {
    pub _bindgen_opaque_blob: [u64; 112usize],
}

But this fails to compile:

error[E0277]: the trait bound `[u64; 112]: std::fmt::Debug` is not satisfied
    --> /home/tomwhoiscontrary/src/github/initech/clp-sys/target/debug/build/clp-sys-515894cd11841cff/out/bindings.rs:2993:5
     |
2993 |     pub _bindgen_opaque_blob: [u64; 112usize],
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::fmt::Debug` is not implemented for `[u64; 112]`
     |

If i make the type non-opaque, it comes out like this:

#[repr(C)]
#[derive(Debug)]
pub struct OsiClpSolverInterface {
    pub vtable_: *const OsiClpSolverInterface__bindgen_vtable,
    // skip numerous fields
    pub __bindgen_padding_0: [u64; 37usize],

Which also fails:

error[E0277]: the trait bound `[u64; 37]: std::fmt::Debug` is not satisfied
    --> /home/tomwhoiscontrary/src/github/initech/clp-sys/target/debug/build/clp-sys-515894cd11841cff/out/bindings.rs:3122:5
     |
3122 |     pub __bindgen_padding_0: [u64; 37usize],
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::fmt::Debug` is not implemented for `[u64; 37]`
     |

The latter case looks similar to @64's bug. I wonder if this is related to #648?

I can work around this by setting .derive_debug(false). I don't think the debugging printout on these objects is going to be very helpful anyway!

As an aside, should there really be 37 64-bit words of padding? I don't know much about C++ object layout at all, but that surprised me.

@fitzgen
Copy link
Member Author

fitzgen commented Aug 28, 2017

@tomwhoiscontrary would you mind filing a new issue and including a test case so we can reproduce the issue locally? Thanks!

@tomwhoiscontrary
Copy link

I'll see what i can do about a test case. The code i'm binding is pretty huge, so i'll need to extract a subset which exhibits the problem.

@fitzgen
Copy link
Member Author

fitzgen commented Aug 29, 2017

The code i'm binding is pretty huge, so i'll need to extract a subset which exhibits the problem.

This is where C-Reduce and bindgen::Builder::dump_preprocessed_input come in really handy ;)

https://github.com/rust-lang-nursery/rust-bindgen/blob/master/CONTRIBUTING.md#using-creduce-to-minimize-test-cases

@mmacedoeu
Copy link

mmacedoeu commented Nov 7, 2019

That's a different issue, and it deserves another bug, I think. That's when generating padding for a struct, which is a different case.

I can file as soon as I arrive home.

@emilio
I got that bug today running on windows as well, did you manage to file the bug and maybe there is a fix already ?

@martinthomson
Copy link

FYI, this is what I'm getting after upgrading to 1.39:

error[E0277]: arrays only have std trait implementations for lengths 0..=32
    --> $FILE:1155:5
     |
1155 |     pub test: [::std::os::raw::c_char; 104usize],
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i8; 104]`
     |
     = note: required because of the requirements on the impl of `std::fmt::Debug` for `[i8; 104]`
     = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[i8; 104]`
     = note: required for the cast to the object type `dyn std::fmt::Debug`

@emilio
Copy link
Contributor

emilio commented Nov 12, 2019

@martinthomson / @mmacedoeu do you have a test-case for that?

@mmacedoeu
Copy link

@martinthomson / @mmacedoeu do you have a test-case for that?

Not really a short test-case, It is a closed source code, but It seams any attempt to generate bindgen where a window.h header is present lead to this. I will have some time soon to try and isolate the problem. Is there any tool that could help automate the test-case ?

@emilio
Copy link
Contributor

emilio commented Nov 12, 2019

Yeah, you can use creduce as explained here to minimize test-cases.

@martinthomson
Copy link

The test case is from neqo, but shove this in a header:

struct Test {
  char test[104];
};

@emilio
Copy link
Contributor

emilio commented Nov 12, 2019

I cannot reproduce that, is there any chance you're using a combination of:

  • An old version of bindgen (<0.51.1), and...
  • A new version (1.39+) of rustc?

If so, that's #1627 / rust-lang/rust#64710.

@martinthomson
Copy link

Yeah, that's it. Thanks. It was 0.51.0. I'll get the latest.

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

6 participants