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