Merge "Remove __overloadable/__RENAME_CLANG"
diff --git a/README.md b/README.md
index f0be759..a6cf467 100644
--- a/README.md
+++ b/README.md
@@ -144,8 +144,23 @@
 </pre>
 
 
-Adding system calls
--------------------
+Adding libc wrappers for system calls
+-------------------------------------
+
+The first question you should ask is "should I add a libc wrapper for
+this system call?". The answer is usually "no".
+
+The answer is "yes" if the system call is part of the POSIX standard.
+
+The answer is probably "yes" if the system call has a wrapper in at
+least one other C library.
+
+The answer may be "yes" if the system call has three/four distinct
+users in different projects, and there isn't a more specific library
+that would make more sense as the place to add the wrapper.
+
+In all other cases, you should use
+[syscall(3)](http://man7.org/linux/man-pages/man2/syscall.2.html) instead.
 
 Adding a system call usually involves:
 
@@ -157,7 +172,8 @@
      kernel uapi header files, in which case you just need to make sure that
      the appropriate POSIX header file in libc/include/ includes the
      relevant file or files.
-  4. Add function declarations to the appropriate header file.
+  4. Add function declarations to the appropriate header file. Don't forget
+     to include the appropriate `__INTRODUCED_IN()`.
   5. Add the function name to the correct section in libc/libc.map.txt and
      run `./libc/tools/genversion-scripts.py`.
   6. Add at least basic tests. Even a test that deliberately supplies
diff --git a/libc/arch-arm/bionic/exidx_static.c b/libc/arch-arm/bionic/exidx_static.c
index 1686d6a..ef3745f 100644
--- a/libc/arch-arm/bionic/exidx_static.c
+++ b/libc/arch-arm/bionic/exidx_static.c
@@ -35,10 +35,15 @@
  * EXIDX section.
  */
 
-extern unsigned __exidx_end;
-extern unsigned __exidx_start;
+struct exidx_entry {
+  uint32_t key;
+  uint32_t value;
+};
+
+extern struct exidx_entry __exidx_end;
+extern struct exidx_entry __exidx_start;
 
 _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr pc __attribute__((unused)), int* pcount) {
-  *pcount = (&__exidx_end - &__exidx_start) / 8;
+  *pcount = (&__exidx_end - &__exidx_start);
   return (_Unwind_Ptr)&__exidx_start;
 }
diff --git a/libc/arch-arm/bionic/setjmp.S b/libc/arch-arm/bionic/setjmp.S
index 30e7e23..5fbcaf3 100644
--- a/libc/arch-arm/bionic/setjmp.S
+++ b/libc/arch-arm/bionic/setjmp.S
@@ -58,17 +58,15 @@
 // 0      sigflag/cookie  setjmp cookie in top 31 bits, signal mask flag in low bit
 // 1      sigmask         64-bit signal mask (not used with _setjmp / _longjmp)
 // 2      "               "
-// 3      reserved        (unused to allow float_base to be maximally aligned)
+// 3      reserved        (unused to allow float_base to be maximally aligned;
+//                        this avoids software emulation of unaligned loads/stores)
 // 4      float_base      base of float registers (d8 to d15)
 // 20     float_state     floating-point status and control register
 // 21     core_base       base of core registers (r4-r11, r13-r14)
-// 31     checksum        checksum of all of the core registers, to give better error messages.
+// 31     checksum        checksum of all of the core registers, to give better error messages
 // 32     reserved        reserved entries (room to grow)
-// 64
-//
-// NOTE: float_base must be at an even word index, since the
-//       FP registers will be loaded/stored with instructions
-//       that expect 8-byte alignment.
+// ...
+// 63     "               "
 
 #define _JB_SIGFLAG     0
 #define _JB_SIGMASK     (_JB_SIGFLAG + 1)
