Merge "Refactor pthread_mutex to support 32-bit owner_tid on 64-bit devices."
diff --git a/README.md b/README.md
index 2c42b3b..79bb72a 100644
--- a/README.md
+++ b/README.md
@@ -208,19 +208,17 @@
 The host tests require that you have `lunch`ed either an x86 or x86_64 target.
 
     $ mma
-    # 64-bit tests for 64-bit targets, 32-bit otherwise.
-    $ mm bionic-unit-tests-run-on-host
-    # Only exists for 64-bit targets.
     $ mm bionic-unit-tests-run-on-host32
+    $ mm bionic-unit-tests-run-on-host64  # For 64-bit *targets* only.
 
 ### Against glibc
 
 As a way to check that our tests do in fact test the correct behavior (and not
 just the behavior we think is correct), it is possible to run the tests against
-the host's glibc.
+the host's glibc. The executables are already in your path.
 
     $ mma
-    $ bionic-unit-tests-glibc32 # already in your path
+    $ bionic-unit-tests-glibc32
     $ bionic-unit-tests-glibc64
 
 
diff --git a/libc/Android.mk b/libc/Android.mk
index e438552..0de0fb2 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -1347,9 +1347,6 @@
 LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
 
-# TODO: This is to work around b/19059885. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
-
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
 LOCAL_SRC_FILES := \
     $(libc_arch_dynamic_src_files) \
@@ -1359,8 +1356,10 @@
 
 LOCAL_MODULE := libc
 LOCAL_CLANG := $(use_clang)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_REQUIRED_MODULES := tzdata
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+    $(libc_common_additional_dependencies) \
+    $(LOCAL_PATH)/version_script.txt \
 
 # Leave the symbols in the shared library so that stack unwinders can produce
 # meaningful name resolution.
@@ -1379,11 +1378,17 @@
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 
+# Don't re-export new/delete and friends, even if the compiler really wants to.
+LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
+
 # We'd really like to do this for all architectures, but since this wasn't done
 # before, these symbols must continue to be exported on LP32 for binary
 # compatibility.
 LOCAL_LDFLAGS_64 := -Wl,--exclude-libs,libgcc.a
 
+# TODO: This is to work around b/19059885. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
 $(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_arch_dynamic_src_files))
 # special for arm
@@ -1431,7 +1436,9 @@
 
 LOCAL_MODULE := libc_malloc_debug_leak
 LOCAL_CLANG := $(use_clang)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+    $(libc_common_additional_dependencies) \
+    $(LOCAL_PATH)/version_script.txt \
 
 LOCAL_SHARED_LIBRARIES := libc libdl
 LOCAL_CXX_STL := none
@@ -1442,6 +1449,9 @@
 LOCAL_STATIC_LIBRARIES += libc++abi
 LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
 
+# Don't re-export new/delete and friends, even if the compiler really wants to.
+LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
+
 # Don't install on release build
 LOCAL_MODULE_TAGS := eng debug
 LOCAL_ADDRESS_SANITIZER := false
@@ -1471,12 +1481,17 @@
 
 LOCAL_MODULE := libc_malloc_debug_qemu
 LOCAL_CLANG := $(use_clang)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+    $(libc_common_additional_dependencies) \
+    $(LOCAL_PATH)/version_script.txt \
 
 LOCAL_SHARED_LIBRARIES := libc libdl
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 
+# Don't re-export new/delete and friends, even if the compiler really wants to.
+LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
+
 # Don't install on release build
 LOCAL_MODULE_TAGS := eng debug
 LOCAL_ADDRESS_SANITIZER := false
diff --git a/libc/bionic/libgen.cpp b/libc/bionic/libgen.cpp
index b98f504..2f29d7b 100644
--- a/libc/bionic/libgen.cpp
+++ b/libc/bionic/libgen.cpp
@@ -36,6 +36,9 @@
 
 #include "private/ThreadLocalBuffer.h"
 
+static ThreadLocalBuffer<char, MAXPATHLEN> g_basename_tls_buffer;
+static ThreadLocalBuffer<char, MAXPATHLEN> g_dirname_tls_buffer;
+
 __LIBC64_HIDDEN__ int basename_r(const char* path, char* buffer, size_t buffer_size) {
   const char* startp = NULL;
   const char* endp = NULL;
@@ -147,17 +150,14 @@
   return result;
 }
 
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(basename);
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(dirname);
-
 char* basename(const char* path) {
-  LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, basename, MAXPATHLEN);
-  int rc = basename_r(path, basename_tls_buffer, basename_tls_buffer_size);
-  return (rc < 0) ? NULL : basename_tls_buffer;
+  char* buf = g_basename_tls_buffer.get();
+  int rc = basename_r(path, buf, g_basename_tls_buffer.size());
+  return (rc < 0) ? NULL : buf;
 }
 
 char* dirname(const char* path) {
-  LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, dirname, MAXPATHLEN);
-  int rc = dirname_r(path, dirname_tls_buffer, dirname_tls_buffer_size);
-  return (rc < 0) ? NULL : dirname_tls_buffer;
+  char* buf = g_dirname_tls_buffer.get();
+  int rc = dirname_r(path, buf, g_dirname_tls_buffer.size());
+  return (rc < 0) ? NULL : buf;
 }
