Merge "linker: Change the library search order"
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 526b6d0..e045049 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -223,6 +223,7 @@
 int           timerfd_create(clockid_t, int)   all
 int           timerfd_settime(int, int, const struct itimerspec*, struct itimerspec*)   all
 int           timerfd_gettime(int, struct itimerspec*)   all
+int           adjtimex(struct timex*)   all
 
 # signals
 int     __sigaction:sigaction(int, const struct sigaction*, struct sigaction*)  arm,mips,x86
diff --git a/libc/arch-arm/syscalls/adjtimex.S b/libc/arch-arm/syscalls/adjtimex.S
new file mode 100644
index 0000000..614036e
--- /dev/null
+++ b/libc/arch-arm/syscalls/adjtimex.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(adjtimex)
+    mov     ip, r7
+    ldr     r7, =__NR_adjtimex
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno_internal
+END(adjtimex)
diff --git a/libc/arch-arm64/syscalls/adjtimex.S b/libc/arch-arm64/syscalls/adjtimex.S
new file mode 100644
index 0000000..712e468
--- /dev/null
+++ b/libc/arch-arm64/syscalls/adjtimex.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(adjtimex)
+    mov     x8, __NR_adjtimex
+    svc     #0
+
+    cmn     x0, #(MAX_ERRNO + 1)
+    cneg    x0, x0, hi
+    b.hi    __set_errno_internal
+
+    ret
+END(adjtimex)
diff --git a/libc/arch-mips/syscalls/adjtimex.S b/libc/arch-mips/syscalls/adjtimex.S
new file mode 100644
index 0000000..fef215f
--- /dev/null
+++ b/libc/arch-mips/syscalls/adjtimex.S
@@ -0,0 +1,19 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(adjtimex)
+    .set noreorder
+    .cpload t9
+    li v0, __NR_adjtimex
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    la t9,__set_errno_internal
+    j t9
+    nop
+    .set reorder
+END(adjtimex)
diff --git a/libc/arch-mips64/syscalls/adjtimex.S b/libc/arch-mips64/syscalls/adjtimex.S
new file mode 100644
index 0000000..57b012c
--- /dev/null
+++ b/libc/arch-mips64/syscalls/adjtimex.S
@@ -0,0 +1,25 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(adjtimex)
+    .set push
+    .set noreorder
+    li v0, __NR_adjtimex
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    move t0, ra
+    bal     2f
+    nop
+2:
+    .cpsetup ra, t1, 2b
+    LA t9,__set_errno_internal
+    .cpreturn
+    j t9
+    move ra, t0
+    .set pop
+END(adjtimex)
diff --git a/libc/arch-x86/syscalls/adjtimex.S b/libc/arch-x86/syscalls/adjtimex.S
new file mode 100644
index 0000000..2a91f90
--- /dev/null
+++ b/libc/arch-x86/syscalls/adjtimex.S
@@ -0,0 +1,21 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(adjtimex)
+    pushl   %ebx
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset ebx, 0
+    mov     8(%esp), %ebx
+    movl    $__NR_adjtimex, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno_internal
+    addl    $4, %esp
+1:
+    popl    %ebx
+    ret
+END(adjtimex)
diff --git a/libc/arch-x86_64/syscalls/adjtimex.S b/libc/arch-x86_64/syscalls/adjtimex.S
new file mode 100644
index 0000000..292b9f3
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/adjtimex.S
@@ -0,0 +1,15 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(adjtimex)
+    movl    $__NR_adjtimex, %eax
+    syscall
+    cmpq    $-MAX_ERRNO, %rax
+    jb      1f
+    negl    %eax
+    movl    %eax, %edi
+    call    __set_errno_internal
+1:
+    ret
+END(adjtimex)
diff --git a/libc/bionic/tmpfile.cpp b/libc/bionic/tmpfile.cpp
index 602d407..dc142a9 100644
--- a/libc/bionic/tmpfile.cpp
+++ b/libc/bionic/tmpfile.cpp
@@ -112,3 +112,4 @@
   }
   return fp;
 }
+__strong_alias(tmpfile64, tmpfile);
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index b618091..623995b 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -109,14 +109,11 @@
 int	 fflush(FILE *);
 int	 fgetc(FILE *);
 char	*fgets(char * __restrict, int, FILE * __restrict);
-FILE	*fopen(const char * __restrict , const char * __restrict);
 int	 fprintf(FILE * __restrict , const char * __restrict, ...)
 		__printflike(2, 3);
 int	 fputc(int, FILE *);
 int	 fputs(const char * __restrict, FILE * __restrict);
 size_t	 fread(void * __restrict, size_t, size_t, FILE * __restrict);
-FILE	*freopen(const char * __restrict, const char * __restrict,
-	    FILE * __restrict);
 int	 fscanf(FILE * __restrict, const char * __restrict, ...)
 		__scanflike(2, 3);
 size_t	 fwrite(const void * __restrict, size_t, size_t, FILE * __restrict);
@@ -140,7 +137,6 @@
 int	 setvbuf(FILE * __restrict, char * __restrict, int, size_t);
 int	 sscanf(const char * __restrict, const char * __restrict, ...)
 		__scanflike(2, 3);
-FILE	*tmpfile(void);
 int	 ungetc(int, FILE *);
 int	 vfprintf(FILE * __restrict, const char * __restrict, __va_list)
 		__printflike(2, 0);
@@ -208,6 +204,13 @@
                 int (*)(void*));
 #endif
 
+FILE* fopen(const char* __restrict, const char* __restrict);
+FILE* fopen64(const char* __restrict, const char* __restrict);
+FILE* freopen(const char* __restrict, const char* __restrict, FILE* __restrict);
+FILE* freopen64(const char* __restrict, const char* __restrict, FILE* __restrict);
+FILE* tmpfile(void);
+FILE* tmpfile64(void);
+
 #if __ISO_C_VISIBLE >= 1999 || __BSD_VISIBLE
 int	 snprintf(char * __restrict, size_t, const char * __restrict, ...)
 		__printflike(3, 4);
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 342cfad..f51942b 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -462,8 +462,8 @@
 #define __size_mul_overflow(a, b, result) __builtin_umul_overflow(a, b, result)
 #endif
 #else
