1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ;
use crate;
use find_output_mod_root;
use quote;
/// Make an opaque wrapper around a bindgen type.
// Constraints here (thanks to dtolnay@ for this explanation of why the
// following is needed:)
// (1) If the real alignment of the C++ type is smaller and a reference
// is returned from C++ to Rust, mere existence of an insufficiently
// aligned reference in Rust causes UB even if never dereferenced
// by Rust code
// (see https://doc.rust-lang.org/1.47.0/reference/behavior-considered-undefined.html).
// Rustc can use least-significant bits of the reference for other storage.
// (if we have layout information from bindgen we use that instead)
// (2) We want to ensure the type is !Unpin
// (3) We want to ensure it's not Send or Sync
// In addition, we want to avoid UB:
// (4) By marking the data as MaybeUninit we ensure there's no UB
// by Rust assuming it's initialized
// (5) By marking it as UnsafeCell we perhaps help reduce aliasing UB.
// This is on the assumption that references to this type may pass
// through C++ and get duplicated, so there may be multiple Rust
// references to the same underlying data.
// The correct solution to this is to put autocxx into the mode
// where it uses CppRef<T> instead of Rust references, but otherwise,
// using UnsafeCell here may help a bit. It probably does not
// eliminate the UB here for the following reasons:
// a) The references floating around are to the outer type, not the
// data stored within the UnsafeCell. (I think this is OK)
// b) C++ may have multiple mutable references, or may have mutable
// references coexisting with immutable references, and no amount
// of UnsafeCell can make that safe.
// Nevertheless the use of UnsafeCell here may (*may*) reduce the
// opportunities for aliasing UB. Again, the only actual way to
// eliminate UB is to use CppRef<T> everywhere instead of &T and &mut T.
//
// For opaque types, the Rusty opaque structure could in fact be generated
// by four different things:
// a) bindgen, using its --opaque-type command line argument or the library
// equivalent;
// b) us (autocxx), by making a [u8; N] byte long structure
// c) us (autocxx), by making a struct containing the bindgen struct
// in an inaccessible field (that's what we do here)
// d) cxx, using "type B;" in an "extern "C++"" section
// We never use (a) because bindgen requires an allowlist of opaque types.
// Furthermore, it sometimes then discards struct definitions entirely
// and says "type A = [u8;2];" or something else which makes our life
// much more difficult.
// We use (d) for abstract types. For everything else, we do (c)
// for maximal control. See codegen_rs/mod.rs generate_type for more notes.
// We could switch to (b) and earlier version of autocxx did that.
//
// It is worth noting that our constraints here are a bit more severe than
// for cxx. In the case of cxx, C++ types are usually represented as
// zero-sized types within Rust. Zero-sized types, by definition, can't
// have overlapping references and thus can't have aliasing UB. We can't
// do that because we want C++ types to be representable on the Rust stack,
// and thus we need to tell Rust their real size and alignment.
pub