diff --git a/libc/bionic/mntent.cpp b/libc/bionic/mntent.cpp
index 4afacda..d169e29 100644
--- a/libc/bionic/mntent.cpp
+++ b/libc/bionic/mntent.cpp
@@ -31,14 +31,13 @@
 
 #include "private/ThreadLocalBuffer.h"
 
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(getmntent_mntent);
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(getmntent_strings);
+static ThreadLocalBuffer<mntent> g_getmntent_mntent_tls_buffer;
+static ThreadLocalBuffer<char, BUFSIZ> g_getmntent_strings_tls_buffer;
 
 mntent* getmntent(FILE* fp) {
-  LOCAL_INIT_THREAD_LOCAL_BUFFER(mntent*, getmntent_mntent, sizeof(mntent));
-  LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, getmntent_strings, BUFSIZ);
-  return getmntent_r(fp, getmntent_mntent_tls_buffer,
-                     getmntent_strings_tls_buffer, getmntent_strings_tls_buffer_size);
+  return getmntent_r(fp, g_getmntent_mntent_tls_buffer.get(),
+                     g_getmntent_strings_tls_buffer.get(),
+                     g_getmntent_strings_tls_buffer.size());
 }
 
 mntent* getmntent_r(FILE* fp, struct mntent* e, char* buf, int buf_len) {
diff --git a/libc/bionic/pty.cpp b/libc/bionic/pty.cpp
index 8847147..1a37847 100644
--- a/libc/bionic/pty.cpp
+++ b/libc/bionic/pty.cpp
@@ -38,8 +38,8 @@
 
 #include "private/ThreadLocalBuffer.h"
 
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(ptsname);
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(ttyname);
+static ThreadLocalBuffer<char, 32> g_ptsname_tls_buffer;
+static ThreadLocalBuffer<char, 64> g_ttyname_tls_buffer;
 
 int getpt() {
   return posix_openpt(O_RDWR|O_NOCTTY);
@@ -54,9 +54,9 @@
 }
 
 char* ptsname(int fd) {
-  LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, ptsname, 32);
-  int error = ptsname_r(fd, ptsname_tls_buffer, ptsname_tls_buffer_size);
-  return (error == 0) ? ptsname_tls_buffer : NULL;
+  char* buf = g_ptsname_tls_buffer.get();
+  int error = ptsname_r(fd, buf, g_ptsname_tls_buffer.size());
+  return (error == 0) ? buf : NULL;
 }
 
 int ptsname_r(int fd, char* buf, size_t len) {
@@ -80,9 +80,9 @@
 }
 
 char* ttyname(int fd) {
-  LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, ttyname, 64);
-  int error = ttyname_r(fd, ttyname_tls_buffer, ttyname_tls_buffer_size);
-  return (error == 0) ? ttyname_tls_buffer : NULL;
+  char* buf = g_ttyname_tls_buffer.get();
+  int error = ttyname_r(fd, buf, g_ttyname_tls_buffer.size());
+  return (error == 0) ? buf : NULL;
 }
 
 int ttyname_r(int fd, char* buf, size_t len) {
diff --git a/libc/bionic/strerror.cpp b/libc/bionic/strerror.cpp
index d1518ff..f74194f 100644
--- a/libc/bionic/strerror.cpp
+++ b/libc/bionic/strerror.cpp
@@ -31,16 +31,16 @@
 
 extern "C" const char* __strerror_lookup(int);
 
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(strerror);
+static ThreadLocalBuffer<char, NL_TEXTMAX> g_strerror_tls_buffer;
 
 char* strerror(int error_number) {
   // Just return the original constant in the easy cases.
   char* result = const_cast<char*>(__strerror_lookup(error_number));
-  if (result != NULL) {
+  if (result != nullptr) {
     return result;
   }
 
-  LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, strerror, NL_TEXTMAX);
-  strerror_r(error_number, strerror_tls_buffer, strerror_tls_buffer_size);
-  return strerror_tls_buffer;
+  result = g_strerror_tls_buffer.get();
+  strerror_r(error_number, result, g_strerror_tls_buffer.size());
+  return result;
 }
diff --git a/libc/bionic/strsignal.cpp b/libc/bionic/strsignal.cpp
index 9f0193a..c389ddd 100644
--- a/libc/bionic/strsignal.cpp
+++ b/libc/bionic/strsignal.cpp
@@ -32,7 +32,7 @@
 extern "C" const char* __strsignal_lookup(int);
 extern "C" const char* __strsignal(int, char*, size_t);
 
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(strsignal);
+static ThreadLocalBuffer<char, NL_TEXTMAX> g_strsignal_tls_buffer;
 
 char* strsignal(int signal_number) {
   // Just return the original constant in the easy cases.
@@ -41,6 +41,6 @@
     return result;
   }
 
-  LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, strsignal, NL_TEXTMAX);
-  return const_cast<char*>(__strsignal(signal_number, strsignal_tls_buffer, strsignal_tls_buffer_size));
+  return const_cast<char*>(__strsignal(signal_number, g_strsignal_tls_buffer.get(),
+                                       g_strsignal_tls_buffer.size()));
 }
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index f9a31b9..c971d1b 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -35,6 +35,7 @@
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include "private/android_filesystem_config.h"
@@ -49,25 +50,12 @@
 // functions to share state, but <grp.h> functions can't clobber <passwd.h>
 // functions' state and vice versa.
 
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(group);
-
 struct group_state_t {
   group group_;
   char* group_members_[2];
   char group_name_buffer_[32];
 };
 
-static group_state_t* __group_state() {
-  LOCAL_INIT_THREAD_LOCAL_BUFFER(group_state_t*, group, sizeof(group_state_t));
-  if (group_tls_buffer != NULL) {
-    memset(group_tls_buffer, 0, sizeof(group_state_t));
-    group_tls_buffer->group_.gr_mem = group_tls_buffer->group_members_;
-  }
-  return group_tls_buffer;
-}
-
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(passwd);
-
 struct passwd_state_t {
   passwd passwd_;
   char name_buffer_[32];
@@ -75,9 +63,16 @@
   char sh_buffer_[32];
 };
 
-static passwd_state_t* __passwd_state() {
-  LOCAL_INIT_THREAD_LOCAL_BUFFER(passwd_state_t*, passwd, sizeof(passwd_state_t));
-  return passwd_tls_buffer;
+static ThreadLocalBuffer<group_state_t> g_group_tls_buffer;
+static ThreadLocalBuffer<passwd_state_t> g_passwd_tls_buffer;
+
+static group_state_t* __group_state() {
+  group_state_t* result = g_group_tls_buffer.get();
+  if (result != nullptr) {
+    memset(result, 0, sizeof(group_state_t));
+    result->group_.gr_mem = result->group_members_;
+  }
+  return result;
 }
 
 static int do_getpw_r(int by_name, const char* name, uid_t uid,
@@ -361,7 +356,7 @@
 }
 
 passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
-  passwd_state_t* state = __passwd_state();
+  passwd_state_t* state = g_passwd_tls_buffer.get();
   if (state == NULL) {
     return NULL;
   }
@@ -374,7 +369,7 @@
 }
 
 passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
-  passwd_state_t* state = __passwd_state();
+  passwd_state_t* state = g_passwd_tls_buffer.get();
   if (state == NULL) {
     return NULL;
   }
diff --git a/libc/dns/resolv/res_state.c b/libc/dns/resolv/res_state.c
index 459f073..afccd99 100644
--- a/libc/dns/resolv/res_state.c
+++ b/libc/dns/resolv/res_state.c
@@ -39,8 +39,6 @@
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
-#include "private/ThreadLocalBuffer.h"
-
 /* Set to 1 to enable debug traces */
 #define DEBUG 0
 
@@ -105,7 +103,11 @@
     free(rt);
 }
 