-static __inline__ __always_inline int __size_mul_overflow(__SIZE_TYPE__ a, __SIZE_TYPE__ b,
-                                                          __SIZE_TYPE__ *result) {
+extern __inline__ __always_inline __attribute__((gnu_inline))
+int __size_mul_overflow(__SIZE_TYPE__ a, __SIZE_TYPE__ b, __SIZE_TYPE__ *result) {
     *result = a * b;
     static const __SIZE_TYPE__ mul_no_overflow = 1UL << (sizeof(__SIZE_TYPE__) * 4);
     return (a >= mul_no_overflow || b >= mul_no_overflow) && a > 0 && (__SIZE_TYPE__)-1 / a < b;
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index c0720b8..c7e9acc 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -164,7 +164,9 @@
 #define AF_IEEE802154 36
 #define AF_CAIF 37
 #define AF_ALG 38
-#define AF_MAX 39
+#define AF_NFC 39
+#define AF_VSOCK 40
+#define AF_MAX 41
 
 #define PF_UNSPEC AF_UNSPEC
 #define PF_UNIX AF_UNIX
@@ -205,6 +207,8 @@
 #define PF_IEEE802154 AF_IEEE802154
 #define PF_CAIF AF_CAIF
 #define PF_ALG AF_ALG
+#define PF_NFC AF_NFC
+#define PF_VSOCK AF_VSOCK
 #define PF_MAX AF_MAX
 
 #define SOMAXCONN 128
diff --git a/libc/include/sys/timex.h b/libc/include/sys/timex.h
index 4096e7d..6138ac4 100644
--- a/libc/include/sys/timex.h
+++ b/libc/include/sys/timex.h
@@ -29,6 +29,13 @@
 #ifndef _SYS_TIMEX_H_
 #define _SYS_TIMEX_H_
 
+#include <sys/cdefs.h>
 #include <linux/timex.h>
 
+__BEGIN_DECLS
+
+extern int adjtimex(struct timex *buf);
+
+__END_DECLS
+
 #endif /* _SYS_TIMEX_H_ */
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index 2a1c2de..9251de2 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -1226,9 +1226,12 @@
     __write_chk;
     fgetpos64;
     fileno_unlocked;
+    fopen64;
     freeifaddrs;
+    freopen64;
     fseeko64;
     fsetpos64;
+    ftello64;
     funopen64;
     getgrgid_r;
     getgrnam_r;
@@ -1257,6 +1260,7 @@
     scandirat;
     scandirat64;
     strchrnul;
+    tmpfile64;
 } LIBC;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 02dd58c..f5ddfd3 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1226,9 +1226,12 @@
     __write_chk;
     fgetpos64;
     fileno_unlocked;
+    fopen64;
     freeifaddrs;
+    freopen64;
     fseeko64;
     fsetpos64;
+    ftello64;
     funopen64;
     getgrgid_r;
     getgrnam_r;
@@ -1257,6 +1260,7 @@
     scandirat;
     scandirat64;
     strchrnul;
+    tmpfile64;
 } LIBC;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 0f5f1e8..271460f 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1149,9 +1149,12 @@
     __write_chk;
     fgetpos64;
     fileno_unlocked;
+    fopen64;
     freeifaddrs;
+    freopen64;
     fseeko64;
     fsetpos64;
+    ftello64;
     funopen64;
     getgrgid_r;
     getgrnam_r;
@@ -1179,6 +1182,7 @@
     scandirat;
     scandirat64;
     strchrnul;
+    tmpfile64;
 } LIBC;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 3a8f7d7..c859d81 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1252,9 +1252,12 @@
     __write_chk;
     fgetpos64;
     fileno_unlocked;
+    fopen64;
     freeifaddrs;
+    freopen64;
     fseeko64;
     fsetpos64;
+    ftello64;
     funopen64;
     getgrgid_r;
     getgrnam_r;
@@ -1283,6 +1286,7 @@
     scandirat;
     scandirat64;
     strchrnul;
+    tmpfile64;
 } LIBC;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index 100b78e..e5376be 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -1210,9 +1210,12 @@
     __write_chk;
     fgetpos64;
     fileno_unlocked;
+    fopen64;
     freeifaddrs;
+    freopen64;
     fseeko64;
     fsetpos64;
+    ftello64;
     funopen64;
     getgrgid_r;
     getgrnam_r;
@@ -1241,6 +1244,7 @@
     scandirat;
     scandirat64;
     strchrnul;
+    tmpfile64;
 } LIBC;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 0a92e1e..4902f57 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1210,9 +1210,12 @@
     __write_chk;
     fgetpos64;
     fileno_unlocked;
+    fopen64;
     freeifaddrs;
+    freopen64;
     fseeko64;
     fsetpos64;
+    ftello64;
     funopen64;
     getgrgid_r;
     getgrnam_r;
@@ -1241,6 +1244,7 @@
     scandirat;
     scandirat64;
     strchrnul;
+    tmpfile64;
 } LIBC;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 0f5f1e8..271460f 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1149,9 +1149,12 @@
     __write_chk;
     fgetpos64;
     fileno_unlocked;
+    fopen64;
     freeifaddrs;
+    freopen64;
     fseeko64;
     fsetpos64;
+    ftello64;
     funopen64;
     getgrgid_r;
     getgrnam_r;
@@ -1179,6 +1182,7 @@
     scandirat;
     scandirat64;
     strchrnul;
+    tmpfile64;
 } LIBC;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index db328cf..bbf9d57 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -1209,9 +1209,12 @@
     __write_chk;
     fgetpos64;
     fileno_unlocked;
+    fopen64;
     freeifaddrs;
+    freopen64;
     fseeko64;
     fsetpos64;
+    ftello64;
     funopen64;
     getgrgid_r;
     getgrnam_r;
@@ -1240,6 +1243,7 @@
     scandirat;
     scandirat64;
     strchrnul;
+    tmpfile64;
 } LIBC;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index f3c6e59..fb0f109 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1209,9 +1209,12 @@
     __write_chk;
     fgetpos64;
     fileno_unlocked;