diff --git a/libc/arch-common/bionic/crtbegin.c b/libc/arch-common/bionic/crtbegin.c
index 31ad621..c4d2a5a 100644
--- a/libc/arch-common/bionic/crtbegin.c
+++ b/libc/arch-common/bionic/crtbegin.c
@@ -53,7 +53,7 @@
 #elif defined(__arm__)
 __asm__(PRE "mov r0,sp; b _start_main" POST);
 #elif defined(__i386__)
-__asm__(PRE "movl %esp,%eax; andl $~0xf,%esp; pushl %eax; calll _start_main" POST);
+__asm__(PRE "movl %esp,%eax; andl $~0xf,%esp; subl $12,%esp; pushl %eax; calll _start_main" POST);
 #elif defined(__x86_64__)
 __asm__(PRE "movq %rsp,%rdi; andq $~0xf,%rsp; callq _start_main" POST);
 #else
diff --git a/libc/arch-common/bionic/pthread_atfork.h b/libc/arch-common/bionic/pthread_atfork.h
index c6a33ff..742d078 100644
--- a/libc/arch-common/bionic/pthread_atfork.h
+++ b/libc/arch-common/bionic/pthread_atfork.h
@@ -16,9 +16,9 @@
 
 #include <android/api-level.h>
 
-// __register_atfork wasn't available until android-23. We need to build a
-// pre-23 and 23+ version of crtbegin.
-#if __ANDROID_API__ >= __ANDROID_API_M__
+// __register_atfork wasn't available until android-23. When using libc.a, we're
+// using the latest library regardless of target API level.
+#if defined(_FORCE_CRT_ATFORK) || __ANDROID_API__ >= __ANDROID_API_M__
 
 extern void* __dso_handle;
 
diff --git a/libc/bionic/bionic_arc4random.cpp b/libc/bionic/bionic_arc4random.cpp
index 391eb0c..fa2617f 100644
--- a/libc/bionic/bionic_arc4random.cpp
+++ b/libc/bionic/bionic_arc4random.cpp
@@ -28,8 +28,6 @@
 
 #include "private/bionic_arc4random.h"
 
-#include <errno.h>
-#include <stdatomic.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/auxv.h>
@@ -39,15 +37,12 @@
 
 #include "private/KernelArgumentBlock.h"
 
-bool __libc_arc4random_has_unlimited_entropy() {
-  static bool have_urandom = access("/dev/urandom", R_OK) == 0;
-  return have_urandom;
-}
-
 void __libc_safe_arc4random_buf(void* buf, size_t n, KernelArgumentBlock& args) {
-  // Only call arc4random_buf once we `have_urandom', since in getentropy_getrandom we may fallback
-  // to use /dev/urandom, if the kernel entropy pool hasn't been initialized or not enough bytes
-  if (__libc_arc4random_has_unlimited_entropy()) {
+  // Only call arc4random_buf once we have `/dev/urandom` because getentropy(3)
+  // will fall back to using `/dev/urandom` if getrandom(2) fails, and abort if
+  // if can't use `/dev/urandom`.
+  static bool have_urandom = access("/dev/urandom", R_OK) == 0;
+  if (have_urandom) {
     arc4random_buf(buf, n);
     return;
   }
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 1f201d1..940c418 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -69,6 +69,7 @@
     Malloc(malloc_disable),
     Malloc(malloc_enable),
     Malloc(mallopt),
+    Malloc(aligned_alloc),
   };
 
 // In a VM process, this is set to 1 after fork()ing out of zygote.
@@ -142,6 +143,14 @@
   return Malloc(posix_memalign)(memptr, alignment, size);
 }
 
+extern "C" void* aligned_alloc(size_t alignment, size_t size) {
+  auto _aligned_alloc = __libc_globals->malloc_dispatch.aligned_alloc;
+  if (__predict_false(_aligned_alloc != nullptr)) {
+    return _aligned_alloc(alignment, size);
+  }
+  return Malloc(aligned_alloc)(alignment, size);
+}
+
 extern "C" void* realloc(void* old_mem, size_t bytes) {
   auto _realloc = __libc_globals->malloc_dispatch.realloc;
   if (__predict_false(_realloc != nullptr)) {
@@ -276,6 +285,10 @@
                                                prefix, "posix_memalign")) {
     return false;
   }
