From fa9b5e3c3fa4f81ec2b945d8b8645f538020c934 Mon Sep 17 00:00:00 2001 From: Zhiting Zhu Date: Mon, 23 Oct 2017 22:39:11 -0500 Subject: [PATCH] Fix mistakenly derive hash for struct that contains IncompleteArrayField --- src/ir/analysis/derive_hash.rs | 5 +- tests/expectations/tests/class.rs | 90 ++++++++++++- tests/expectations/tests/class_1_0.rs | 86 +++++++++++++ ...erive-hash-struct-with-incomplete-array.rs | 121 ++++++++++++++++++ tests/headers/class.hpp | 18 ++- tests/headers/class_1_0.hpp | 18 +++ ...derive-hash-struct-with-incomplete-array.h | 17 +++ 7 files changed, 351 insertions(+), 4 deletions(-) create mode 100644 tests/expectations/tests/derive-hash-struct-with-incomplete-array.rs create mode 100644 tests/headers/derive-hash-struct-with-incomplete-array.h diff --git a/src/ir/analysis/derive_hash.rs b/src/ir/analysis/derive_hash.rs index 569c724612..d2eac677d2 100644 --- a/src/ir/analysis/derive_hash.rs +++ b/src/ir/analysis/derive_hash.rs @@ -187,7 +187,10 @@ impl<'ctx> MonotoneFramework for CannotDeriveHash<'ctx> { return self.insert(id); } - if len <= RUST_DERIVE_IN_ARRAY_LIMIT { + if len == 0 { + trace!(" cannot derive `Hash` for incomplete arrays"); + self.insert(id) + } else if len <= RUST_DERIVE_IN_ARRAY_LIMIT { trace!(" array is small enough to derive Hash"); ConstrainResult::Same } else { diff --git a/tests/expectations/tests/class.rs b/tests/expectations/tests/class.rs index 351f041a2b..eb09d75303 100644 --- a/tests/expectations/tests/class.rs +++ b/tests/expectations/tests/class.rs @@ -142,6 +142,47 @@ impl Default for C_with_zero_length_array { } } #[repr(C)] +#[derive(Debug, Default)] +pub struct C_with_zero_length_array_2 { + pub a: ::std::os::raw::c_int, + pub zero_length_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_C_with_zero_length_array_2() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(C_with_zero_length_array_2)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(C_with_zero_length_array_2)) + ); + assert_eq!( + unsafe { &(*(0 as *const C_with_zero_length_array_2)).a as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(C_with_zero_length_array_2), + "::", + stringify!(a) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const C_with_zero_length_array_2)).zero_length_array as *const _ as usize + }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(C_with_zero_length_array_2), + "::", + stringify!(zero_length_array) + ) + ); +} +#[repr(C)] pub struct C_with_incomplete_array { pub a: ::std::os::raw::c_int, pub big_array: [::std::os::raw::c_char; 33usize], @@ -166,6 +207,25 @@ impl Default for C_with_incomplete_array { } } #[repr(C)] +#[derive(Debug, Default)] +pub struct C_with_incomplete_array_2 { + pub a: ::std::os::raw::c_int, + pub incomplete_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_C_with_incomplete_array_2() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(C_with_incomplete_array_2)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(C_with_incomplete_array_2)) + ); +} +#[repr(C)] pub struct C_with_zero_length_array_and_incomplete_array { pub a: ::std::os::raw::c_int, pub big_array: [::std::os::raw::c_char; 33usize], @@ -197,7 +257,33 @@ impl Default for C_with_zero_length_array_and_incomplete_array { } } #[repr(C)] -#[derive(Debug, Default, Hash, PartialEq, Eq)] +#[derive(Debug, Default)] +pub struct C_with_zero_length_array_and_incomplete_array_2 { + pub a: ::std::os::raw::c_int, + pub zero_length_array: __IncompleteArrayField<::std::os::raw::c_char>, + pub incomplete_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_C_with_zero_length_array_and_incomplete_array_2() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!( + "Size of: ", + stringify!(C_with_zero_length_array_and_incomplete_array_2) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!( + "Alignment of ", + stringify!(C_with_zero_length_array_and_incomplete_array_2) + ) + ); +} +#[repr(C)] +#[derive(Debug, Default, Hash, PartialOrd, Ord, PartialEq, Eq)] pub struct WithDtor { pub b: ::std::os::raw::c_int, } @@ -336,7 +422,7 @@ impl Default for WithUnion { } } #[repr(C)] -#[derive(Debug, Default, Copy, Hash, PartialEq, Eq)] +#[derive(Debug, Default, Copy, Hash, PartialOrd, Ord, PartialEq, Eq)] pub struct RealAbstractionWithTonsOfMethods { pub _address: u8, } diff --git a/tests/expectations/tests/class_1_0.rs b/tests/expectations/tests/class_1_0.rs index 1127c88b65..c54edcdbf4 100644 --- a/tests/expectations/tests/class_1_0.rs +++ b/tests/expectations/tests/class_1_0.rs @@ -190,6 +190,47 @@ impl Default for C_with_zero_length_array { } } #[repr(C)] +#[derive(Debug, Default)] +pub struct C_with_zero_length_array_2 { + pub a: ::std::os::raw::c_int, + pub zero_length_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_C_with_zero_length_array_2() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(C_with_zero_length_array_2)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(C_with_zero_length_array_2)) + ); + assert_eq!( + unsafe { &(*(0 as *const C_with_zero_length_array_2)).a as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(C_with_zero_length_array_2), + "::", + stringify!(a) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const C_with_zero_length_array_2)).zero_length_array as *const _ as usize + }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(C_with_zero_length_array_2), + "::", + stringify!(zero_length_array) + ) + ); +} +#[repr(C)] pub struct C_with_incomplete_array { pub a: ::std::os::raw::c_int, pub big_array: [::std::os::raw::c_char; 33usize], @@ -214,6 +255,25 @@ impl Default for C_with_incomplete_array { } } #[repr(C)] +#[derive(Debug, Default)] +pub struct C_with_incomplete_array_2 { + pub a: ::std::os::raw::c_int, + pub incomplete_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_C_with_incomplete_array_2() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(C_with_incomplete_array_2)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(C_with_incomplete_array_2)) + ); +} +#[repr(C)] pub struct C_with_zero_length_array_and_incomplete_array { pub a: ::std::os::raw::c_int, pub big_array: [::std::os::raw::c_char; 33usize], @@ -245,6 +305,32 @@ impl Default for C_with_zero_length_array_and_incomplete_array { } } #[repr(C)] +#[derive(Debug, Default)] +pub struct C_with_zero_length_array_and_incomplete_array_2 { + pub a: ::std::os::raw::c_int, + pub zero_length_array: __IncompleteArrayField<::std::os::raw::c_char>, + pub incomplete_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_C_with_zero_length_array_and_incomplete_array_2() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!( + "Size of: ", + stringify!(C_with_zero_length_array_and_incomplete_array_2) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!( + "Alignment of ", + stringify!(C_with_zero_length_array_and_incomplete_array_2) + ) + ); +} +#[repr(C)] #[derive(Debug, Default, Hash, PartialEq, Eq)] pub struct WithDtor { pub b: ::std::os::raw::c_int, diff --git a/tests/expectations/tests/derive-hash-struct-with-incomplete-array.rs b/tests/expectations/tests/derive-hash-struct-with-incomplete-array.rs new file mode 100644 index 0000000000..a2179f417d --- /dev/null +++ b/tests/expectations/tests/derive-hash-struct-with-incomplete-array.rs @@ -0,0 +1,121 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + + +#[repr(C)] +#[derive(Default)] +pub struct __IncompleteArrayField(::std::marker::PhantomData); +impl __IncompleteArrayField { + #[inline] + pub fn new() -> Self { + __IncompleteArrayField(::std::marker::PhantomData) + } + #[inline] + pub unsafe fn as_ptr(&self) -> *const T { + ::std::mem::transmute(self) + } + #[inline] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + ::std::mem::transmute(self) + } + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + ::std::slice::from_raw_parts(self.as_ptr(), len) + } + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } +} +impl ::std::fmt::Debug for __IncompleteArrayField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fmt.write_str("__IncompleteArrayField") + } +} +impl ::std::clone::Clone for __IncompleteArrayField { + #[inline] + fn clone(&self) -> Self { + Self::new() + } +} +impl ::std::marker::Copy for __IncompleteArrayField {} +#[repr(C)] +#[derive(Debug, Default)] +pub struct test { + pub a: ::std::os::raw::c_int, + pub zero_length_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_test() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(test)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(test)) + ); + assert_eq!( + unsafe { &(*(0 as *const test)).a as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(test), + "::", + stringify!(a) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const test)).zero_length_array as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(test), + "::", + stringify!(zero_length_array) + ) + ); +} +#[repr(C)] +#[derive(Debug, Default)] +pub struct test2 { + pub a: ::std::os::raw::c_int, + pub incomplete_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_test2() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(test2)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(test2)) + ); +} +#[repr(C)] +#[derive(Debug, Default)] +pub struct test3 { + pub a: ::std::os::raw::c_int, + pub zero_length_array: __IncompleteArrayField<::std::os::raw::c_char>, + pub incomplete_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_test3() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(test3)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(test3)) + ); +} diff --git a/tests/headers/class.hpp b/tests/headers/class.hpp index ac2da1a469..f77ac92a66 100644 --- a/tests/headers/class.hpp +++ b/tests/headers/class.hpp @@ -1,4 +1,4 @@ -// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq +// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --with-derive-partialord --with-derive-ord // class C { int a; @@ -13,6 +13,11 @@ class C_with_zero_length_array { char zero_length_array[0]; }; +class C_with_zero_length_array_2 { + int a; + char zero_length_array[0]; +}; + class C_with_incomplete_array { int a; // More than rust limits (32) @@ -20,6 +25,11 @@ class C_with_incomplete_array { char incomplete_array[]; }; +class C_with_incomplete_array_2 { + int a; + char incomplete_array[]; +}; + class C_with_zero_length_array_and_incomplete_array { int a; // More than rust limits (32) @@ -28,6 +38,12 @@ class C_with_zero_length_array_and_incomplete_array { char incomplete_array[]; }; +class C_with_zero_length_array_and_incomplete_array_2 { + int a; + char zero_length_array[0]; + char incomplete_array[]; +}; + class WithDtor { int b; diff --git a/tests/headers/class_1_0.hpp b/tests/headers/class_1_0.hpp index 6fa01e95f9..e3735eb68d 100644 --- a/tests/headers/class_1_0.hpp +++ b/tests/headers/class_1_0.hpp @@ -13,6 +13,11 @@ class C_with_zero_length_array { char zero_length_array[0]; }; +class C_with_zero_length_array_2 { + int a; + char zero_length_array[0]; +}; + class C_with_incomplete_array { int a; // More than rust limits (32) @@ -20,6 +25,12 @@ class C_with_incomplete_array { char incomplete_array[]; }; +class C_with_incomplete_array_2 { + int a; + char incomplete_array[]; +}; + + class C_with_zero_length_array_and_incomplete_array { int a; // More than rust limits (32) @@ -28,6 +39,13 @@ class C_with_zero_length_array_and_incomplete_array { char incomplete_array[]; }; +class C_with_zero_length_array_and_incomplete_array_2 { + int a; + char zero_length_array[0]; + char incomplete_array[]; +}; + + class WithDtor { int b; diff --git a/tests/headers/derive-hash-struct-with-incomplete-array.h b/tests/headers/derive-hash-struct-with-incomplete-array.h new file mode 100644 index 0000000000..65c009db0c --- /dev/null +++ b/tests/headers/derive-hash-struct-with-incomplete-array.h @@ -0,0 +1,17 @@ +// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --with-derive-partialord --with-derive-ord +// +struct test { + int a; + char zero_length_array[0]; +}; + +struct test2 { + int a; + char incomplete_array[]; +}; + +struct test3 { + int a; + char zero_length_array[0]; + char incomplete_array[]; +};