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));