-BIONIC_PTHREAD_KEY_WITH_CONSTRUCTOR(_res_key, _res_thread_free);
+static pthread_key_t _res_key;
+
+__attribute__((constructor)) static void __res_key_init() {
+    pthread_key_create(&_res_key, _res_thread_free);
+}
 
 static _res_thread*
 _res_thread_get(void)
diff --git a/libc/kernel/uapi/linux/can/netlink.h b/libc/kernel/uapi/linux/can/netlink.h
index 96a90ff..a1c3159 100644
--- a/libc/kernel/uapi/linux/can/netlink.h
+++ b/libc/kernel/uapi/linux/can/netlink.h
@@ -79,33 +79,35 @@
 #define CAN_CTRLMODE_BERR_REPORTING 0x10
 #define CAN_CTRLMODE_FD 0x20
 #define CAN_CTRLMODE_PRESUME_ACK 0x40
-struct can_device_stats {
+#define CAN_CTRLMODE_FD_NON_ISO 0x80
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct can_device_stats {
   __u32 bus_error;
   __u32 error_warning;
   __u32 error_passive;
-  __u32 bus_off;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __u32 bus_off;
   __u32 arbitration_lost;
   __u32 restarts;
 };
-enum {
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+enum {
   IFLA_CAN_UNSPEC,
   IFLA_CAN_BITTIMING,
   IFLA_CAN_BITTIMING_CONST,
-  IFLA_CAN_CLOCK,
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  IFLA_CAN_CLOCK,
   IFLA_CAN_STATE,
   IFLA_CAN_CTRLMODE,
   IFLA_CAN_RESTART_MS,
-  IFLA_CAN_RESTART,
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  IFLA_CAN_RESTART,
   IFLA_CAN_BERR_COUNTER,
   IFLA_CAN_DATA_BITTIMING,
   IFLA_CAN_DATA_BITTIMING_CONST,
-  __IFLA_CAN_MAX
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __IFLA_CAN_MAX
 };
 #define IFLA_CAN_MAX (__IFLA_CAN_MAX - 1)
 #endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
diff --git a/libc/kernel/uapi/linux/in6.h b/libc/kernel/uapi/linux/in6.h
index 15bde3d..e54bc33 100644
--- a/libc/kernel/uapi/linux/in6.h
+++ b/libc/kernel/uapi/linux/in6.h
@@ -128,84 +128,87 @@
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_TLV_JUMBO 194
 #define IPV6_TLV_HAO 201
+#if __UAPI_DEF_IPV6_OPTIONS
 #define IPV6_ADDRFORM 1
-#define IPV6_2292PKTINFO 2
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define IPV6_2292PKTINFO 2
 #define IPV6_2292HOPOPTS 3
 #define IPV6_2292DSTOPTS 4
 #define IPV6_2292RTHDR 5
-#define IPV6_2292PKTOPTIONS 6
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define IPV6_2292PKTOPTIONS 6
 #define IPV6_CHECKSUM 7
 #define IPV6_2292HOPLIMIT 8
 #define IPV6_NEXTHOP 9
-#define IPV6_AUTHHDR 10
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define IPV6_AUTHHDR 10
 #define IPV6_FLOWINFO 11
 #define IPV6_UNICAST_HOPS 16
 #define IPV6_MULTICAST_IF 17
-#define IPV6_MULTICAST_HOPS 18
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define IPV6_MULTICAST_HOPS 18
 #define IPV6_MULTICAST_LOOP 19
 #define IPV6_ADD_MEMBERSHIP 20
 #define IPV6_DROP_MEMBERSHIP 21
-#define IPV6_ROUTER_ALERT 22
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define IPV6_ROUTER_ALERT 22
 #define IPV6_MTU_DISCOVER 23
 #define IPV6_MTU 24
 #define IPV6_RECVERR 25
-#define IPV6_V6ONLY 26
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define IPV6_V6ONLY 26
 #define IPV6_JOIN_ANYCAST 27
 #define IPV6_LEAVE_ANYCAST 28
 #define IPV6_PMTUDISC_DONT 0
-#define IPV6_PMTUDISC_WANT 1
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define IPV6_PMTUDISC_WANT 1
 #define IPV6_PMTUDISC_DO 2
 #define IPV6_PMTUDISC_PROBE 3
 #define IPV6_PMTUDISC_INTERFACE 4
-#define IPV6_PMTUDISC_OMIT 5
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define IPV6_PMTUDISC_OMIT 5
 #define IPV6_FLOWLABEL_MGR 32
 #define IPV6_FLOWINFO_SEND 33
 #define IPV6_IPSEC_POLICY 34
-#define IPV6_XFRM_POLICY 35
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define IPV6_XFRM_POLICY 35
+#endif
 #define IPV6_RECVPKTINFO 49
 #define IPV6_PKTINFO 50
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_RECVHOPLIMIT 51
 #define IPV6_HOPLIMIT 52
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_RECVHOPOPTS 53
 #define IPV6_HOPOPTS 54
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_RTHDRDSTOPTS 55
 #define IPV6_RECVRTHDR 56
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_RTHDR 57
 #define IPV6_RECVDSTOPTS 58
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_DSTOPTS 59
 #define IPV6_RECVPATHMTU 60
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_PATHMTU 61
 #define IPV6_DONTFRAG 62
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_RECVTCLASS 66
 #define IPV6_TCLASS 67
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_AUTOFLOWLABEL 70
 #define IPV6_ADDR_PREFERENCES 72
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_PREFER_SRC_TMP 0x0001
 #define IPV6_PREFER_SRC_PUBLIC 0x0002
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100
 #define IPV6_PREFER_SRC_COA 0x0004
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_PREFER_SRC_HOME 0x0400
 #define IPV6_PREFER_SRC_CGA 0x0008
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_PREFER_SRC_NONCGA 0x0800
 #define IPV6_MINHOPCOUNT 73
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_ORIGDSTADDR 74
 #define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define IPV6_TRANSPARENT 75
 #define IPV6_UNICAST_IF 76
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #endif
diff --git a/libc/kernel/uapi/linux/libc-compat.h b/libc/kernel/uapi/linux/libc-compat.h
index 7854520..b66ebe2 100644
--- a/libc/kernel/uapi/linux/libc-compat.h
+++ b/libc/kernel/uapi/linux/libc-compat.h
@@ -32,29 +32,33 @@
 #define __UAPI_DEF_IPV6_MREQ 0
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define __UAPI_DEF_IPPROTO_V6 0
+#define __UAPI_DEF_IPV6_OPTIONS 0
 #else
 #define __UAPI_DEF_IN6_ADDR 1
-#define __UAPI_DEF_IN6_ADDR_ALT 1
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define __UAPI_DEF_IN6_ADDR_ALT 1
 #define __UAPI_DEF_SOCKADDR_IN6 1
 #define __UAPI_DEF_IPV6_MREQ 1
 #define __UAPI_DEF_IPPROTO_V6 1
-#endif
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define __UAPI_DEF_IPV6_OPTIONS 1
+#endif
 #ifdef _SYS_XATTR_H
 #define __UAPI_DEF_XATTR 0
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #else
 #define __UAPI_DEF_XATTR 1
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #endif
 #else
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define __UAPI_DEF_IN6_ADDR 1
 #define __UAPI_DEF_IN6_ADDR_ALT 1
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define __UAPI_DEF_SOCKADDR_IN6 1
 #define __UAPI_DEF_IPV6_MREQ 1
-#define __UAPI_DEF_IPPROTO_V6 1
-#define __UAPI_DEF_XATTR 1
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define __UAPI_DEF_IPPROTO_V6 1
+#define __UAPI_DEF_IPV6_OPTIONS 1
+#define __UAPI_DEF_XATTR 1
 #endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #endif
diff --git a/libc/kernel/uapi/linux/target_core_user.h b/libc/kernel/uapi/linux/target_core_user.h
index ce6d26d..7e0cf43 100644
--- a/libc/kernel/uapi/linux/target_core_user.h
+++ b/libc/kernel/uapi/linux/target_core_user.h
@@ -21,75 +21,71 @@
 #include <linux/types.h>
 #include <linux/uio.h>
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
-#ifndef __packed
-#define __packed __attribute__((packed))
-#endif
 #define TCMU_VERSION "1.0"
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define TCMU_MAILBOX_VERSION 1
 #define ALIGN_SIZE 64
 struct tcmu_mailbox {
-  __u16 version;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __u16 version;
   __u16 flags;
   __u32 cmdr_off;
   __u32 cmdr_size;
-  __u32 cmd_head;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __u32 cmd_head;
   __u32 cmd_tail __attribute__((__aligned__(ALIGN_SIZE)));
 } __packed;
 enum tcmu_opcode {
-  TCMU_OP_PAD = 0,
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  TCMU_OP_PAD = 0,
   TCMU_OP_CMD,
 };
 struct tcmu_cmd_entry_hdr {
-  __u32 len_op;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __u32 len_op;
 } __packed;
 #define TCMU_OP_MASK 0x7
 #define TCMU_SENSE_BUFFERSIZE 96
-struct tcmu_cmd_entry {
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct tcmu_cmd_entry {
   struct tcmu_cmd_entry_hdr hdr;
   uint16_t cmd_id;
   uint16_t __pad1;
-  union {
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  union {
     struct {
       uint64_t cdb_off;
       uint64_t iov_cnt;
-      struct iovec iov[0];
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+      struct iovec iov[0];
     } req;
     struct {
       uint8_t scsi_status;
-      uint8_t __pad1;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+      uint8_t __pad1;
       uint16_t __pad2;
       uint32_t __pad3;
       char sense_buffer[TCMU_SENSE_BUFFERSIZE];
-    } rsp;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+    } rsp;
   };
 } __packed;
 #define TCMU_OP_ALIGN_SIZE sizeof(uint64_t)
-enum tcmu_genl_cmd {
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+enum tcmu_genl_cmd {
   TCMU_CMD_UNSPEC,
   TCMU_CMD_ADDED_DEVICE,
   TCMU_CMD_REMOVED_DEVICE,
-  __TCMU_CMD_MAX,
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __TCMU_CMD_MAX,
 };
 #define TCMU_CMD_MAX (__TCMU_CMD_MAX - 1)
 enum tcmu_genl_attr {
-  TCMU_ATTR_UNSPEC,
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  TCMU_ATTR_UNSPEC,
   TCMU_ATTR_DEVICE,
   TCMU_ATTR_MINOR,
   __TCMU_ATTR_MAX,
-};
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+};
 #define TCMU_ATTR_MAX (__TCMU_ATTR_MAX - 1)
 #endif
diff --git a/libc/kernel/uapi/linux/version.h b/libc/kernel/uapi/linux/version.h
index cb6842a..a6c6a2f 100644
--- a/libc/kernel/uapi/linux/version.h
+++ b/libc/kernel/uapi/linux/version.h
@@ -16,5 +16,5 @@
  ***
  ****************************************************************************
  ****************************************************************************/
-#define LINUX_VERSION_CODE 201219
+#define LINUX_VERSION_CODE 201226
 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
diff --git a/libc/private/ThreadLocalBuffer.h b/libc/private/ThreadLocalBuffer.h
index cc47317..5e43665 100644
--- a/libc/private/ThreadLocalBuffer.h
+++ b/libc/private/ThreadLocalBuffer.h
@@ -32,32 +32,30 @@
 #include <malloc.h>
 #include <pthread.h>
 
-// libstdc++ currently contains __cxa_guard_acquire and __cxa_guard_release,
-// so we make do with macros instead of a C++ class.
-// TODO: move __cxa_guard_acquire and __cxa_guard_release into libc.
+// TODO: use __thread instead?
 
-// We used to use pthread_once to initialize the keys, but life is more predictable
-// if we allocate them all up front when the C library starts up, via __constructor__.
-#define BIONIC_PTHREAD_KEY_WITH_CONSTRUCTOR(key_name, key_destructor) \
-  static pthread_key_t key_name; \
-  __attribute__((constructor)) static void __bionic_tls_ ## key_name ## _key_init() { \
-    pthread_key_create(&key_name, key_destructor); \
+template <typename T, size_t Size = sizeof(T)>
+class ThreadLocalBuffer {
+ public:
+  ThreadLocalBuffer() {
+    // We used to use pthread_once to initialize the keys, but life is more predictable
+    // if we allocate them all up front when the C library starts up, via __constructor__.
+    pthread_key_create(&key_, free);
   }
 
-#define GLOBAL_INIT_THREAD_LOCAL_BUFFER(name) \
-  static void __bionic_tls_ ## name ## _key_destroy(void* buffer) { \
-    free(buffer); \
-  } \
-  BIONIC_PTHREAD_KEY_WITH_CONSTRUCTOR(__bionic_tls_ ## name ## _key, __bionic_tls_ ## name ## _key_destroy)
+  T* get() {
+    T* result = reinterpret_cast<T*>(pthread_getspecific(key_));
+    if (result == nullptr) {
+      result = reinterpret_cast<T*>(calloc(1, Size));
+      pthread_setspecific(key_, result);
+    }
+    return result;
+  }
 
-// Leaves "name_tls_buffer" and "name_tls_buffer_size" defined and initialized.
-#define LOCAL_INIT_THREAD_LOCAL_BUFFER(type, name, byte_count) \
-  type name ## _tls_buffer = \
-      reinterpret_cast<type>(pthread_getspecific(__bionic_tls_ ## name ## _key)); \
-  if (name ## _tls_buffer == NULL) { \
-    name ## _tls_buffer = reinterpret_cast<type>(calloc(1, byte_count)); \
-    pthread_setspecific(__bionic_tls_ ## name ## _key, name ## _tls_buffer); \
-  } \
-  const size_t name ## _tls_buffer_size __attribute__((unused)) = byte_count
+  size_t size() { return Size; }
+
+ private:
+  pthread_key_t key_;
+};
 
 #endif // _BIONIC_THREAD_LOCAL_BUFFER_H_included
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 1ab8d4a..414d171 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -72,22 +72,26 @@
 
 /*
  * Bionic uses some pthread keys internally. All pthread keys used internally
- * should be created in constructors, except for keys that may be used in or before constructors.
+ * should be created in constructors, except for keys that may be used in or
+ * before constructors.
+ *
  * We need to manually maintain the count of pthread keys used internally, but
  * pthread_test should fail if we forget.
- * Following are current pthread keys used internally by libc:
- *  basename               libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- *  dirname                libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
+ *
+ * These are the pthread keys currently used internally by libc:
+ *
+ *  basename               libc (ThreadLocalBuffer)
+ *  dirname                libc (ThreadLocalBuffer)
  *  uselocale              libc (can be used in constructors)
- *  getmntent_mntent       libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- *  getmntent_strings      libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- *  ptsname                libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- *  ttyname                libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- *  strerror               libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- *  strsignal              libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- *  passwd                 libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- *  group                  libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- *  _res_key               libc (BIONIC_PTHREAD_KEY_WITH_CONSTRUCTOR)
+ *  getmntent_mntent       libc (ThreadLocalBuffer)
+ *  getmntent_strings      libc (ThreadLocalBuffer)
+ *  ptsname                libc (ThreadLocalBuffer)
+ *  ttyname                libc (ThreadLocalBuffer)
+ *  strerror               libc (ThreadLocalBuffer)
+ *  strsignal              libc (ThreadLocalBuffer)
+ *  passwd                 libc (ThreadLocalBuffer)
+ *  group                  libc (ThreadLocalBuffer)
+ *  _res_key               libc (constructor in BSD code)
  */
 
 #define LIBC_PTHREAD_KEY_RESERVED_COUNT 12
diff --git a/libc/version_script.txt b/libc/version_script.txt
new file mode 100644
index 0000000..afc5e5c
--- /dev/null
+++ b/libc/version_script.txt
@@ -0,0 +1,12 @@
+LIBC {
+  local:
+    _ZSt7nothrow;
+    _ZdaPv;
+    _ZdaPvRKSt9nothrow_t;
+    _ZdlPv;
+    _ZdlPvRKSt9nothrow_t;
+    _Znaj;
+    _ZnajRKSt9nothrow_t;
+    _Znwj;
+    _ZnwjRKSt9nothrow_t;
+};
diff --git a/linker/debugger.cpp b/linker/debugger.cpp
index 6fe9524..357fbdc 100644
--- a/linker/debugger.cpp
+++ b/linker/debugger.cpp
@@ -221,7 +221,7 @@
   if (ret != 0) {
     if (ret == EBUSY) {
       __libc_format_log(ANDROID_LOG_INFO, "libc",
-                        "Another thread has contacted debuggerd first, stop and wait for process to die.");
+          "Another thread contacted debuggerd first; not contacting debuggerd.");
       // This will never complete since the lock is never released.
       pthread_mutex_lock(&crash_mutex);
     } else {
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 8e8ba84..ebf125e 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -140,10 +140,13 @@
 
 // This function is an empty stub where GDB locates a breakpoint to get notified
 // about linker activity.
-extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
+extern "C"
+void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
 
 static pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
-static r_debug _r_debug = {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
+static r_debug _r_debug =
+    {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
+
 static link_map* r_debug_tail = 0;
 
 static void insert_soinfo_into_debug_map(soinfo* info) {
@@ -233,7 +236,8 @@
   g_soinfo_links_allocator.free(entry);
 }
 
-static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, uint32_t rtld_flags) {
+static soinfo* soinfo_alloc(const char* name, struct stat* file_stat,
+                            off64_t file_offset, uint32_t rtld_flags) {
   if (strlen(name) >= SOINFO_NAME_LEN) {
     DL_ERR("library name \"%s\" too long", name);
     return nullptr;
@@ -434,7 +438,8 @@
 
   for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
     ElfW(Sym)* s = symtab_ + n;
-    if (strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 && is_symbol_global_and_defined(this, s)) {
+    if (strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
+        is_symbol_global_and_defined(this, s)) {
       TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
                symbol_name.get_name(), name, reinterpret_cast<void*>(s->st_value),
                static_cast<size_t>(s->st_size));
@@ -448,7 +453,8 @@
   return nullptr;
 }
 
-soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags) {
+soinfo::soinfo(const char* name, const struct stat* file_stat,
+               off64_t file_offset, int rtld_flags) {
   memset(this, 0, sizeof(*this));
 
   strlcpy(this->name, name, sizeof(this->name));
@@ -1002,7 +1008,8 @@
     return nullptr;
   }
   if (file_offset >= file_stat.st_size) {
-    DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64, name, file_offset, file_stat.st_size);
+    DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
+        name, file_offset, file_stat.st_size);
     return nullptr;
   }
 
@@ -1014,7 +1021,8 @@
         si->get_st_dev() == file_stat.st_dev &&
         si->get_st_ino() == file_stat.st_ino &&
         si->get_file_offset() == file_offset) {
-      TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name);
+      TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
+          "will return existing soinfo", name, si->name);
       return si;
     }
   }
@@ -1067,7 +1075,8 @@
   return nullptr;
 }
 
-static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
+static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name,
+                                     int rtld_flags, const android_dlextinfo* extinfo) {
   soinfo* si = find_loaded_library_by_soname(name);
 
   // Library might still be loaded, the accurate detection
@@ -1141,7 +1150,8 @@
   });
 
   // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
-  for (LoadTask::unique_ptr task(load_tasks.pop_front()); task.get() != nullptr; task.reset(load_tasks.pop_front())) {
+  for (LoadTask::unique_ptr task(load_tasks.pop_front());
+      task.get() != nullptr; task.reset(load_tasks.pop_front())) {
     soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo);
     if (si == nullptr) {
       return false;
@@ -1320,8 +1330,8 @@
   // snprintf again.
   size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2;
   if (buffer_size < required_len) {
-    __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: buffer len %zu, required len %zu",
-                 buffer_size, required_len);
+    __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
+                 "buffer len %zu, required len %zu", buffer_size, required_len);
   }
   char* end = stpcpy(buffer, kDefaultLdPaths[0]);
   *end = ':';
@@ -1344,7 +1354,8 @@
     }
     if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
         (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
-      DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
+      DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
+          "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
       return nullptr;
     }
   }
