1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <android/log.h>
6 #include <unistd.h>
7 #include <cstddef>
8 #include <cstdlib>
9
10 // Custom implementation of new and delete, this prevents dragging
11 // the libc++ implementation, which drags exception-related machine
12 // code that is not needed here. This helps reduce the size of the
13 // final binary considerably.
14
15 // These symbols are not exported, thus this does not affect the libraries that
16 // it will load, only the linker binary itself.
operator new(size_t size)17 void* operator new(size_t size) {
18 void* ptr = ::malloc(size);
19 if (ptr != nullptr)
20 return ptr;
21
22 // Don't assume it is possible to call any C library function like
23 // snprintf() here, since it might allocate heap memory and crash at
24 // runtime. Hence our fatal message does not contain the number of
25 // bytes requested by the allocation.
26 static const char kFatalMessage[] = "Out of memory!";
27 #ifdef __ANDROID__
28 __android_log_write(ANDROID_LOG_FATAL, "linker", kFatalMessage);
29 #else
30 ::write(STDERR_FILENO, kFatalMessage, sizeof(kFatalMessage) - 1);
31 #endif
32 _exit(1);
33 #if defined(__GNUC__)
34 __builtin_unreachable();
35 #endif
36
37 // Adding a 'return nullptr' here will make the compiler error with a message
38 // stating that 'operator new(size_t)' is not allowed to return nullptr.
39 //
40 // Indeed, an new expression like 'new T' shall never return nullptr,
41 // according to the C++ specification, and an optimizing compiler will gladly
42 // remove any null-checks after them (something the Fuschsia team had to
43 // learn the hard way when writing their kernel in C++). What is meant here
44 // is something like:
45 //
46 // Foo* foo = new Foo(10);
47 // if (!foo) { <-- entire check and branch
48 // ... Handle out-of-memory condition. <-- removed by an optimizing
49 // } <-- compiler.
50 //
51 // Note that some C++ library implementations (e.g. recent libc++) recognize
52 // when they are compiled with -fno-exceptions and provide a simpler version
53 // of operator new that can return nullptr. However, it is very hard to
54 // guarantee at build time that this code is linked against such a version
55 // of the runtime. Moreoever, technically disabling exceptions is completely
56 // out-of-spec regarding the C++ language, and what the compiler is allowed
57 // to do in this case is mostly implementation-defined, so better be safe
58 // than sorry here.
59 //
60 // C++ provides a non-throwing new expression that can return a nullptr
61 // value, but it must be written as 'new (std::nothrow) T' instead of
62 // 'new T', and thus nobody uses this. This ends up calling
63 // 'operator new(size_t, const std::nothrow_t&)' which is not implemented
64 // here.
65 }
66
operator new[](size_t size)67 void* operator new[](size_t size) {
68 return operator new(size);
69 }
70
operator delete(void * ptr)71 void operator delete(void* ptr) {
72 // The compiler-generated code already checked that |ptr != nullptr|
73 // so don't to it a second time.
74 ::free(ptr);
75 }
76
operator delete[](void * ptr)77 void operator delete[](void* ptr) {
78 ::free(ptr);
79 }
80