xref: /freebsd/contrib/llvm-project/libcxx/src/include/refstring.h (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
1349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
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 
12*cb14a3feSDimitry Andric #include "atomic_support.h"
130b57cec5SDimitry Andric #include <__config>
140b57cec5SDimitry Andric #include <cstddef>
150b57cec5SDimitry Andric #include <cstring>
16*cb14a3feSDimitry Andric #include <stdexcept>
17e8d8bef9SDimitry Andric 
18e8d8bef9SDimitry Andric // MacOS and iOS used to ship with libstdc++, and still support old applications
19e8d8bef9SDimitry Andric // linking against libstdc++. The libc++ and libstdc++ exceptions are supposed
20e8d8bef9SDimitry Andric // to be ABI compatible, such that they can be thrown from one library and caught
21e8d8bef9SDimitry Andric // in the other.
22e8d8bef9SDimitry Andric //
23e8d8bef9SDimitry Andric // For that reason, we must look for libstdc++ in the same process and if found,
24e8d8bef9SDimitry Andric // check the string stored in the exception object to see if it is the GCC empty
25e8d8bef9SDimitry Andric // string singleton before manipulating the reference count. This is done so that
26e8d8bef9SDimitry Andric // if an exception is created with a zero-length string in libstdc++, libc++abi
27e8d8bef9SDimitry Andric // won't try to delete the memory.
28*cb14a3feSDimitry Andric #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
29e8d8bef9SDimitry Andric #  define _LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE
300b57cec5SDimitry Andric #  include <dlfcn.h>
310b57cec5SDimitry Andric #  include <mach-o/dyld.h>
320b57cec5SDimitry Andric #endif
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
350b57cec5SDimitry Andric 
36*cb14a3feSDimitry Andric namespace __refstring_imp {
37*cb14a3feSDimitry Andric 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 
56e8d8bef9SDimitry Andric #if defined(_LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE)
57*cb14a3feSDimitry Andric inline const char* compute_gcc_empty_string_storage() noexcept {
580b57cec5SDimitry Andric   void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);
590b57cec5SDimitry Andric   if (handle == nullptr)
600b57cec5SDimitry Andric     return nullptr;
610b57cec5SDimitry Andric   void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE");
620b57cec5SDimitry Andric   if (sym == nullptr)
630b57cec5SDimitry Andric     return nullptr;
640b57cec5SDimitry Andric   return data_from_rep(reinterpret_cast<_Rep_base*>(sym));
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
67*cb14a3feSDimitry Andric inline const char* get_gcc_empty_string_storage() noexcept {
680b57cec5SDimitry Andric   static const char* p = compute_gcc_empty_string_storage();
690b57cec5SDimitry Andric   return p;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric #endif
720b57cec5SDimitry Andric 
73*cb14a3feSDimitry Andric } // namespace
74*cb14a3feSDimitry Andric } // namespace __refstring_imp
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric using namespace __refstring_imp;
770b57cec5SDimitry Andric 
78*cb14a3feSDimitry Andric inline __libcpp_refstring::__libcpp_refstring(const char* msg) {
790b57cec5SDimitry Andric   std::size_t len = strlen(msg);
800b57cec5SDimitry Andric   _Rep_base* rep  = static_cast<_Rep_base*>(::operator new(sizeof(*rep) + len + 1));
810b57cec5SDimitry Andric   rep->len        = len;
820b57cec5SDimitry Andric   rep->cap        = len;
830b57cec5SDimitry Andric   rep->count      = 0;
840b57cec5SDimitry Andric   char* data      = data_from_rep(rep);
850b57cec5SDimitry Andric   std::memcpy(data, msg, len + 1);
860b57cec5SDimitry Andric   __imp_ = data;
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric 
89*cb14a3feSDimitry Andric inline __libcpp_refstring::__libcpp_refstring(const __libcpp_refstring& s) noexcept : __imp_(s.__imp_) {
900b57cec5SDimitry Andric   if (__uses_refcount())
910b57cec5SDimitry Andric     __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric 
94*cb14a3feSDimitry Andric inline __libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) noexcept {
950b57cec5SDimitry Andric   bool adjust_old_count     = __uses_refcount();
960b57cec5SDimitry Andric   struct _Rep_base* old_rep = rep_from_data(__imp_);
970b57cec5SDimitry Andric   __imp_                    = s.__imp_;
980b57cec5SDimitry Andric   if (__uses_refcount())
990b57cec5SDimitry Andric     __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
100*cb14a3feSDimitry Andric   if (adjust_old_count) {
101*cb14a3feSDimitry Andric     if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0) {
1020b57cec5SDimitry Andric       ::operator delete(old_rep);
1030b57cec5SDimitry Andric     }
1040b57cec5SDimitry Andric   }
1050b57cec5SDimitry Andric   return *this;
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric 
108*cb14a3feSDimitry Andric inline __libcpp_refstring::~__libcpp_refstring() {
1090b57cec5SDimitry Andric   if (__uses_refcount()) {
1100b57cec5SDimitry Andric     _Rep_base* rep = rep_from_data(__imp_);
1110b57cec5SDimitry Andric     if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) {
1120b57cec5SDimitry Andric       ::operator delete(rep);
1130b57cec5SDimitry Andric     }
1140b57cec5SDimitry Andric   }
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric 
117*cb14a3feSDimitry Andric inline bool __libcpp_refstring::__uses_refcount() const {
118e8d8bef9SDimitry Andric #if defined(_LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE)
1190b57cec5SDimitry Andric   return __imp_ != get_gcc_empty_string_storage();
1200b57cec5SDimitry Andric #else
1210b57cec5SDimitry Andric   return true;
1220b57cec5SDimitry Andric #endif
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric #endif //_LIBCPP_REFSTRING_H
128