@@ -1366,7 +1377,8 @@
   typedef ElfW(Addr) (*ifunc_resolver_t)(void);
   ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
   ElfW(Addr) ifunc_addr = ifunc_resolver();
-  TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p", ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
+  TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
+      ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
 
   return ifunc_addr;
 }
@@ -1378,7 +1390,8 @@
 }
 #else
 static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
-  if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE || ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
+  if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
+      ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
     return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
   }
   return 0;
@@ -1386,7 +1399,8 @@
 #endif
 
 template<typename ElfRelIteratorT>
-bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
+bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& global_group,
+                      const soinfo_list_t& local_group) {
   for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
     const auto rel = rel_iterator.next();
     if (rel == nullptr) {
@@ -1523,15 +1537,18 @@
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
                    reloc, (sym_addr + addend), sym_name);
-        if ((static_cast<ElfW(Addr)>(INT32_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + addend))) &&
-            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + addend)) <= static_cast<ElfW(Addr)>(UINT32_MAX))) {
-          *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
-        } else {
-          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
-                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + addend)),
-                 static_cast<ElfW(Addr)>(INT32_MIN),
-                 static_cast<ElfW(Addr)>(UINT32_MAX));
-          return false;
+        {
+          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
+          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
+          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
+          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
+              ((reloc_value + (sym_addr + addend)) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
+          } else {
+            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
+                   (reloc_value + (sym_addr + addend)), min_value, max_value);
+            return false;
+          }
         }
         break;
       case R_AARCH64_ABS16:
