xref: /aosp_15_r20/external/cronet/base/android/linker/linker_minimal_libcxx.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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