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 | |