@@ -1539,15 +1556,18 @@
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
                    reloc, (sym_addr + addend), sym_name);
-        if ((static_cast<ElfW(Addr)>(INT16_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + addend))) &&
-            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + addend)) <= static_cast<ElfW(Addr)>(UINT16_MAX))) {
-          *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
-        } else {
-          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
-                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + addend)),
-                 static_cast<ElfW(Addr)>(INT16_MIN),
-                 static_cast<ElfW(Addr)>(UINT16_MAX));
-          return false;
+        {
+          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
+          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
+          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
+          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
+              ((reloc_value + (sym_addr + addend)) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
+          } else {
+            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
+                   reloc_value + (sym_addr + addend), min_value, max_value);
+            return false;
+          }
         }
         break;
       case R_AARCH64_PREL64:
@@ -1562,15 +1582,18 @@
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
                    reloc, (sym_addr + addend), rel->r_offset, sym_name);
-        if ((static_cast<ElfW(Addr)>(INT32_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + addend) - rel->r_offset))) &&
-            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + addend) - rel->r_offset)) <= static_cast<ElfW(Addr)>(UINT32_MAX))) {
-          *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
-        } else {
-          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
-                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + addend) - rel->r_offset)),
-                 static_cast<ElfW(Addr)>(INT32_MIN),
-                 static_cast<ElfW(Addr)>(UINT32_MAX));
-          return false;
+        {
+          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
+          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
+          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
+          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
+              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
+          } else {
+            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
+                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
+            return false;
+          }
         }
         break;
       case R_AARCH64_PREL16:
