10b57cec5SDimitry Andric //===------------------------ __refstring ---------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #ifndef _LIBCPP_REFSTRING_H 100b57cec5SDimitry Andric #define _LIBCPP_REFSTRING_H 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include <__config> 130b57cec5SDimitry Andric #include <stdexcept> 140b57cec5SDimitry Andric #include <cstddef> 150b57cec5SDimitry Andric #include <cstring> 16*e8d8bef9SDimitry Andric #include "atomic_support.h" 17*e8d8bef9SDimitry Andric 18*e8d8bef9SDimitry Andric // MacOS and iOS used to ship with libstdc++, and still support old applications 19*e8d8bef9SDimitry Andric // linking against libstdc++. The libc++ and libstdc++ exceptions are supposed 20*e8d8bef9SDimitry Andric // to be ABI compatible, such that they can be thrown from one library and caught 21*e8d8bef9SDimitry Andric // in the other. 22*e8d8bef9SDimitry Andric // 23*e8d8bef9SDimitry Andric // For that reason, we must look for libstdc++ in the same process and if found, 24*e8d8bef9SDimitry Andric // check the string stored in the exception object to see if it is the GCC empty 25*e8d8bef9SDimitry Andric // string singleton before manipulating the reference count. This is done so that 26*e8d8bef9SDimitry Andric // if an exception is created with a zero-length string in libstdc++, libc++abi 27*e8d8bef9SDimitry Andric // won't try to delete the memory. 28*e8d8bef9SDimitry Andric #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || \ 29*e8d8bef9SDimitry Andric defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) 30*e8d8bef9SDimitry Andric # define _LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE 310b57cec5SDimitry Andric # include <dlfcn.h> 320b57cec5SDimitry Andric # include <mach-o/dyld.h> 330b57cec5SDimitry Andric #endif 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric namespace __refstring_imp { namespace { 380b57cec5SDimitry Andric typedef int count_t; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric struct _Rep_base { 410b57cec5SDimitry Andric std::size_t len; 420b57cec5SDimitry Andric std::size_t cap; 430b57cec5SDimitry Andric count_t count; 440b57cec5SDimitry Andric }; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric inline _Rep_base* rep_from_data(const char *data_) noexcept { 470b57cec5SDimitry Andric char *data = const_cast<char *>(data_); 480b57cec5SDimitry Andric return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base)); 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric inline char * data_from_rep(_Rep_base *rep) noexcept { 520b57cec5SDimitry Andric char *data = reinterpret_cast<char *>(rep); 530b57cec5SDimitry Andric return data + sizeof(*rep); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 56*e8d8bef9SDimitry Andric #if defined(_LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE) 570b57cec5SDimitry Andric inline 580b57cec5SDimitry Andric const char* compute_gcc_empty_string_storage() _NOEXCEPT 590b57cec5SDimitry Andric { 600b57cec5SDimitry Andric void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD); 610b57cec5SDimitry Andric if (handle == nullptr) 620b57cec5SDimitry Andric return nullptr; 630b57cec5SDimitry Andric void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE"); 640b57cec5SDimitry Andric if (sym == nullptr) 650b57cec5SDimitry Andric return nullptr; 660b57cec5SDimitry Andric return data_from_rep(reinterpret_cast<_Rep_base *>(sym)); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric inline 700b57cec5SDimitry Andric const char* 710b57cec5SDimitry Andric get_gcc_empty_string_storage() _NOEXCEPT 720b57cec5SDimitry Andric { 730b57cec5SDimitry Andric static const char* p = compute_gcc_empty_string_storage(); 740b57cec5SDimitry Andric return p; 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric #endif 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric }} // namespace __refstring_imp 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric using namespace __refstring_imp; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric inline 830b57cec5SDimitry Andric __libcpp_refstring::__libcpp_refstring(const char* msg) { 840b57cec5SDimitry Andric std::size_t len = strlen(msg); 850b57cec5SDimitry Andric _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1)); 860b57cec5SDimitry Andric rep->len = len; 870b57cec5SDimitry Andric rep->cap = len; 880b57cec5SDimitry Andric rep->count = 0; 890b57cec5SDimitry Andric char *data = data_from_rep(rep); 900b57cec5SDimitry Andric std::memcpy(data, msg, len + 1); 910b57cec5SDimitry Andric __imp_ = data; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric inline 950b57cec5SDimitry Andric __libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT 960b57cec5SDimitry Andric : __imp_(s.__imp_) 970b57cec5SDimitry Andric { 980b57cec5SDimitry Andric if (__uses_refcount()) 990b57cec5SDimitry Andric __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric inline 1030b57cec5SDimitry Andric __libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT { 1040b57cec5SDimitry Andric bool adjust_old_count = __uses_refcount(); 1050b57cec5SDimitry Andric struct _Rep_base *old_rep = rep_from_data(__imp_); 1060b57cec5SDimitry Andric __imp_ = s.__imp_; 1070b57cec5SDimitry Andric if (__uses_refcount()) 1080b57cec5SDimitry Andric __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); 1090b57cec5SDimitry Andric if (adjust_old_count) 1100b57cec5SDimitry Andric { 1110b57cec5SDimitry Andric if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0) 1120b57cec5SDimitry Andric { 1130b57cec5SDimitry Andric ::operator delete(old_rep); 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric return *this; 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric inline 1200b57cec5SDimitry Andric __libcpp_refstring::~__libcpp_refstring() { 1210b57cec5SDimitry Andric if (__uses_refcount()) { 1220b57cec5SDimitry Andric _Rep_base* rep = rep_from_data(__imp_); 1230b57cec5SDimitry Andric if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) { 1240b57cec5SDimitry Andric ::operator delete(rep); 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric inline 1300b57cec5SDimitry Andric bool __libcpp_refstring::__uses_refcount() const { 131*e8d8bef9SDimitry Andric #if defined(_LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE) 1320b57cec5SDimitry Andric return __imp_ != get_gcc_empty_string_storage(); 1330b57cec5SDimitry Andric #else 1340b57cec5SDimitry Andric return true; 1350b57cec5SDimitry Andric #endif 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric #endif //_LIBCPP_REFSTRING_H 141