1*8975f5c5SAndroid Build Coastguard Worker // Copyright 2021 The Chromium Authors
2*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
4*8975f5c5SAndroid Build Coastguard Worker
5*8975f5c5SAndroid Build Coastguard Worker #include <cstddef>
6*8975f5c5SAndroid Build Coastguard Worker #include <cstring>
7*8975f5c5SAndroid Build Coastguard Worker
8*8975f5c5SAndroid Build Coastguard Worker #include "build/build_config.h"
9*8975f5c5SAndroid Build Coastguard Worker #include "build/rust/std/alias.h"
10*8975f5c5SAndroid Build Coastguard Worker #include "build/rust/std/buildflags.h"
11*8975f5c5SAndroid Build Coastguard Worker #include "build/rust/std/immediate_crash.h"
12*8975f5c5SAndroid Build Coastguard Worker
13*8975f5c5SAndroid Build Coastguard Worker #if BUILDFLAG(RUST_ALLOCATOR_USES_PARTITION_ALLOC)
14*8975f5c5SAndroid Build Coastguard Worker #include "partition_alloc/partition_alloc_constants.h" // nogncheck
15*8975f5c5SAndroid Build Coastguard Worker #include "partition_alloc/shim/allocator_shim.h" // nogncheck
16*8975f5c5SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_WIN)
17*8975f5c5SAndroid Build Coastguard Worker #include <cstdlib>
18*8975f5c5SAndroid Build Coastguard Worker #endif
19*8975f5c5SAndroid Build Coastguard Worker
20*8975f5c5SAndroid Build Coastguard Worker // When linking a final binary, rustc has to pick between either:
21*8975f5c5SAndroid Build Coastguard Worker // * The default Rust allocator
22*8975f5c5SAndroid Build Coastguard Worker // * Any #[global_allocator] defined in *any rlib in its dependency tree*
23*8975f5c5SAndroid Build Coastguard Worker // (https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/global-allocators.html)
24*8975f5c5SAndroid Build Coastguard Worker //
25*8975f5c5SAndroid Build Coastguard Worker // In this latter case, this fact will be recorded in some of the metadata
26*8975f5c5SAndroid Build Coastguard Worker // within the .rlib file. (An .rlib file is just a .a file, but does have
27*8975f5c5SAndroid Build Coastguard Worker // additional metadata for use by rustc. This is, as far as I know, the only
28*8975f5c5SAndroid Build Coastguard Worker // such metadata we would ideally care about.)
29*8975f5c5SAndroid Build Coastguard Worker //
30*8975f5c5SAndroid Build Coastguard Worker // In all the linked rlibs,
31*8975f5c5SAndroid Build Coastguard Worker // * If 0 crates define a #[global_allocator], rustc uses its default allocator
32*8975f5c5SAndroid Build Coastguard Worker // * If 1 crate defines a #[global_allocator], rustc uses that
33*8975f5c5SAndroid Build Coastguard Worker // * If >1 crates define a #[global_allocator], rustc bombs out.
34*8975f5c5SAndroid Build Coastguard Worker //
35*8975f5c5SAndroid Build Coastguard Worker // Because rustc does these checks, it doesn't just have the __rust_alloc
36*8975f5c5SAndroid Build Coastguard Worker // symbols defined anywhere (neither in the stdlib nor in any of these
37*8975f5c5SAndroid Build Coastguard Worker // crates which have a #[global_allocator] defined.)
38*8975f5c5SAndroid Build Coastguard Worker //
39*8975f5c5SAndroid Build Coastguard Worker // Instead:
40*8975f5c5SAndroid Build Coastguard Worker // Rust's final linking stage invokes dynamic LLVM codegen to create symbols
41*8975f5c5SAndroid Build Coastguard Worker // for the basic heap allocation operations. It literally creates a
42*8975f5c5SAndroid Build Coastguard Worker // __rust_alloc symbol at link time. Unless any crate has specified a
43*8975f5c5SAndroid Build Coastguard Worker // #[global_allocator], it simply calls from __rust_alloc into
44*8975f5c5SAndroid Build Coastguard Worker // __rdl_alloc, which is the default Rust allocator. The same applies to a
45*8975f5c5SAndroid Build Coastguard Worker // few other symbols.
46*8975f5c5SAndroid Build Coastguard Worker //
47*8975f5c5SAndroid Build Coastguard Worker // We're not (always) using rustc for final linking. For cases where we're not
48*8975f5c5SAndroid Build Coastguard Worker // Rustc as the final linker, we'll define those symbols here instead. This
49*8975f5c5SAndroid Build Coastguard Worker // allows us to redirect allocation to PartitionAlloc if clang is doing the
50*8975f5c5SAndroid Build Coastguard Worker // link.
51*8975f5c5SAndroid Build Coastguard Worker //
52*8975f5c5SAndroid Build Coastguard Worker // We use unchecked allocation paths in PartitionAlloc rather than going through
53*8975f5c5SAndroid Build Coastguard Worker // its shims in `malloc()` etc so that we can support fallible allocation paths
54*8975f5c5SAndroid Build Coastguard Worker // such as Vec::try_reserve without crashing on allocation failure.
55*8975f5c5SAndroid Build Coastguard Worker //
56*8975f5c5SAndroid Build Coastguard Worker // In future, we should build a crate with a #[global_allocator] and
57*8975f5c5SAndroid Build Coastguard Worker // redirect these symbols back to Rust in order to use to that crate instead.
58*8975f5c5SAndroid Build Coastguard Worker // This would allow Rust-linked executables to:
59*8975f5c5SAndroid Build Coastguard Worker // 1. Use PartitionAlloc on Windows. The stdlib uses Windows heap functions
60*8975f5c5SAndroid Build Coastguard Worker // directly that PartitionAlloc can not intercept.
61*8975f5c5SAndroid Build Coastguard Worker // 2. Have `Vec::try_reserve` to fail at runtime on Linux instead of crashing in
62*8975f5c5SAndroid Build Coastguard Worker // malloc() where PartitionAlloc replaces that function.
63*8975f5c5SAndroid Build Coastguard Worker //
64*8975f5c5SAndroid Build Coastguard Worker // They're weak symbols, because this file will sometimes end up in targets
65*8975f5c5SAndroid Build Coastguard Worker // which are linked by rustc, and thus we would otherwise get duplicate
66*8975f5c5SAndroid Build Coastguard Worker // definitions. The following definitions will therefore only end up being
67*8975f5c5SAndroid Build Coastguard Worker // used in targets which are linked by our C++ toolchain.
68*8975f5c5SAndroid Build Coastguard Worker //
69*8975f5c5SAndroid Build Coastguard Worker // # On Windows ASAN
70*8975f5c5SAndroid Build Coastguard Worker //
71*8975f5c5SAndroid Build Coastguard Worker // In ASAN builds, PartitionAlloc-Everywhere is disabled, meaning malloc() and
72*8975f5c5SAndroid Build Coastguard Worker // friends in C++ do not go to PartitionAlloc. So we also don't point the Rust
73*8975f5c5SAndroid Build Coastguard Worker // allocation functions at PartitionAlloc. Generally, this means we just direct
74*8975f5c5SAndroid Build Coastguard Worker // them to the Standard Library's allocator.
75*8975f5c5SAndroid Build Coastguard Worker //
76*8975f5c5SAndroid Build Coastguard Worker // However, on Windows the Standard Library uses HeapAlloc() and Windows ASAN
77*8975f5c5SAndroid Build Coastguard Worker // does *not* hook that method, so ASAN does not get to hear about allocations
78*8975f5c5SAndroid Build Coastguard Worker // made in Rust. To resolve this, we redirect allocation to _aligned_malloc
79*8975f5c5SAndroid Build Coastguard Worker // which Windows ASAN *does* hook.
80*8975f5c5SAndroid Build Coastguard Worker //
81*8975f5c5SAndroid Build Coastguard Worker // Note that there is a runtime option to make ASAN hook HeapAlloc() but
82*8975f5c5SAndroid Build Coastguard Worker // enabling it breaks Win32 APIs like CreateProcess:
83*8975f5c5SAndroid Build Coastguard Worker // https://issues.chromium.org/u/1/issues/368070343#comment29
84*8975f5c5SAndroid Build Coastguard Worker
85*8975f5c5SAndroid Build Coastguard Worker extern "C" {
86*8975f5c5SAndroid Build Coastguard Worker
87*8975f5c5SAndroid Build Coastguard Worker #ifdef COMPONENT_BUILD
88*8975f5c5SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
89*8975f5c5SAndroid Build Coastguard Worker #define REMAP_ALLOC_ATTRIBUTES __declspec(dllexport) __attribute__((weak))
90*8975f5c5SAndroid Build Coastguard Worker #else
91*8975f5c5SAndroid Build Coastguard Worker #define REMAP_ALLOC_ATTRIBUTES \
92*8975f5c5SAndroid Build Coastguard Worker __attribute__((visibility("default"))) __attribute__((weak))
93*8975f5c5SAndroid Build Coastguard Worker #endif
94*8975f5c5SAndroid Build Coastguard Worker #else
95*8975f5c5SAndroid Build Coastguard Worker #define REMAP_ALLOC_ATTRIBUTES __attribute__((weak))
96*8975f5c5SAndroid Build Coastguard Worker #endif // COMPONENT_BUILD
97*8975f5c5SAndroid Build Coastguard Worker
98*8975f5c5SAndroid Build Coastguard Worker #if !BUILDFLAG(RUST_ALLOCATOR_USES_PARTITION_ALLOC) && BUILDFLAG(IS_WIN) && \
99*8975f5c5SAndroid Build Coastguard Worker defined(ADDRESS_SANITIZER)
100*8975f5c5SAndroid Build Coastguard Worker #define USE_WIN_ALIGNED_MALLOC 1
101*8975f5c5SAndroid Build Coastguard Worker #else
102*8975f5c5SAndroid Build Coastguard Worker #define USE_WIN_ALIGNED_MALLOC 0
103*8975f5c5SAndroid Build Coastguard Worker #endif
104*8975f5c5SAndroid Build Coastguard Worker
105*8975f5c5SAndroid Build Coastguard Worker // This must exist as the stdlib depends on it to prove that we know the
106*8975f5c5SAndroid Build Coastguard Worker // alloc shims below are unstable. In the future we may be required to replace
107*8975f5c5SAndroid Build Coastguard Worker // them with a #[global_allocator] crate (see file comment above for more).
108*8975f5c5SAndroid Build Coastguard Worker //
109*8975f5c5SAndroid Build Coastguard Worker // Marked as weak as when Rust drives linking it includes this symbol itself,
110*8975f5c5SAndroid Build Coastguard Worker // and we don't want a collision due to C++ being in the same link target, where
111*8975f5c5SAndroid Build Coastguard Worker // C++ causes us to explicitly link in the stdlib and this symbol here.
112*8975f5c5SAndroid Build Coastguard Worker [[maybe_unused]]
113*8975f5c5SAndroid Build Coastguard Worker __attribute__((weak)) unsigned char __rust_no_alloc_shim_is_unstable;
114*8975f5c5SAndroid Build Coastguard Worker
__rust_alloc(size_t size,size_t align)115*8975f5c5SAndroid Build Coastguard Worker REMAP_ALLOC_ATTRIBUTES void* __rust_alloc(size_t size, size_t align) {
116*8975f5c5SAndroid Build Coastguard Worker #if BUILDFLAG(RUST_ALLOCATOR_USES_PARTITION_ALLOC)
117*8975f5c5SAndroid Build Coastguard Worker // PartitionAlloc will crash if given an alignment larger than this.
118*8975f5c5SAndroid Build Coastguard Worker if (align > partition_alloc::internal::kMaxSupportedAlignment) {
119*8975f5c5SAndroid Build Coastguard Worker return nullptr;
120*8975f5c5SAndroid Build Coastguard Worker }
121*8975f5c5SAndroid Build Coastguard Worker
122*8975f5c5SAndroid Build Coastguard Worker if (align <= alignof(std::max_align_t)) {
123*8975f5c5SAndroid Build Coastguard Worker return allocator_shim::UncheckedAlloc(size);
124*8975f5c5SAndroid Build Coastguard Worker } else {
125*8975f5c5SAndroid Build Coastguard Worker return allocator_shim::UncheckedAlignedAlloc(size, align);
126*8975f5c5SAndroid Build Coastguard Worker }
127*8975f5c5SAndroid Build Coastguard Worker #elif USE_WIN_ALIGNED_MALLOC
128*8975f5c5SAndroid Build Coastguard Worker return _aligned_malloc(size, align);
129*8975f5c5SAndroid Build Coastguard Worker #else
130*8975f5c5SAndroid Build Coastguard Worker extern void* __rdl_alloc(size_t size, size_t align);
131*8975f5c5SAndroid Build Coastguard Worker return __rdl_alloc(size, align);
132*8975f5c5SAndroid Build Coastguard Worker #endif
133*8975f5c5SAndroid Build Coastguard Worker }
134*8975f5c5SAndroid Build Coastguard Worker
__rust_dealloc(void * p,size_t size,size_t align)135*8975f5c5SAndroid Build Coastguard Worker REMAP_ALLOC_ATTRIBUTES void __rust_dealloc(void* p, size_t size, size_t align) {
136*8975f5c5SAndroid Build Coastguard Worker #if BUILDFLAG(RUST_ALLOCATOR_USES_PARTITION_ALLOC)
137*8975f5c5SAndroid Build Coastguard Worker if (align <= alignof(std::max_align_t)) {
138*8975f5c5SAndroid Build Coastguard Worker allocator_shim::UncheckedFree(p);
139*8975f5c5SAndroid Build Coastguard Worker } else {
140*8975f5c5SAndroid Build Coastguard Worker allocator_shim::UncheckedAlignedFree(p);
141*8975f5c5SAndroid Build Coastguard Worker }
142*8975f5c5SAndroid Build Coastguard Worker #elif USE_WIN_ALIGNED_MALLOC
143*8975f5c5SAndroid Build Coastguard Worker return _aligned_free(p);
144*8975f5c5SAndroid Build Coastguard Worker #else
145*8975f5c5SAndroid Build Coastguard Worker extern void __rdl_dealloc(void* p, size_t size, size_t align);
146*8975f5c5SAndroid Build Coastguard Worker __rdl_dealloc(p, size, align);
147*8975f5c5SAndroid Build Coastguard Worker #endif
148*8975f5c5SAndroid Build Coastguard Worker }
149*8975f5c5SAndroid Build Coastguard Worker
__rust_realloc(void * p,size_t old_size,size_t align,size_t new_size)150*8975f5c5SAndroid Build Coastguard Worker REMAP_ALLOC_ATTRIBUTES void* __rust_realloc(void* p,
151*8975f5c5SAndroid Build Coastguard Worker size_t old_size,
152*8975f5c5SAndroid Build Coastguard Worker size_t align,
153*8975f5c5SAndroid Build Coastguard Worker size_t new_size) {
154*8975f5c5SAndroid Build Coastguard Worker #if BUILDFLAG(RUST_ALLOCATOR_USES_PARTITION_ALLOC)
155*8975f5c5SAndroid Build Coastguard Worker if (align <= alignof(std::max_align_t)) {
156*8975f5c5SAndroid Build Coastguard Worker return allocator_shim::UncheckedRealloc(p, new_size);
157*8975f5c5SAndroid Build Coastguard Worker } else {
158*8975f5c5SAndroid Build Coastguard Worker return allocator_shim::UncheckedAlignedRealloc(p, new_size, align);
159*8975f5c5SAndroid Build Coastguard Worker }
160*8975f5c5SAndroid Build Coastguard Worker #elif USE_WIN_ALIGNED_MALLOC
161*8975f5c5SAndroid Build Coastguard Worker return _aligned_realloc(p, new_size, align);
162*8975f5c5SAndroid Build Coastguard Worker #else
163*8975f5c5SAndroid Build Coastguard Worker extern void* __rdl_realloc(void* p, size_t old_size, size_t align,
164*8975f5c5SAndroid Build Coastguard Worker size_t new_size);
165*8975f5c5SAndroid Build Coastguard Worker return __rdl_realloc(p, old_size, align, new_size);
166*8975f5c5SAndroid Build Coastguard Worker #endif
167*8975f5c5SAndroid Build Coastguard Worker }
168*8975f5c5SAndroid Build Coastguard Worker
__rust_alloc_zeroed(size_t size,size_t align)169*8975f5c5SAndroid Build Coastguard Worker REMAP_ALLOC_ATTRIBUTES void* __rust_alloc_zeroed(size_t size, size_t align) {
170*8975f5c5SAndroid Build Coastguard Worker #if BUILDFLAG(RUST_ALLOCATOR_USES_PARTITION_ALLOC) || USE_WIN_ALIGNED_MALLOC
171*8975f5c5SAndroid Build Coastguard Worker // TODO(danakj): When RUST_ALLOCATOR_USES_PARTITION_ALLOC is true, it's
172*8975f5c5SAndroid Build Coastguard Worker // possible that a partition_alloc::UncheckedAllocZeroed() call would perform
173*8975f5c5SAndroid Build Coastguard Worker // better than partition_alloc::UncheckedAlloc() + memset. But there is no
174*8975f5c5SAndroid Build Coastguard Worker // such API today. See b/342251590.
175*8975f5c5SAndroid Build Coastguard Worker void* p = __rust_alloc(size, align);
176*8975f5c5SAndroid Build Coastguard Worker if (p) {
177*8975f5c5SAndroid Build Coastguard Worker memset(p, 0, size);
178*8975f5c5SAndroid Build Coastguard Worker }
179*8975f5c5SAndroid Build Coastguard Worker return p;
180*8975f5c5SAndroid Build Coastguard Worker #else
181*8975f5c5SAndroid Build Coastguard Worker extern void* __rdl_alloc_zeroed(size_t size, size_t align);
182*8975f5c5SAndroid Build Coastguard Worker return __rdl_alloc_zeroed(size, align);
183*8975f5c5SAndroid Build Coastguard Worker #endif
184*8975f5c5SAndroid Build Coastguard Worker }
185*8975f5c5SAndroid Build Coastguard Worker
__rust_alloc_error_handler(size_t size,size_t align)186*8975f5c5SAndroid Build Coastguard Worker REMAP_ALLOC_ATTRIBUTES void __rust_alloc_error_handler(size_t size,
187*8975f5c5SAndroid Build Coastguard Worker size_t align) {
188*8975f5c5SAndroid Build Coastguard Worker NO_CODE_FOLDING();
189*8975f5c5SAndroid Build Coastguard Worker IMMEDIATE_CRASH();
190*8975f5c5SAndroid Build Coastguard Worker }
191*8975f5c5SAndroid Build Coastguard Worker
192*8975f5c5SAndroid Build Coastguard Worker REMAP_ALLOC_ATTRIBUTES extern const unsigned char
193*8975f5c5SAndroid Build Coastguard Worker __rust_alloc_error_handler_should_panic = 0;
194*8975f5c5SAndroid Build Coastguard Worker
195*8975f5c5SAndroid Build Coastguard Worker } // extern "C"
196