@@ -1578,15 +1601,18 @@
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
                    reloc, (sym_addr + addend), rel->r_offset, sym_name);
-        if ((static_cast<ElfW(Addr)>(INT16_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + addend) - rel->r_offset))) &&
-            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + addend) - rel->r_offset)) <= static_cast<ElfW(Addr)>(UINT16_MAX))) {
-          *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
-        } else {
-          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
-                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + addend) - rel->r_offset)),
-                 static_cast<ElfW(Addr)>(INT16_MIN),
-                 static_cast<ElfW(Addr)>(UINT16_MAX));
-          return false;
+        {
+          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
+          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
+          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
+          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
+              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
+          } else {
+            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
+                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
+            return false;
+          }
         }
         break;
 
@@ -1683,7 +1709,8 @@
 }
 #endif  // !defined(__mips__)
 
-void soinfo::call_array(const char* array_name __unused, linker_function_t* functions, size_t count, bool reverse) {
+void soinfo::call_array(const char* array_name __unused, linker_function_t* functions,
+                        size_t count, bool reverse) {
   if (functions == nullptr) {
     return;
   }
@@ -2056,10 +2083,12 @@
         gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
         gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
         // amend chain for symndx = header[1]
-        gnu_chain_ = gnu_bucket_ + gnu_nbucket_ - reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
+        gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
+            reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
 
         if (!powerof2(gnu_maskwords_)) {
-          DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two", gnu_maskwords_, name);
+          DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
+              gnu_maskwords_, name);
           return false;
         }
         --gnu_maskwords_;
@@ -2316,7 +2345,8 @@
       case DT_MIPS_RLD_MAP2:
         // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB.
         {
-          r_debug** dp = reinterpret_cast<r_debug**>(reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
+          r_debug** dp = reinterpret_cast<r_debug**>(
+              reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
           *dp = &_r_debug;
         }
         break;
diff --git a/linker/linker.h b/linker/linker.h
index 05735f6..bf3e7bf 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -238,7 +238,8 @@
   void call_destructors();
   void call_pre_init_constructors();
   bool prelink_image();
-  bool link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group, const android_dlextinfo* extinfo);
+  bool link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
+                  const android_dlextinfo* extinfo);
 
   void add_child(soinfo* child);
   void remove_all_links();
@@ -289,7 +290,8 @@
   void call_array(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
   void call_function(const char* function_name, linker_function_t function);
   template<typename ElfRelIteratorT>
-  bool relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& global_group, const soinfo_list_t& local_group);
+  bool relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& global_group,
+                const soinfo_list_t& local_group);
 
  private:
   // This part of the structure is only available
diff --git a/linker/linker_mips.cpp b/linker/linker_mips.cpp
index f0bde55..44d39fd 100644
--- a/linker/linker_mips.cpp
+++ b/linker/linker_mips.cpp
@@ -47,7 +47,9 @@
     const soinfo_list_t& local_group);
 
 template <typename ElfRelIteratorT>
-bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
+bool soinfo::relocate(ElfRelIteratorT&& rel_iterator,
+                      const soinfo_list_t& global_group,
+                      const soinfo_list_t& local_group) {
   for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
     const auto rel = rel_iterator.next();
 
@@ -115,7 +117,8 @@
   return true;
 }
 
-bool soinfo::mips_relocate_got(const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
+bool soinfo::mips_relocate_got(const soinfo_list_t& global_group,
+                               const soinfo_list_t& local_group) {
   ElfW(Addr)** got = plt_got_;
   if (got == nullptr) {
     return true;
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 38e6262..638c9d6 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -240,7 +240,8 @@
 
   phdr_size_ = page_max - page_min;
 
-  void* mmap_result = mmap64(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, file_offset_ + page_min);
+  void* mmap_result =
+      mmap64(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, file_offset_ + page_min);
   if (mmap_result == MAP_FAILED) {
     DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
     return false;
@@ -428,9 +429,15 @@
     ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
     ElfW(Addr) seg_page_end   = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
 
+    int prot = PFLAGS_TO_PROT(phdr->p_flags);
+    if ((extra_prot_flags & PROT_WRITE) != 0) {
+      // make sure we're never simultaneously writable / executable
+      prot &= ~PROT_EXEC;
+    }
+
     int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
                        seg_page_end - seg_page_start,
-                       PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags);
+                       prot | extra_prot_flags);
     if (ret < 0) {
       return -1;
     }
@@ -449,7 +456,8 @@
  * Return:
  *   0 on error, -1 on failure (error code in errno).
  */
-int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
+int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table,
+                                size_t phdr_count, ElfW(Addr) load_bias) {
   return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, 0);
 }
 
@@ -469,7 +477,8 @@
  * Return:
  *   0 on error, -1 on failure (error code in errno).
  */
-int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
+int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table,
+                                  size_t phdr_count, ElfW(Addr) load_bias) {
   return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, PROT_WRITE);
 }
 
@@ -531,7 +540,8 @@
  * Return:
  *   0 on error, -1 on failure (error code in errno).
  */
-int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias) {
+int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table,
+                                 size_t phdr_count, ElfW(Addr) load_bias) {
   return _phdr_table_set_gnu_relro_prot(phdr_table, phdr_count, load_bias, PROT_READ);
 }
 
@@ -547,7 +557,9 @@
  * Return:
  *   0 on error, -1 on failure (error code in errno).
  */
-int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
+int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table,
+                                   size_t phdr_count,
+                                   ElfW(Addr) load_bias,
                                    int fd) {
   const ElfW(Phdr)* phdr = phdr_table;
   const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
@@ -592,7 +604,9 @@
  * Return:
  *   0 on error, -1 on failure (error code in errno).
  */
-int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
+int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table,
+                             size_t phdr_count,
+                             ElfW(Addr) load_bias,
                              int fd) {
   // Map the file at a temporary location so we can compare its contents.
   struct stat file_stat;
@@ -725,11 +739,12 @@
                                     ElfW(Addr) load_bias, ElfW(Dyn)** dynamic,
                                     ElfW(Word)* dynamic_flags) {
   *dynamic = nullptr;
-  for (const ElfW(Phdr)* phdr = phdr_table, *phdr_limit = phdr + phdr_count; phdr < phdr_limit; phdr++) {
-    if (phdr->p_type == PT_DYNAMIC) {
-      *dynamic = reinterpret_cast<ElfW(Dyn)*>(load_bias + phdr->p_vaddr);
+  for (size_t i = 0; i<phdr_count; ++i) {
+    const ElfW(Phdr)& phdr = phdr_table[i];
+    if (phdr.p_type == PT_DYNAMIC) {
+      *dynamic = reinterpret_cast<ElfW(Dyn)*>(load_bias + phdr.p_vaddr);
       if (dynamic_flags) {
-        *dynamic_flags = phdr->p_flags;
+        *dynamic_flags = phdr.p_flags;
       }
       return;
     }
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 6b917b4..50f2117 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -84,17 +84,20 @@
 size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
                                 ElfW(Addr)* min_vaddr = nullptr, ElfW(Addr)* max_vaddr = nullptr);
 
-int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias);
+int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table,
+                                size_t phdr_count, ElfW(Addr) load_bias);
 
-int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias);
+int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                  ElfW(Addr) load_bias);
 
-int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias);
+int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                 ElfW(Addr) load_bias);
 
-int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
-                                   int fd);
+int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                   ElfW(Addr) load_bias, int fd);
 
-int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
-                             int fd);
+int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                             ElfW(Addr) load_bias, int fd);
 
 #if defined(__arm__)
 int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
diff --git a/linker/linker_reloc_iterators.h b/linker/linker_reloc_iterators.h
index 5db31f9..f28c0e0 100644
--- a/linker/linker_reloc_iterators.h
+++ b/linker/linker_reloc_iterators.h
@@ -21,15 +21,10 @@
 
 #include <string.h>
 
-#define RELOCATION_GROUPED_BY_INFO_FLAG 1
-#define RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG 2
-#define RELOCATION_GROUPED_BY_ADDEND_FLAG 4
-#define RELOCATION_GROUP_HAS_ADDEND_FLAG 8
-
-#define RELOCATION_GROUPED_BY_INFO(flags) (((flags) & RELOCATION_GROUPED_BY_INFO_FLAG) != 0)
-#define RELOCATION_GROUPED_BY_OFFSET_DELTA(flags) (((flags) & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0)
-#define RELOCATION_GROUPED_BY_ADDEND(flags) (((flags) & RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0)
-#define RELOCATION_GROUP_HAS_ADDEND(flags) (((flags) & RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0)
+const size_t RELOCATION_GROUPED_BY_INFO_FLAG = 1;
+const size_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2;
+const size_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 4;
+const size_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 8;
 
 class plain_reloc_iterator {
 #if defined(USE_RELA)
@@ -89,18 +84,19 @@
       }
     }
 