+    fopen64;
     freeifaddrs;
+    freopen64;
     fseeko64;
     fsetpos64;
+    ftello64;
     funopen64;
     getgrgid_r;
     getgrnam_r;
@@ -1240,6 +1243,7 @@
     scandirat;
     scandirat64;
     strchrnul;
+    tmpfile64;
 } LIBC;
 
 LIBC_PRIVATE {
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 0f5f1e8..271460f 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1149,9 +1149,12 @@
     __write_chk;
     fgetpos64;
     fileno_unlocked;
+    fopen64;
     freeifaddrs;
+    freopen64;
     fseeko64;
     fsetpos64;
+    ftello64;
     funopen64;
     getgrgid_r;
     getgrnam_r;
@@ -1179,6 +1182,7 @@
     scandirat;
     scandirat64;
     strchrnul;
+    tmpfile64;
 } LIBC;
 
 LIBC_PRIVATE {
diff --git a/libc/malloc_debug/BacktraceData.cpp b/libc/malloc_debug/BacktraceData.cpp
index 9f39068..61267f0 100644
--- a/libc/malloc_debug/BacktraceData.cpp
+++ b/libc/malloc_debug/BacktraceData.cpp
@@ -42,11 +42,9 @@
 #include "malloc_debug.h"
 
 BacktraceData::BacktraceData(const Config& config, size_t* offset) {
-  size_t hdr_len = sizeof(BacktraceHeader) + sizeof(uintptr_t) * config.backtrace_frames - 1;
+  size_t hdr_len = sizeof(BacktraceHeader) + sizeof(uintptr_t) * config.backtrace_frames;
   alloc_offset_ = *offset;
   *offset += BIONIC_ALIGN(hdr_len, sizeof(uintptr_t));
-  free_offset_ = *offset;
-  *offset += BIONIC_ALIGN(hdr_len, sizeof(uintptr_t));
 }
 
 static BacktraceData* g_backtrace_data = nullptr;
diff --git a/libc/malloc_debug/BacktraceData.h b/libc/malloc_debug/BacktraceData.h
index 10daec7..842e372 100644
--- a/libc/malloc_debug/BacktraceData.h
+++ b/libc/malloc_debug/BacktraceData.h
@@ -44,14 +44,12 @@
   bool Initialize(const Config& config);
 
   inline size_t alloc_offset() { return alloc_offset_; }
-  inline size_t free_offset() { return free_offset_; }
 
   bool enabled() { return enabled_; }
   void set_enabled(bool enabled) { enabled_ = enabled; }
 
  private:
   size_t alloc_offset_ = 0;
-  size_t free_offset_ = 0;
 
   volatile bool enabled_ = false;
 
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index 224bb08..032c1fc 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -195,9 +195,17 @@
   error_log("    Instead, keep XX of these allocations around and then verify");
   error_log("    that they have not been modified when the total number of freed");
   error_log("    allocations exceeds the XX amount. When the program terminates,");
-  error_log("    the rest of these allocations are verified.");
+  error_log("    the rest of these allocations are verified. When this option is");
+  error_log("    enabled, it automatically records the backtrace at the time of the free.");
   error_log("    The default is to record 100 allocations.");
   error_log("");
+  error_log("  free_track_backtrace_num_frames[=XX]");
+  error_log("    This option only has meaning if free_track is set. This indicates");
+  error_log("    how many backtrace frames to capture when an allocation is freed.");
+  error_log("    If XX is set, that is the number of frames to capture. If XX");
+  error_log("    is set to zero, then no backtrace will be captured.");
+  error_log("    The default is to record 16 frames.");
+  error_log("");
   error_log("  leak_track");
   error_log("    Enable the leak tracking of memory allocations.");
 }
@@ -245,6 +253,7 @@
   front_guard_value = PropertyParser::DEFAULT_FRONT_GUARD_VALUE;
   rear_guard_value = PropertyParser::DEFAULT_REAR_GUARD_VALUE;
   backtrace_signal = SIGRTMIN + 10;
+  free_track_backtrace_num_frames = 16;
 
   // Parse the options are of the format:
   //   option_name or option_name=XX
@@ -286,6 +295,10 @@
     // fill on free.
     Feature("free_track", 100, 1, 16384, FREE_TRACK | FILL_ON_FREE, &this->free_track_allocations,
             nullptr, false),
+    // Number of backtrace frames to keep when free_track is enabled. If this
+    // value is set to zero, no backtrace will be kept.
+    Feature("free_track_backtrace_num_frames", 16, 0, 256, 0,
+            &this->free_track_backtrace_num_frames, nullptr, false),
 
     // Enable printing leaked allocations.
     Feature("leak_track", 0, 0, 0, LEAK_TRACK | TRACK_ALLOCS, nullptr, nullptr, false),
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index 4b91e2b..d2cc56d 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -61,6 +61,7 @@
   size_t expand_alloc_bytes = 0;
 
   size_t free_track_allocations = 0;
+  size_t free_track_backtrace_num_frames = 0;
 
   uint64_t options = 0;
   uint8_t fill_alloc_value;
diff --git a/libc/malloc_debug/DebugData.h b/libc/malloc_debug/DebugData.h
index e023c51..40978db 100644
--- a/libc/malloc_debug/DebugData.h
+++ b/libc/malloc_debug/DebugData.h
@@ -67,11 +67,6 @@
     return reinterpret_cast<BacktraceHeader*>(value + backtrace->alloc_offset());
   }
 