+  if (!InitMallocFunction<MallocAlignedAlloc>(malloc_impl_handler, &table->aligned_alloc,
+                                              prefix, "aligned_alloc")) {
+    return false;
+  }
   if (!InitMallocFunction<MallocRealloc>(malloc_impl_handler, &table->realloc,
                                          prefix, "realloc")) {
     return false;
diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp
index e5a7d5f..19a08e6 100644
--- a/libc/bionic/sigaction.cpp
+++ b/libc/bionic/sigaction.cpp
@@ -81,7 +81,6 @@
 #else
 
 extern "C" int __rt_sigaction(int, const struct sigaction64*, struct sigaction64*, size_t);
-extern "C" int __sigaction(int, const struct sigaction*, struct sigaction*);
 
 int sigaction(int signal, const struct sigaction* bionic_new, struct sigaction* bionic_old) {
   // The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t,
@@ -91,6 +90,9 @@
     kernel_new = {};
     kernel_new.sa_flags = bionic_new->sa_flags;
     kernel_new.sa_handler = bionic_new->sa_handler;
+#if defined(SA_RESTORER)
+    kernel_new.sa_restorer = bionic_new->sa_restorer;
+#endif
     memcpy(&kernel_new.sa_mask, &bionic_new->sa_mask, sizeof(bionic_new->sa_mask));
   }
 
@@ -100,6 +102,9 @@
     *bionic_old = {};
     bionic_old->sa_flags = kernel_old.sa_flags;
     bionic_old->sa_handler = kernel_old.sa_handler;
+#if defined(SA_RESTORER)
+    bionic_old->sa_restorer = kernel_old.sa_restorer;
+#endif
     memcpy(&bionic_old->sa_mask, &kernel_old.sa_mask, sizeof(bionic_old->sa_mask));
   }
   return result;