-    if (RELOCATION_GROUPED_BY_OFFSET_DELTA(group_flags_)) {
+    if (is_relocation_grouped_by_offset_delta()) {
       reloc_.r_offset += group_r_offset_delta_;
     } else {
       reloc_.r_offset += decoder_.pop_front();
     }
 
-    if (!RELOCATION_GROUPED_BY_INFO(group_flags_)) {
+    if (!is_relocation_grouped_by_info()) {
       reloc_.r_info = decoder_.pop_front();
     }
 
 #if defined(USE_RELA)
-    if (RELOCATION_GROUP_HAS_ADDEND(group_flags_) && !RELOCATION_GROUPED_BY_ADDEND(group_flags_)) {
+    if (is_relocation_group_has_addend() &&
+        !is_relocation_grouped_by_addend()) {
       reloc_.r_addend += decoder_.pop_front();
     }
 #endif
@@ -115,22 +111,23 @@
     group_size_ = decoder_.pop_front();
     group_flags_ = decoder_.pop_front();
 
-    if (RELOCATION_GROUPED_BY_OFFSET_DELTA(group_flags_)) {
+    if (is_relocation_grouped_by_offset_delta()) {
       group_r_offset_delta_ = decoder_.pop_front();
     }
 
-    if (RELOCATION_GROUPED_BY_INFO(group_flags_)) {
+    if (is_relocation_grouped_by_info()) {
       reloc_.r_info = decoder_.pop_front();
     }
 
-    if (RELOCATION_GROUP_HAS_ADDEND(group_flags_) && RELOCATION_GROUPED_BY_ADDEND(group_flags_)) {
+    if (is_relocation_group_has_addend() &&
+        is_relocation_grouped_by_addend()) {
 #if !defined(USE_RELA)
       // This platform does not support rela, and yet we have it encoded in android_rel section.
       DL_ERR("unexpected r_addend in android.rel section");
       return false;
 #else
       reloc_.r_addend += decoder_.pop_front();
-    } else if (!RELOCATION_GROUP_HAS_ADDEND(group_flags_)) {
+    } else if (!is_relocation_group_has_addend()) {
       reloc_.r_addend = 0;
 #endif
     }
@@ -139,6 +136,22 @@
     return true;
   }
 
+  bool is_relocation_grouped_by_info() {
+    return (group_flags_ & RELOCATION_GROUPED_BY_INFO_FLAG) != 0;
+  }
+
+  bool is_relocation_grouped_by_offset_delta() {
+    return (group_flags_ & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0;
+  }
+
+  bool is_relocation_grouped_by_addend() {
+    return (group_flags_ & RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0;
+  }
+
+  bool is_relocation_group_has_addend() {
+    return (group_flags_ & RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0;
+  }
+
   decoder_t decoder_;
   size_t relocation_count_;
   size_t group_size_;
diff --git a/tests/ftw_test.cpp b/tests/ftw_test.cpp
index 6741d00..b7e5bd5 100644
--- a/tests/ftw_test.cpp
+++ b/tests/ftw_test.cpp
@@ -30,11 +30,11 @@
   char path[PATH_MAX];
 
   snprintf(path, sizeof(path), "%s/dir", root);
-  ASSERT_EQ(0, mkdir(path, 0555));
+  ASSERT_EQ(0, mkdir(path, 0755)) << path;
   snprintf(path, sizeof(path), "%s/dir/sub", root);
-  ASSERT_EQ(0, mkdir(path, 0555));
+  ASSERT_EQ(0, mkdir(path, 0555)) << path;
   snprintf(path, sizeof(path), "%s/unreadable-dir", root);
-  ASSERT_EQ(0, mkdir(path, 0000));
+  ASSERT_EQ(0, mkdir(path, 0000)) << path;
 
   snprintf(path, sizeof(path), "%s/dangler", root);
   ASSERT_EQ(0, symlink("/does-not-exist", path));
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index bf2b695..692b7e8 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -277,8 +277,8 @@
 // PrettyUnitTestResultPrinter. The reason for copy is that PrettyUnitTestResultPrinter
 // is defined and used in gtest.cc, which is hard to reuse.
 static void OnTestIterationStartPrint(const std::vector<TestCase>& testcase_list, size_t iteration,
-                                      size_t iteration_count) {
-  if (iteration_count > 1) {
+                                      int iteration_count) {
+  if (iteration_count != 1) {
     printf("\nRepeating all tests (iteration %zu) . . .\n\n", iteration);
   }
   ColoredPrintf(COLOR_GREEN,  "[==========] ");
@@ -743,7 +743,7 @@
 // makes deadlock to use fork in multi-thread.
 // Returns true if all tests run successfully, otherwise return false.
 static bool RunTestInSeparateProc(int argc, char** argv, std::vector<TestCase>& testcase_list,
-                                  size_t iteration_count, size_t job_count,
+                                  int iteration_count, size_t job_count,
                                   const std::string& xml_output_filename) {
   // Stop default result printer to avoid environment setup/teardown information for each test.
   testing::UnitTest::GetInstance()->listeners().Release(
@@ -762,7 +762,9 @@
 
   bool all_tests_passed = true;
 
-  for (size_t iteration = 1; iteration <= iteration_count; ++iteration) {
+  for (size_t iteration = 1;
+       iteration_count < 0 || iteration <= static_cast<size_t>(iteration_count);
+       ++iteration) {
     OnTestIterationStartPrint(testcase_list, iteration, iteration_count);
     int64_t iteration_start_time_ns = NanoTime();
     time_t epoch_iteration_start_time = time(NULL);
@@ -875,7 +877,7 @@
   int test_warnline_ms;
   std::string gtest_color;
   bool gtest_print_time;
-  size_t gtest_repeat;
+  int gtest_repeat;
   std::string gtest_output;
 };
 
@@ -993,12 +995,9 @@
     } else if (strcmp(args[i], "--gtest_print_time=0") == 0) {
       options.gtest_print_time = false;
     } else if (strncmp(args[i], "--gtest_repeat=", strlen("--gtest_repeat=")) == 0) {
-      int repeat = atoi(args[i] + strlen("--gtest_repeat="));
-      if (repeat < 0) {
-        fprintf(stderr, "invalid gtest_repeat count: %d\n", repeat);
-        return false;
-      }
-      options.gtest_repeat = repeat;
+      // If the value of gtest_repeat is < 0, then it indicates the tests
+      // should be repeated forever.
+      options.gtest_repeat = atoi(args[i] + strlen("--gtest_repeat="));
       // Remove --gtest_repeat=xx from arguments, so child process only run one iteration for a single test.
       args.erase(args.begin() + i);
       --i;
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 7bcef51..5ab1f11 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -68,8 +68,7 @@
 
   for (int i = 0; i < nkeys; ++i) {
     pthread_key_t key;
-    // If this fails, it's likely that GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT is
-    // wrong.
+    // If this fails, it's likely that LIBC_PTHREAD_KEY_RESERVED_COUNT is wrong.
     ASSERT_EQ(0, pthread_key_create(&key, NULL)) << i << " of " << nkeys;
     keys.push_back(key);
     ASSERT_EQ(0, pthread_setspecific(key, reinterpret_cast<void*>(i)));