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 <limits.h>
29 #include <sys/mman.h>
30 
31 #include <cassert>
32 #include <cstdio>
33 #include <cstdlib>
34 #include <exception>
35 #include <pthread.h>
36 
37 #include "cxxabi_defines.h"
38 #include "helper_func_internal.h"
39 
40 namespace {
41 
42   using namespace __cxxabiv1;
43 
isOurCxxException(uint64_t exc)44   bool isOurCxxException(uint64_t exc) {
45     // Compatible with GNU
46     return exc == __gxx_exception_class;
47   }
48 
defaultExceptionCleanupFunc(_Unwind_Reason_Code reason,_Unwind_Exception * exc)49   void defaultExceptionCleanupFunc(_Unwind_Reason_Code reason,
50                                    _Unwind_Exception* exc) {
51     __cxa_free_exception(exc+1);
52   }
53 
54   // Helper class used to ensure a lock is acquire immediately, and released
55   // on scope exit. Usage example:
56   //
57   //     {
58   //       AutoLock lock(some_mutex);   // acquires the mutex.
59   //       ... do stuff
60   //       if (error)
61   //          return;                   // releases mutex before returning.
62   //       ... do other stuff.
63   //     }                              // releases mutex before exiting scope.
64   //
65   class AutoLock {
66   public:
AutoLock(pthread_mutex_t & lock)67     AutoLock(pthread_mutex_t& lock) : lock_(lock) {
68       pthread_mutex_lock(&lock_);
69     }
70 
~AutoLock(void)71     ~AutoLock(void) {
72       pthread_mutex_unlock(&lock_);
73     }
74   private:
75     pthread_mutex_t& lock_;
76 
77     AutoLock(const AutoLock&);
78     AutoLock& operator=(const AutoLock&);
79   };
80 
81   // MMap-based memory allocator for fixed-sized items.
82   //
83   // IMPORTANT: This must be POD-struct compatible, which means:
84   //    - No constructor or destructor.
85   //    - No virtual methods.
86   //
87   // This allocates large blocks of memory, called 'slabs' that can contain
88   // several items of the same size. A slab contains an array of item slots,
89   // followed by a pointer, used to put all slabs in a single linked list.
90   class PageBasedAllocator {
91   public:
92     // Used to initialize this allocator to hold items of type |T|.
93     template <typename T>
Init()94     void Init() {
95       InitExplicit(sizeof(T), __alignof__(T));
96     }
97 
98     // Used to initialize this instance to hold items of |item_size| bytes,
99     // with alignment |align_size|.
InitExplicit(size_t item_size,size_t align_size)100     void InitExplicit(size_t item_size, size_t align_size) {
101       const size_t ptr_size = sizeof(void*);
102       if (align_size < ptr_size)
103         align_size = ptr_size;
104       item_size_ = (item_size + align_size - 1) & ~(align_size - 1);
105       slab_next_offset_ = kSlabSize - ptr_size;
106       item_slab_count_ = slab_next_offset_ / item_size_;
107 
108       pthread_mutex_init(&lock_, NULL);
109       free_items_ = NULL;
110       slab_list_ = NULL;
111     }
112 
113     // Call this to deallocate this instance. This releases all pages directly.
114     // Ensure that all items are freed first, or bad things could happen.
Deinit()115     void Deinit() {
116       pthread_mutex_lock(&lock_);
117       while (slab_list_) {
118         void* slab = slab_list_;
119         void* next_slab = *(void**)((char*)slab + slab_next_offset_);
120         slab_list_ = next_slab;
121         ::munmap(slab, PAGE_SIZE);
122       }
123       pthread_mutex_unlock(&lock_);
124       pthread_mutex_destroy(&lock_);
125     }
126 
127     // Allocate a new item, or NULL in case of failure.
Alloc()128     void* Alloc() {
129       AutoLock lock(lock_);
130 
131       if (!free_items_ && !AllocateSlab())
132         return NULL;
133 
134       FreeItem* item = free_items_;
135       free_items_ = item->next;
136       ::memset(item, 0, item_size_);
137       return item;
138     }
139 
Release(void * obj)140     void Release(void* obj) {
141       if (!obj)
142         return;
143 
144       AutoLock lock(lock_);
145       FreeItem* item = reinterpret_cast<FreeItem*>(obj);
146       item->next = free_items_;
147       free_items_ = item;
148     }
149 
150   private:
151     static const size_t kSlabSize = PAGE_SIZE;
152 
AllocateSlab()153     bool AllocateSlab() {
154       // No more free items, allocate a new slab with mmap().
155       void* new_slab = mmap(NULL, kSlabSize, PROT_READ|PROT_WRITE,
156                             MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
157       if (new_slab == MAP_FAILED)
158         return false;
159 
160       // Prepend to the slab list.
161       *((void**)((char*)new_slab + slab_next_offset_)) = slab_list_;
162       slab_list_ = new_slab;
163 
164       // Put all item slots in the new slab into the free item list.
165       FreeItem** pparent = &free_items_;
166       FreeItem* item = reinterpret_cast<FreeItem*>(new_slab);
167       for (size_t n = 0; n < item_slab_count_; ++n) {
168         *pparent = item;
169         pparent = &item->next;
170         item = reinterpret_cast<FreeItem*>((char*)item + item_size_);
171       }
172       *pparent = NULL;
173 
174       // Done.
175       return true;
176     }
177 
178     struct FreeItem {
179       FreeItem* next;
180     };
181 
182     size_t item_size_;         // size of each item in bytes.
183     size_t item_slab_count_;   // number of items in each slab.
184     size_t slab_next_offset_;  // offset of pointer to next slab in list.
185     pthread_mutex_t lock_;     // mutex synchronizing access to data below.
186     void* slab_list_;          // Linked list of slabs.
187     FreeItem* free_items_;     // Linked list of free items.
188   };
189 
190   // Technical note:
191   // Use a pthread_key_t to hold the key used to store our thread-specific
192   // __cxa_eh_globals objects. The key is created and destroyed through
193   // a static C++ object.
194   //
195 
196   // Due to a bug in the dynamic linker that was only fixed in Froyo, the
197   // static C++ destructor may be called with a value of NULL for the
198   // 'this' pointer. As such, any attempt to access any field in the
199   // object there will result in a crash. To work-around this, store
200   // the members of CxaThreadKey as static variables outside of the
201   // C++ object.
202   static pthread_key_t __cxa_thread_key;
203   static PageBasedAllocator __cxa_eh_globals_allocator;
204 
205   class CxaThreadKey {
206   public:
207     // Called at program initialization time, or when the shared library
208     // is loaded through dlopen().
CxaThreadKey()209     CxaThreadKey() {
210       if (pthread_key_create(&__cxa_thread_key, freeObject) != 0)
211         __gabixx::__fatal_error("Can't allocate C++ runtime pthread_key_t");
212       __cxa_eh_globals_allocator.Init<__cxa_eh_globals>();
213     }
214 
215     // Called at program exit time, or when the shared library is
216     // unloaded through dlclose(). See note above.
~CxaThreadKey()217     ~CxaThreadKey() {
218       __cxa_eh_globals_allocator.Deinit();
219       pthread_key_delete(__cxa_thread_key);
220     }
221 
getFast()222     static __cxa_eh_globals* getFast() {
223       void* obj = pthread_getspecific(__cxa_thread_key);
224       return reinterpret_cast<__cxa_eh_globals*>(obj);
225     }
226 
getSlow()227     static __cxa_eh_globals* getSlow() {
228       void* obj = pthread_getspecific(__cxa_thread_key);
229       if (obj == NULL) {
230         // malloc() cannot be used here because this method is sometimes
231         // called from malloc() on Android, and this would dead-lock.
232         //
233         // More specifically, if the libc.debug.malloc system property is not 0
234         // on a userdebug or eng build of the platform, malloc() will call
235         // backtrace() to record stack traces of allocation. On ARM, this
236         // forces an unwinding operation which will call this function at
237         // some point.
238         obj = __cxa_eh_globals_allocator.Alloc();
239         if (!obj) {
240           // Shouldn't happen, but better be safe than sorry.
241           __gabixx::__fatal_error(
242               "Can't allocate thread-specific C++ runtime info block.");
243         }
244         pthread_setspecific(__cxa_thread_key, obj);
245       }
246       return reinterpret_cast<__cxa_eh_globals*>(obj);
247     }
248 
249   private:
250     // Called when a thread is destroyed.
freeObject(void * obj)251     static void freeObject(void* obj) {
252       __cxa_eh_globals_allocator.Release(obj);
253     }
254 
255   };
256 
257   // The single static instance, this forces the compiler to register
258   // a constructor and destructor for this object in the final library
259   // file. They handle the pthread_key_t allocation/deallocation.
260   static CxaThreadKey instance;
261 
throwException(__cxa_exception * header)262   _GABIXX_NORETURN void throwException(__cxa_exception *header) {
263     __cxa_eh_globals* globals = __cxa_get_globals();
264     header->unexpectedHandler = std::get_unexpected();
265     header->terminateHandler = std::get_terminate();
266     globals->uncaughtExceptions += 1;
267 
268     _Unwind_RaiseException(&header->unwindHeader);
269 
270     // Should not be here
271     call_terminate(&header->unwindHeader);
272   }
273 
274 } // anonymous namespace
275 
276 
277 namespace __cxxabiv1 {
~__shim_type_info()278   __shim_type_info::~__shim_type_info() {
279 }  // namespace __cxxabiv1
280 
__cxa_pure_virtual()281   extern "C" void __cxa_pure_virtual() {
282     __gabixx::__fatal_error("Pure virtual function called!");
283   }
284 
__cxa_deleted_virtual()285   extern "C" void __cxa_deleted_virtual() {
286     __gabixx::__fatal_error("Deleted virtual function called!");
287   }
288 
__cxa_get_globals()289   extern "C" __cxa_eh_globals* __cxa_get_globals() _GABIXX_NOEXCEPT {
290     return CxaThreadKey::getSlow();
291   }
292 
__cxa_get_globals_fast()293   extern "C" __cxa_eh_globals* __cxa_get_globals_fast() _GABIXX_NOEXCEPT {
294     return CxaThreadKey::getFast();
295   }
296 
__cxa_allocate_exception(size_t thrown_size)297   extern "C" void *__cxa_allocate_exception(size_t thrown_size) _GABIXX_NOEXCEPT {
298     size_t size = thrown_size + sizeof(__cxa_exception);
299     __cxa_exception *buffer = static_cast<__cxa_exception*>(memalign(__alignof__(__cxa_exception), size));
300     if (!buffer) {
301       // Since Android uses memory-overcommit, we enter here only when
302       // the exception object is VERY large. This will propably never happen.
303       // Therefore, we decide to use no emergency spaces.
304       __gabixx::__fatal_error("Not enough memory to allocate exception!");
305     }
306 
307     ::memset(buffer, 0, sizeof(__cxa_exception));
308     return buffer + 1;
309   }
310 
__cxa_free_exception(void * thrown_exception)311   extern "C" void __cxa_free_exception(void* thrown_exception) _GABIXX_NOEXCEPT {
312     __cxa_exception *exc = static_cast<__cxa_exception*>(thrown_exception)-1;
313 
314     if (exc->exceptionDestructor) {
315       try {
316         exc->exceptionDestructor(thrown_exception);
317       } catch (...) {
318         __gabixx::__fatal_error("Exception destructor has thrown!");
319       }
320     }
321 
322     free(exc);
323   }
324 
__cxa_throw(void * thrown_exc,std::type_info * tinfo,void (* dest)(void *))325   extern "C" void __cxa_throw(void* thrown_exc,
326                               std::type_info* tinfo,
327                               void (*dest)(void*)) {
328     __cxa_exception* header = static_cast<__cxa_exception*>(thrown_exc)-1;
329     header->exceptionType = tinfo;
330     header->exceptionDestructor = dest;
331 
332     header->unwindHeader.exception_class = __gxx_exception_class;
333     header->unwindHeader.exception_cleanup = defaultExceptionCleanupFunc;
334 
335     throwException(header);
336   }
337 
__cxa_rethrow()338   extern "C" void __cxa_rethrow() {
339     __cxa_eh_globals *globals = __cxa_get_globals();
340     __cxa_exception* header = globals->caughtExceptions;
341     _Unwind_Exception* exception = &header->unwindHeader;
342     if (!header) {
343       __gabixx::__fatal_error(
344           "Attempting to rethrow an exception that doesn't exist!");
345     }
346 
347     if (isOurCxxException(exception->exception_class)) {
348       header->handlerCount = -header->handlerCount; // Set rethrow flag
349     } else {
350       globals->caughtExceptions = 0;
351     }
352 
353     throwException(header);
354   }
355 
__cxa_begin_catch(void * exc)356   extern "C" void* __cxa_begin_catch(void* exc) _GABIXX_NOEXCEPT {
357     _Unwind_Exception *exception = static_cast<_Unwind_Exception*>(exc);
358     __cxa_exception* header = reinterpret_cast<__cxa_exception*>(exception+1)-1;
359     __cxa_eh_globals* globals = __cxa_get_globals();
360 
361     if (!isOurCxxException(exception->exception_class)) {
362       if (globals->caughtExceptions) {
363         __gabixx::__fatal_error("Can't handle non-C++ exception!");
364       }
365     }
366 
367     // Check rethrow flag
368     header->handlerCount = (header->handlerCount < 0) ?
369       (-header->handlerCount+1) : (header->handlerCount+1);
370 
371     if (header != globals->caughtExceptions) {
372       header->nextException = globals->caughtExceptions;
373       globals->caughtExceptions = header;
374     }
375     globals->uncaughtExceptions -= 1;
376 
377     return header->adjustedPtr;
378   }
379 
__cxa_end_catch()380   extern "C" void __cxa_end_catch() _GABIXX_NOEXCEPT {
381     __cxa_eh_globals *globals = __cxa_get_globals_fast();
382     __cxa_exception *header = globals->caughtExceptions;
383     _Unwind_Exception* exception = &header->unwindHeader;
384 
385     if (!header) {
386       return;
387     }
388 
389     if (!isOurCxxException(exception->exception_class)) {
390       globals->caughtExceptions = 0;
391       _Unwind_DeleteException(exception);
392       return;
393     }
394 
395     int count = header->handlerCount;
396     if (count < 0) { // Rethrow
397       if (++count == 0) {
398         globals->caughtExceptions = header->nextException;
399       }
400     } else if (--count == 0) {
401       globals->caughtExceptions = header->nextException;
402       __cxa_free_exception(header+1);
403       return;
404     } else if (count < 0) {
405       __gabixx::__fatal_error("Internal error during exception handling!");
406     }
407 
408     header->handlerCount = count;
409   }
410 
__cxa_get_exception_ptr(void * exceptionObject)411   extern "C" void* __cxa_get_exception_ptr(void* exceptionObject) _GABIXX_NOEXCEPT {
412     __cxa_exception* header =
413       reinterpret_cast<__cxa_exception*>(
414         reinterpret_cast<_Unwind_Exception *>(exceptionObject)+1)-1;
415     return header->adjustedPtr;
416   }
417 
__cxa_uncaught_exception()418   extern "C" bool __cxa_uncaught_exception() _GABIXX_NOEXCEPT {
419     __cxa_eh_globals* globals = __cxa_get_globals();
420     if (globals == NULL)
421       return false;
422     return globals->uncaughtExceptions == 0;
423   }
424 
__cxa_decrement_exception_refcount(void * exceptionObject)425   extern "C" void __cxa_decrement_exception_refcount(void* exceptionObject)
426       _GABIXX_NOEXCEPT {
427     if (exceptionObject != NULL)
428     {
429       __cxa_exception* header =
430           reinterpret_cast<__cxa_exception*>(exceptionObject)-1;
431       if (__sync_sub_and_fetch(&header->referenceCount, 1) == 0)
432         __cxa_free_exception(exceptionObject);
433     }
434   }
435 
__cxa_increment_exception_refcount(void * exceptionObject)436   extern "C" void __cxa_increment_exception_refcount(void* exceptionObject)
437       _GABIXX_NOEXCEPT {
438     if (exceptionObject != NULL)
439     {
440       __cxa_exception* header =
441           reinterpret_cast<__cxa_exception*>(exceptionObject)-1;
442       __sync_add_and_fetch(&header->referenceCount, 1);
443     }
444   }
445 
__cxa_rethrow_primary_exception(void * primary_exception)446   extern "C" void __cxa_rethrow_primary_exception(void* primary_exception) {
447 #if defined(LIBCXXABI)
448 // Only warn if we're building for libcxx since other libraries do not use
449 // this.
450 #warning "not implemented."
451 #endif /* defined(LIBCXXABI) */
452   }
453 
__cxa_current_primary_exception()454   extern "C" void* __cxa_current_primary_exception() _GABIXX_NOEXCEPT {
455 #if defined(LIBCXXABI)
456 // Only warn if we're building for libcxx since other libraries do not use
457 // this.
458 #warning "not implemented."
459 #endif /* defined(LIBCXXABI) */
460     return NULL;
461   }
462 
463 } // namespace __cxxabiv1
464