1 //===------------------------ stdexcept.cpp -------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #if defined(LIBCXXABI)
11 
12 #include "stdexcept"
13 #include "new"
14 #include <cstdlib>
15 #include <cstring>
16 #include <cstdint>
17 #include <cstddef>
18 
19 #if __APPLE__
20 #include <dlfcn.h>
21 #include <mach-o/dyld.h>
22 #endif
23 
24 // Note:  optimize for size
25 
26 #pragma GCC visibility push(hidden)
27 
28 namespace
29 {
30 
31 class __libcpp_nmstr
32 {
33 private:
34     const char* str_;
35 
36     typedef int count_t;
37 
38     struct _Rep_base
39     {
40         std::size_t len;
41         std::size_t cap;
42         count_t     count;
43     };
44 
45     static const std::ptrdiff_t offset = static_cast<std::ptrdiff_t>(sizeof(_Rep_base));
46 
count() const47     count_t& count() const _NOEXCEPT {return ((_Rep_base*)(str_ - offset))->count;}
48 
49 #if __APPLE__
50     static
51     const void*
compute_gcc_empty_string_storage()52     compute_gcc_empty_string_storage() _NOEXCEPT
53     {
54         void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);
55         if (handle == 0)
56             return 0;
57         return (const char*)dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE") + offset;
58     }
59 
60     static
61     const void*
get_gcc_empty_string_storage()62     get_gcc_empty_string_storage() _NOEXCEPT
63     {
64         static const void* p = compute_gcc_empty_string_storage();
65         return p;
66     }
67 #endif
68 
69 public:
70     explicit __libcpp_nmstr(const char* msg);
71     __libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT;
72     __libcpp_nmstr& operator=(const __libcpp_nmstr& s) _NOEXCEPT;
73     ~__libcpp_nmstr();
c_str() const74     const char* c_str() const _NOEXCEPT {return str_;}
75 };
76 
__libcpp_nmstr(const char * msg)77 __libcpp_nmstr::__libcpp_nmstr(const char* msg)
78 {
79     std::size_t len = strlen(msg);
80     str_ = static_cast<const char*>(::operator new(len + 1 + offset));
81     _Rep_base* c = (_Rep_base*)str_;
82     c->len = c->cap = len;
83     str_ += offset;
84     count() = 0;
85     std::memcpy(const_cast<char*>(c_str()), msg, len + 1);
86 }
87 
88 inline
__libcpp_nmstr(const __libcpp_nmstr & s)89 __libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT
90     : str_(s.str_)
91 {
92 #if __APPLE__
93     if (str_ != get_gcc_empty_string_storage())
94 #endif
95         __sync_add_and_fetch(&count(), 1);
96 }
97 
98 __libcpp_nmstr&
operator =(const __libcpp_nmstr & s)99 __libcpp_nmstr::operator=(const __libcpp_nmstr& s) _NOEXCEPT
100 {
101     const char* p = str_;
102     str_ = s.str_;
103 #if __APPLE__
104     if (str_ != get_gcc_empty_string_storage())
105 #endif
106         __sync_add_and_fetch(&count(), 1);
107 #if __APPLE__
108     if (p != get_gcc_empty_string_storage())
109 #endif
110         if (__sync_add_and_fetch((count_t*)(p-sizeof(count_t)), count_t(-1)) < 0)
111         {
112             ::operator delete(const_cast<char*>(p-offset));
113         }
114     return *this;
115 }
116 
117 inline
~__libcpp_nmstr()118 __libcpp_nmstr::~__libcpp_nmstr()
119 {
120 #if __APPLE__
121     if (str_ != get_gcc_empty_string_storage())
122 #endif
123         if (__sync_add_and_fetch(&count(), count_t(-1)) < 0)
124         {
125             ::operator delete(const_cast<char*>(str_ - offset));
126         }
127 }
128 
129 }
130 
131 #pragma GCC visibility pop
132 
133 namespace std  // purposefully not using versioning namespace
134 {
135 
~logic_error()136 logic_error::~logic_error() _NOEXCEPT
137 {
138     __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
139     s.~__libcpp_nmstr();
140 }
141 
142 const char*
what() const143 logic_error::what() const _NOEXCEPT
144 {
145     __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
146     return s.c_str();
147 }
148 
~runtime_error()149 runtime_error::~runtime_error() _NOEXCEPT
150 {
151     __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
152     s.~__libcpp_nmstr();
153 }
154 
155 const char*
what() const156 runtime_error::what() const _NOEXCEPT
157 {
158     __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
159     return s.c_str();
160 }
161 
~domain_error()162 domain_error::~domain_error() _NOEXCEPT {}
~invalid_argument()163 invalid_argument::~invalid_argument() _NOEXCEPT {}
~length_error()164 length_error::~length_error() _NOEXCEPT {}
~out_of_range()165 out_of_range::~out_of_range() _NOEXCEPT {}
166 
~range_error()167 range_error::~range_error() _NOEXCEPT {}
~overflow_error()168 overflow_error::~overflow_error() _NOEXCEPT {}
~underflow_error()169 underflow_error::~underflow_error() _NOEXCEPT {}
170 
171 }  // std
172 
173 #endif // LIBCXXABI
174