• 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 <cxxabi.h>
32 #include <exception>
33 #include <pthread.h>
34 
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, _Unwind_Exception* exc) {
47     __cxa_free_exception(exc+1);
48   }
49 
50   // Technical note:
51   // Use a pthread_key_t to hold the key used to store our thread-specific
52   // __cxa_thread_info objects. The key is created and destroyed through
53   // a static C++ object.
54   //
55 
56   // Due to a bug in the dynamic linker that was only fixed in Froyo, the
57   // static C++ destructor may be called with a value of NULL for the
58   // 'this' pointer. As such, any attempt to access any field in the
59   // object there will result in a crash. To work-around this, store
60   // the key object as a 'static' variable outside of the C++ object.
61   static pthread_key_t __cxa_thread_key;
62 
63   class CxaThreadKey {
64   public:
65     // Called at program initialization time, or when the shared library
66     // is loaded through dlopen().
CxaThreadKey()67     CxaThreadKey() {
68       if (pthread_key_create(&__cxa_thread_key, freeObject) != 0) {
69         fatalError("Can't allocate C++ runtime pthread_key_t");
70       }
71     }
72 
73     // Called at program exit time, or when the shared library is
74     // unloaded through dlclose(). See note above.
~CxaThreadKey()75     ~CxaThreadKey() {
76       pthread_key_delete(__cxa_thread_key);
77     }
78 
getFast()79     static __cxa_thread_info* getFast() {
80       void* obj = pthread_getspecific(__cxa_thread_key);
81       return reinterpret_cast<__cxa_thread_info*>(obj);
82     }
83 
getSlow()84     static __cxa_thread_info* getSlow() {
85       void* obj = pthread_getspecific(__cxa_thread_key);
86       if (obj == NULL) {
87         obj = malloc(sizeof(__cxa_thread_info));
88         if (!obj) {
89           // Shouldn't happen, but better be safe than sorry.
90           fatalError("Can't allocate thread-specific C++ runtime info block.");
91         }
92         memset(obj, 0, sizeof(__cxa_thread_info));
93         pthread_setspecific(__cxa_thread_key, obj);
94       }
95       return reinterpret_cast<__cxa_thread_info*>(obj);
96     }
97 
98   private:
99     // Called when a thread is destroyed.
freeObject(void * obj)100     static void freeObject(void* obj) {
101       free(obj);
102     }
103 
104   };
105 
106   // The single static instance, this forces the compiler to register
107   // a constructor and destructor for this object in the final library
108   // file. They handle the pthread_key_t allocation/deallocation.
109   static CxaThreadKey instance;
110 
throwException(__cxa_exception * header)111   void throwException(__cxa_exception *header) {
112     __cxa_thread_info *info = CxaThreadKey::getSlow();
113     header->unexpectedHandler = info->unexpectedHandler;
114     if (!header->unexpectedHandler) {
115       header->unexpectedHandler = std::get_unexpected();
116     }
117     header->terminateHandler = info->terminateHandler;
118     if (!header->terminateHandler) {
119       header->terminateHandler = std::get_terminate();
120     }
121     info->globals.uncaughtExceptions += 1;
122 
123     _Unwind_Reason_Code ret = _Unwind_RaiseException(&header->unwindHeader);
124 
125     // Should not be here
126     call_terminate(&header->unwindHeader);
127   }
128 
129 } // anonymous namespace
130 
131 
132 namespace __cxxabiv1 {
~__shim_type_info()133   __shim_type_info::~__shim_type_info() {
134   }
135 
__cxa_pure_virtual()136   extern "C" void __cxa_pure_virtual() {
137     fatalError("Pure virtual function called!");
138   }
139 
__cxa_get_globals()140   extern "C" __cxa_eh_globals* __cxa_get_globals() {
141     __cxa_thread_info* info = CxaThreadKey::getSlow();
142     return &info->globals;
143   }
144 
__cxa_get_globals_fast()145   extern "C" __cxa_eh_globals* __cxa_get_globals_fast() {
146     __cxa_thread_info* info = CxaThreadKey::getFast();
147     return &info->globals;
148   }
149 
150 
__cxa_allocate_exception(size_t thrown_size)151   extern "C" void *__cxa_allocate_exception(size_t thrown_size) {
152     size_t size = thrown_size + sizeof(__cxa_exception);
153     __cxa_exception *buffer = static_cast<__cxa_exception*>(malloc(size));
154     if (!buffer) {
155       // Since Android uses memory-overcommit, we enter here only when
156       // the exception object is VERY large. This will propably never happen.
157       // Therefore, we decide to use no emergency spaces.
158       fatalError("Not enough memory to allocate exception!");
159     }
160 
161     memset(buffer, 0, sizeof(__cxa_exception));
162     return buffer + 1;
163   }
164 
__cxa_free_exception(void * thrown_exception)165   extern "C" void __cxa_free_exception(void* thrown_exception) {
166     __cxa_exception *exc = static_cast<__cxa_exception*>(thrown_exception)-1;
167 
168     if (exc->exceptionDestructor) {
169       try {
170         exc->exceptionDestructor(thrown_exception);
171       } catch (...) {
172         fatalError("Exception destructor has thrown!");
173       }
174     }
175 
176     free(exc);
177   }
178 
179 
__cxa_throw(void * thrown_exc,std::type_info * tinfo,void (* dest)(void *))180   extern "C" void __cxa_throw(void* thrown_exc,
181                               std::type_info* tinfo,
182                               void (*dest)(void*)) {
183     __cxa_exception* header = static_cast<__cxa_exception*>(thrown_exc)-1;
184     header->exceptionType = tinfo;
185     header->exceptionDestructor = dest;
186 
187     header->unwindHeader.exception_class = __gxx_exception_class;
188     header->unwindHeader.exception_cleanup = defaultExceptionCleanupFunc;
189 
190     throwException(header);
191   }
192 
__cxa_rethrow()193   extern "C" void __cxa_rethrow() {
194     __cxa_eh_globals *globals = __cxa_get_globals();
195     __cxa_exception* header = globals->caughtExceptions;
196     _Unwind_Exception* exception = &header->unwindHeader;
197     if (!header) {
198       fatalError("Attempting to rethrow an exception that doesn't exist!");
199     }
200 
201     if (isOurCxxException(exception->exception_class)) {
202       header->handlerCount = -header->handlerCount; // Set rethrow flag
203     } else {
204       globals->caughtExceptions = 0;
205     }
206 
207     throwException(header);
208   }
209 
210 
__cxa_begin_catch(void * exc)211   extern "C" void* __cxa_begin_catch(void* exc) {
212     _Unwind_Exception *exception = static_cast<_Unwind_Exception*>(exc);
213     __cxa_exception* header = reinterpret_cast<__cxa_exception*>(exception+1)-1;
214     __cxa_eh_globals* globals = __cxa_get_globals();
215 
216     if (!isOurCxxException(exception->exception_class)) {
217       if (globals->caughtExceptions) {
218         fatalError("Can't handle non-C++ exception!");
219       }
220     }
221 
222     // Check rethrow flag
223     header->handlerCount = (header->handlerCount < 0) ?
224       (-header->handlerCount+1) : (header->handlerCount+1);
225 
226     if (header != globals->caughtExceptions) {
227       header->nextException = globals->caughtExceptions;
228       globals->caughtExceptions = header;
229     }
230     globals->uncaughtExceptions -= 1;
231 
232     return header->adjustedPtr;
233   }
234 
__cxa_end_catch()235   extern "C" void __cxa_end_catch() {
236     __cxa_eh_globals *globals = __cxa_get_globals_fast();
237     __cxa_exception *header = globals->caughtExceptions;
238     _Unwind_Exception* exception = &header->unwindHeader;
239 
240     if (!header) {
241       return;
242     }
243 
244     if (!isOurCxxException(exception->exception_class)) {
245       globals->caughtExceptions = 0;
246       _Unwind_DeleteException(exception);
247       return;
248     }
249 
250     int count = header->handlerCount;
251     if (count < 0) { // Rethrow
252       if (++count == 0) {
253         globals->caughtExceptions = header->nextException;
254       }
255     } else if (--count == 0) {
256       globals->caughtExceptions = header->nextException;
257       __cxa_free_exception(header+1);
258       return;
259     } else if (count < 0) {
260       fatalError("Internal error during exception handling!");
261     }
262 
263     header->handlerCount = count;
264   }
265 
__cxa_get_exception_ptr(void * exceptionObject)266   extern "C" void* __cxa_get_exception_ptr(void* exceptionObject) {
267     __cxa_exception* header =
268       reinterpret_cast<__cxa_exception*>(
269         reinterpret_cast<_Unwind_Exception *>(exceptionObject)+1)-1;
270     return header->adjustedPtr;
271   }
272 
__cxa_uncaught_exception()273   extern "C" bool __cxa_uncaught_exception() throw() {
274     __cxa_eh_globals* globals = __cxa_get_globals();
275     if (globals == NULL)
276       return false;
277     return globals->uncaughtExceptions == 0;
278   }
279 
__cxa_decrement_exception_refcount(void * exceptionObject)280   extern "C" void __cxa_decrement_exception_refcount(void* exceptionObject) throw() {
281     if (exceptionObject != NULL)
282     {
283       __cxa_exception* header =
284           reinterpret_cast<__cxa_exception*>(exceptionObject)-1;
285       if (__sync_sub_and_fetch(&header->referenceCount, 1) == 0)
286         __cxa_free_exception(exceptionObject);
287     }
288   }
289 
__cxa_increment_exception_refcount(void * exceptionObject)290   extern "C" void __cxa_increment_exception_refcount(void* exceptionObject) throw() {
291     if (exceptionObject != NULL)
292     {
293       __cxa_exception* header =
294           reinterpret_cast<__cxa_exception*>(exceptionObject)-1;
295       __sync_add_and_fetch(&header->referenceCount, 1);
296     }
297   }
298 
__cxa_rethrow_primary_exception(void * primary_exception)299   extern "C" void __cxa_rethrow_primary_exception(void* primary_exception) {
300 #if defined(GABIXX_LIBCXX)
301 // Only warn if we're building for libcxx since other libraries do not use
302 // this.
303 #warning "not implemented."
304 #endif /* defined(GABIXX_LIBCXX) */
305   }
306 
__cxa_current_primary_exception()307   extern "C" void* __cxa_current_primary_exception() throw() {
308 #if defined(GABIXX_LIBCXX)
309 // Only warn if we're building for libcxx since other libraries do not use
310 // this.
311 #warning "not implemented."
312 #endif /* defined(GABIXX_LIBCXX) */
313   }
314 
315 } // namespace __cxxabiv1
316