Merge "tests: use clang's -verify instead of FileCheck"
diff --git a/libc/Android.bp b/libc/Android.bp
index fa1eab6..5554f28 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -76,6 +76,7 @@
},
native_coverage: false,
recovery_available: true,
+ native_bridge_supported: true,
// lld complains about duplicate symbols in libcrt and libgcc. Suppress the
// warning since this is intended right now.
@@ -1692,6 +1693,7 @@
host_supported: true,
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
no_libcrt: true,
no_libgcc: true,
@@ -1824,6 +1826,7 @@
defaults: ["linux_bionic_supported"],
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
cflags: [
"-Wno-gcc-compat",
@@ -2082,6 +2085,7 @@
ndk_library {
name: "libc",
+ native_bridge_supported: true,
symbol_file: "libc.map.txt",
first_version: "9",
}
@@ -2091,6 +2095,7 @@
symbol_file: "libc.map.txt",
export_headers_as_system: true,
export_preprocessed_headers: ["include"],
+ native_bridge_supported: true,
export_include_dirs: [
"kernel/android/uapi",
"kernel/uapi",
diff --git a/libc/async_safe/Android.bp b/libc/async_safe/Android.bp
index fbaaad1..c28d53a 100644
--- a/libc/async_safe/Android.bp
+++ b/libc/async_safe/Android.bp
@@ -10,6 +10,7 @@
name: "libasync_safe",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
include_dirs: ["bionic/libc"],
header_libs: ["libc_headers", "liblog_headers"],
@@ -22,6 +23,7 @@
cc_library_headers {
name: "libasync_safe_headers",
recovery_available: true,
+ native_bridge_supported: true,
defaults: ["linux_bionic_supported"],
export_include_dirs: ["include"],
diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp
index fd99814..bf0494d 100644
--- a/libc/bionic/jemalloc_wrapper.cpp
+++ b/libc/bionic/jemalloc_wrapper.cpp
@@ -128,10 +128,10 @@
__BEGIN_DECLS
-size_t __mallinfo_narenas();
-size_t __mallinfo_nbins();
-struct mallinfo __mallinfo_arena_info(size_t);
-struct mallinfo __mallinfo_bin_info(size_t, size_t);
+size_t je_mallinfo_narenas();
+size_t je_mallinfo_nbins();
+struct mallinfo je_mallinfo_arena_info(size_t);
+struct mallinfo je_mallinfo_bin_info(size_t, size_t);
__END_DECLS
@@ -144,8 +144,8 @@
MallocXmlElem root(fp, "malloc", "version=\"jemalloc-1\"");
// Dump all of the large allocations in the arenas.
- for (size_t i = 0; i < __mallinfo_narenas(); i++) {
- struct mallinfo mi = __mallinfo_arena_info(i);
+ for (size_t i = 0; i < je_mallinfo_narenas(); i++) {
+ struct mallinfo mi = je_mallinfo_arena_info(i);
if (mi.hblkhd != 0) {
MallocXmlElem arena_elem(fp, "heap", "nr=\"%d\"", i);
{
@@ -154,8 +154,8 @@
MallocXmlElem(fp, "allocated-bins").Contents("%zu", mi.fsmblks);
size_t total = 0;
- for (size_t j = 0; j < __mallinfo_nbins(); j++) {
- struct mallinfo mi = __mallinfo_bin_info(i, j);
+ for (size_t j = 0; j < je_mallinfo_nbins(); j++) {
+ struct mallinfo mi = je_mallinfo_bin_info(i, j);
if (mi.ordblks != 0) {
MallocXmlElem bin_elem(fp, "bin", "nr=\"%d\"", j);
MallocXmlElem(fp, "allocated").Contents("%zu", mi.ordblks);
diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp
index 599ac6a..8035746 100644
--- a/libc/bionic/malloc_common_dynamic.cpp
+++ b/libc/bionic/malloc_common_dynamic.cpp
@@ -500,3 +500,40 @@
return HeapprofdMallopt(opcode, arg, arg_size);
}
// =============================================================================
+
+#if !defined(__LP64__) && defined(__arm__)
+// =============================================================================
+// Old platform only functions that some old 32 bit apps are still using.
+// See b/132175052.
+// Only compile the functions for 32 bit arm, so that new apps do not use
+// these functions.
+// =============================================================================
+extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size,
+ size_t* total_memory, size_t* backtrace_size) {
+ if (info == nullptr || overall_size == nullptr || info_size == nullptr ||
+ total_memory == nullptr || backtrace_size == nullptr) {
+ return;
+ }
+
+ *info = nullptr;
+ *overall_size = 0;
+ *info_size = 0;
+ *total_memory = 0;
+ *backtrace_size = 0;
+
+ android_mallopt_leak_info_t leak_info = {};
+ if (android_mallopt(M_GET_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info))) {
+ *info = leak_info.buffer;
+ *overall_size = leak_info.overall_size;
+ *info_size = leak_info.info_size;
+ *total_memory = leak_info.total_memory;
+ *backtrace_size = leak_info.backtrace_size;
+ }
+}
+
+extern "C" void free_malloc_leak_info(uint8_t* info) {
+ android_mallopt_leak_info_t leak_info = { .buffer = info };
+ android_mallopt(M_FREE_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info));
+}
+// =============================================================================
+#endif
diff --git a/libc/bionic/malloc_heapprofd.cpp b/libc/bionic/malloc_heapprofd.cpp
index 2aeb9bf..5d3735d 100644
--- a/libc/bionic/malloc_heapprofd.cpp
+++ b/libc/bionic/malloc_heapprofd.cpp
@@ -143,22 +143,23 @@
}
}
+constexpr char kHeapprofdProgramPropertyPrefix[] = "heapprofd.enable.";
+constexpr size_t kHeapprofdProgramPropertyPrefixSize = sizeof(kHeapprofdProgramPropertyPrefix) - 1;
+constexpr size_t kMaxCmdlineSize = 512;
+
static bool GetHeapprofdProgramProperty(char* data, size_t size) {
- constexpr char prefix[] = "heapprofd.enable.";
- // - 1 to skip nullbyte, which we will write later.
- constexpr size_t prefix_size = sizeof(prefix) - 1;
- if (size < prefix_size) {
+ if (size < kHeapprofdProgramPropertyPrefixSize) {
error_log("%s: Overflow constructing heapprofd property", getprogname());
return false;
}
- memcpy(data, prefix, prefix_size);
+ memcpy(data, kHeapprofdProgramPropertyPrefix, kHeapprofdProgramPropertyPrefixSize);
int fd = open("/proc/self/cmdline", O_RDONLY | O_CLOEXEC);
if (fd == -1) {
error_log("%s: Failed to open /proc/self/cmdline", getprogname());
return false;
}
- char cmdline[128];
+ char cmdline[kMaxCmdlineSize];
ssize_t rd = read(fd, cmdline, sizeof(cmdline) - 1);
close(fd);
if (rd == -1) {
@@ -167,7 +168,7 @@
}
cmdline[rd] = '\0';
char* first_arg = static_cast<char*>(memchr(cmdline, '\0', rd));
- if (first_arg == nullptr || first_arg == cmdline + size - 1) {
+ if (first_arg == nullptr) {
error_log("%s: Overflow reading cmdline", getprogname());
return false;
}
@@ -192,12 +193,12 @@
}
size_t name_size = static_cast<size_t>(first_arg - start);
- if (name_size >= size - prefix_size) {
+ if (name_size >= size - kHeapprofdProgramPropertyPrefixSize) {
error_log("%s: overflow constructing heapprofd property.", getprogname());
return false;
}
// + 1 to also copy the trailing null byte.
- memcpy(data + prefix_size, start, name_size + 1);
+ memcpy(data + kHeapprofdProgramPropertyPrefixSize, start, name_size + 1);
return true;
}
@@ -213,7 +214,7 @@
return true;
}
- char program_property[128];
+ char program_property[kHeapprofdProgramPropertyPrefixSize + kMaxCmdlineSize];
if (!GetHeapprofdProgramProperty(program_property,
sizeof(program_property))) {
return false;
diff --git a/libc/include/bits/seek_constants.h b/libc/include/bits/seek_constants.h
index 6b88606..6f3f22d 100644
--- a/libc/include/bits/seek_constants.h
+++ b/libc/include/bits/seek_constants.h
@@ -39,3 +39,23 @@
#define SEEK_CUR 1
/** Seek relative to the end of the file. */
#define SEEK_END 2
+
+#if defined(__USE_GNU)
+
+/**
+ * Seek to the first data (non-hole) location in the file
+ * greater than or equal to the given offset.
+ *
+ * See [lseek(2)](http://man7.org/linux/man-pages/man2/lseek.2.html).
+ */
+#define SEEK_DATA 3
+
+/**
+ * Seek to the first hole (non-data) location in the file
+ * greater than or equal to the given offset.
+ *
+ * See [lseek(2)](http://man7.org/linux/man-pages/man2/lseek.2.html).
+ */
+#define SEEK_HOLE 4
+
+#endif
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 4a734fc..bc26d2a 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1742,6 +1742,8 @@
LIBC_DEPRECATED {
global:
__system_property_wait_any;
+ free_malloc_leak_info; # arm
+ get_malloc_leak_info; # arm
};
LIBC_PLATFORM {
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 91e1d26..53fcead 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -29,6 +29,7 @@
#include <errno.h>
#include <inttypes.h>
#include <malloc.h>
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -103,6 +104,32 @@
__END_DECLS
// ------------------------------------------------------------------------
+class ScopedConcurrentLock {
+ public:
+ ScopedConcurrentLock() {
+ pthread_rwlock_rdlock(&lock_);
+ }
+ ~ScopedConcurrentLock() {
+ pthread_rwlock_unlock(&lock_);
+ }
+
+ static void Init() {
+ pthread_rwlockattr_t attr;
+ // Set the attribute so that when a write lock is pending, read locks are no
+ // longer granted.
+ pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
+ pthread_rwlock_init(&lock_, &attr);
+ }
+
+ static void BlockAllOperations() {
+ pthread_rwlock_wrlock(&lock_);
+ }
+
+ private:
+ static pthread_rwlock_t lock_;
+};
+pthread_rwlock_t ScopedConcurrentLock::lock_;
+
static void InitAtfork() {
static pthread_once_t atfork_init = PTHREAD_ONCE_INIT;
pthread_once(&atfork_init, []() {
@@ -257,6 +284,8 @@
info_log("%s: malloc debug enabled", getprogname());
}
+ ScopedConcurrentLock::Init();
+
return true;
}
@@ -265,6 +294,10 @@
return;
}
+ // Make sure that there are no other threads doing debug allocations
+ // before we kill everything.
+ ScopedConcurrentLock::BlockAllOperations();
+
// Turn off capturing allocations calls.
DebugDisableSet(true);
@@ -292,6 +325,8 @@
void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size,
size_t* total_memory, size_t* backtrace_size) {
+ ScopedConcurrentLock lock;
+
ScopedDisableDebugCalls disable;
// Verify the arguments.
@@ -325,6 +360,7 @@
if (DebugCallsDisabled() || pointer == nullptr) {
return g_dispatch->malloc_usable_size(pointer);
}
+ ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
if (!VerifyPointer(pointer, "malloc_usable_size")) {
@@ -388,6 +424,7 @@
if (DebugCallsDisabled()) {
return g_dispatch->malloc(size);
}
+ ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
void* pointer = InternalMalloc(size);
@@ -463,6 +500,7 @@
if (DebugCallsDisabled() || pointer == nullptr) {
return g_dispatch->free(pointer);
}
+ ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
if (g_debug->config().options() & RECORD_ALLOCS) {
@@ -480,6 +518,7 @@
if (DebugCallsDisabled()) {
return g_dispatch->memalign(alignment, bytes);
}
+ ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
if (bytes == 0) {
@@ -558,6 +597,7 @@
if (DebugCallsDisabled()) {
return g_dispatch->realloc(pointer, bytes);
}
+ ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
if (pointer == nullptr) {
@@ -676,6 +716,7 @@
if (DebugCallsDisabled()) {
return g_dispatch->calloc(nmemb, bytes);
}
+ ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
size_t size;
@@ -737,6 +778,8 @@
if (DebugCallsDisabled() || !g_debug->TrackPointers()) {
return g_dispatch->malloc_info(options, fp);
}
+ ScopedConcurrentLock lock;
+ ScopedDisableDebugCalls disable;
MallocXmlElem root(fp, "malloc", "version=\"debug-malloc-1\"");
std::vector<ListInfoType> list;
@@ -786,6 +829,7 @@
int debug_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t, size_t, void*),
void* arg) {
+ ScopedConcurrentLock lock;
if (g_debug->TrackPointers()) {
// Since malloc is disabled, don't bother acquiring any locks.
for (auto it = PointerData::begin(); it != PointerData::end(); ++it) {
@@ -800,6 +844,7 @@
}
void debug_malloc_disable() {
+ ScopedConcurrentLock lock;
g_dispatch->malloc_disable();
if (g_debug->pointer) {
g_debug->pointer->PrepareFork();
@@ -807,6 +852,7 @@
}
void debug_malloc_enable() {
+ ScopedConcurrentLock lock;
if (g_debug->pointer) {
g_debug->pointer->PostForkParent();
}
@@ -817,6 +863,7 @@
if (DebugCallsDisabled() || pointer == nullptr) {
return 0;
}
+ ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
if (!(g_debug->config().options() & BACKTRACE)) {
@@ -870,6 +917,7 @@
}
bool debug_write_malloc_leak_info(FILE* fp) {
+ ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
std::lock_guard<std::mutex> guard(g_dump_lock);
@@ -883,6 +931,7 @@
}
void debug_dump_heap(const char* file_name) {
+ ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
std::lock_guard<std::mutex> guard(g_dump_lock);
diff --git a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
index 71e8ebf..f85c45b 100644
--- a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
@@ -42,13 +42,15 @@
#include <log/log.h>
#include <string>
+#include <thread>
#include <vector>
#include "private/bionic_malloc.h"
-static constexpr time_t kTimeoutSeconds = 5;
+static constexpr time_t kTimeoutSeconds = 10;
-static void Exec(const char* test_name, const char* debug_options, pid_t* pid) {
+static void Exec(const char* test_name, const char* debug_options, pid_t* pid, int exit_code = 0,
+ time_t timeout_seconds = kTimeoutSeconds) {
int fds[2];
ASSERT_NE(-1, pipe(fds));
ASSERT_NE(-1, fcntl(fds[0], F_SETFL, O_NONBLOCK));
@@ -94,7 +96,8 @@
output.append(buffer.data(), bytes);
}
- if ((time(nullptr) - start_time) > kTimeoutSeconds) {
+ if ((time(nullptr) - start_time) > timeout_seconds) {
+ kill(*pid, SIGINT);
break;
}
}
@@ -109,7 +112,7 @@
done = true;
break;
}
- if ((time(nullptr) - start_time) > kTimeoutSeconds) {
+ if ((time(nullptr) - start_time) > timeout_seconds) {
break;
}
}
@@ -119,21 +122,23 @@
while (true) {
int kill_status;
int wait_pid = waitpid(*pid, &kill_status, WNOHANG);
- if (wait_pid == *pid || (time(nullptr) - start_time) > kTimeoutSeconds) {
+ if (wait_pid == *pid || (time(nullptr) - start_time) > timeout_seconds) {
break;
}
}
}
ASSERT_TRUE(done) << "Timed out waiting for waitpid, output:\n" << output;
- ASSERT_EQ(0, WEXITSTATUS(status)) << "Output:\n" << output;
+ ASSERT_FALSE(WIFSIGNALED(status))
+ << "Failed with signal " << WTERMSIG(status) << "\nOutput:\n" << output;
+ ASSERT_EQ(exit_code, WEXITSTATUS(status)) << "Output:\n" << output;
}
-static void GetLogStr(pid_t pid, std::string* log_str) {
+static void GetLogStr(pid_t pid, std::string* log_str, log_id log = LOG_ID_MAIN) {
log_str->clear();
logger_list* list;
- list = android_logger_list_open(LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid);
+ list = android_logger_list_open(log, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid);
ASSERT_TRUE(list != nullptr);
while (true) {
@@ -168,7 +173,8 @@
android_logger_list_close(list);
}
-static void FindStrings(pid_t pid, std::vector<const char*> match_strings) {
+static void FindStrings(pid_t pid, std::vector<const char*> match_strings,
+ time_t timeout_seconds = kTimeoutSeconds) {
std::string log_str;
time_t start = time(nullptr);
bool found_all;
@@ -184,7 +190,7 @@
if (found_all) {
return;
}
- if ((time(nullptr) - start) > kTimeoutSeconds) {
+ if ((time(nullptr) - start) > timeout_seconds) {
break;
}
}
@@ -414,3 +420,47 @@
TEST(MallocDebugSystemTest, verify_leak_allocation_limit) {
VerifyLeak("leak_memory_limit_");
}
+
+static constexpr int kExpectedExitCode = 30;
+
+TEST(MallocTests, DISABLED_exit_while_threads_allocating) {
+ std::atomic_uint32_t thread_mask;
+ thread_mask = 0;
+
+ for (size_t i = 0; i < 32; i++) {
+ std::thread malloc_thread([&thread_mask, i] {
+ while (true) {
+ void* ptr = malloc(100);
+ if (ptr == nullptr) {
+ exit(1000);
+ }
+ free(ptr);
+ thread_mask.fetch_or(1 << i);
+ }
+ });
+ malloc_thread.detach();
+ }
+
+ // Wait until each thread has done at least one allocation.
+ while (thread_mask.load() != 0xffffffff)
+ ;
+ exit(kExpectedExitCode);
+}
+
+// Verify that exiting while other threads are doing malloc operations,
+// that there are no crashes.
+TEST(MallocDebugSystemTest, exit_while_threads_allocating) {
+ for (size_t i = 0; i < 100; i++) {
+ SCOPED_TRACE(::testing::Message() << "Run " << i);
+ pid_t pid;
+ ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_exit_while_threads_allocating",
+ "verbose backtrace", &pid, kExpectedExitCode));
+
+ ASSERT_NO_FATAL_FAILURE(FindStrings(pid, std::vector<const char*>{"malloc debug enabled"}));
+
+ std::string log_str;
+ GetLogStr(pid, &log_str, LOG_ID_CRASH);
+ ASSERT_TRUE(log_str.find("Fatal signal") == std::string::npos)
+ << "Found crash in log.\nLog message: " << log_str;
+ }
+}
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index d306a21..1ecf122 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -204,6 +204,7 @@
__LIBC32_LEGACY_PUBLIC__ int _fwalk(int (*)(FILE*));
off64_t __sseek64(void*, off64_t, int);
+int __sflush_locked(FILE*);
int __swhatbuf(FILE*, size_t*, int*);
wint_t __fgetwc_unlock(FILE*);
wint_t __ungetwc(wint_t, FILE*);
diff --git a/libc/stdio/refill.c b/libc/stdio/refill.c
index cfa2bfd..1df4191 100644
--- a/libc/stdio/refill.c
+++ b/libc/stdio/refill.c
@@ -40,7 +40,7 @@
lflush(FILE *fp)
{
if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR))
- return (__sflush(fp)); /* ignored... */
+ return (__sflush_locked(fp)); /* ignored... */
return (0);
}
diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp
index 4cec757..91c7689 100644
--- a/libc/stdio/stdio.cpp
+++ b/libc/stdio/stdio.cpp
@@ -106,7 +106,7 @@
FILE* stdout = &__sF[1];
FILE* stderr = &__sF[2];
-static pthread_mutex_t __stdio_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+static pthread_mutex_t __stdio_mutex = PTHREAD_MUTEX_INITIALIZER;
static uint64_t __get_file_tag(FILE* fp) {
// Don't use a tag for the standard streams.
@@ -211,21 +211,23 @@
}
int _fwalk(int (*callback)(FILE*)) {
- pthread_mutex_lock(&__stdio_mutex);
int result = 0;
for (glue* g = &__sglue; g != nullptr; g = g->next) {
FILE* fp = g->iobs;
for (int n = g->niobs; --n >= 0; ++fp) {
- ScopedFileLock sfl(fp);
if (fp->_flags != 0 && (fp->_flags & __SIGN) == 0) {
result |= (*callback)(fp);
}
}
}
- pthread_mutex_unlock(&__stdio_mutex);
return result;
}
+extern "C" __LIBC_HIDDEN__ void __libc_stdio_cleanup(void) {
+ // Equivalent to fflush(nullptr), but without all the locking since we're shutting down anyway.
+ _fwalk(__sflush);
+}
+
static FILE* __fopen(int fd, int flags) {
#if !defined(__LP64__)
if (fd > SHRT_MAX) {
@@ -520,6 +522,11 @@
return 0;
}
+int __sflush_locked(FILE* fp) {
+ ScopedFileLock sfl(fp);
+ return __sflush(fp);
+}
+
int __sread(void* cookie, char* buf, int n) {
FILE* fp = reinterpret_cast<FILE*>(cookie);
return TEMP_FAILURE_RETRY(read(fp->_file, buf, n));
@@ -1061,7 +1068,7 @@
}
static int fflush_all() {
- return _fwalk(__sflush);
+ return _fwalk(__sflush_locked);
}
int fflush(FILE* fp) {
diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c
index 692e0c0..0efb118 100644
--- a/libc/stdlib/atexit.c
+++ b/libc/stdlib/atexit.c
@@ -188,7 +188,8 @@
/* If called via exit(), flush output of all open files. */
if (dso == NULL) {
- fflush(NULL);
+ extern void __libc_stdio_cleanup(void);
+ __libc_stdio_cleanup();
}
/* BEGIN android-changed: call __unregister_atfork if dso is not null */
diff --git a/libc/system_properties/Android.bp b/libc/system_properties/Android.bp
index 911afb1..8780dda 100644
--- a/libc/system_properties/Android.bp
+++ b/libc/system_properties/Android.bp
@@ -1,6 +1,7 @@
cc_library_static {
name: "libsystemproperties",
defaults: ["libc_defaults"],
+ native_bridge_supported: true,
srcs: [
"context_node.cpp",
"contexts_split.cpp",
diff --git a/libdl/Android.bp b/libdl/Android.bp
index b1ee5ab..e36ddc5 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -5,6 +5,7 @@
name: "libdl_static",
defaults: ["linux_bionic_supported"],
recovery_available: true,
+ native_bridge_supported: true,
srcs: [
"libdl.cpp",
@@ -32,6 +33,7 @@
cc_library {
name: "libdl",
recovery_available: true,
+ native_bridge_supported: true,
static_ndk_lib: true,
defaults: ["linux_bionic_supported"],
@@ -47,6 +49,7 @@
ldflags: [
"-Wl,--exclude-libs=libgcc.a",
+ "-Wl,--exclude-libs=libgcc_stripped.a",
"-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
"-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
"-Wl,--exclude-libs=libclang_rt.builtins-x86-android.a",
@@ -115,6 +118,7 @@
defaults: ["linux_bionic_supported"],
recovery_available: true,
+ native_bridge_supported: true,
// NOTE: --exclude-libs=libgcc.a makes sure that any symbols libdl.so pulls from
// libgcc.a are made static to libdl.so. This in turn ensures that libraries that
@@ -127,6 +131,7 @@
ldflags: [
"-Wl,--exclude-libs=libgcc.a",
+ "-Wl,--exclude-libs=libgcc_stripped.a",
"-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
"-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
"-Wl,--exclude-libs=libclang_rt.builtins-x86-android.a",
@@ -179,12 +184,14 @@
ndk_library {
name: "libdl",
+ native_bridge_supported: true,
symbol_file: "libdl.map.txt",
first_version: "9",
}
llndk_library {
name: "libdl",
+ native_bridge_supported: true,
symbol_file: "libdl.map.txt",
}
diff --git a/libm/Android.bp b/libm/Android.bp
index 8c32810..48b9a5f 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -507,6 +507,7 @@
integer_overflow: false,
},
stl: "none",
+ native_bridge_supported: true,
stubs: {
symbol_file: "libm.map.txt",
@@ -516,12 +517,14 @@
ndk_library {
name: "libm",
+ native_bridge_supported: true,
symbol_file: "libm.map.txt",
first_version: "9",
}
llndk_library {
name: "libm",
+ native_bridge_supported: true,
symbol_file: "libm.map.txt",
}
diff --git a/linker/Android.bp b/linker/Android.bp
index 95fd4f7..23ef5ac 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -2,6 +2,7 @@
name: "liblinker_malloc",
defaults: ["linux_bionic_supported"],
recovery_available: true,
+ native_bridge_supported: true,
srcs: [
"linker_memory.cpp",
@@ -318,6 +319,7 @@
ldflags: [
"-Wl,--exclude-libs=libgcc.a",
+ "-Wl,--exclude-libs=libgcc_stripped.a",
"-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
"-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
"-Wl,--exclude-libs=libclang_rt.builtins-x86-android.a",
@@ -360,6 +362,7 @@
name: "ld-android",
defaults: ["linux_bionic_supported"],
recovery_available: true,
+ native_bridge_supported: true,
nocrt: true,
system_shared_libs: [],
diff --git a/linker/linker.cpp b/linker/linker.cpp
index b59df73..0de17f7 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1039,7 +1039,7 @@
ZipEntry entry;
- if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
+ if (FindEntry(handle, file_path, &entry) != 0) {
// Entry was not found.
close(fd);
return -1;
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index eed84a4..67ebf37 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -134,10 +134,7 @@
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchive(lib_path.c_str(), &handle));
ZipEntry zip_entry;
- ZipString zip_name;
- zip_name.name = reinterpret_cast<const uint8_t*>(kLibZipSimpleZip);
- zip_name.name_length = strlen(kLibZipSimpleZip);
- ASSERT_EQ(0, FindEntry(handle, zip_name, &zip_entry));
+ ASSERT_EQ(0, FindEntry(handle, kLibZipSimpleZip, &zip_entry));
extinfo.library_fd_offset = zip_entry.offset;
CloseArchive(handle);
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 706de15..983592f 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -395,6 +395,60 @@
#endif
}
+TEST(malloc, malloc_info_matches_mallinfo) {
+#ifdef __BIONIC__
+ SKIP_WITH_HWASAN; // hwasan does not implement malloc_info
+
+ char* buf;
+ size_t bufsize;
+ FILE* memstream = open_memstream(&buf, &bufsize);
+ ASSERT_NE(nullptr, memstream);
+ size_t mallinfo_before_allocated_bytes = mallinfo().uordblks;
+ ASSERT_EQ(0, malloc_info(0, memstream));
+ size_t mallinfo_after_allocated_bytes = mallinfo().uordblks;
+ ASSERT_EQ(0, fclose(memstream));
+
+ tinyxml2::XMLDocument doc;
+ ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(buf));
+
+ size_t total_allocated_bytes = 0;
+ auto root = doc.FirstChildElement();
+ ASSERT_NE(nullptr, root);
+ ASSERT_STREQ("malloc", root->Name());
+ if (std::string(root->Attribute("version")) == "jemalloc-1") {
+ // Verify jemalloc version of this data.
+ ASSERT_STREQ("jemalloc-1", root->Attribute("version"));
+
+ auto arena = root->FirstChildElement();
+ for (; arena != nullptr; arena = arena->NextSiblingElement()) {
+ int val;
+
+ ASSERT_STREQ("heap", arena->Name());
+ ASSERT_EQ(tinyxml2::XML_SUCCESS, arena->QueryIntAttribute("nr", &val));
+ ASSERT_EQ(tinyxml2::XML_SUCCESS,
+ arena->FirstChildElement("allocated-large")->QueryIntText(&val));
+ total_allocated_bytes += val;
+ ASSERT_EQ(tinyxml2::XML_SUCCESS,
+ arena->FirstChildElement("allocated-huge")->QueryIntText(&val));
+ total_allocated_bytes += val;
+ ASSERT_EQ(tinyxml2::XML_SUCCESS,
+ arena->FirstChildElement("allocated-bins")->QueryIntText(&val));
+ total_allocated_bytes += val;
+ ASSERT_EQ(tinyxml2::XML_SUCCESS,
+ arena->FirstChildElement("bins-total")->QueryIntText(&val));
+ }
+ // The total needs to be between the mallinfo call before and after
+ // since malloc_info allocates some memory.
+ EXPECT_LE(mallinfo_before_allocated_bytes, total_allocated_bytes);
+ EXPECT_GE(mallinfo_after_allocated_bytes, total_allocated_bytes);
+ } else {
+ // Only verify that this is debug-malloc-1, the malloc debug unit tests
+ // verify the output.
+ ASSERT_STREQ("debug-malloc-1", root->Attribute("version"));
+ }
+#endif
+}
+
TEST(malloc, calloc_usable_size) {
for (size_t size = 1; size <= 2048; size++) {
void* pointer = malloc(size);
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 65a942c..01b4dba 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -19,6 +19,7 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <linux/fs.h>
#include <math.h>
#include <stdio.h>
#include <sys/types.h>
@@ -29,6 +30,7 @@
#include <locale.h>
#include <string>
+#include <thread>
#include <vector>
#include <android-base/file.h>
@@ -2577,3 +2579,34 @@
ASSERT_LT(0, length);
ASSERT_EQ("/proc/self/fd/2", std::string(path, length));
}
+
+TEST(STDIO_TEST, fread_with_locked_file) {
+ // Reading an unbuffered/line-buffered file from one thread shouldn't block on
+ // files locked on other threads, even if it flushes some line-buffered files.
+ FILE* fp1 = fopen("/dev/zero", "r");
+ ASSERT_TRUE(fp1 != nullptr);
+ flockfile(fp1);
+
+ std::thread([] {
+ for (int mode : { _IONBF, _IOLBF }) {
+ FILE* fp2 = fopen("/dev/zero", "r");
+ ASSERT_TRUE(fp2 != nullptr);
+ setvbuf(fp2, nullptr, mode, 0);
+ ASSERT_EQ('\0', fgetc(fp2));
+ fclose(fp2);
+ }
+ }).join();
+
+ funlockfile(fp1);
+ fclose(fp1);
+}
+
+TEST(STDIO_TEST, SEEK_macros) {
+ ASSERT_EQ(0, SEEK_SET);
+ ASSERT_EQ(1, SEEK_CUR);
+ ASSERT_EQ(2, SEEK_END);
+ ASSERT_EQ(3, SEEK_DATA);
+ ASSERT_EQ(4, SEEK_HOLE);
+ // So we'll notice if Linux grows another constant in <linux/fs.h>...
+ ASSERT_EQ(SEEK_MAX, SEEK_HOLE);
+}