-  BacktraceHeader* GetFreeBacktrace(const Header* header) {
-    uintptr_t value = reinterpret_cast<uintptr_t>(header);
-    return reinterpret_cast<BacktraceHeader*>(value + backtrace->free_offset());
-  }
-
   uint8_t* GetFrontGuard(const Header* header) {
     uintptr_t value = reinterpret_cast<uintptr_t>(header);
     return reinterpret_cast<uint8_t*>(value + front_guard->offset());
diff --git a/libc/malloc_debug/FreeTrackData.cpp b/libc/malloc_debug/FreeTrackData.cpp
index 3466861..3ac54bf 100644
--- a/libc/malloc_debug/FreeTrackData.cpp
+++ b/libc/malloc_debug/FreeTrackData.cpp
@@ -36,7 +36,8 @@
 #include "FreeTrackData.h"
 #include "malloc_debug.h"
 
-FreeTrackData::FreeTrackData(const Config& config) {
+FreeTrackData::FreeTrackData(const Config& config)
+    : backtrace_num_frames_(config.free_track_backtrace_num_frames) {
   cmp_mem_.resize(4096);
   memset(cmp_mem_.data(), config.fill_free_value, cmp_mem_.size());
 }
@@ -53,18 +54,19 @@
       error_log("  pointer[%zu] = 0x%02x (expected 0x%02x)", i, pointer[i], fill_free_value);
     }
   }
-  if (debug.config().options & BACKTRACE) {
-    BacktraceHeader* back_header = debug.GetFreeBacktrace(header);
-    if (back_header->num_frames > 0) {
-      error_log("Backtrace at time of free:");
-      backtrace_log(&back_header->frames[0], back_header->num_frames);
-    }
+  auto back_iter = backtraces_.find(header);
+  if (back_iter != backtraces_.end()) {
+    const BacktraceHeader* back_header = back_iter->second;
+    error_log("Backtrace at time of free:");
+    backtrace_log(&back_header->frames[0], back_header->num_frames);
   }
   error_log(LOG_DIVIDER);
 }
 
 void FreeTrackData::VerifyAndFree(DebugData& debug, const Header* header,
                                   const void* pointer) {
+  ScopedDisableDebugCalls disable;
+
   const uint8_t* memory = reinterpret_cast<const uint8_t*>(pointer);
   size_t bytes = header->usable_size;
   bytes = (bytes < debug.config().fill_on_free_bytes) ? bytes : debug.config().fill_on_free_bytes;
@@ -77,6 +79,11 @@
     bytes -= bytes_to_cmp;
     memory = &memory[bytes_to_cmp];
   }
+  auto back_iter = backtraces_.find(header);
+  if (back_iter != backtraces_.end()) {
+    g_dispatch->free(reinterpret_cast<void*>(back_iter->second));
+    backtraces_.erase(header);
+  }
   g_dispatch->free(header->orig_pointer);
 }
 
@@ -86,10 +93,20 @@
 
   pthread_mutex_lock(&mutex_);
   if (list_.size() == debug.config().free_track_allocations) {
-    VerifyAndFree(debug, list_.back(), debug.GetPointer(list_.back()));
+    const Header* old_header = list_.back();
+    VerifyAndFree(debug, old_header, debug.GetPointer(old_header));
     list_.pop_back();
   }
 
+  // Only log the free backtrace if we are using the free track feature.
+  if (backtrace_num_frames_ > 0) {
+    BacktraceHeader* back_header = reinterpret_cast<BacktraceHeader*>(
+      g_dispatch->malloc(sizeof(BacktraceHeader) + backtrace_num_frames_ * sizeof(uintptr_t)));
+    if (back_header) {
+      back_header->num_frames = backtrace_get(&back_header->frames[0], backtrace_num_frames_);
+      backtraces_[header] = back_header;
+    }
+  }
   list_.push_front(header);
 
   pthread_mutex_unlock(&mutex_);
@@ -104,3 +121,15 @@
   }
   list_.clear();
 }
+
+void FreeTrackData::LogBacktrace(const Header* header) {
+  ScopedDisableDebugCalls disable;
+
+  auto back_iter = backtraces_.find(header);
+  if (back_iter == backtraces_.end()) {
+    return;
+  }
+
+  error_log("Backtrace of original free:");
+  backtrace_log(&back_iter->second->frames[0], back_iter->second->num_frames);
+}
diff --git a/libc/malloc_debug/FreeTrackData.h b/libc/malloc_debug/FreeTrackData.h
index 5888a0e..804b5a6 100644
--- a/libc/malloc_debug/FreeTrackData.h
+++ b/libc/malloc_debug/FreeTrackData.h
@@ -33,6 +33,7 @@
 #include <pthread.h>
 
 #include <deque>
+#include <unordered_map>
 #include <vector>
 
 #include <private/bionic_macros.h>
@@ -41,6 +42,7 @@
 struct Header;
 class DebugData;
 struct Config;
+struct BacktraceHeader;
 
 class FreeTrackData {
  public:
@@ -51,6 +53,8 @@
 
   void VerifyAll(DebugData& debug);
 
+  void LogBacktrace(const Header* header);
+
  private:
   void LogFreeError(DebugData& debug, const Header* header, const uint8_t* pointer);
   void VerifyAndFree(DebugData& debug, const Header* header, const void* pointer);
@@ -58,6 +62,8 @@
   pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
   std::deque<const Header*> list_;
   std::vector<uint8_t> cmp_mem_;
+  std::unordered_map<const Header*, BacktraceHeader*> backtraces_;
+  size_t backtrace_num_frames_;
 
   DISALLOW_COPY_AND_ASSIGN(FreeTrackData);
 };
diff --git a/libc/malloc_debug/backtrace.cpp b/libc/malloc_debug/backtrace.cpp
index 00290fd..8549dc4 100644
--- a/libc/malloc_debug/backtrace.cpp
+++ b/libc/malloc_debug/backtrace.cpp
@@ -143,7 +143,7 @@
   return state.cur_frame;
 }
 
