Skip to content

Fix an UB in layout tests #2055

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

Closed

Conversation

Apostoln
Copy link

  • Replaced dereferencing of null ptr with
    zero bit pattern + transmute + std::ptr::addr_of!
    to avoid UB. It affects only checks of fields offsets
  • Overwritten expected with BINDGEN_OVERWRITE_EXPECTED=1
  • Overwritten test_multiple_header_calls_in_builder and test_mixed_header_and_header_contents
    manually because Some expected are not overwritten with BINDGEN_OVERWRITE_EXPECTED=1  #2054
  • Do not check the layout for repr(C) unions
  • Do not call the destructor of tmp struct to avoid other UB

Close #1651

Note: This way is not ideal (see the latest comments in related issue). Zero bit pattern can be replaces with manual initialization of the fields, but I have no time to investigate how to do it when

  1. The item is a struct contains other structs.
  2. The item is a union.

However, I think this way is good enough, because there no UB anymore. The only one unsafe block with transmute will not cause an UB, because all C types allows zero bit pattern. Anyway, it's better than current implementation with UB and warnings.

Any feedback or commits are appreciated. Thanks.

 - Replaced dereferencing of null ptr with
   zero bit pattern + transmute + std::ptr::addr_of!
   to avoid UB. It affects only checks of fields offsets
 - Overwritten expected with BINDGEN_OVERWRITE_EXPECTED=1
 - Overwritten test_multiple_header_calls_in_builder and test_mixed_header_and_header_contents
   manually because rust-lang#2054
 - Do not check the layout for repr(C) unions
 - Do not call the destructor of tmp struct to avoid other UB
@highfive
Copy link

warning Warning warning

  • These commits modify unsafe code. Please review it carefully!

@Apostoln
Copy link
Author

r? @emilio

@Apostoln
Copy link
Author

r? @fitzgen

@highfive highfive assigned fitzgen and unassigned emilio May 16, 2021
Copy link
Contributor

@emilio emilio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still not guaranteed to be ub-free, think of a rust enum field like:

enum Foo { Bar = 1, Baz, }

Using a zeroed buffer for that seems like itd still be UB.

But anyhow this is better than what we're doing so it seems ok to me with the suggestion below.

{
// Create an instance of #canonical_ident struct from zero bit pattern
const STRUCT_SIZE: usize = std::mem::size_of::<#canonical_ident>();
let buffer = [0u8; STRUCT_SIZE];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not guaranteed to be aligned right? I think using std::mem::zeroed should be better.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed

Though, I don't catch why there is a wrong alignment. AFAIU, In case of mem::zeroed the padding bytes are not zeroed but the total behavior is the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, let's say you have a struct with an u32 member. The compiler would make sure that that is aligned appropriately, but if you use a flat array of u8s then it's not.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emilio
Ok, thank you. Replaced it with mem::zeroed

@Apostoln Apostoln requested a review from emilio May 17, 2021 11:39
@emilio
Copy link
Contributor

emilio commented May 18, 2021

It seems there are still some tests to update, but I'll try to get to this myself if you can't.

@Apostoln
Copy link
Author

Yeah, I've missed errors on CI, locally it was OK. I'm going to fix it but a bit later.

Comment on lines +2114 to +2119
let struct_instance = unsafe {
std::mem::zeroed::<#canonical_ident>()
};

// Get the pointers to the struct and its field
let struct_ptr = &struct_instance as *const #canonical_ident;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This potential UB can be avoided:

Suggested change
let struct_instance = unsafe {
std::mem::zeroed::<#canonical_ident>()
};
// Get the pointers to the struct and its field
let struct_ptr = &struct_instance as *const #canonical_ident;
let struct_instance = core::mem::MaybeUninit::<#canonical_ident>::uninit();
// Get the pointers to the struct and its field
let struct_ptr = struct_instance.as_ptr();

@bors-servo
Copy link

☔ The latest upstream changes (presumably 310f7f8) made this pull request unmergeable. Please resolve the merge conflicts.

@kulp
Copy link
Member

kulp commented May 18, 2022

This might be obsoleted since #2203 was completed.

@kulp
Copy link
Member

kulp commented Jun 1, 2022

  • Do not check the layout for repr(C) unions
  • Do not call the destructor of tmp struct to avoid other UB

It appears that this (like #2064) has a little more in it than #2203 did, but since #1651 is now closed, I am inferring that this PR is no longer needed, so I am closing it.

If I missed something, let me know.

@kulp kulp closed this Jun 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Generated tests use UB in their calculations
7 participants