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 <__config> 13#include <stdexcept> 14#include <cstddef> 15#include <cstring> 16#include "atomic_support.h" 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__) || \ 29 defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) 30# define _LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE 31# include <dlfcn.h> 32# include <mach-o/dyld.h> 33#endif 34 35_LIBCPP_BEGIN_NAMESPACE_STD 36 37namespace __refstring_imp { namespace { 38typedef int count_t; 39 40struct _Rep_base { 41 std::size_t len; 42 std::size_t cap; 43 count_t count; 44}; 45 46inline _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 51inline 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) 57inline 58const char* compute_gcc_empty_string_storage() noexcept 59{ 60 void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD); 61 if (handle == nullptr) 62 return nullptr; 63 void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE"); 64 if (sym == nullptr) 65 return nullptr; 66 return data_from_rep(reinterpret_cast<_Rep_base *>(sym)); 67} 68 69inline 70const char* 71get_gcc_empty_string_storage() noexcept 72{ 73 static const char* p = compute_gcc_empty_string_storage(); 74 return p; 75} 76#endif 77 78}} // namespace __refstring_imp 79 80using namespace __refstring_imp; 81 82inline 83__libcpp_refstring::__libcpp_refstring(const char* msg) { 84 std::size_t len = strlen(msg); 85 _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1)); 86 rep->len = len; 87 rep->cap = len; 88 rep->count = 0; 89 char *data = data_from_rep(rep); 90 std::memcpy(data, msg, len + 1); 91 __imp_ = data; 92} 93 94inline 95__libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) noexcept 96 : __imp_(s.__imp_) 97{ 98 if (__uses_refcount()) 99 __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); 100} 101 102inline 103__libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) noexcept { 104 bool adjust_old_count = __uses_refcount(); 105 struct _Rep_base *old_rep = rep_from_data(__imp_); 106 __imp_ = s.__imp_; 107 if (__uses_refcount()) 108 __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); 109 if (adjust_old_count) 110 { 111 if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0) 112 { 113 ::operator delete(old_rep); 114 } 115 } 116 return *this; 117} 118 119inline 120__libcpp_refstring::~__libcpp_refstring() { 121 if (__uses_refcount()) { 122 _Rep_base* rep = rep_from_data(__imp_); 123 if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) { 124 ::operator delete(rep); 125 } 126 } 127} 128 129inline 130bool __libcpp_refstring::__uses_refcount() const { 131#if defined(_LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE) 132 return __imp_ != get_gcc_empty_string_storage(); 133#else 134 return true; 135#endif 136} 137 138_LIBCPP_END_NAMESPACE_STD 139 140#endif //_LIBCPP_REFSTRING_H 141