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
40namespace {
41
42  using namespace __cxxabiv1;
43
44  bool isOurCxxException(uint64_t exc) {
45    // Compatible with GNU
46    return exc == __gxx_exception_class;
47  }
48
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:
67    AutoLock(pthread_mutex_t& lock) : lock_(lock) {
68      pthread_mutex_lock(&lock_);
69    }
70
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>
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|.
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.
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.
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
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
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().
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.
217    ~CxaThreadKey() {
218      __cxa_eh_globals_allocator.Deinit();
219      pthread_key_delete(__cxa_thread_key);
220    }
221
222    static __cxa_eh_globals* getFast() {
223      void* obj = pthread_getspecific(__cxa_thread_key);
224      return reinterpret_cast<__cxa_eh_globals*>(obj);
225    }
226
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.
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
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
277namespace __cxxabiv1 {
278  __shim_type_info::~__shim_type_info() {
279}  // namespace __cxxabiv1
280
281  extern "C" void __cxa_pure_virtual() {
282    __gabixx::__fatal_error("Pure virtual function called!");
283  }
284
285  extern "C" void __cxa_deleted_virtual() {
286    __gabixx::__fatal_error("Deleted virtual function called!");
287  }
288
289  extern "C" __cxa_eh_globals* __cxa_get_globals() _GABIXX_NOEXCEPT {
290    return CxaThreadKey::getSlow();
291  }
292
293  extern "C" __cxa_eh_globals* __cxa_get_globals_fast() _GABIXX_NOEXCEPT {
294    return CxaThreadKey::getFast();
295  }
296
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
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
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
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
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
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
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
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
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
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
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
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