1eb8650a7SLouis Dionne //===----------------------------------------------------------------------===// 2e3e7c0fbSEric Fiselier // 357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e3e7c0fbSEric Fiselier // 7e3e7c0fbSEric Fiselier //===----------------------------------------------------------------------===// 8e3e7c0fbSEric Fiselier 9e3e7c0fbSEric Fiselier #ifndef _LIBCPP_REFSTRING_H 10e3e7c0fbSEric Fiselier #define _LIBCPP_REFSTRING_H 11e3e7c0fbSEric Fiselier 12*9783f28cSLouis Dionne #include "atomic_support.h" 13e3e7c0fbSEric Fiselier #include <__config> 14e3e7c0fbSEric Fiselier #include <cstddef> 15e3e7c0fbSEric Fiselier #include <cstring> 16*9783f28cSLouis Dionne #include <stdexcept> 172728293bSLouis Dionne 182728293bSLouis Dionne // MacOS and iOS used to ship with libstdc++, and still support old applications 192728293bSLouis Dionne // linking against libstdc++. The libc++ and libstdc++ exceptions are supposed 202728293bSLouis Dionne // to be ABI compatible, such that they can be thrown from one library and caught 212728293bSLouis Dionne // in the other. 222728293bSLouis Dionne // 232728293bSLouis Dionne // For that reason, we must look for libstdc++ in the same process and if found, 242728293bSLouis Dionne // check the string stored in the exception object to see if it is the GCC empty 252728293bSLouis Dionne // string singleton before manipulating the reference count. This is done so that 262728293bSLouis Dionne // if an exception is created with a zero-length string in libstdc++, libc++abi 272728293bSLouis Dionne // won't try to delete the memory. 28*9783f28cSLouis Dionne #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) 292728293bSLouis Dionne # define _LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE 30e3e7c0fbSEric Fiselier # include <dlfcn.h> 31e3e7c0fbSEric Fiselier # include <mach-o/dyld.h> 32e3e7c0fbSEric Fiselier #endif 33e3e7c0fbSEric Fiselier 34e3e7c0fbSEric Fiselier _LIBCPP_BEGIN_NAMESPACE_STD 35e3e7c0fbSEric Fiselier 36*9783f28cSLouis Dionne namespace __refstring_imp { 37*9783f28cSLouis Dionne namespace { 38e3e7c0fbSEric Fiselier typedef int count_t; 39e3e7c0fbSEric Fiselier 40e3e7c0fbSEric Fiselier struct _Rep_base { 41e3e7c0fbSEric Fiselier std::size_t len; 42e3e7c0fbSEric Fiselier std::size_t cap; 43e3e7c0fbSEric Fiselier count_t count; 44e3e7c0fbSEric Fiselier }; 45e3e7c0fbSEric Fiselier 46e3e7c0fbSEric Fiselier inline _Rep_base* rep_from_data(const char* data_) noexcept { 47e3e7c0fbSEric Fiselier char* data = const_cast<char*>(data_); 48e3e7c0fbSEric Fiselier return reinterpret_cast<_Rep_base*>(data - sizeof(_Rep_base)); 49e3e7c0fbSEric Fiselier } 50e3e7c0fbSEric Fiselier 51e3e7c0fbSEric Fiselier inline char* data_from_rep(_Rep_base* rep) noexcept { 52e3e7c0fbSEric Fiselier char* data = reinterpret_cast<char*>(rep); 53e3e7c0fbSEric Fiselier return data + sizeof(*rep); 54e3e7c0fbSEric Fiselier } 55e3e7c0fbSEric Fiselier 562728293bSLouis Dionne #if defined(_LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE) 57*9783f28cSLouis Dionne inline const char* compute_gcc_empty_string_storage() noexcept { 58e3e7c0fbSEric Fiselier void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD); 59e3e7c0fbSEric Fiselier if (handle == nullptr) 60e3e7c0fbSEric Fiselier return nullptr; 61e3e7c0fbSEric Fiselier void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE"); 62e3e7c0fbSEric Fiselier if (sym == nullptr) 63e3e7c0fbSEric Fiselier return nullptr; 64e3e7c0fbSEric Fiselier return data_from_rep(reinterpret_cast<_Rep_base*>(sym)); 65e3e7c0fbSEric Fiselier } 66e3e7c0fbSEric Fiselier 67*9783f28cSLouis Dionne inline const char* get_gcc_empty_string_storage() noexcept { 68e3e7c0fbSEric Fiselier static const char* p = compute_gcc_empty_string_storage(); 69e3e7c0fbSEric Fiselier return p; 70e3e7c0fbSEric Fiselier } 71e3e7c0fbSEric Fiselier #endif 72e3e7c0fbSEric Fiselier 73*9783f28cSLouis Dionne } // namespace 74*9783f28cSLouis Dionne } // namespace __refstring_imp 75e3e7c0fbSEric Fiselier 76e3e7c0fbSEric Fiselier using namespace __refstring_imp; 77e3e7c0fbSEric Fiselier 78*9783f28cSLouis Dionne inline __libcpp_refstring::__libcpp_refstring(const char* msg) { 79e3e7c0fbSEric Fiselier std::size_t len = strlen(msg); 80e3e7c0fbSEric Fiselier _Rep_base* rep = static_cast<_Rep_base*>(::operator new(sizeof(*rep) + len + 1)); 81e3e7c0fbSEric Fiselier rep->len = len; 82e3e7c0fbSEric Fiselier rep->cap = len; 83e3e7c0fbSEric Fiselier rep->count = 0; 84e3e7c0fbSEric Fiselier char* data = data_from_rep(rep); 85e3e7c0fbSEric Fiselier std::memcpy(data, msg, len + 1); 86e3e7c0fbSEric Fiselier __imp_ = data; 87e3e7c0fbSEric Fiselier } 88e3e7c0fbSEric Fiselier 89*9783f28cSLouis Dionne inline __libcpp_refstring::__libcpp_refstring(const __libcpp_refstring& s) noexcept : __imp_(s.__imp_) { 90e3e7c0fbSEric Fiselier if (__uses_refcount()) 91fbfaec70SWeiming Zhao __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); 92e3e7c0fbSEric Fiselier } 93e3e7c0fbSEric Fiselier 94*9783f28cSLouis Dionne inline __libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) noexcept { 95e3e7c0fbSEric Fiselier bool adjust_old_count = __uses_refcount(); 96e3e7c0fbSEric Fiselier struct _Rep_base* old_rep = rep_from_data(__imp_); 97e3e7c0fbSEric Fiselier __imp_ = s.__imp_; 98e3e7c0fbSEric Fiselier if (__uses_refcount()) 99fbfaec70SWeiming Zhao __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); 100*9783f28cSLouis Dionne if (adjust_old_count) { 101*9783f28cSLouis Dionne if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0) { 102e3e7c0fbSEric Fiselier ::operator delete(old_rep); 103e3e7c0fbSEric Fiselier } 104e3e7c0fbSEric Fiselier } 105e3e7c0fbSEric Fiselier return *this; 106e3e7c0fbSEric Fiselier } 107e3e7c0fbSEric Fiselier 108*9783f28cSLouis Dionne inline __libcpp_refstring::~__libcpp_refstring() { 109e3e7c0fbSEric Fiselier if (__uses_refcount()) { 110e3e7c0fbSEric Fiselier _Rep_base* rep = rep_from_data(__imp_); 111fbfaec70SWeiming Zhao if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) { 112e3e7c0fbSEric Fiselier ::operator delete(rep); 113e3e7c0fbSEric Fiselier } 114e3e7c0fbSEric Fiselier } 115e3e7c0fbSEric Fiselier } 116e3e7c0fbSEric Fiselier 117*9783f28cSLouis Dionne inline bool __libcpp_refstring::__uses_refcount() const { 1182728293bSLouis Dionne #if defined(_LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE) 119e3e7c0fbSEric Fiselier return __imp_ != get_gcc_empty_string_storage(); 120e3e7c0fbSEric Fiselier #else 121e3e7c0fbSEric Fiselier return true; 122e3e7c0fbSEric Fiselier #endif 123e3e7c0fbSEric Fiselier } 124e3e7c0fbSEric Fiselier 125e3e7c0fbSEric Fiselier _LIBCPP_END_NAMESPACE_STD 126e3e7c0fbSEric Fiselier 127e3e7c0fbSEric Fiselier #endif // _LIBCPP_REFSTRING_H 128