stdc++compat.cpp (7614B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include <ostream> 6 #include <istream> 7 #include <sstream> 8 #include <memory> 9 #include <string> 10 #include <stdarg.h> 11 #include <stdio.h> 12 #include <mozilla/Assertions.h> 13 #include <cxxabi.h> 14 15 /* 16 GLIBCXX_3.4.19 is from gcc 4.8.1 (199309) 17 GLIBCXX_3.4.20 is from gcc 4.9.0 (199307) 18 GLIBCXX_3.4.21 is from gcc 5.0 (210290) 19 GLIBCXX_3.4.22 is from gcc 6.0 (222482) 20 GLIBCXX_3.4.23 is from gcc 7 21 GLIBCXX_3.4.24 is from gcc 8 22 GLIBCXX_3.4.25 is from gcc 8 23 GLIBCXX_3.4.26 is from gcc 9 24 GLIBCXX_3.4.27 is from gcc 10 25 GLIBCXX_3.4.28 is from gcc 10 26 GLIBCXX_3.4.29 is from gcc 11 27 28 This file adds the necessary compatibility tricks to avoid symbols with 29 version GLIBCXX_3.4.20 and bigger, keeping binary compatibility with 30 libstdc++ 4.8.1. 31 32 WARNING: all symbols from this file must be defined weak when they 33 overlap with libstdc++. 34 */ 35 36 /* Expose the definitions for the old ABI, allowing us to call its functions */ 37 #define _GLIBCXX_THREAD_ABI_COMPAT 1 38 #include <thread> 39 40 #if !defined(__aarch64__) 41 /* The __cxa_thread_atexit_impl symbol is only available on GLIBC 2.18, but we 42 * want things to keep working on 2.17. It's not actually used directly from 43 * C++ code, but through __cxa_thead_atexit in libstdc++. The problem we have, 44 * though, is that rust's libstd also uses it, introducing a dependency we 45 * don't actually want. Fortunately, we can fall back to libstdc++'s wrapper 46 * (which, on systems without __cxa_thread_atexit_impl, has its own compatible 47 * implementation). 48 * The __cxa_thread_atexit symbol itself is marked CXXABI_1.3.7, which is 49 * equivalent to GLIBCXX_3.4.18. 50 */ 51 extern "C" int __cxa_thread_atexit_impl(void (*dtor)(void*), void* obj, 52 void* dso_handle) { 53 return __cxxabiv1::__cxa_thread_atexit(dtor, obj, dso_handle); 54 } 55 56 namespace std { 57 58 /* We shouldn't be throwing exceptions at all, but it sadly turns out 59 we call STL (inline) functions that do. This avoids the GLIBCXX_3.4.20 60 symbol version. */ 61 void __attribute__((weak)) __throw_out_of_range_fmt(char const* fmt, ...) { 62 va_list ap; 63 char buf[1024]; // That should be big enough. 64 65 va_start(ap, fmt); 66 vsnprintf(buf, sizeof(buf), fmt, ap); 67 buf[sizeof(buf) - 1] = 0; 68 va_end(ap); 69 70 __throw_range_error(buf); 71 } 72 73 } // namespace std 74 75 namespace __cxxabiv1 { 76 /* Calls to this function are added by the compiler itself on `new Class[n]` 77 * calls. This avoids the GLIBCXX_3.4.20 symbol version. */ 78 extern "C" void __attribute__((weak)) __cxa_throw_bad_array_new_length() { 79 MOZ_CRASH(); 80 } 81 } // namespace __cxxabiv1 82 83 namespace std { 84 /* Instantiate this template to avoid GLIBCXX_3.4.21 symbol versions 85 * depending on optimization level */ 86 template basic_ios<char, char_traits<char>>::operator bool() const; 87 } // namespace std 88 89 # if !defined(MOZ_ASAN) && !defined(MOZ_TSAN) 90 /* operator delete with size is only available in CXXAPI_1.3.9, equivalent to 91 * GLIBCXX_3.4.21. */ 92 void operator delete(void* ptr, size_t size) noexcept(true) { 93 ::operator delete(ptr); 94 } 95 # endif 96 97 /* While we generally don't build with exceptions, we have some host tools 98 * that do use them. libstdc++ from GCC 5.0 added exception constructors with 99 * char const* argument. Older versions only have a constructor with 100 * std::string. This avoids the GLIBCXX_3.4.21 symbol version. */ 101 namespace std { 102 __attribute__((weak)) runtime_error::runtime_error(char const* s) 103 : runtime_error(std::string(s)) {} 104 __attribute__((weak)) out_of_range::out_of_range(char const* s) 105 : out_of_range(std::string(s)) {} 106 __attribute__((weak)) invalid_argument::invalid_argument(char const* s) 107 : invalid_argument(std::string(s)) {} 108 } // namespace std 109 110 namespace std { 111 /* The old ABI has a thread::_M_start_thread(shared_ptr<_Impl_base>), 112 * while the new has thread::_M_start_thread(unique_ptr<_State>, void(*)()). 113 * There is an intermediate ABI at version 3.4.21, with 114 * thread::_M_start_thread(shared_ptr<_Impl_base>, void(*)()). 115 * The void(*)() parameter is only there to keep a reference to pthread_create 116 * on the caller side, and is unused in the implementation 117 * We're creating an entry point for the new and intermediate ABIs, and make 118 * them call the old ABI. This avoids the GLIBCXX_3.4.21 symbol version. */ 119 __attribute__((weak)) void thread::_M_start_thread(shared_ptr<_Impl_base> impl, 120 void (*)()) { 121 _M_start_thread(std::move(impl)); 122 } 123 } // namespace std 124 125 #endif // !defined(__aarch64__) 126 127 namespace std { 128 /* We need a _Impl_base-derived class wrapping a _State to call the old ABI 129 * from what we got by diverting the new API. This avoids the GLIBCXX_3.4.22 130 * symbol version. */ 131 struct StateWrapper : public thread::_Impl_base { 132 unique_ptr<thread::_State> mState; 133 134 StateWrapper(unique_ptr<thread::_State> aState) : mState(std::move(aState)) {} 135 136 void _M_run() override { mState->_M_run(); } 137 }; 138 139 /* This avoids the GLIBCXX_3.4.22 symbol version. */ 140 __attribute__((weak)) void thread::_M_start_thread(unique_ptr<_State> aState, 141 void (*)()) { 142 auto impl = std::make_shared<StateWrapper>(std::move(aState)); 143 _M_start_thread(std::move(impl)); 144 } 145 146 /* For some reason this is a symbol exported by new versions of libstdc++, 147 * even though the destructor is default there too. This avoids the 148 * GLIBCXX_3.4.22 symbol version. */ 149 __attribute__((weak)) thread::_State::~_State() = default; 150 151 #if _GLIBCXX_RELEASE >= 9 152 // Ideally we'd define 153 // bool _Sp_make_shared_tag::_S_eq(const type_info& ti) noexcept 154 // but we wouldn't be able to change its visibility because of the existing 155 // definition in C++ headers. We do need to change its visibility because we 156 // don't want it to be shadowing the one provided by libstdc++ itself, because 157 // it doesn't support RTTI. Not supporting RTTI doesn't matter for Firefox 158 // itself because it's built with RTTI disabled. 159 // So we define via the mangled symbol. 160 // This avoids the GLIBCXX_3.4.26 symbol version. 161 extern "C" __attribute__((visibility("hidden"))) bool 162 _ZNSt19_Sp_make_shared_tag5_S_eqERKSt9type_info(const type_info*) noexcept { 163 return false; 164 } 165 #endif 166 167 /* Instantiate this template to avoid GLIBCXX_3.4.23 symbol versions 168 * depending on optimization level */ 169 template basic_string<char, char_traits<char>, allocator<char>>::basic_string( 170 const basic_string&, size_t, const allocator<char>&); 171 172 #if _GLIBCXX_RELEASE >= 9 173 // This avoids the GLIBCXX_3.4.26 symbol version. 174 template basic_stringstream<char, char_traits<char>, 175 allocator<char>>::basic_stringstream(); 176 177 template basic_istringstream<char, char_traits<char>, 178 allocator<char>>::basic_istringstream(); 179 180 template basic_ostringstream<char, char_traits<char>, 181 allocator<char>>::basic_ostringstream(); 182 183 template char* 184 basic_string<char, char_traits<char>, allocator<char>>::data() noexcept; 185 186 template basic_stringbuf<char, char_traits<char>, 187 allocator<char>>::basic_stringbuf(); 188 189 #endif 190 191 #if _GLIBCXX_RELEASE >= 11 192 // This avoids the GLIBCXX_3.4.29 symbol version. 193 template void basic_string<char, char_traits<char>, allocator<char>>::reserve(); 194 195 template void 196 basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>>::reserve(); 197 198 void __attribute__((weak)) __throw_bad_array_new_length() { MOZ_CRASH(); } 199 #endif 200 201 } // namespace std