Merge changes Iba5f74e1,I92b88939
* changes:
Fix CtsJniTestCases
Fix formatting
diff --git a/libc/Android.bp b/libc/Android.bp
index 182e8f7..0950662 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -2425,3 +2425,54 @@
static_libs: ["libbase"],
},
}
+
+// This is a temporary library that will use scudo as the native memory
+// allocator. To use it, add it as the first shared library.
+cc_library_shared {
+ name: "libc_scudo",
+ vendor_available: true,
+ srcs: [
+ "bionic/malloc_common.cpp",
+ "bionic/malloc_common_dynamic.cpp",
+ "bionic/malloc_heapprofd.cpp",
+ "bionic/malloc_limit.cpp",
+ "bionic/scudo_wrapper.cpp",
+ "bionic/__set_errno.cpp",
+ ],
+ cflags: ["-DUSE_SCUDO"],
+ stl: "none",
+ system_shared_libs: [],
+
+ header_libs: ["libc_headers"],
+
+ static_libs: ["libasync_safe"],
+
+ allow_undefined_symbols: true,
+ shared_libs: ["libscudo_wrapper"],
+
+ arch: {
+ arm: {
+ srcs: ["arch-arm/syscalls/__rt_sigprocmask.S"],
+ },
+ arm64: {
+ srcs: ["arch-arm64/syscalls/__rt_sigprocmask.S"],
+ },
+ x86: {
+ srcs: [
+ "arch-x86/bionic/__libc_init_sysinfo.cpp",
+ "arch-x86/syscalls/__rt_sigprocmask.S",
+ ],
+ },
+ x86_64: {
+ srcs: ["arch-x86_64/syscalls/__rt_sigprocmask.S"],
+ },
+ },
+
+ // Mark this library as global so it overrides all the allocation
+ // definitions properly.
+ ldflags: ["-Wl,-z,global"],
+}
+
+subdirs = [
+ "bionic/scudo",
+]
diff --git a/libc/bionic/bionic_allocator.cpp b/libc/bionic/bionic_allocator.cpp
index da0f7d0..168d6ba 100644
--- a/libc/bionic/bionic_allocator.cpp
+++ b/libc/bionic/bionic_allocator.cpp
@@ -45,11 +45,11 @@
//
// BionicAllocator is a general purpose allocator designed to provide the same
-// functionality as the malloc/free/realloc libc functions.
+// functionality as the malloc/free/realloc/memalign libc functions.
//
// On alloc:
-// If size is >= 1k allocator proxies malloc call directly to mmap
-// If size < 1k allocator uses SmallObjectAllocator for the size
+// If size is > 1k allocator proxies malloc call directly to mmap.
+// If size <= 1k allocator uses BionicSmallObjectAllocator for the size
// rounded up to the nearest power of two.
//
// On free:
@@ -57,10 +57,10 @@
// For a pointer allocated using proxy-to-mmap allocator unmaps
// the memory.
//
-// For a pointer allocated using SmallObjectAllocator it adds
+// For a pointer allocated using BionicSmallObjectAllocator it adds
// the block to free_blocks_list in the corresponding page. If the number of
-// free pages reaches 2, SmallObjectAllocator munmaps one of the pages keeping
-// the other one in reserve.
+// free pages reaches 2, BionicSmallObjectAllocator munmaps one of the pages
+// keeping the other one in reserve.
// Memory management for large objects is fairly straightforward, but for small
// objects it is more complicated. If you are changing this code, one simple
diff --git a/libc/bionic/malloc_common.h b/libc/bionic/malloc_common.h
index a40501d..7f3b711 100644
--- a/libc/bionic/malloc_common.h
+++ b/libc/bionic/malloc_common.h
@@ -55,11 +55,20 @@
#else // __has_feature(hwaddress_sanitizer)
+#if defined(USE_SCUDO)
+
+#include "scudo.h"
+#define Malloc(function) scudo_ ## function
+
+#else
+
#include "jemalloc.h"
#define Malloc(function) je_ ## function
#endif
+#endif
+
extern int gMallocLeakZygoteChild;
static inline const MallocDispatch* GetDispatchTable() {
diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp
index e12c247..3ccaed6 100644
--- a/libc/bionic/malloc_common_dynamic.cpp
+++ b/libc/bionic/malloc_common_dynamic.cpp
@@ -307,8 +307,6 @@
atomic_store(&globals->current_dispatch_table, &globals->malloc_dispatch_table);
}
- info_log("%s: malloc %s enabled", getprogname(), prefix);
-
// Use atexit to trigger the cleanup function. This avoids a problem
// where another atexit function is used to cleanup allocated memory,
// but the finalize function was already called. This particular error
@@ -316,7 +314,7 @@
int ret_value = __cxa_atexit(MallocFiniImpl, nullptr, nullptr);
if (ret_value != 0) {
// We don't consider this a fatal error.
- info_log("failed to set atexit cleanup function: %d", ret_value);
+ warning_log("failed to set atexit cleanup function: %d", ret_value);
}
return true;
}
diff --git a/libc/bionic/scudo.h b/libc/bionic/scudo.h
new file mode 100644
index 0000000..d9933c4
--- /dev/null
+++ b/libc/bionic/scudo.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdio.h>
+#include <malloc.h>
+
+#include <private/bionic_config.h>
+
+__BEGIN_DECLS
+
+void* scudo_aligned_alloc(size_t, size_t);
+void* scudo_calloc(size_t, size_t);
+void scudo_free(void*);
+struct mallinfo scudo_mallinfo();
+void* scudo_malloc(size_t);
+int scudo_malloc_info(int, FILE*);
+size_t scudo_malloc_usable_size(const void*);
+int scudo_mallopt(int, int);
+void* scudo_memalign(size_t, size_t);
+void* scudo_realloc(void*, size_t);
+int scudo_posix_memalign(void**, size_t, size_t);
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+void* scudo_pvalloc(size_t);
+void* scudo_valloc(size_t);
+#endif
+
+int scudo_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*);
+void scudo_malloc_disable();
+void scudo_malloc_enable();
+
+__END_DECLS
diff --git a/libc/bionic/scudo/Android.bp b/libc/bionic/scudo/Android.bp
new file mode 100644
index 0000000..8b518bb
--- /dev/null
+++ b/libc/bionic/scudo/Android.bp
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2019 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.
+//
+
+cc_library_shared {
+ name: "libscudo_wrapper",
+ vendor_available: true,
+ srcs: ["scudo.cpp"],
+
+ stl: "none",
+ system_shared_libs: [],
+ host_supported: false,
+
+ header_libs: ["libc_headers"],
+ include_dirs: [
+ "bionic/libc",
+ "bionic/libc/bionic",
+ ],
+
+ whole_static_libs: ["libasync_safe"],
+
+ arch: {
+ arm: {
+ whole_static_libs: ["libclang_rt.scudo_minimal-arm-android.static"],
+ },
+ arm64: {
+ whole_static_libs: ["libclang_rt.scudo_minimal-aarch64-android.static"],
+ },
+ x86: {
+ whole_static_libs: ["libclang_rt.scudo_minimal-i686-android.static"],
+ },
+ x86_64: {
+ whole_static_libs: ["libclang_rt.scudo_minimal-x86_64-android.static"],
+ },
+ },
+
+ // Will be referencing other libc code that won't be defined here.
+ allow_undefined_symbols: true,
+
+ multilib: {
+ lib32: {
+ version_script: "exported32.map",
+ },
+ lib64: {
+ version_script: "exported64.map",
+ },
+ },
+}
diff --git a/libc/bionic/scudo/exported32.map b/libc/bionic/scudo/exported32.map
new file mode 100644
index 0000000..4b6791d
--- /dev/null
+++ b/libc/bionic/scudo/exported32.map
@@ -0,0 +1,16 @@
+LIBC_SCUDO {
+ global:
+ scudo_aligned_alloc;
+ scudo_calloc;
+ scudo_free;
+ scudo_mallinfo;
+ scudo_malloc;
+ scudo_malloc_usable_size;
+ scudo_memalign;
+ scudo_posix_memalign;
+ scudo_pvalloc;
+ scudo_realloc;
+ scudo_valloc;
+ local:
+ *;
+};
diff --git a/libc/bionic/scudo/exported64.map b/libc/bionic/scudo/exported64.map
new file mode 100644
index 0000000..1346b4b
--- /dev/null
+++ b/libc/bionic/scudo/exported64.map
@@ -0,0 +1,14 @@
+LIBC_SCUDO {
+ global:
+ scudo_aligned_alloc;
+ scudo_calloc;
+ scudo_free;
+ scudo_mallinfo;
+ scudo_malloc;
+ scudo_malloc_usable_size;
+ scudo_memalign;
+ scudo_posix_memalign;
+ scudo_realloc;
+ local:
+ *;
+};
diff --git a/libc/bionic/scudo/scudo.cpp b/libc/bionic/scudo/scudo.cpp
new file mode 100644
index 0000000..fb09b92
--- /dev/null
+++ b/libc/bionic/scudo/scudo.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/prctl.h>
+
+#include "private/bionic_macros.h"
+
+#include "scudo.h"
+
+// Disable Scudo's mismatch allocation check, as it is being triggered
+// by some third party code.
+extern "C" const char *__scudo_default_options() {
+ return "DeallocationTypeMismatch=false";
+}
+
+static inline bool AllocTooBig(size_t bytes) {
+#if defined(__LP64__)
+ if (__predict_false(bytes > 0x10000000000ULL)) {
+#else
+ if (__predict_false(bytes > 0x80000000ULL)) {
+#endif
+ return true;
+ }
+ return false;
+}
+
+void* scudo_aligned_alloc(size_t alignment, size_t size) {
+ if (alignment == 0 || !powerof2(alignment) || (size % alignment) != 0) {
+ errno = EINVAL;
+ return nullptr;
+ }
+ if (AllocTooBig(size)) {
+ errno = ENOMEM;
+ return nullptr;
+ }
+
+ return aligned_alloc(alignment, size);
+}
+
+void* scudo_calloc(size_t item_count, size_t item_size) {
+ size_t total;
+ if (__builtin_mul_overflow(item_count, item_size, &total) || AllocTooBig(total)) {
+ errno = ENOMEM;
+ return nullptr;
+ }
+ return calloc(item_count, item_size);
+}
+
+void scudo_free(void* ptr) {
+ free(ptr);
+}
+
+extern "C" size_t __sanitizer_get_current_allocated_bytes();
+extern "C" size_t __sanitizer_get_heap_size();
+
+struct mallinfo scudo_mallinfo() {
+ struct mallinfo info {};
+ info.uordblks = __sanitizer_get_current_allocated_bytes();
+ info.hblkhd = __sanitizer_get_heap_size();
+ info.usmblks = info.hblkhd;
+ return info;
+}
+
+void* scudo_malloc(size_t byte_count) {
+ if (AllocTooBig(byte_count)) {
+ errno = ENOMEM;
+ return nullptr;
+ }
+ return malloc(byte_count);
+}
+
+size_t scudo_malloc_usable_size(const void* ptr) {
+ return malloc_usable_size(ptr);
+}
+
+void* scudo_memalign(size_t alignment, size_t byte_count) {
+ if (AllocTooBig(byte_count)) {
+ errno = ENOMEM;
+ return nullptr;
+ }
+ if (alignment != 0) {
+ if (!powerof2(alignment)) {
+ alignment = BIONIC_ROUND_UP_POWER_OF_2(alignment);
+ }
+ } else {
+ alignment = 1;
+ }
+ return memalign(alignment, byte_count);
+}
+
+void* scudo_realloc(void* ptr, size_t byte_count) {
+ if (AllocTooBig(byte_count)) {
+ errno = ENOMEM;
+ return nullptr;
+ }
+ return realloc(ptr, byte_count);
+}
+
+int scudo_posix_memalign(void** memptr, size_t alignment, size_t size) {
+ if (alignment < sizeof(void*) || !powerof2(alignment)) {
+ return EINVAL;
+ }
+ if (AllocTooBig(size)) {
+ return ENOMEM;
+ }
+ return posix_memalign(memptr, alignment, size);
+}
+
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+extern "C" void* pvalloc(size_t);
+
+void* scudo_pvalloc(size_t size) {
+ if (AllocTooBig(size)) {
+ errno = ENOMEM;
+ return nullptr;
+ }
+ return pvalloc(size);
+}
+
+extern "C" void* valloc(size_t);
+
+void* scudo_valloc(size_t size) {
+ if (AllocTooBig(size)) {
+ errno = ENOMEM;
+ return nullptr;
+ }
+ return valloc(size);
+}
+#endif
+
+// Do not try and name the scudo maps by overriding __sanitizer::internal_mmap.
+// There is already a function called MmapNamed that names the maps.
+// Unfortunately, there is no easy way to override MmapNamed because
+// too much of the code is not compiled into functions available in the
+// library, and the code is complicated.
diff --git a/libc/bionic/scudo_wrapper.cpp b/libc/bionic/scudo_wrapper.cpp
new file mode 100644
index 0000000..e17f20b
--- /dev/null
+++ b/libc/bionic/scudo_wrapper.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "scudo.h"
+#include "private/bionic_globals.h"
+#include "private/WriteProtected.h"
+
+__LIBC_HIDDEN__ WriteProtected<libc_globals> __libc_globals;
+
+#if defined(__i386__)
+__LIBC_HIDDEN__ void* __libc_sysinfo = reinterpret_cast<void*>(__libc_int0x80);
+#endif
+
+int scudo_mallopt(int /*param*/, int /*value*/) {
+ return 0;
+}
+
+int scudo_malloc_info(int /*options*/, FILE* /*fp*/) {
+ errno = ENOTSUP;
+ return -1;
+}
+
+int scudo_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*) {
+ return 0;
+}
+
+void scudo_malloc_disable() {
+}
+
+void scudo_malloc_enable() {
+}
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index dd20b5c..dbd3eac 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -135,6 +135,9 @@
{
"abort_on_error", {ABORT_ON_ERROR, &Config::VerifyValueEmpty},
},
+ {
+ "verbose", {VERBOSE, &Config::VerifyValueEmpty},
+ },
};
bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value,
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index 011dc77..1b5c748 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -45,6 +45,7 @@
constexpr uint64_t RECORD_ALLOCS = 0x200;
constexpr uint64_t BACKTRACE_FULL = 0x400;
constexpr uint64_t ABORT_ON_ERROR = 0x800;
+constexpr uint64_t VERBOSE = 0x1000;
// In order to guarantee posix compliance, set the minimum alignment
// to 8 bytes for 32 bit systems and 16 bytes for 64 bit systems.
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
index 6c7d8fa..617d128 100644
--- a/libc/malloc_debug/PointerData.cpp
+++ b/libc/malloc_debug/PointerData.cpp
@@ -105,8 +105,10 @@
error_log("Unable to set up backtrace signal enable function: %s", strerror(errno));
return false;
}
- info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
- config.backtrace_signal(), getpid());
+ if (config.options() & VERBOSE) {
+ info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
+ config.backtrace_signal(), getpid());
+ }
}
if (config.options() & BACKTRACE) {
@@ -117,8 +119,10 @@
error_log("Unable to set up backtrace dump signal function: %s", strerror(errno));
return false;
}
- info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
- config.backtrace_dump_signal(), getpid());
+ if (config.options() & VERBOSE) {
+ info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
+ config.backtrace_dump_signal(), getpid());
+ }
}
backtrace_dump_ = false;
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index 93b9b1e..bebc1c1 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -401,6 +401,21 @@
**NOTE**: If leak\_track is enabled, no abort occurs if leaks have been
detected when the process is exiting.
+### verbose
+As of Android Q, all info messages will be turned off by default. For example,
+in Android P and older, enabling malloc debug would result in this message
+in the log:
+
+ 08-16 15:54:16.060 26947 26947 I libc : /system/bin/app_process64: malloc debug enabled
+
+In android Q, this message will not be displayed because these info messages
+slow down process start up. However, if you want to re-enable these messages,
+add the verbose option. All of the "Run XXX" messages are also silenced unless
+the verbose option is specified. This is an example of the type
+of messages that are no longer displayed:
+
+ 09-10 01:03:50.070 557 557 I malloc_debug: /system/bin/audioserver: Run: 'kill -47 557' to dump the backtrace.
+
Additional Errors
-----------------
There are a few other error messages that might appear in the log.
diff --git a/libc/malloc_debug/RecordData.cpp b/libc/malloc_debug/RecordData.cpp
index aea2513..5c550c0 100644
--- a/libc/malloc_debug/RecordData.cpp
+++ b/libc/malloc_debug/RecordData.cpp
@@ -181,8 +181,10 @@
}
pthread_setspecific(key_, nullptr);
- info_log("%s: Run: 'kill -%d %d' to dump the allocation records.", getprogname(),
- config.record_allocs_signal(), getpid());
+ if (config.options() & VERBOSE) {
+ info_log("%s: Run: 'kill -%d %d' to dump the allocation records.", getprogname(),
+ config.record_allocs_signal(), getpid());
+ }
num_entries_ = config.record_allocs_num_entries();
entries_ = new const RecordEntry*[num_entries_];
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 093bdee..1145796 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -30,6 +30,7 @@
#include <inttypes.h>
#include <malloc.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/param.h>
@@ -252,6 +253,10 @@
// of different error cases.
backtrace_startup();
+ if (g_debug->config().options() & VERBOSE) {
+ info_log("%s: malloc debug enabled", getprogname());
+ }
+
return true;
}
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index fb54ee5..42d1415 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -743,3 +743,21 @@
"which does not take a value\n");
ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
}
+
+TEST_F(MallocDebugConfigTest, verbose) {
+ ASSERT_TRUE(InitConfig("verbose")) << getFakeLogPrint();
+ ASSERT_EQ(VERBOSE, config->options());
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, trigger_verbose_fail) {
+ ASSERT_FALSE(InitConfig("verbose=200")) << getFakeLogPrint();
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ std::string log_msg(
+ "6 malloc_debug malloc_testing: value set for option 'verbose' "
+ "which does not take a value\n");
+ ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
diff --git a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
index 4fcd04c..71e8ebf 100644
--- a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
@@ -195,7 +195,7 @@
TEST(MallocDebugSystemTest, smoke) {
pid_t pid;
- ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_smoke", "backtrace", &pid));
+ ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_smoke", "verbose backtrace", &pid));
ASSERT_NO_FATAL_FAILURE(FindStrings(pid, std::vector<const char*>{"malloc debug enabled"}));
}
@@ -399,7 +399,7 @@
pid_t pid;
SCOPED_TRACE(testing::Message() << functions[i].name << " expected size " << functions[i].size);
std::string test = std::string("MallocTests.DISABLED_") + test_prefix + functions[i].name;
- EXPECT_NO_FATAL_FAILURE(Exec(test.c_str(), "backtrace leak_track", &pid));
+ EXPECT_NO_FATAL_FAILURE(Exec(test.c_str(), "verbose backtrace leak_track", &pid));
std::string expected_leak = android::base::StringPrintf("leaked block of size %zu at", functions[i].size);
EXPECT_NO_FATAL_FAILURE(FindStrings(
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 66955db..f611f3d 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -154,7 +154,7 @@
return diff;
}
-void VerifyAllocCalls(bool backtrace_enabled) {
+void VerifyAllocCalls(bool all_options) {
size_t alloc_size = 1024;
// Verify debug_malloc.
@@ -209,21 +209,28 @@
ASSERT_STREQ("", getFakeLogBuf().c_str());
std::string expected_log;
- if (backtrace_enabled) {
+ if (all_options) {
+ expected_log += android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to enable backtracing.\n",
+ SIGRTMAX - 19, getpid());
expected_log += android::base::StringPrintf(
"4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
SIGRTMAX - 17, getpid());
+ expected_log += android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
+ SIGRTMAX - 18, getpid());
}
+ expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, fill_generic) {
- Init("fill");
+ Init("verbose fill");
VerifyAllocCalls(false);
}
TEST_F(MallocDebugTest, fill_on_alloc_generic) {
- Init("fill_on_alloc");
+ Init("verbose fill_on_alloc");
VerifyAllocCalls(false);
}
@@ -241,6 +248,46 @@
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
+TEST_F(MallocDebugTest, verbose_only) {
+ Init("verbose");
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("4 malloc_debug malloc_testing: malloc debug enabled\n", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, verbose_backtrace_enable_on_signal) {
+ Init("verbose backtrace_enable_on_signal");
+
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to enable backtracing.\n",
+ SIGRTMAX - 19, getpid());
+ expected_log += android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, verbose_backtrace) {
+ Init("verbose backtrace");
+
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, verbose_record_allocs) {
+ Init("verbose record_allocs");
+
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
+ SIGRTMAX - 18, getpid());
+ expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
TEST_F(MallocDebugTest, fill_on_free) {
Init("fill_on_free free_track free_track_backtrace_num_frames=0");
@@ -302,7 +349,9 @@
}
TEST_F(MallocDebugTest, all_options) {
- Init("guard backtrace fill expand_alloc free_track leak_track");
+ Init(
+ "guard backtrace backtrace_enable_on_signal fill expand_alloc free_track leak_track "
+ "record_allocs verify_pointers abort_on_error verbose");
VerifyAllocCalls(true);
}
@@ -667,9 +716,6 @@
ASSERT_STREQ("", getFakeLogBuf().c_str());
std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- expected_log += android::base::StringPrintf(
"6 malloc_debug +++ malloc_testing leaked block of size 1024 at %p (leak 1 of 3)\n",
pointer3);
expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
@@ -1096,10 +1142,7 @@
ASSERT_EQ(0U, backtrace_size);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, get_malloc_leak_info_single) {
@@ -1143,10 +1186,7 @@
debug_free(pointer);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, get_malloc_leak_info_multi) {
@@ -1226,10 +1266,7 @@
debug_free(pointers[2]);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, get_malloc_backtrace_with_header) {
@@ -1261,10 +1298,7 @@
initialized = false;
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
}
static std::string SanitizeHeapData(const std::string& data) {
@@ -1375,9 +1409,6 @@
ASSERT_STREQ("", getFakeLogBuf().c_str());
std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- expected_log += android::base::StringPrintf(
"6 malloc_debug Dumping to file: /data/local/tmp/backtrace_heap.%d.txt\n\n", getpid());
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
@@ -1649,13 +1680,7 @@
debug_free_malloc_leak_info(info);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to enable backtracing.\n",
- SIGRTMAX - 19, getpid());
- expected_log += android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, backtrace_same_stack) {
@@ -1712,10 +1737,7 @@
debug_free(pointers[3]);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, backtrace_same_stack_zygote) {
@@ -1774,10 +1796,7 @@
debug_free(pointers[3]);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, backtrace_same_stack_mix_zygote) {
@@ -1844,10 +1863,7 @@
debug_free(pointers[3]);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, backtrace_frame_data_nullptr_same_size) {
@@ -1891,10 +1907,7 @@
debug_free(pointers[3]);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, overflow) {
@@ -2022,10 +2035,7 @@
debug_free(pointer);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
- SIGRTMAX - 17, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, max_size) {
@@ -2193,10 +2203,7 @@
ASSERT_STREQ(expected.c_str(), actual.c_str());
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
- SIGRTMAX - 18, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
debug_free(pointer);
}
@@ -2251,10 +2258,7 @@
ASSERT_STREQ(expected.c_str(), actual.c_str());
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
- SIGRTMAX - 18, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
debug_free(pointer);
}
@@ -2293,10 +2297,7 @@
ASSERT_STREQ(expected.c_str(), actual.c_str());
ASSERT_STREQ("", getFakeLogBuf().c_str());
- std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
- SIGRTMAX - 18, getpid());
- ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
debug_free(pointer);
}
@@ -2348,9 +2349,6 @@
ASSERT_STREQ("", getFakeLogBuf().c_str());
std::string expected_log = android::base::StringPrintf(
- "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
- SIGRTMAX - 18, getpid());
- expected_log += android::base::StringPrintf(
"6 malloc_debug Cannot create record alloc file %s: Too many symbolic links encountered\n",
RECORD_ALLOCS_FILE);
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
diff --git a/libc/private/bionic_lock.h b/libc/private/bionic_lock.h
index 410e637..ec179d1 100644
--- a/libc/private/bionic_lock.h
+++ b/libc/private/bionic_lock.h
@@ -70,8 +70,9 @@
}
void unlock() {
+ bool shared = process_shared; /* cache to local variable */
if (atomic_exchange_explicit(&state, Unlocked, memory_order_release) == LockedWithWaiter) {
- __futex_wake_ex(&state, process_shared, 1);
+ __futex_wake_ex(&state, shared, 1);
}
}
};
diff --git a/libc/symbol_ordering b/libc/symbol_ordering
index 6fcc09e..10245db 100644
--- a/libc/symbol_ordering
+++ b/libc/symbol_ordering
@@ -3,200 +3,209 @@
# symbols by size, we usually have less dirty pages at runtime, because small
# symbols are grouped together.
-_ZZ17__find_icu_symbolPKcE9found_icu
-_ZL24gHeapprofdInitInProgress
-_ZL27gHeapprofdInitHookInstalled
+ctl_initialized
+gGlobalsMutating
+global_hashtable_initialized
+gmtcheck.gmt_is_set
+had_conf_error
+je_background_thread_enabled_state
+je_log_init_done
je_opt_abort
je_opt_abort_conf
+je_opt_background_thread
je_opt_junk_alloc
je_opt_junk_free
+je_opt_stats_print
je_opt_utrace
je_opt_xmalloc
je_opt_zero
+je_tsd_booted
malloc_disabled_tcache
-had_conf_error
malloc_slow_flags
-je_opt_background_thread
-ctl_initialized
-je_log_init_done
mmap_flags
os_overcommits
-je_opt_stats_print
-je_tsd_booted
-global_hashtable_initialized
-gmtcheck.gmt_is_set
restartloop
-_ZZ12bindresvportE4port
-ru_counter
+_ZL24gHeapprofdInitInProgress
+_ZL27gHeapprofdInitHookInstalled
+_ZL29gMallocZygoteChildProfileable
+_ZZ17__find_icu_symbolPKcE9found_icu
ru_a
-ru_x
ru_b
-ru_seed
+ru_counter
ru_g
-ru_seed2
ru_msb
-je_narenas_auto
-je_ncpus
-je_init_system_thp_mode
-je_nhbins
-je_tsd_tsd
-optreset
-_rs_forked
-daylight
-gMallocLeakZygoteChild
-_ZL18netdClientInitOnce
-je_opt_narenas
-narenas_total
-je_malloc_disable.once_control
-je_opt_metadata_thp
-je_opt_thp
-stack_nelms
-tcaches_past
-ncleanups
-error_message_count
-error_one_per_line
-_ZZ13error_at_lineE9last_line
-_ZL13g_locale_once
-_ZL30g_propservice_protocol_version
-_res_cache_once
-_res_key
-_rs_forkdetect._rs_pid
-ru_pid
-lcl_is_set
-__cxa_finalize.call_depth
-seed48.sseed
-ether_aton.addr
-je_background_thread_info
-je_malloc_message
-je_tcache_bin_info
-je_tcache_maxclass
-je_tcaches
-optarg
-suboptarg
-timezone
-_ZGVZ17__find_icu_symbolPKcE9found_icu
-_ZL17g_libicuuc_handle
-__malloc_hook
-__realloc_hook
-__free_hook
-__memalign_hook
-je_malloc_conf
-malloc_initializer
+ru_seed
+ru_seed2
+ru_x
+_ZZ12bindresvportE4port
a0
-je_opt_dirty_decay_ms
-je_opt_muzzy_decay_ms
-dirty_decay_ms_default.0
-muzzy_decay_ms_default.0
+__atexit
+atexit_mutex
b0
ctl_arenas
ctl_stats
-je_hooks_arena_new_hook
-os_page
-tcaches_avail
-_ZN9prop_area8pa_size_E
-_ZN9prop_area13pa_data_size_E
-_ZL6g_lock
-_ZL6g_tags
-_ZZ8c16rtombE15__private_state
-_ZZ8c32rtombE15__private_state
+__cxa_finalize.call_depth
+daylight
+dirty_decay_ms_default.0
environ
+error_message_count
+error_one_per_line
error_print_progname
-_ZZ13error_at_lineE9last_file
-_ZZ14__icu_charTypejE10u_charType
-_ZGVZ14__icu_charTypejE10u_charType
-_ZZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
-_ZGVZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
-_ZZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
-_ZGVZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
-__progname
-_ZZ8mbrtoc16E15__private_state
-_ZZ8mbrtoc32E15__private_state
-_ZL14syslog_log_tag
-__system_property_area__
-_ZZ7mbrtowcE15__private_state
-_ZZ10mbsnrtowcsE15__private_state
-_ZZ7wcrtombE15__private_state
-_ZZ10wcsnrtombsE15__private_state
-_ZZ8iswcntrlE10u_charType
-_ZGVZ8iswcntrlE10u_charType
-_ZZ8iswdigitE9u_isdigit
-_ZGVZ8iswdigitE9u_isdigit
-_ZZ8iswpunctE9u_ispunct
-_ZGVZ8iswpunctE9u_ispunct
-_ZZ8towlowerE9u_tolower
-_ZGVZ8towlowerE9u_tolower
-_ZZ8towupperE9u_toupper
-_ZGVZ8towupperE9u_toupper
+__free_hook
+g_atexit_lock
+gGlobalsMutateLock
global_hashtable
+gMallocLeakZygoteChild
+gmtptr
handlers
-p5s
-ut
-rs
-rsx
+je_background_thread_info
+je_hooks_arena_new_hook
+je_init_system_thp_mode
+je_malloc_conf
+je_malloc_disable.once_control
+je_malloc_message
+je_narenas_auto
+je_ncpus
+je_nhbins
+je_opt_dirty_decay_ms
+je_opt_metadata_thp
+je_opt_muzzy_decay_ms
+je_opt_narenas
+je_opt_thp
+je_tcache_bin_info
+je_tcache_maxclass
+je_tcaches
+je_tsd_tsd
+lastenv
+lcl_is_set
+lclptr
+locallock
+malloc_disabled_lock
+__malloc_hook
+malloc_initializer
mbrlen.mbs
mbtowc.mbs
-wctomb.mbs
-ru_reseed
+__memalign_hook
+muzzy_decay_ms_default.0
+narenas_total
+ncleanups
+optarg
+optreset
+os_page
+p5s
+__progname
+random_mutex
+__realloc_hook
+_res_cache_list_lock
+_res_cache_once
+_res_key
+__res_randomid.__libc_mutex_random
+rs
+_rs_forkdetect._rs_pid
+_rs_forked
+rsx
+ru_pid
ru_prf
-tmpnam.tmpcount
-lastenv
-strtok.last
+ru_reseed
__stack_chk_guard
-lclptr
-gmtptr
-_ZGVZ14tzset_unlockedE20persist_sys_timezone
+stack_nelms
+strtok.last
+suboptarg
+__system_property_area__
+tcaches_avail
+tcaches_past
+timezone
+tmpnam.tmpcount
+ut
+wctomb.mbs
+_ZL11g_arc4_lock
+_ZL13g_locale_once
_ZL13g_thread_list
-__atexit
+_ZL14syslog_log_tag
+_ZL16gHeapprofdHandle
+_ZL17g_libicuuc_handle
+_ZL18netdClientInitOnce
+_ZL30g_propservice_protocol_version
+_ZN9prop_area13pa_data_size_E
+_ZN9prop_area8pa_size_E
+_ZZ10mbsnrtowcsE15__private_state
+_ZZ10wcsnrtombsE15__private_state
+_ZZ13error_at_lineE9last_file
+_ZZ13error_at_lineE9last_line
+_ZZ14__icu_charTypejE10u_charType
+_ZZ23__bionic_get_shell_pathE7sh_path
+_ZZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
+_ZZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
+_ZZ7mbrtowcE15__private_state
+_ZZ7wcrtombE15__private_state
+_ZZ8c16rtombE15__private_state
+_ZZ8c32rtombE15__private_state
+_ZZ8iswcntrlE10u_charType
+_ZZ8iswdigitE9u_isdigit
+_ZZ8iswpunctE9u_ispunct
+_ZZ8mbrtoc16E15__private_state
+_ZZ8mbrtoc32E15__private_state
+_ZZ8towlowerE9u_tolower
+_ZZ8towupperE9u_toupper
+ether_aton.addr
+seed48.sseed
+__dtoa_locks
+_ZGVZ14__icu_charTypejE10u_charType
+_ZGVZ14tzset_unlockedE20persist_sys_timezone
+_ZGVZ17__find_icu_symbolPKcE9found_icu
+_ZGVZ23__bionic_get_shell_pathE7sh_path
+_ZGVZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
+_ZGVZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
+_ZGVZ8iswcntrlE10u_charType
+_ZGVZ8iswdigitE9u_isdigit
+_ZGVZ8iswpunctE9u_ispunct
+_ZGVZ8towlowerE9u_tolower
+_ZGVZ8towupperE9u_toupper
+_ZL10gAllocated
+_ZL11gAllocLimit
+_ZL13g_atfork_list
+_ZL6g_lock
+_ZL6g_tags
je_opt_stats_print_opts
nuls
precsize_ntoa.retbuf
__p_secstodate.output
-_ZL13g_atfork_list
-inet_ntoa.b
ether_ntoa.buf
-__sym_ntos.unname
-__sym_ntop.unname
-__p_type.typebuf
+inet_ntoa.b
__p_class.classbuf
-malloc_disabled_lock
-_ZL11g_arc4_lock
-_res_cache_list_lock
+__p_type.typebuf
+__sym_ntop.unname
+__sym_ntos.unname
+_ZL10gFunctions
+_ZL12vendor_group
+_ZL13vendor_passwd
+freelist
__p_option.nbuf
__p_time.nbuf
-atexit_mutex
-random_mutex
-__res_randomid.__libc_mutex_random
-locallock
-g_atexit_lock
-_ZL10gFunctions
-_ZL13vendor_passwd
-_ZL12vendor_group
-tm
_ZL18g_thread_list_lock
-buf_asctime
-__dtoa_locks
-freelist
-__loc_ntoa.tmpbuf
+tm
_ZL8g_locale
+ctl_mtx
+init_lock
je_arenas_lock
je_background_thread_lock
-init_lock
-ctl_mtx
tcaches_mtx
je_tsd_init_head
+buf_asctime
+__loc_ntoa.tmpbuf
+utmp
_ZZ14tzset_unlockedE20persist_sys_timezone
arena_binind_div_info
__hexdig_D2A
lcl_TZname
-utmp
inet_nsap_ntoa_tmpbuf
-_ZL17system_properties
_ZL7key_map
+_ZL17system_properties
private_mem
+_res_cache_list
__libc_globals
tmpnam.buf
-_res_cache_list
-_nres
-je_extent_mutex_pool
-je_arenas
je_extents_rtree
+_nres
+je_arenas
+je_extent_mutex_pool
diff --git a/linker/linker.cpp b/linker/linker.cpp
index c60ab6a..d62eaec 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2383,9 +2383,26 @@
if (sym != nullptr) {
uint32_t bind = ELF_ST_BIND(sym->st_info);
+ uint32_t type = ELF_ST_TYPE(sym->st_info);
if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
- *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
+ if (type == STT_TLS) {
+ // For a TLS symbol, dlsym returns the address of the current thread's
+ // copy of the symbol. This function may allocate a DTV and/or storage
+ // for the source TLS module. (Allocating a DTV isn't necessary if the
+ // symbol is part of static TLS, but it's simpler to reuse
+ // __tls_get_addr.)
+ soinfo_tls* tls_module = found->get_tls();
+ if (tls_module == nullptr) {
+ DL_ERR("TLS symbol \"%s\" in solib \"%s\" with no TLS segment",
+ sym_name, found->get_realpath());
+ return false;
+ }
+ const TlsIndex ti { tls_module->module_id, sym->st_value };
+ *symbol = TLS_GET_ADDR(&ti);
+ } else {
+ *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
+ }
failure_guard.Disable();
LD_LOG(kLogDlsym,
"... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
@@ -3987,7 +4004,7 @@
/* Handle serializing/sharing the RELRO segment */
if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
- extinfo->relro_fd) < 0) {
+ extinfo->relro_fd, relro_fd_offset) < 0) {
DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
get_realpath(), strerror(errno));
return false;
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 1aaa17f..3534287 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -831,16 +831,17 @@
* phdr_count -> number of entries in tables
* load_bias -> load bias
* fd -> writable file descriptor to use
+ * file_offset -> pointer to offset into file descriptor to use/update
* Return:
* 0 on error, -1 on failure (error code in errno).
*/
int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table,
size_t phdr_count,
ElfW(Addr) load_bias,
- int fd) {
+ int fd,
+ size_t* file_offset) {
const ElfW(Phdr)* phdr = phdr_table;
const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
- ssize_t file_offset = 0;
for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
if (phdr->p_type != PT_GNU_RELRO) {
@@ -856,11 +857,11 @@
return -1;
}
void* map = mmap(reinterpret_cast<void*>(seg_page_start), size, PROT_READ,
- MAP_PRIVATE|MAP_FIXED, fd, file_offset);
+ MAP_PRIVATE|MAP_FIXED, fd, *file_offset);
if (map == MAP_FAILED) {
return -1;
}
- file_offset += size;
+ *file_offset += size;
}
return 0;
}
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 9761bc8..5d1cfc2 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -119,7 +119,7 @@
ElfW(Addr) load_bias);
int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
- ElfW(Addr) load_bias, int fd);
+ ElfW(Addr) load_bias, int fd, size_t* file_offset);
int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr) load_bias, int fd, size_t* file_offset);
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 89119aa..31ee74c 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -297,7 +297,11 @@
}
static bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
+ // Skip TLS symbols. A TLS symbol's value is relative to the start of the TLS segment rather than
+ // to the start of the solib. The solib only reserves space for the initialized part of the TLS
+ // segment. (i.e. .tdata is followed by .tbss, and .tbss overlaps other sections.)
return sym->st_shndx != SHN_UNDEF &&
+ ELF_ST_TYPE(sym->st_info) != STT_TLS &&
soaddr >= sym->st_value &&
soaddr < sym->st_value + sym->st_size;
}
diff --git a/tests/Android.bp b/tests/Android.bp
index d1625d2..71cf8a6 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -426,6 +426,11 @@
cc_defaults {
name: "bionic_unit_tests_defaults",
host_supported: false,
+ gtest: false,
+
+ defaults: [
+ "bionic_tests_defaults",
+ ],
whole_static_libs: [
"libBionicTests",
@@ -437,12 +442,14 @@
"libtinyxml2",
"liblog",
"libbase",
+ "libgtest_isolated",
],
srcs: [
// TODO: Include __cxa_thread_atexit_test.cpp to glibc tests once it is upgraded (glibc 2.18+)
"__cxa_thread_atexit_test.cpp",
"gtest_globals.cpp",
+ "gtest_main.cpp",
"thread_local_test.cpp",
],
@@ -461,6 +468,7 @@
android: {
shared_libs: [
"ld-android",
+ "libandroidicu",
"libdl",
"libdl_android",
"libdl_preempt_test_1",
@@ -489,29 +497,6 @@
],
},
},
-}
-
-cc_test {
- name: "bionic-unit-tests",
- gtest: false,
- defaults: [
- "bionic_unit_tests_defaults",
- "bionic_tests_defaults",
- ],
-
- srcs: [
- "gtest_main.cpp",
- ],
-
- static_libs: [
- "libgtest_isolated",
- ],
-
- target: {
- android: {
- shared_libs: ["libandroidicu"],
- },
- },
required: [
"cfi_test_helper",
@@ -656,6 +641,24 @@
],
}
+cc_test {
+ name: "bionic-unit-tests",
+ defaults: [
+ "bionic_unit_tests_defaults",
+ ],
+}
+
+cc_test {
+ name: "bionic-unit-tests-scudo",
+ defaults: [
+ "bionic_unit_tests_defaults",
+ ],
+
+ shared_libs: [
+ "libc_scudo",
+ ],
+}
+
// -----------------------------------------------------------------------------
// Tests for the device linked against bionic's static library. Run with:
// adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static
@@ -698,10 +701,6 @@
static_executable: true,
stl: "libc++_static",
-
- // libclang_rt.builtins does not work with libm
- // http://b/117167374
- no_libcrt: true,
}
// -----------------------------------------------------------------------------
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 1bc5030..3af52d4 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -450,7 +450,21 @@
fprintf(stderr, "in child: %s\n", dlerror());
exit(1);
}
- exit(0);
+ fn f = reinterpret_cast<fn>(dlsym(handle, "getRandomNumber"));
+ ASSERT_DL_NOTNULL(f);
+ EXPECT_EQ(4, f());
+
+ if (recursive) {
+ fn f = reinterpret_cast<fn>(dlsym(handle, "getBiggerRandomNumber"));
+ ASSERT_DL_NOTNULL(f);
+ EXPECT_EQ(8, f());
+ }
+
+ uint32_t* taxicab_number =
+ reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
+ ASSERT_DL_NOTNULL(taxicab_number);
+ EXPECT_EQ(1729U, *taxicab_number);
+ exit(testing::Test::HasFailure());
}
// continuing in parent
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index f3be988..c6d7ddb 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -982,16 +982,16 @@
}
#if defined (__aarch64__)
-#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm64/"
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib64/arm64/"
#elif defined (__arm__)
#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm/"
#elif defined (__i386__)
#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86/"
#elif defined (__x86_64__)
-#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86_64/"
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib64/x86_64/"
#elif defined (__mips__)
#if defined(__LP64__)
-#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips64/"
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib64/mips64/"
#else
#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips/"
#endif
diff --git a/tests/elftls_dl_test.cpp b/tests/elftls_dl_test.cpp
index 88225d8..6d88880 100644
--- a/tests/elftls_dl_test.cpp
+++ b/tests/elftls_dl_test.cpp
@@ -269,3 +269,69 @@
GTEST_SKIP() << "test doesn't apply to glibc";
#endif
}
+
+// Use dlsym to get the address of a TLS variable in static TLS and compare it
+// against the ordinary address of the variable.
+TEST(elftls_dl, dlsym_static_tls) {
+ void* lib = dlopen("libtest_elftls_shared_var.so", RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, lib);
+
+ int* var_addr = static_cast<int*>(dlsym(lib, "elftls_shared_var"));
+ ASSERT_EQ(&elftls_shared_var, var_addr);
+
+ std::thread([lib] {
+ int* var_addr = static_cast<int*>(dlsym(lib, "elftls_shared_var"));
+ ASSERT_EQ(&elftls_shared_var, var_addr);
+ }).join();
+}
+
+// Use dlsym to get the address of a TLS variable in dynamic TLS and compare it
+// against the ordinary address of the variable.
+TEST(elftls_dl, dlsym_dynamic_tls) {
+ void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, lib);
+ auto get_var_addr = reinterpret_cast<int*(*)()>(dlsym(lib, "get_large_tls_var_addr"));
+ ASSERT_NE(nullptr, get_var_addr);
+
+ int* var_addr = static_cast<int*>(dlsym(lib, "large_tls_var"));
+ ASSERT_EQ(get_var_addr(), var_addr);
+
+ std::thread([lib, get_var_addr] {
+ int* var_addr = static_cast<int*>(dlsym(lib, "large_tls_var"));
+ ASSERT_EQ(get_var_addr(), var_addr);
+ }).join();
+}
+
+// Calling dladdr on a TLS variable's address doesn't find anything.
+TEST(elftls_dl, dladdr_on_tls_var) {
+ Dl_info info;
+
+ // Static TLS variable
+ ASSERT_EQ(0, dladdr(&elftls_shared_var, &info));
+
+ // Dynamic TLS variable
+ void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, lib);
+ int* var_addr = static_cast<int*>(dlsym(lib, "large_tls_var"));
+ ASSERT_EQ(0, dladdr(var_addr, &info));
+}
+
+// Verify that dladdr does not misinterpret a TLS symbol's value as a virtual
+// address.
+TEST(elftls_dl, dladdr_skip_tls_symbol) {
+ void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+
+ auto get_local_addr = reinterpret_cast<void*(*)()>(dlsym(lib, "get_local_addr"));
+ ASSERT_NE(nullptr, get_local_addr);
+ void* local_addr = get_local_addr();
+
+ Dl_info info;
+ ASSERT_NE(0, dladdr(local_addr, &info));
+
+ std::string libpath = GetTestlibRoot() + "/libtest_elftls_dynamic.so";
+ char dli_realpath[PATH_MAX];
+ ASSERT_TRUE(realpath(info.dli_fname, dli_realpath));
+ ASSERT_STREQ(libpath.c_str(), dli_realpath);
+ ASSERT_STREQ(nullptr, info.dli_sname);
+ ASSERT_EQ(nullptr, info.dli_saddr);
+}
diff --git a/tests/libs/elftls_dynamic.cpp b/tests/libs/elftls_dynamic.cpp
index 7fa239c..6da2f6f 100644
--- a/tests/libs/elftls_dynamic.cpp
+++ b/tests/libs/elftls_dynamic.cpp
@@ -27,6 +27,24 @@
*/
// This shared object test library is dlopen'ed by the main test executable.
+
+// Export a large TLS variable from a solib for testing dladdr and dlsym. The
+// TLS symbol's value will appear to overlap almost everything else in the
+// shared object, but dladdr must not return it.
+__thread char large_tls_var[4 * 1024 * 1024];
+
+extern "C" char* get_large_tls_var_addr() {
+ return large_tls_var;
+}
+
+// For testing dladdr, return an address that's part of the solib's .bss
+// section, but does not have an entry in the dynsym table and whose
+// solib-relative address appears to overlap with the large TLS variable.
+extern "C" void* get_local_addr() {
+ static char dummy[1024];
+ return &dummy[512];
+}
+
// This variable comes from libtest_elftls_shared_var.so, which is part of
// static TLS. Verify that a GD-model access can access the variable.
//