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