xref: /freebsd/contrib/llvm-project/libcxx/src/include/refstring.h (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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