-void backtrace_log(uintptr_t* frames, size_t frame_count) {
+void backtrace_log(const uintptr_t* frames, size_t frame_count) {
   ScopedDisableDebugCalls disable;
 
   for (size_t frame_num = 0; frame_num < frame_count; frame_num++) {
diff --git a/libc/malloc_debug/backtrace.h b/libc/malloc_debug/backtrace.h
index 513a649..9e01009 100644
--- a/libc/malloc_debug/backtrace.h
+++ b/libc/malloc_debug/backtrace.h
@@ -35,6 +35,6 @@
 void backtrace_startup();
 void backtrace_shutdown();
 size_t backtrace_get(uintptr_t* frames, size_t frame_count);
-void backtrace_log(uintptr_t* frames, size_t frame_count);
+void backtrace_log(const uintptr_t* frames, size_t frame_count);
 
 #endif // MALLOC_DEBUG_BACKTRACE_H
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index f55d488..4f86579 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -88,7 +88,14 @@
   ScopedDisableDebugCalls disable;
 
   error_log(LOG_DIVIDER);
-  error_log("+++ ALLOCATION %p HAS INVALID TAG %" PRIx32 " (%s)", pointer, header->tag, name);
+  if (header->tag == DEBUG_FREE_TAG) {
+    error_log("+++ ALLOCATION %p USED AFTER FREE (%s)", pointer, name);
+    if (g_debug->config().options & FREE_TRACK) {
+      g_debug->free_track->LogBacktrace(header);
+    }
+  } else {
+    error_log("+++ ALLOCATION %p HAS INVALID TAG %" PRIx32 " (%s)", pointer, header->tag, name);
+  }
   error_log("Backtrace at time of failure:");
   std::vector<uintptr_t> frames(64);
   size_t frame_num = backtrace_get(frames.data(), frames.size());
@@ -129,14 +136,12 @@
   if (g_debug->config().options & BACKTRACE) {
     BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
     if (g_debug->backtrace->enabled()) {
-      back_header->num_frames = backtrace_get(&back_header->frames[0],
-                                              g_debug->config().backtrace_frames);
+      back_header->num_frames = backtrace_get(
+          &back_header->frames[0], g_debug->config().backtrace_frames);
       backtrace_found = back_header->num_frames > 0;
     } else {
       back_header->num_frames = 0;
     }
-    back_header = g_debug->GetFreeBacktrace(header);
-    back_header->num_frames = 0;
   }
 
   if (g_debug->config().options & TRACK_ALLOCS) {
@@ -313,18 +318,12 @@
     }
 
     if (g_debug->config().options & FREE_TRACK) {
-      // Only log the free backtrace if we are using the free track feature.
-      if ((g_debug->config().options & BACKTRACE) && g_debug->backtrace->enabled()) {
-        BacktraceHeader* back_header = g_debug->GetFreeBacktrace(header);
-        back_header->num_frames = backtrace_get(&back_header->frames[0],
-                                                g_debug->config().backtrace_frames);
-      }
-
       g_debug->free_track->Add(*g_debug, header);
 
       // Do not free this pointer just yet.
       free_pointer = nullptr;
     }
+    header->tag = DEBUG_FREE_TAG;
 
     bytes = header->usable_size;
   } else {
diff --git a/libc/malloc_debug/malloc_debug.h b/libc/malloc_debug/malloc_debug.h
index 4a15f77..6f9f90f 100644
--- a/libc/malloc_debug/malloc_debug.h
+++ b/libc/malloc_debug/malloc_debug.h
@@ -39,7 +39,6 @@
 // will still be in this order.
 //   Header          (Required)
 //   BacktraceHeader (Optional: For the allocation backtrace)
-//   BacktraceHeader (Optional: For the free backtrace)
 //   uint8_t data    (Optional: Front guard, will be a multiple of sizeof(uintptr_t))
 //   allocation data
 //   uint8_t data    (Optional: End guard)
@@ -59,17 +58,13 @@
   static size_t max_size() { return (1U << 31) - 1; }
 } __attribute__((packed));
 
-struct TrackHeader {
-  Header* prev = nullptr;
-  Header* next = nullptr;
-} __attribute__((packed));
-
 struct BacktraceHeader {
   size_t num_frames;
   uintptr_t frames[0];
 } __attribute__((packed));
 
 constexpr uint32_t DEBUG_TAG = 0x1ee7d00d;
+constexpr uint32_t DEBUG_FREE_TAG = 0x1cc7dccd;
 constexpr char LOG_DIVIDER[] = "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***";
 constexpr size_t FREE_TRACK_MEM_BUFFER_SIZE = 4096;
 
diff --git a/libc/malloc_debug/tests/backtrace_fake.cpp b/libc/malloc_debug/tests/backtrace_fake.cpp
index 32da696..db542e5 100644
--- a/libc/malloc_debug/tests/backtrace_fake.cpp
+++ b/libc/malloc_debug/tests/backtrace_fake.cpp
@@ -52,7 +52,7 @@
   return total_frames;
 }
 
-void backtrace_log(uintptr_t* frames, size_t frame_count) {
+void backtrace_log(const uintptr_t* frames, size_t frame_count) {
   for (size_t i = 0; i < frame_count; i++) {
     error_log("  #%02zd pc %p", i, reinterpret_cast<void*>(frames[i]));
   }
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index 247e319..551e498 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -99,9 +99,17 @@
   "6 malloc_debug     Instead, keep XX of these allocations around and then verify\n"
   "6 malloc_debug     that they have not been modified when the total number of freed\n"
   "6 malloc_debug     allocations exceeds the XX amount. When the program terminates,\n"
-  "6 malloc_debug     the rest of these allocations are verified.\n"
+  "6 malloc_debug     the rest of these allocations are verified. When this option is\n"
+  "6 malloc_debug     enabled, it automatically records the backtrace at the time of the free.\n"
   "6 malloc_debug     The default is to record 100 allocations.\n"
   "6 malloc_debug \n"
+  "6 malloc_debug   free_track_backtrace_num_frames[=XX]\n"
+  "6 malloc_debug     This option only has meaning if free_track is set. This indicates\n"
+  "6 malloc_debug     how many backtrace frames to capture when an allocation is freed.\n"
+  "6 malloc_debug     If XX is set, that is the number of frames to capture. If XX\n"
+  "6 malloc_debug     is set to zero, then no backtrace will be captured.\n"
+  "6 malloc_debug     The default is to record 16 frames.\n"
+  "6 malloc_debug \n"
   "6 malloc_debug   leak_track\n"
   "6 malloc_debug     Enable the leak tracking of memory allocations.\n"
 );
@@ -339,11 +347,13 @@
   ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
   ASSERT_EQ(1234U, config->free_track_allocations);
   ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes);
+  ASSERT_EQ(16U, config->free_track_backtrace_num_frames);
 
   ASSERT_TRUE(InitConfig("free_track"));
   ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
   ASSERT_EQ(100U, config->free_track_allocations);
   ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes);
