Skip to content

Commit 5e6673d

Browse files
authored
Merge pull request google#1365 from google/reduce-opaque-type-ub
Avoid UB on opaque types.
2 parents fd4babd + 6b098d2 commit 5e6673d

File tree

1 file changed

+27
-1
lines changed

1 file changed

+27
-1
lines changed

engine/src/conversion/codegen_rs/non_pod_struct.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,25 @@ pub(crate) fn make_non_pod(s: &mut ItemStruct, layout: Option<Layout>) {
3838
// (if we have layout information from bindgen we use that instead)
3939
// (2) We want to ensure the type is !Unpin
4040
// (3) We want to ensure it's not Send or Sync
41+
// In addition, we want to avoid UB:
42+
// (4) By marking the data as MaybeUninit we ensure there's no UB
43+
// by Rust assuming it's initialized
44+
// (5) By marking it as UnsafeCell we perhaps help reduce aliasing UB.
45+
// This is on the assumption that references to this type may pass
46+
// through C++ and get duplicated, so there may be multiple Rust
47+
// references to the same underlying data.
48+
// The correct solution to this is to put autocxx into the mode
49+
// where it uses CppRef<T> instead of Rust references, but otherwise,
50+
// using UnsafeCell here may help a bit. It definitely does not
51+
// eliminate the UB here for the following reasons:
52+
// a) The references floating around are to the outer type, not the
53+
// data stored within the UnsafeCell.
54+
// b) C++ may have multiple mutable references, or may have mutable
55+
// references coexisting with immutable references, and no amount
56+
// of UnsafeCell can make that safe.
57+
// Nevertheless the use of UnsafeCell here may (*may*) reduce the
58+
// opportunities for aliasing UB. Again, the only actual way to
59+
// eliminate UB is to use CppRef<T> everywhere instead of &T and &mut T.
4160
//
4261
// For opaque types, the Rusty opaque structure could in fact be generated
4362
// by three different things:
@@ -51,6 +70,13 @@ pub(crate) fn make_non_pod(s: &mut ItemStruct, layout: Option<Layout>) {
5170
// much more difficult.
5271
// We use (c) for abstract types. For everything else, we do it ourselves
5372
// for maximal control. See codegen_rs/mod.rs generate_type for more notes.
73+
//
74+
// It is worth noting that our constraints here are a bit more severe than
75+
// for cxx. In the case of cxx, C++ types are usually represented as
76+
// zero-sized types within Rust. Zero-sized types, by definition, can't
77+
// have overlapping references and thus can't have aliasing UB. We can't
78+
// do that because we want C++ types to be representable on the Rust stack,
79+
// and thus we need to tell Rust their real size and alignment.
5480
// First work out attributes.
5581
let doc_attr = s
5682
.attrs
@@ -98,7 +124,7 @@ pub(crate) fn make_non_pod(s: &mut ItemStruct, layout: Option<Layout>) {
98124
Some(
99125
syn::Field::parse_named
100126
.parse2(quote! {
101-
_data: [u8; #size]
127+
_data: ::core::cell::UnsafeCell<::core::mem::MaybeUninit<[u8; #size]>>
102128
})
103129
.unwrap(),
104130
)

0 commit comments

Comments
 (0)