• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2012 The Android Open Source Project
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 //    notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 //    notice, this list of conditions and the following disclaimer in the
11 //    documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the project nor the names of its contributors
13 //    may be used to endorse or promote products derived from this software
14 //    without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 // SUCH DAMAGE.
27 
28 #include <cassert>
29 #include <cstdio>
30 #include <cstdlib>
31 #include <exception>
32 #include <pthread.h>
33 
34 #include "cxxabi_defines.h"
35 #include "helper_func_internal.h"
36 
37 namespace {
38 
39   using namespace __cxxabiv1;
40 
isOurCxxException(uint64_t exc)41   bool isOurCxxException(uint64_t exc) {
42     // Compatible with GNU
43     return exc == __gxx_exception_class;
44   }
45 
defaultExceptionCleanupFunc(_Unwind_Reason_Code reason,_Unwind_Exception * exc)46   void defaultExceptionCleanupFunc(_Unwind_Reason_Code reason,
47                                    _Unwind_Exception* exc) {
48     __cxa_free_exception(exc+1);
49   }
50 
51   // Technical note:
52   // Use a pthread_key_t to hold the key used to store our thread-specific
53   // __cxa_eh_globals objects. The key is created and destroyed through
54   // a static C++ object.
55   //
56 
57   // Due to a bug in the dynamic linker that was only fixed in Froyo, the
58   // static C++ destructor may be called with a value of NULL for the
59   // 'this' pointer. As such, any attempt to access any field in the
60   // object there will result in a crash. To work-around this, store
61   // the key object as a 'static' variable outside of the C++ object.
62   static pthread_key_t __cxa_thread_key;
63 
64   class CxaThreadKey {
65   public:
66     // Called at program initialization time, or when the shared library
67     // is loaded through dlopen().
CxaThreadKey()68     CxaThreadKey() {
69       if (pthread_key_create(&__cxa_thread_key, freeObject) != 0) {
70         __gabixx::__fatal_error("Can't allocate C++ runtime pthread_key_t");
71       }
72     }
73 
74     // Called at program exit time, or when the shared library is
75     // unloaded through dlclose(). See note above.
~CxaThreadKey()76     ~CxaThreadKey() {
77       pthread_key_delete(__cxa_thread_key);
78     }
79 
getFast()80     static __cxa_eh_globals* getFast() {
81       void* obj = pthread_getspecific(__cxa_thread_key);
82       return reinterpret_cast<__cxa_eh_globals*>(obj);
83     }
84 
getSlow()85     static __cxa_eh_globals* getSlow() {
86       void* obj = pthread_getspecific(__cxa_thread_key);
87       if (obj == NULL) {
88         obj = malloc(sizeof(__cxa_eh_globals));
89         if (!obj) {
90           // Shouldn't happen, but better be safe than sorry.
91           __gabixx::__fatal_error(
92               "Can't allocate thread-specific C++ runtime info block.");
93         }
94         memset(obj, 0, sizeof(__cxa_eh_globals));
95         pthread_setspecific(__cxa_thread_key, obj);
96       }
97       return reinterpret_cast<__cxa_eh_globals*>(obj);
98     }
99 
100   private:
101     // Called when a thread is destroyed.
freeObject(void * obj)102     static void freeObject(void* obj) {
103       free(obj);
104     }
105 
106   };
107 
108   // The single static instance, this forces the compiler to register
109   // a constructor and destructor for this object in the final library
110   // file. They handle the pthread_key_t allocation/deallocation.
111   static CxaThreadKey instance;
112 
throwException(__cxa_exception * header)113   void throwException(__cxa_exception *header) {
114     __cxa_eh_globals* globals = __cxa_get_globals();
115     header->unexpectedHandler = std::get_unexpected();
116     header->terminateHandler = std::get_terminate();
117     globals->uncaughtExceptions += 1;
118 
119     _Unwind_RaiseException(&header->unwindHeader);
120 
121     // Should not be here
122     call_terminate(&header->unwindHeader);
123   }
124 
125 } // anonymous namespace
126 
127 
128 namespace __cxxabiv1 {
~__shim_type_info()129   __shim_type_info::~__shim_type_info() {
130   }
131 
__cxa_pure_virtual()132   extern "C" void __cxa_pure_virtual() {
133     __gabixx::__fatal_error("Pure virtual function called!");
134   }
135 
__cxa_get_globals()136   extern "C" __cxa_eh_globals* __cxa_get_globals() {
137     return CxaThreadKey::getSlow();
138   }
139 
__cxa_get_globals_fast()140   extern "C" __cxa_eh_globals* __cxa_get_globals_fast() {
141     return CxaThreadKey::getFast();
142   }
143 
144 
__cxa_allocate_exception(size_t thrown_size)145   extern "C" void *__cxa_allocate_exception(size_t thrown_size) {
146     size_t size = thrown_size + sizeof(__cxa_exception);
147     __cxa_exception *buffer = static_cast<__cxa_exception*>(malloc(size));
148     if (!buffer) {
149       // Since Android uses memory-overcommit, we enter here only when
150       // the exception object is VERY large. This will propably never happen.
151       // Therefore, we decide to use no emergency spaces.
152       __gabixx::__fatal_error("Not enough memory to allocate exception!");
153     }
154 
155     memset(buffer, 0, sizeof(__cxa_exception));
156     return buffer + 1;
157   }
158 
__cxa_free_exception(void * thrown_exception)159   extern "C" void __cxa_free_exception(void* thrown_exception) {
160     __cxa_exception *exc = static_cast<__cxa_exception*>(thrown_exception)-1;
161 
162     if (exc->exceptionDestructor) {
163       try {
164         exc->exceptionDestructor(thrown_exception);
165       } catch (...) {
166         __gabixx::__fatal_error("Exception destructor has thrown!");
167       }
168     }
169 
170     free(exc);
171   }
172 
173 
__cxa_throw(void * thrown_exc,std::type_info * tinfo,void (* dest)(void *))174   extern "C" void __cxa_throw(void* thrown_exc,
175                               std::type_info* tinfo,
176                               void (*dest)(void*)) {
177     __cxa_exception* header = static_cast<__cxa_exception*>(thrown_exc)-1;
178     header->exceptionType = tinfo;
179     header->exceptionDestructor = dest;
180 
181     header->unwindHeader.exception_class = __gxx_exception_class;
182     header->unwindHeader.exception_cleanup = defaultExceptionCleanupFunc;
183 
184     throwException(header);
185   }
186 
__cxa_rethrow()187   extern "C" void __cxa_rethrow() {
188     __cxa_eh_globals *globals = __cxa_get_globals();
189     __cxa_exception* header = globals->caughtExceptions;
190     _Unwind_Exception* exception = &header->unwindHeader;
191     if (!header) {
192       __gabixx::__fatal_error(
193           "Attempting to rethrow an exception that doesn't exist!");
194     }
195 
196     if (isOurCxxException(exception->exception_class)) {
197       header->handlerCount = -header->handlerCount; // Set rethrow flag
198     } else {
199       globals->caughtExceptions = 0;
200     }
201 
202     throwException(header);
203   }
204 
205 
__cxa_begin_catch(void * exc)206   extern "C" void* __cxa_begin_catch(void* exc) {
207     _Unwind_Exception *exception = static_cast<_Unwind_Exception*>(exc);
208     __cxa_exception* header = reinterpret_cast<__cxa_exception*>(exception+1)-1;
209     __cxa_eh_globals* globals = __cxa_get_globals();
210 
211     if (!isOurCxxException(exception->exception_class)) {
212       if (globals->caughtExceptions) {
213         __gabixx::__fatal_error("Can't handle non-C++ exception!");
214       }
215     }
216 
217     // Check rethrow flag
218     header->handlerCount = (header->handlerCount < 0) ?
219       (-header->handlerCount+1) : (header->handlerCount+1);
220 
221     if (header != globals->caughtExceptions) {
222       header->nextException = globals->caughtExceptions;
223       globals->caughtExceptions = header;
224     }
225     globals->uncaughtExceptions -= 1;
226 
227     return header->adjustedPtr;
228   }
229 
__cxa_end_catch()230   extern "C" void __cxa_end_catch() {
231     __cxa_eh_globals *globals = __cxa_get_globals_fast();
232     __cxa_exception *header = globals->caughtExceptions;
233     _Unwind_Exception* exception = &header->unwindHeader;
234 
235     if (!header) {
236       return;
237     }
238 
239     if (!isOurCxxException(exception->exception_class)) {
240       globals->caughtExceptions = 0;
241       _Unwind_DeleteException(exception);
242       return;
243     }
244 
245     int count = header->handlerCount;
246     if (count < 0) { // Rethrow
247       if (++count == 0) {
248         globals->caughtExceptions = header->nextException;
249       }
250     } else if (--count == 0) {
251       globals->caughtExceptions = header->nextException;
252       __cxa_free_exception(header+1);
253       return;
254     } else if (count < 0) {
255       __gabixx::__fatal_error("Internal error during exception handling!");
256     }
257 
258     header->handlerCount = count;
259   }
260 
__cxa_get_exception_ptr(void * exceptionObject)261   extern "C" void* __cxa_get_exception_ptr(void* exceptionObject) {
262     __cxa_exception* header =
263       reinterpret_cast<__cxa_exception*>(
264         reinterpret_cast<_Unwind_Exception *>(exceptionObject)+1)-1;
265     return header->adjustedPtr;
266   }
267 
__cxa_uncaught_exception()268   extern "C" bool __cxa_uncaught_exception() _GABIXX_NOEXCEPT {
269     __cxa_eh_globals* globals = __cxa_get_globals();
270     if (globals == NULL)
271       return false;
272     return globals->uncaughtExceptions == 0;
273   }
274 
__cxa_decrement_exception_refcount(void * exceptionObject)275   extern "C" void __cxa_decrement_exception_refcount(void* exceptionObject)
276       _GABIXX_NOEXCEPT {
277     if (exceptionObject != NULL)
278     {
279       __cxa_exception* header =
280           reinterpret_cast<__cxa_exception*>(exceptionObject)-1;
281       if (__sync_sub_and_fetch(&header->referenceCount, 1) == 0)
282         __cxa_free_exception(exceptionObject);
283     }
284   }
285 
__cxa_increment_exception_refcount(void * exceptionObject)286   extern "C" void __cxa_increment_exception_refcount(void* exceptionObject)
287       _GABIXX_NOEXCEPT {
288     if (exceptionObject != NULL)
289     {
290       __cxa_exception* header =
291           reinterpret_cast<__cxa_exception*>(exceptionObject)-1;
292       __sync_add_and_fetch(&header->referenceCount, 1);
293     }
294   }
295 
__cxa_rethrow_primary_exception(void * primary_exception)296   extern "C" void __cxa_rethrow_primary_exception(void* primary_exception) {
297 #if defined(GABIXX_LIBCXX)
298 // Only warn if we're building for libcxx since other libraries do not use
299 // this.
300 #warning "not implemented."
301 #endif /* defined(GABIXX_LIBCXX) */
302   }
303 
__cxa_current_primary_exception()304   extern "C" void* __cxa_current_primary_exception() _GABIXX_NOEXCEPT {
305 #if defined(GABIXX_LIBCXX)
306 // Only warn if we're building for libcxx since other libraries do not use
307 // this.
308 #warning "not implemented."
309 #endif /* defined(GABIXX_LIBCXX) */
310   }
311 
312 } // namespace __cxxabiv1
313