@@ -109,10 +114,12 @@
   struct sigaction64 kernel_new;
   if (bionic_new) {
     kernel_new = *bionic_new;
+#if defined(SA_RESTORER)
     if (!(kernel_new.sa_flags & SA_RESTORER)) {
       kernel_new.sa_flags |= SA_RESTORER;
       kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
     }
+#endif
   }
 
   return __rt_sigaction(signal,
diff --git a/libc/include/android/legacy_stdlib_inlines.h b/libc/include/android/legacy_stdlib_inlines.h
index 4896d2e..439b486 100644
--- a/libc/include/android/legacy_stdlib_inlines.h
+++ b/libc/include/android/legacy_stdlib_inlines.h
@@ -45,7 +45,7 @@
 
 __END_DECLS
 
-#endif
+#endif  /* __ANDROID_API__ < __ANDROID_API_K__ */
 
 #if __ANDROID_API__ < __ANDROID_API_L__
 
@@ -83,5 +83,29 @@
 
 __END_DECLS
 
-#endif
+#endif  /* __ANDROID_API__ < __ANDROID_API_L__ */
+
+#if __ANDROID_API__ < __ANDROID_API_O__
+
+#include <stdlib.h>
+#include <xlocale.h>
+
+__BEGIN_DECLS
+
+static __inline double strtod_l(const char* __s, char** __end_ptr, locale_t __l) {
+  return strtod(__s, __end_ptr);
+}
+
+static __inline float strtof_l(const char* __s, char** __end_ptr, locale_t __l) {
+  return strtof(__s, __end_ptr);
+}
+
+static __inline long strtol_l(const char* __s, char** __end_ptr, int __base, locale_t __l) {
+  return strtol(__s, __end_ptr, __base);
+}
+
+__END_DECLS
+
+#endif  /* __ANDROID_API__ < __ANDROID_API_O__ */
+
 #endif /* _ANDROID_LEGACY_STDLIB_INLINES_H_ */
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index 944d72b..ef97538 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -79,6 +79,8 @@
 
 int posix_memalign(void** __memptr, size_t __alignment, size_t __size) __INTRODUCED_IN(16);
 
+void* aligned_alloc(size_t __alignment, size_t __size) __INTRODUCED_IN(28);
+
 double strtod(const char* __s, char** __end_ptr);
 long double strtold(const char* __s, char** __end_ptr) __RENAME_LDBL(strtod, 3, 21);
 
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 839c406..a7977eb 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1322,6 +1322,7 @@
   global:
     __freading;
     __fwriting;
+    aligned_alloc;
     endhostent;
     endnetent;
     endprotoent;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index a39a233..1cae22b 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1242,6 +1242,7 @@
   global:
     __freading;
     __fwriting;
+    aligned_alloc;
     endhostent;
     endnetent;
     endprotoent;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index b3bfa8a..1188a85 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1347,6 +1347,7 @@
   global:
     __freading;
     __fwriting;
+    aligned_alloc;
     endhostent;
     endnetent;
     endprotoent;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 2a93132..3d95079 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1306,6 +1306,7 @@
   global:
     __freading;
     __fwriting;
+    aligned_alloc;
     endhostent;
     endnetent;
     endprotoent;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index a39a233..1cae22b 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1242,6 +1242,7 @@
   global:
     __freading;
     __fwriting;
+    aligned_alloc;
     endhostent;
     endnetent;
     endprotoent;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index d2e7399..bcb5feb 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1304,6 +1304,7 @@
   global:
     __freading;
     __fwriting;
+    aligned_alloc;
     endhostent;
     endnetent;
     endprotoent;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index a39a233..1cae22b 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1242,6 +1242,7 @@
   global:
     __freading;
     __fwriting;
+    aligned_alloc;
     endhostent;
     endnetent;
     endprotoent;
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index b7a12a5..69d0648 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -23,6 +23,7 @@
 * `realloc`
 * `posix_memalign`
 * `memalign`
+* `aligned_alloc`
 * `malloc_usable_size`
 
 On 32 bit systems, these two deprecated functions are also replaced:
@@ -324,6 +325,10 @@
 
 **THREAD\_ID**: memalign pointer alignment size
 
+pointer = aligned\_alloc(alignment, size)
+
+**THREAD\_ID**: memalign pointer alignment size
+
 posix\_memalign(&pointer, alignment, size)
 
 **THREAD\_ID**: memalign pointer alignment size
diff --git a/libc/malloc_debug/RecordData.cpp b/libc/malloc_debug/RecordData.cpp
index 55d9943..8e9c671 100644
--- a/libc/malloc_debug/RecordData.cpp
+++ b/libc/malloc_debug/RecordData.cpp
@@ -86,7 +86,7 @@
                                      old_pointer_, size_);
 }
 
-// posix_memalign, memalgin, pvalloc, valloc all recorded with this class.
+// aligned_alloc, posix_memalign, memalign, pvalloc, valloc all recorded with this class.
 MemalignEntry::MemalignEntry(void* pointer, size_t size, size_t alignment)
     : MallocEntry(pointer, size), alignment_(alignment) {
 }
diff --git a/libc/malloc_debug/RecordData.h b/libc/malloc_debug/RecordData.h
index ccabac2..97ad813 100644
--- a/libc/malloc_debug/RecordData.h
+++ b/libc/malloc_debug/RecordData.h
@@ -129,7 +129,7 @@
   DISALLOW_COPY_AND_ASSIGN(ReallocEntry);
 };
 