+  ASSERT_EQ(16U, config->free_track_backtrace_num_frames);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -354,11 +364,50 @@
   ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
   ASSERT_EQ(1234U, config->free_track_allocations);
   ASSERT_EQ(32U, config->fill_on_free_bytes);
+  ASSERT_EQ(16U, config->free_track_backtrace_num_frames);
 
   ASSERT_TRUE(InitConfig("free_track fill_on_free=60"));
   ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
   ASSERT_EQ(100U, config->free_track_allocations);
   ASSERT_EQ(60U, config->fill_on_free_bytes);
+  ASSERT_EQ(16U, config->free_track_backtrace_num_frames);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, free_track_backtrace_num_frames) {
+  ASSERT_TRUE(InitConfig("free_track_backtrace_num_frames=123"));
+
+  ASSERT_EQ(0U, config->options);
+  ASSERT_EQ(123U, config->free_track_backtrace_num_frames);
+
+  ASSERT_TRUE(InitConfig("free_track_backtrace_num_frames"));
+  ASSERT_EQ(0U, config->options);
+  ASSERT_EQ(16U, config->free_track_backtrace_num_frames);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, free_track_backtrace_num_frames_zero) {
+  ASSERT_TRUE(InitConfig("free_track_backtrace_num_frames=0"));
+
+  ASSERT_EQ(0U, config->options);
+  ASSERT_EQ(0U, config->free_track_backtrace_num_frames);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, free_track_backtrace_num_frames_and_free_track) {
+  ASSERT_TRUE(InitConfig("free_track free_track_backtrace_num_frames=123"));
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
+  ASSERT_EQ(123U, config->free_track_backtrace_num_frames);
+
+  ASSERT_TRUE(InitConfig("free_track free_track_backtrace_num_frames"));
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
+  ASSERT_EQ(16U, config->free_track_backtrace_num_frames);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -550,3 +599,13 @@
       "value must be <= 16384: 21000\n");
   ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
 }