-// posix_memalign, memalign, pvalloc, valloc all recorded with this class.
+// aligned_alloc, posix_memalign, memalign, pvalloc, valloc all recorded with this class.
 class MemalignEntry : public MallocEntry {
  public:
   MemalignEntry(void* pointer, size_t size, size_t alignment);
diff --git a/libc/malloc_debug/exported32.map b/libc/malloc_debug/exported32.map
index e92a7cf..78a6990 100644
--- a/libc/malloc_debug/exported32.map
+++ b/libc/malloc_debug/exported32.map
@@ -1,5 +1,6 @@
 LIBC_MALLOC_DEBUG {
   global:
+    debug_aligned_alloc;
     debug_calloc;
     debug_dump_heap;
     debug_finalize;
diff --git a/libc/malloc_debug/exported64.map b/libc/malloc_debug/exported64.map
index 94104b0..2bfc38b 100644
--- a/libc/malloc_debug/exported64.map
+++ b/libc/malloc_debug/exported64.map
@@ -1,5 +1,6 @@
 LIBC_MALLOC_DEBUG {
   global:
+    debug_aligned_alloc;
     debug_calloc;
     debug_dump_heap;
     debug_finalize;
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index a2ada2f..ecfbd71 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -77,6 +77,7 @@
 size_t debug_malloc_usable_size(void* pointer);
 void* debug_malloc(size_t size);
 void debug_free(void* pointer);
+void* debug_aligned_alloc(size_t alignment, size_t size);
 void* debug_memalign(size_t alignment, size_t bytes);
 void* debug_realloc(void* pointer, size_t bytes);
 void* debug_calloc(size_t nmemb, size_t bytes);
@@ -669,6 +670,17 @@
   return g_dispatch->mallopt(param, value);
 }
 
+void* debug_aligned_alloc(size_t alignment, size_t size) {
+  if (DebugCallsDisabled()) {
+    return g_dispatch->aligned_alloc(alignment, size);
+  }
+  if (!powerof2(alignment)) {
+    errno = EINVAL;
+    return nullptr;
+  }
+  return debug_memalign(alignment, size);
+}
+
 int debug_posix_memalign(void** memptr, size_t alignment, size_t size) {
   if (DebugCallsDisabled()) {
     return g_dispatch->posix_memalign(memptr, alignment, size);
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 4e90668..0e4a7d8 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -54,6 +54,7 @@
 void* debug_realloc(void*, size_t);
 int debug_posix_memalign(void**, size_t, size_t);
 void* debug_memalign(size_t, size_t);
+void* debug_aligned_alloc(size_t, size_t);
 size_t debug_malloc_usable_size(void*);
 void debug_get_malloc_leak_info(uint8_t**, size_t*, size_t*, size_t*, size_t*);
 void debug_free_malloc_leak_info(uint8_t*);
@@ -136,6 +137,7 @@
   nullptr,
   nullptr,
   mallopt,
+  aligned_alloc,
 };
 
 void VerifyAllocCalls(bool backtrace_enabled) {
@@ -308,6 +310,11 @@
   ASSERT_LE(1039U, debug_malloc_usable_size(pointer));
   debug_free(pointer);
 
+  pointer = debug_aligned_alloc(128, 15);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_LE(1039U, debug_malloc_usable_size(pointer));
+  debug_free(pointer);
+
   pointer = debug_realloc(nullptr, 30);
   ASSERT_TRUE(pointer != nullptr);
   ASSERT_LE(1054U, debug_malloc_usable_size(pointer));
@@ -1772,6 +1779,12 @@
   debug_free(pointer);
   expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
 
+  pointer = debug_aligned_alloc(32, 50);
+  ASSERT_TRUE(pointer != nullptr);
+  expected += android::base::StringPrintf("%d: memalign %p 32 50\n", getpid(), pointer);
+  debug_free(pointer);
+  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+
   ASSERT_EQ(0, debug_posix_memalign(&pointer, 32, 50));
   ASSERT_TRUE(pointer != nullptr);
   expected += android::base::StringPrintf("%d: memalign %p 32 50\n", getpid(), pointer);
diff --git a/libc/private/bionic_arc4random.h b/libc/private/bionic_arc4random.h
index b51f818..0e9376e 100644
--- a/libc/private/bionic_arc4random.h
+++ b/libc/private/bionic_arc4random.h
@@ -33,18 +33,11 @@
 
 #include "private/KernelArgumentBlock.h"
 
-/*
- * arc4random aborts if it's unable to fetch entropy, which is always the case
- * for init on devices without getrandom(2), since /dev/random hasn't been
- * created yet. Provide a wrapper function that falls back to AT_RANDOM if
- * we don't have getrandom and /dev/urandom is missing.
- */
+// arc4random(3) aborts if it's unable to fetch entropy, which is always
+// the case for init on devices. GCE kernels have a workaround to ensure
+// sufficient entropy during early boot, but no device kernels do. This
+// wrapper falls back to AT_RANDOM if the kernel doesn't have enough
+// entropy for getrandom(2) or /dev/urandom.
 void __libc_safe_arc4random_buf(void* buf, size_t n, KernelArgumentBlock& args);
 
-/*
- * Return true if libc has an unlimited entropy source (something other than
- * AT_RANDOM), and arc4random* calls will always succeed.
- */
-bool __libc_arc4random_has_unlimited_entropy();
-
 #endif
diff --git a/libc/private/bionic_malloc_dispatch.h b/libc/private/bionic_malloc_dispatch.h
index cdae466..0dce03d 100644
--- a/libc/private/bionic_malloc_dispatch.h
+++ b/libc/private/bionic_malloc_dispatch.h
@@ -46,6 +46,7 @@
 typedef void (*MallocMallocDisable)();
 typedef void (*MallocMallocEnable)();
 typedef int (*MallocMallopt)(int, int);
+typedef void* (*MallocAlignedAlloc)(size_t, size_t);
 
 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
 typedef void* (*MallocPvalloc)(size_t);
@@ -71,6 +72,7 @@
   MallocMallocDisable malloc_disable;
   MallocMallocEnable malloc_enable;
   MallocMallopt mallopt;
+  MallocAlignedAlloc aligned_alloc;
 } __attribute__((aligned(32)));
 
 #endif
diff --git a/linker/linker_memory.cpp b/linker/linker_memory.cpp
index 472c4e8..6a54c13 100644
--- a/linker/linker_memory.cpp
+++ b/linker/linker_memory.cpp
@@ -32,27 +32,28 @@
 #include <sys/cdefs.h>
 #include <unistd.h>
 
+#include <atomic>
+
 #include <async_safe/log.h>
 
 static LinkerMemoryAllocator g_linker_allocator;
-static pid_t fallback_tid = 0;
+static std::atomic<pid_t> fallback_tid(0);
 
 // Used by libdebuggerd_handler to switch allocators during a crash dump, in
 // case the linker heap is corrupted. Do not use this function.
-extern "C" void __linker_enable_fallback_allocator() {
-  if (fallback_tid != 0) {
-    async_safe_fatal("attempted to use currently-in-use fallback allocator");
-  }
-
-  fallback_tid = gettid();
+extern "C" bool __linker_enable_fallback_allocator() {
+  pid_t expected = 0;
+  return fallback_tid.compare_exchange_strong(expected, gettid());
 }
 
 extern "C" void __linker_disable_fallback_allocator() {
-  if (fallback_tid == 0) {
+  pid_t previous = fallback_tid.exchange(0);
+  if (previous == 0) {
     async_safe_fatal("attempted to disable unused fallback allocator");
+  } else if (previous != gettid()) {
+    async_safe_fatal("attempted to disable fallback allocator in use by another thread (%d)",
+                     previous);
   }
-
-  fallback_tid = 0;
 }
 
 static LinkerMemoryAllocator& get_fallback_allocator() {
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 87a918f..2b414e5 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -285,6 +285,7 @@
   ASSERT_TRUE(original_sa.sa_handler == NULL);
   ASSERT_TRUE(original_sa.sa_sigaction == NULL);
   ASSERT_EQ(0U, original_sa.sa_flags & ~sa_restorer);
+  ASSERT_EQ(bool(original_sa.sa_flags & sa_restorer), bool(original_sa.sa_restorer));
 
   // Set a traditional sa_handler signal handler.
   auto no_op_signal_handler = [](int) {};
@@ -300,6 +301,7 @@
   ASSERT_TRUE(sa.sa_handler == no_op_signal_handler);
   ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler);
   ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK), sa.sa_flags & ~sa_restorer);
+  ASSERT_EQ(bool(sa.sa_flags & sa_restorer), bool(sa.sa_restorer));
 
   // Set a new-style sa_sigaction signal handler.
   auto no_op_sigaction = [](int, siginfo_t*, void*) {};
@@ -315,6 +317,7 @@
   ASSERT_TRUE(sa.sa_sigaction == no_op_sigaction);
   ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler);
   ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK | SA_SIGINFO), sa.sa_flags & ~sa_restorer);