+
+TEST_F(MallocDebugConfigTest, free_track_backtrace_num_frames_max_error) {
+  ASSERT_FALSE(InitConfig("free_track_backtrace_num_frames=400"));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg(
+      "6 malloc_debug malloc_testing: bad value for option 'free_track_backtrace_num_frames', "
+      "value must be <= 256: 400\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 08731c2..9fc8a57 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -67,17 +67,12 @@
 constexpr char DIVIDER[] =
     "6 malloc_debug *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n";
 
-constexpr uint32_t TRACK_HEADER = 0x2;
-constexpr uint32_t BACKTRACE_HEADER = 0x4;
+constexpr uint32_t BACKTRACE_HEADER = 0x1;
 
 static size_t get_tag_offset(uint32_t flags = 0, size_t backtrace_frames = 0) {
   size_t offset = BIONIC_ALIGN(sizeof(Header), sizeof(uintptr_t));
-  if (flags & TRACK_HEADER) {
-    offset += BIONIC_ALIGN(sizeof(TrackHeader), sizeof(uintptr_t));
-  }
   if (flags & BACKTRACE_HEADER) {
-    offset += BIONIC_ALIGN(sizeof(BacktraceHeader) + sizeof(uintptr_t) * backtrace_frames - 1, sizeof(uintptr_t));
-    offset += BIONIC_ALIGN(sizeof(BacktraceHeader) + sizeof(uintptr_t) * backtrace_frames - 1, sizeof(uintptr_t));
+    offset += BIONIC_ALIGN(sizeof(BacktraceHeader) + sizeof(uintptr_t) * backtrace_frames, sizeof(uintptr_t));
   }
   return offset;
 }
@@ -209,7 +204,7 @@
 }
 
 TEST_F(MallocDebugTest, fill_on_free) {
-  Init("fill_on_free free_track");
+  Init("fill_on_free free_track free_track_backtrace_num_frames=0");
 
   uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
   ASSERT_TRUE(pointer != nullptr);
@@ -226,7 +221,7 @@
 }
 
 TEST_F(MallocDebugTest, fill_on_free_partial) {
-  Init("fill_on_free=30 free_track");
+  Init("fill_on_free=30 free_track free_track_backtrace_num_frames=0");
 
   uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
   ASSERT_TRUE(pointer != nullptr);
@@ -246,7 +241,7 @@
 }
 
 TEST_F(MallocDebugTest, free_track_partial) {
-  Init("fill_on_free=30 free_track");
+  Init("fill_on_free=30 free_track free_track_backtrace_num_frames=0");
 
   uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
   ASSERT_TRUE(pointer != nullptr);
@@ -688,7 +683,7 @@
 }
 
 TEST_F(MallocDebugTest, free_track) {
-  Init("free_track=5");
+  Init("free_track=5 free_track_backtrace_num_frames=0");
 
   void* pointers[10];
   for (size_t i = 0; i < sizeof(pointers) / sizeof(void*); i++) {
@@ -714,7 +709,7 @@
 }
 
 TEST_F(MallocDebugTest, free_track_use_after_free) {
-  Init("free_track=5");
+  Init("free_track=5 free_track_backtrace_num_frames=0");
 
   uint8_t* pointers[5];
   for (size_t i = 0; i < sizeof(pointers) / sizeof(void*); i++) {
@@ -779,7 +774,7 @@
 }
 
 TEST_F(MallocDebugTest, free_track_use_after_free_finalize) {
-  Init("free_track=100");
+  Init("free_track=100 free_track_backtrace_num_frames=0");
 
   uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
   ASSERT_TRUE(pointer != nullptr);
@@ -803,10 +798,8 @@
 }
 
 TEST_F(MallocDebugTest, free_track_use_after_free_with_backtrace) {
-  Init("free_track=100 backtrace");
+  Init("free_track=100");
 
-  // Alloc backtrace.
-  backtrace_fake_add(std::vector<uintptr_t> {0xf0, 0xe, 0xd});
   // Free backtrace.
   backtrace_fake_add(std::vector<uintptr_t> {0xfa, 0xeb, 0xdc});
 
@@ -835,6 +828,72 @@
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
 
+TEST_F(MallocDebugTest, free_track_use_after_free_call_realloc) {
+  Init("free_track=100");
+
+  // Free backtrace.
+  backtrace_fake_add(std::vector<uintptr_t> {0xfa, 0xeb, 0xdc});
+  // Backtrace at realloc.
+  backtrace_fake_add(std::vector<uintptr_t> {0x12, 0x22, 0x32, 0x42});
+
+  void* pointer = debug_malloc(200);
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, 200);
+  debug_free(pointer);
+
+  // Choose a size that should not trigger a realloc to verify tag is
+  // verified early.
+  ASSERT_TRUE(debug_realloc(pointer, 200) == nullptr);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log(DIVIDER);
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ ALLOCATION %p USED AFTER FREE (realloc)\n", pointer);
+  expected_log += "6 malloc_debug Backtrace of original free:\n";
+  expected_log += "6 malloc_debug   #00 pc 0xfa\n";
+  expected_log += "6 malloc_debug   #01 pc 0xeb\n";
+  expected_log += "6 malloc_debug   #02 pc 0xdc\n";
+  expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+  expected_log += "6 malloc_debug   #00 pc 0x12\n";
+  expected_log += "6 malloc_debug   #01 pc 0x22\n";
+  expected_log += "6 malloc_debug   #02 pc 0x32\n";
+  expected_log += "6 malloc_debug   #03 pc 0x42\n";
+  expected_log += DIVIDER;
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, free_track_use_after_free_call_free) {
+  Init("free_track=100");
+
+  // Free backtrace.
+  backtrace_fake_add(std::vector<uintptr_t> {0xfa, 0xeb, 0xdc});
+  // Backtrace at second free.
+  backtrace_fake_add(std::vector<uintptr_t> {0x12, 0x22, 0x32, 0x42});
+
+  void* pointer = debug_malloc(200);
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, 200);
+  debug_free(pointer);
+
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log(DIVIDER);
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ ALLOCATION %p USED AFTER FREE (free)\n", pointer);
+  expected_log += "6 malloc_debug Backtrace of original free:\n";
+  expected_log += "6 malloc_debug   #00 pc 0xfa\n";
+  expected_log += "6 malloc_debug   #01 pc 0xeb\n";
+  expected_log += "6 malloc_debug   #02 pc 0xdc\n";
+  expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+  expected_log += "6 malloc_debug   #00 pc 0x12\n";
+  expected_log += "6 malloc_debug   #01 pc 0x22\n";
+  expected_log += "6 malloc_debug   #02 pc 0x32\n";
+  expected_log += "6 malloc_debug   #03 pc 0x42\n";
+  expected_log += DIVIDER;
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
 TEST_F(MallocDebugTest, get_malloc_leak_info_invalid) {
   Init("fill");
 
diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp
index 16cbd55..1c31a27 100644
--- a/libc/stdio/stdio.cpp
+++ b/libc/stdio/stdio.cpp
@@ -222,6 +222,7 @@
 
   return fp;
 }
+__strong_alias(fopen64, fopen);
 
 FILE* fdopen(int fd, const char* mode) {
   int oflags;
@@ -358,6 +359,7 @@
   if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
   return fp;
 }
+__strong_alias(freopen64, freopen);
 
 int fclose(FILE* fp) {
   if (fp->_flags == 0) {
diff --git a/libc/tools/check-symbols-glibc.py b/libc/tools/check-symbols-glibc.py
index 27b92c4..c5dbdcf 100755
--- a/libc/tools/check-symbols-glibc.py
+++ b/libc/tools/check-symbols-glibc.py
@@ -79,6 +79,7 @@
   'fgetln',
   'fpurge',
   'funopen',
+  'funopen64',
   'gamma_r',
   'gammaf_r',
   'getprogname',
diff --git a/tests/Android.mk b/tests/Android.mk
index 3712920..fb3c254 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -162,7 +162,7 @@
       -D_FORTIFY_SOURCE=$(test) \
       -DTEST_NAME=Fortify$(test)_$(compiler)); \
     $(eval fortify$(test)-tests-$(compiler)_src_files := \
-      fortify_test.cpp); \
+      fortify_test_main.cpp); \
     $(eval fortify_libs += fortify$(test)-tests-$(compiler)); \
   ) \
 )
diff --git a/tests/file-check-cxx b/tests/file-check-cxx
index 4018265..d3bc5f7 100755
--- a/tests/file-check-cxx
+++ b/tests/file-check-cxx
@@ -5,7 +5,7 @@
 shift 3
 SOURCE=$(echo "$@" | grep -oP '\S+\.cpp\b')
 OBJ=$(echo "$@" | grep -oP '\S+\.o\b')
-$CXX "$@" 2>&1 | $FILECHECK -check-prefix=$PREFIX $SOURCE
+$CXX "$@" -Wno-error 2>&1 | $FILECHECK -check-prefix=$PREFIX $SOURCE
 if [ "$?" -eq 0 ]; then
   touch $OBJ
 else
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index a349da9..4ffd5f9 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -14,6 +14,14 @@
  * limitations under the License.
  */
 
+// -Werror is on whether we like it or not, and we're intentionally doing awful
+// things in this file. GCC is dumb and doesn't have a specific error class for
+// the fortify failures (it's just -Werror), so we can't use anything more
+// constrained than disabling all the warnings in the file :( It also won't let
+// us use system_header in a .cpp file, so we have to #include this from
+// fortify_test_main.cpp.
+#pragma GCC system_header
+
 #include <gtest/gtest.h>
 #include "BionicDeathTest.h"
 
diff --git a/tests/fortify_test_main.cpp b/tests/fortify_test_main.cpp
new file mode 100644
index 0000000..8e52d42
--- /dev/null
+++ b/tests/fortify_test_main.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fortify_test.cpp"
diff --git a/tests/ifaddrs_test.cpp b/tests/ifaddrs_test.cpp
index 8c45947..2c34633 100644
--- a/tests/ifaddrs_test.cpp
+++ b/tests/ifaddrs_test.cpp
@@ -109,55 +109,55 @@
 }
 
 TEST(ifaddrs, getifaddrs_INET) {
-  std::multimap<std::string,in_addr_t> inetaddrs;
-  std::multimap<std::string,in_addr_t> broadinetaddrs;
+  std::multimap<std::string, in_addr_t> inetaddrs;
+  std::multimap<std::string, in_addr_t> broadinetaddrs;
 
-  {
-    ifaddrs* addrs;
-    ASSERT_EQ(0, getifaddrs(&addrs));
-    for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) {
-      if (addr->ifa_name && addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET) {
-        auto sock = reinterpret_cast<sockaddr_in*>(addr->ifa_addr);
-        inetaddrs.emplace(std::string(addr->ifa_name), sock->sin_addr.s_addr);
-      }
-      if (addr->ifa_name && addr->ifa_broadaddr && addr->ifa_broadaddr->sa_family == AF_INET) {
-        auto sock = reinterpret_cast<sockaddr_in*>(addr->ifa_broadaddr);
-        broadinetaddrs.emplace(std::string(addr->ifa_name), sock->sin_addr.s_addr);
-      }
+  // Collect the IPv4 addresses for each interface.
+  ifaddrs* addrs;
+  ASSERT_EQ(0, getifaddrs(&addrs));
+  for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) {
+    if (addr->ifa_name && addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET) {
+      auto sock = reinterpret_cast<sockaddr_in*>(addr->ifa_addr);
+      inetaddrs.emplace(std::string(addr->ifa_name), sock->sin_addr.s_addr);
     }
-    freeifaddrs(addrs);
+    if (addr->ifa_name && addr->ifa_broadaddr && addr->ifa_broadaddr->sa_family == AF_INET) {
+      auto sock = reinterpret_cast<sockaddr_in*>(addr->ifa_broadaddr);
+      broadinetaddrs.emplace(std::string(addr->ifa_name), sock->sin_addr.s_addr);
+    }
   }
+  freeifaddrs(addrs);
 
-  {
-    int fd = socket(AF_INET, SOCK_DGRAM, 0);
-    ASSERT_TRUE(fd != -1);
+  // Check that the addresses returned by the SIOCGIFADDR and SIOCGIFBRDADDR ioctls
+  // are in our collections.
+  auto check_inet_agrees = [&](std::multimap<std::string, in_addr_t> addrs, int request)->void {
+    for (auto it = addrs.begin(); it != addrs.end(); ) {
+      std::string if_name(it->first);
 
-    auto check_inet_agrees = [&](std::multimap<std::string, in_addr_t> addrs, int request)->bool {
-      for (auto it = addrs.begin(); it != addrs.end(); ) {
-        ifreq ifr;
-        ifr.ifr_addr.sa_family = AF_INET;
-        it->first.copy(ifr.ifr_name, IFNAMSIZ - 1);
-        ioctl(fd, request, &ifr);
+      ifreq ifr;
+      memset(&ifr, 0, sizeof(ifr));
+      ifr.ifr_addr.sa_family = AF_INET;
+      if_name.copy(ifr.ifr_name, IFNAMSIZ - 1);
 
-        sockaddr_in* sock = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr);
-        in_addr_t addr = sock->sin_addr.s_addr;
+      int fd = socket(AF_INET, SOCK_DGRAM, 0);
+      ASSERT_TRUE(fd != -1);
+      ASSERT_EQ(0, ioctl(fd, request, &ifr)) << if_name << ' ' << strerror(errno);
+      close(fd);
 
-        bool found = false;
-        for (auto ub = addrs.upper_bound(it->first); it != ub; ++it) {
-          if (it->second == addr) {
-            found = true;
-          }
+      sockaddr_in* sock = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr);
+      in_addr_t addr = sock->sin_addr.s_addr;
+
+      bool found = false;
+      for (auto ub = addrs.upper_bound(it->first); it != ub; ++it) {
+        if (it->second == addr) {
+          found = true;
         }
-        if (!found) return false;
       }
-      return true;
-    };
+      EXPECT_TRUE(found) << if_name;
+    }
+  };
 
-    ASSERT_TRUE(check_inet_agrees(inetaddrs, SIOCGIFADDR));
-    ASSERT_TRUE(check_inet_agrees(broadinetaddrs, SIOCGIFBRDADDR));
-
-    close(fd);
-  }
+  check_inet_agrees(inetaddrs, SIOCGIFADDR);
+  check_inet_agrees(broadinetaddrs, SIOCGIFBRDADDR);
 }
 
 static void print_sockaddr_ll(const char* what, const sockaddr* p) {
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index b6f6526..2912be4 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -79,6 +79,12 @@
   fclose(fp);
 }
 
+TEST(STDIO_TEST, tmpfile64) {
+  FILE* fp = tmpfile64();
+  ASSERT_TRUE(fp != nullptr);
+  fclose(fp);
+}
+
 TEST(STDIO_TEST, dprintf) {
   TemporaryFile tf;
 
@@ -875,6 +881,14 @@
   fclose(fp);
 }
 
+TEST(STDIO_TEST, fopen64_freopen64) {
+  FILE* fp = fopen64("/proc/version", "r");
+  ASSERT_TRUE(fp != nullptr);
+  fp = freopen64("/proc/version", "re", fp);
+  ASSERT_TRUE(fp != nullptr);
+  fclose(fp);
+}
+
 // https://code.google.com/p/android/issues/detail?id=81155
 // http://b/18556607
 TEST(STDIO_TEST, fread_unbuffered_pathological_performance) {
@@ -1165,6 +1179,7 @@
 static void AssertFileOffsetAt(FILE* fp, off64_t offset) {
   EXPECT_EQ(offset, ftell(fp));
   EXPECT_EQ(offset, ftello(fp));
+  EXPECT_EQ(offset, ftello64(fp));
   fpos_t pos;
   fpos64_t pos64;
   EXPECT_EQ(0, fgetpos(fp, &pos));