+  ASSERT_EQ(bool(sa.sa_flags & sa_restorer), bool(sa.sa_restorer));
 
   // Put everything back how it was.
   ASSERT_EQ(0, sigaction_fn(sig, &original_sa, NULL));
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index caa7a85..2fbd937 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -35,6 +35,14 @@
 #include <limits>
 #include <string>
 
+#if defined(__BIONIC__)
+  #define ALIGNED_ALLOC_AVAILABLE 1
+#elif defined(__GLIBC_PREREQ)
+  #if __GLIBC_PREREQ(2, 16)
+    #define ALIGNED_ALLOC_AVAILABLE 1
+  #endif
+#endif
+
 // The random number generator tests all set the seed, get four values, reset the seed and check
 // that they get the first two values repeated, and then reset the seed and check two more values
 // to rule out the possibility that we're just going round a cycle of four values.
@@ -226,6 +234,50 @@
   ASSERT_NE(0, posix_memalign(&ptr, 16, SIZE_MAX));
 }
 
+TEST(stdlib, aligned_alloc_sweep) {
+#if defined(ALIGNED_ALLOC_AVAILABLE)
+  // Verify powers of 2 up to 2048 allocate, and verify that all other
+  // alignment values between the powers of 2 fail.
+  size_t last_align = 1;
+  for (size_t align = 1; align <= 2048; align <<= 1) {
+    // Try all of the non power of 2 values from the last until this value.
+    for (size_t fail_align = last_align + 1; fail_align < align; fail_align++) {
+      ASSERT_TRUE(aligned_alloc(fail_align, 256) == nullptr)
+          << "Unexpected success at align " << fail_align;
+      ASSERT_EQ(EINVAL, errno) << "Unexpected errno at align " << fail_align;
+    }
+    void* ptr = aligned_alloc(align, 256);
+    ASSERT_TRUE(ptr != nullptr) << "Unexpected failure at align " << align;
+    ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+        << "Did not return a valid aligned ptr " << ptr << " expected alignment " << align;
+    free(ptr);
+    last_align = align;
+  }
+#else
+  GTEST_LOG_(INFO) << "This test requires a C library that has aligned_alloc.\n";
+#endif
+}
+
+TEST(stdlib, aligned_alloc_overflow) {
+#if defined(ALIGNED_ALLOC_AVAILABLE)
+  ASSERT_TRUE(aligned_alloc(16, SIZE_MAX) == nullptr);
+#else
+  GTEST_LOG_(INFO) << "This test requires a C library that has aligned_alloc.\n";
+#endif
+}
+
+TEST(stdlib, aligned_alloc_size_not_multiple_of_alignment) {
+#if defined(ALIGNED_ALLOC_AVAILABLE)
+  for (size_t size = 1; size <= 2048; size++) {
+    void* ptr = aligned_alloc(2048, size);
+    ASSERT_TRUE(ptr != nullptr) << "Failed at size " << std::to_string(size);
+    free(ptr);
+  }
+#else
+  GTEST_LOG_(INFO) << "This test requires a C library that has aligned_alloc.\n";
+#endif
+}
+
 TEST(stdlib, realpath__NULL_filename) {
   errno = 0;
   // Work around the compile-time error generated by FORTIFY here.