Merge "fdsan docs: be more consistent in using API levels." into main
diff --git a/android-changes-for-ndk-developers.md b/android-changes-for-ndk-developers.md
index 8d507d1..e9cfbac 100644
--- a/android-changes-for-ndk-developers.md
+++ b/android-changes-for-ndk-developers.md
@@ -445,6 +445,18 @@
| No `dlclose` | Works | Works | Works |
+## ELF TLS (Available for API level >= 29)
+
+Android supports [ELF TLS](docs/elf-tls.md) starting at API level 29. Since
+NDK r26, clang will automatically enable ELF TLS for `minSdkVersion 29` or
+higher. Otherwise, the existing emutls implementation (which uses
+`pthread_key_create()` behind the scenes) will continue to be used. This
+means that convenient C/C++ thread-local syntax is available at any API level;
+at worst it will perform similarly to "roll your own" thread locals using
+`pthread_key_create()` but at best you'll get the performance benefit of
+ELF TLS, and the NDK will take care of the details.
+
+
## Use of IFUNC in libc (True for all API levels on devices running Android 10)
On devices running API level 29, libc uses
diff --git a/docs/elf-tls.md b/docs/elf-tls.md
index d408b3f..6b03841 100644
--- a/docs/elf-tls.md
+++ b/docs/elf-tls.md
@@ -1,9 +1,4 @@
-# Android ELF TLS (Draft)
-
-Internal links:
- * [go/android-elf-tls](http://go/android-elf-tls)
- * [One-pager](https://docs.google.com/document/d/1leyPTnwSs24P2LGiqnU6HetnN5YnDlZkihigi6qdf_M)
- * Tracking bugs: http://b/110100012, http://b/78026329
+# Android ELF TLS
[TOC]
diff --git a/docs/status.md b/docs/status.md
index bc8ab6a..e0364a8 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -125,6 +125,7 @@
* `getloadavg` (BSD/GNU extension in <stdlib.h>)
New libc behavior in Q (API level 29):
+ * Support for [ELF TLS](elf-tls.md).
* Whole printf family now supports the GNU `%m` extension, rather than a
special-case hack in `syslog`.
* `popen` now always uses `O_CLOEXEC`, not just with the `e` extension.
diff --git a/libc/Android.bp b/libc/Android.bp
index 943d41f..5063364 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1,5 +1,3 @@
-// Define the common source files for all the libc instances
-// =========================================================
package {
default_applicable_licenses: ["bionic_libc_license"],
}
@@ -114,6 +112,26 @@
tidy_disabled_srcs: ["upstream-*/**/*.c"],
}
+// Workaround for b/24465209.
+// We're unlikely to be able to remove this before we just
+// remove ILP32 support completely.
+// Note that we also still have `pack_relocations: false`
+// for both libc and libm, even on LP64.
+// ========================================================
+cc_defaults {
+ name: "bug_24465209_workaround",
+ target: {
+ android_arm: {
+ pack_relocations: false,
+ ldflags: ["-Wl,--hash-style=both"],
+ },
+ android_x86: {
+ pack_relocations: false,
+ ldflags: ["-Wl,--hash-style=both"],
+ },
+ },
+}
+
// Defaults for native allocator libs/includes to make it
// easier to change.
// ========================================================
@@ -1529,6 +1547,7 @@
defaults: [
"libc_defaults",
"libc_native_allocator_defaults",
+ "bug_24465209_workaround",
],
name: "libc_library_defaults",
product_variables: {
@@ -1566,14 +1585,6 @@
// Do not pack libc.so relocations; see http://b/20645321 for details.
pack_relocations: false,
- // WARNING: The only libraries libc.so should depend on are libdl.so and ld-android.so!
- // If you add other libraries, make sure to add -Wl,--exclude-libs=libgcc.a to the
- // LOCAL_LDFLAGS for those libraries. This ensures that symbols that are pulled into
- // those new libraries from libgcc.a are not declared external; if that were the case,
- // then libc would not pull those symbols from libgcc.a as it should, instead relying
- // on the external symbols from the dependent libraries. That would create a "cloaked"
- // dependency on libgcc.a in libc though the libraries, which is not what you wanted!
-
shared_libs: [
"ld-android",
"libdl",
@@ -1586,10 +1597,7 @@
arch: {
arm: {
- // TODO: This is to work around b/24465209. Remove after root cause is fixed.
- pack_relocations: false,
ldflags: [
- "-Wl,--hash-style=both",
// Since we are preserving the debug_frame, do not compress
// in this case to make unwinds as fast as possible.
"-Wl,--compress-debug-sections=none",
@@ -1633,10 +1641,6 @@
},
},
x86: {
- // TODO: This is to work around b/24465209. Remove after root cause is fixed.
- pack_relocations: false,
- ldflags: ["-Wl,--hash-style=both"],
-
version_script: ":libc.x86.map",
no_libcrt: true,
@@ -1916,7 +1920,10 @@
// ========================================================
cc_library {
- defaults: ["libc_defaults"],
+ defaults: [
+ "libc_defaults",
+ "bug_24465209_workaround",
+ ],
include_dirs: ["bionic/libstdc++/include"],
srcs: [
"bionic/__cxa_guard.cpp",
@@ -1941,12 +1948,8 @@
},
},
- //TODO (dimitry): This is to work around b/24465209. Remove after root cause is fixed
arch: {
arm: {
- // TODO: This is to work around b/24465209. Remove after root cause is fixed.
- pack_relocations: false,
- ldflags: ["-Wl,--hash-style=both"],
version_script: ":libstdc++.arm.map",
},
arm64: {
@@ -1956,8 +1959,6 @@
version_script: ":libstdc++.riscv64.map",
},
x86: {
- pack_relocations: false,
- ldflags: ["-Wl,--hash-style=both"],
version_script: ":libstdc++.x86.map",
},
x86_64: {
diff --git a/libc/bionic/heap_tagging.cpp b/libc/bionic/heap_tagging.cpp
index cadab3c..3d92404 100644
--- a/libc/bionic/heap_tagging.cpp
+++ b/libc/bionic/heap_tagging.cpp
@@ -184,6 +184,9 @@
#ifdef __aarch64__
static inline __attribute__((no_sanitize("memtag"))) void untag_memory(void* from, void* to) {
+ if (from == to) {
+ return;
+ }
__asm__ __volatile__(
".arch_extension mte\n"
"1:\n"
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 2dde2f1..541e71c 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -61,8 +61,9 @@
};
void memtag_stack_dlopen_callback() {
- async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "remapping stacks as PROT_MTE");
- __pthread_internal_remap_stack_with_mte();
+ if (__pthread_internal_remap_stack_with_mte()) {
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "remapped stacks as PROT_MTE");
+ }
}
// Use an initializer so __libc_sysinfo will have a fallback implementation
diff --git a/libc/bionic/locale.cpp b/libc/bionic/locale.cpp
index 2f4d206..a1d6909 100644
--- a/libc/bionic/locale.cpp
+++ b/libc/bionic/locale.cpp
@@ -35,17 +35,8 @@
#include <time.h>
#include <wchar.h>
-#include "platform/bionic/macros.h"
-
-#if defined(__BIONIC_BUILD_FOR_ANDROID_SUPPORT)
-#define USE_TLS_SLOT 0
-#else
-#define USE_TLS_SLOT 1
-#endif
-
-#if USE_TLS_SLOT
#include "bionic/pthread_internal.h"
-#endif
+#include "platform/bionic/macros.h"
// We only support two locales, the "C" locale (also known as "POSIX"),
// and the "C.UTF-8" locale (also known as "en_US.UTF-8").
@@ -82,10 +73,6 @@
return get_locale_mb_cur_max(uselocale(nullptr));
}
-#if !USE_TLS_SLOT
-static thread_local locale_t g_current_locale;
-#endif
-
static pthread_once_t g_locale_once = PTHREAD_ONCE_INIT;
static lconv g_locale;
@@ -180,11 +167,7 @@
}
static locale_t* get_current_locale_ptr() {
-#if USE_TLS_SLOT
return &__get_bionic_tls().locale;
-#else
- return &g_current_locale;
-#endif
}
locale_t uselocale(locale_t new_locale) {
diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp
index 2342aff..8b9573f 100644
--- a/libc/bionic/pthread_internal.cpp
+++ b/libc/bionic/pthread_internal.cpp
@@ -176,12 +176,12 @@
async_safe_fatal("stack not found in /proc/self/maps");
}
-void __pthread_internal_remap_stack_with_mte() {
+bool __pthread_internal_remap_stack_with_mte() {
#if defined(__aarch64__)
// If process doesn't have MTE enabled, we don't need to do anything.
- if (!atomic_load(&__libc_globals->memtag)) return;
+ if (!atomic_load(&__libc_globals->memtag)) return false;
bool prev = atomic_exchange(&__libc_memtag_stack, true);
- if (prev) return;
+ if (prev) return false;
uintptr_t lo, hi;
__find_main_stack_limits(&lo, &hi);
@@ -198,7 +198,10 @@
async_safe_fatal("error: failed to set PROT_MTE on thread: %d", t->tid);
}
}
-#endif
+ return true;
+#else
+ return false;
+#endif // defined(__aarch64__)
}
bool android_run_on_all_threads(bool (*func)(void*), void* arg) {
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index c2abdea..b0e9461 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -268,8 +268,9 @@
__LIBC_HIDDEN__ extern void __bionic_atfork_run_child();
__LIBC_HIDDEN__ extern void __bionic_atfork_run_parent();
-// Re-map all threads and successively launched threads with PROT_MTE.
-__LIBC_HIDDEN__ void __pthread_internal_remap_stack_with_mte();
+// Re-map all threads and successively launched threads with PROT_MTE. Returns 'true' if remapping
+// took place, 'false' on error or if the stacks were already remapped in the past.
+__LIBC_HIDDEN__ bool __pthread_internal_remap_stack_with_mte();
extern "C" bool android_run_on_all_threads(bool (*func)(void*), void* arg);
diff --git a/libc/include/math.h b/libc/include/math.h
index fc6c228..343ab98 100644
--- a/libc/include/math.h
+++ b/libc/include/math.h
@@ -68,10 +68,7 @@
#define isnormal(x) __builtin_isnormal(x)
-#define signbit(x) \
- ((sizeof(x) == sizeof(float)) ? __builtin_signbitf(x) \
- : (sizeof(x) == sizeof(double)) ? __builtin_signbit(x) \
- : __builtin_signbitl(x))
+#define signbit(x) __builtin_signbit(x)
double acos(double __x);
float acosf(float __x);
@@ -308,20 +305,6 @@
#define islessgreater(x, y) __builtin_islessgreater((x), (y))
#define isunordered(x, y) __builtin_isunordered((x), (y))
-/*
- * https://code.google.com/p/android/issues/detail?id=271629
- * To be fully compliant with C++, we need to not define these (C doesn't
- * specify them either). Exposing these means that isinf and isnan will have a
- * return type of int in C++ rather than bool like they're supposed to be.
- *
- * GNU libstdc++ 4.9 isn't able to handle a standard compliant C library. Its
- * <cmath> will `#undef isnan` from math.h and only adds the function overloads
- * to the std namespace, making it impossible to use both <cmath> (which gets
- * included by a lot of other standard headers) and ::isnan.
- */
-int (isinf)(double __x) __attribute_const__;
-int (isnan)(double __x) __attribute_const__;
-
/* POSIX extensions. */
extern int signgam;
@@ -362,6 +345,7 @@
double scalb(double __x, double __exponent);
double drem(double __x, double __y);
int finite(double __x) __attribute_const__;
+int isinff(float __x) __attribute_const__;
int isnanf(float __x) __attribute_const__;
double gamma_r(double __x, int* _Nonnull __sign);
double lgamma_r(double __x, int* _Nonnull __sign);
@@ -402,6 +386,8 @@
#define M_2_SQRTPIl 1.128379167095512573896158903121545172L /* 2/sqrt(pi) */
#define M_SQRT2l 1.414213562373095048801688724209698079L /* sqrt(2) */
#define M_SQRT1_2l 0.707106781186547524400844362104849039L /* 1/sqrt(2) */
+int isinfl(long double __x) __attribute_const__;
+int isnanl(long double __x) __attribute_const__;
#endif
__END_DECLS
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index 89a7ce7..0d442b4 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -187,6 +187,10 @@
"record_allocs_file",
{0, &Config::SetRecordAllocsFile},
},
+ {
+ "record_allocs_on_exit",
+ {0, &Config::SetRecordAllocsOnExit},
+ },
{
"verify_pointers",
@@ -401,6 +405,14 @@
return true;
}
+bool Config::SetRecordAllocsOnExit(const std::string& option, const std::string& value) {
+ if (Config::VerifyValueEmpty(option, value)) {
+ record_allocs_on_exit_ = true;
+ return true;
+ }
+ return false;
+}
+
bool Config::VerifyValueEmpty(const std::string& option, const std::string& value) {
if (!value.empty()) {
// This is not valid.
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index 754970f..8551712 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -98,6 +98,7 @@
int record_allocs_signal() const { return record_allocs_signal_; }
size_t record_allocs_num_entries() const { return record_allocs_num_entries_; }
const std::string& record_allocs_file() const { return record_allocs_file_; }
+ bool record_allocs_on_exit() const { return record_allocs_on_exit_; }
int check_unreachable_signal() const { return check_unreachable_signal_; }
@@ -139,6 +140,7 @@
bool SetRecordAllocs(const std::string& option, const std::string& value);
bool SetRecordAllocsFile(const std::string& option, const std::string& value);
+ bool SetRecordAllocsOnExit(const std::string& option, const std::string& value);
bool VerifyValueEmpty(const std::string& option, const std::string& value);
@@ -170,6 +172,7 @@
int record_allocs_signal_ = 0;
size_t record_allocs_num_entries_ = 0;
std::string record_allocs_file_;
+ bool record_allocs_on_exit_ = false;
uint64_t options_ = 0;
uint8_t fill_alloc_value_;
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index 4e39bed..750a469 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -456,6 +456,19 @@
**NOTE**: This option is not available until the O release of Android.
+### record\_allocs\_on\_exit
+This option only has meaning if record\_allocs is set. It indicates that
+when the process terminates, the record file should be created
+automatically.
+
+The only caveat to this option is that when the process terminates,
+the file that will contain the records will be the normal file name
+with **.PID** appended. Where PID is the pid of the process that has
+terminated. This is to avoid cases where a number of processes exit
+at the same time and attempt to write to the same file.
+
+**NOTE**: This option is not available until the V release of Android.
+
### verify\_pointers
Track all live allocations to determine if a pointer is used that does not
exist. This option is a lightweight way to verify that all
diff --git a/libc/malloc_debug/RecordData.cpp b/libc/malloc_debug/RecordData.cpp
index 8a77170..79e051b 100644
--- a/libc/malloc_debug/RecordData.cpp
+++ b/libc/malloc_debug/RecordData.cpp
@@ -131,17 +131,30 @@
record_obj_->WriteEntries();
}
+void RecordData::WriteEntriesOnExit() {
+ if (record_obj_ == nullptr) return;
+
+ // Append the current pid to the file name to avoid multiple processes
+ // writing to the same file.
+ std::string file(record_obj_->file());
+ file += "." + std::to_string(getpid());
+ record_obj_->WriteEntries(file);
+}
+
void RecordData::WriteEntries() {
+ WriteEntries(file_);
+}
+
+void RecordData::WriteEntries(const std::string& file) {
std::lock_guard<std::mutex> entries_lock(entries_lock_);
if (cur_index_ == 0) {
info_log("No alloc entries to write.");
return;
}
- int dump_fd =
- open(dump_file_.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, 0755);
+ int dump_fd = open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, 0755);
if (dump_fd == -1) {
- error_log("Cannot create record alloc file %s: %s", dump_file_.c_str(), strerror(errno));
+ error_log("Cannot create record alloc file %s: %s", file.c_str(), strerror(errno));
return;
}
@@ -179,7 +192,7 @@
entries_.resize(config.record_allocs_num_entries());
cur_index_ = 0U;
- dump_file_ = config.record_allocs_file();
+ file_ = config.record_allocs_file();
return true;
}
diff --git a/libc/malloc_debug/RecordData.h b/libc/malloc_debug/RecordData.h
index a02c956..7efa1f7 100644
--- a/libc/malloc_debug/RecordData.h
+++ b/libc/malloc_debug/RecordData.h
@@ -162,19 +162,23 @@
void AddEntry(const RecordEntry* entry);
void AddEntryOnly(const RecordEntry* entry);
+ const std::string& file() { return file_; }
pthread_key_t key() { return key_; }
+ static void WriteEntriesOnExit();
+
private:
static void WriteData(int, siginfo_t*, void*);
static RecordData* record_obj_;
void WriteEntries();
+ void WriteEntries(const std::string& file);
std::mutex entries_lock_;
pthread_key_t key_;
std::vector<std::unique_ptr<const RecordEntry>> entries_;
size_t cur_index_;
- std::string dump_file_;
+ std::string file_;
BIONIC_DISALLOW_COPY_AND_ASSIGN(RecordData);
};
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index b66b8e2..6d88092 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -451,6 +451,10 @@
PointerData::LogLeaks();
}
+ if ((g_debug->config().options() & RECORD_ALLOCS) && g_debug->config().record_allocs_on_exit()) {
+ RecordData::WriteEntriesOnExit();
+ }
+
if ((g_debug->config().options() & BACKTRACE) && g_debug->config().backtrace_dump_on_exit()) {
debug_dump_heap(android::base::StringPrintf("%s.%d.exit.txt",
g_debug->config().backtrace_dump_prefix().c_str(),
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index 84c9145..c79d052 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -571,6 +571,25 @@
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
+TEST_F(MallocDebugConfigTest, record_allocs_on_exit) {
+ ASSERT_TRUE(InitConfig("record_allocs_on_exit")) << getFakeLogPrint();
+ ASSERT_EQ(0U, config->options());
+ ASSERT_TRUE(config->record_allocs_on_exit());
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, record_allocs_on_exit_error) {
+ ASSERT_FALSE(InitConfig("record_allocs_on_exit=something")) << getFakeLogPrint();
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ std::string log_msg(
+ "6 malloc_debug malloc_testing: value set for option 'record_allocs_on_exit' "
+ "which does not take a value\n");
+ ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
TEST_F(MallocDebugConfigTest, guard_min_error) {
ASSERT_FALSE(InitConfig("guard=0"));
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 334dada..ef8d235 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -185,6 +185,7 @@
}
static void VerifyRecords(std::vector<std::string>& expected, std::string& actual) {
+ ASSERT_TRUE(expected.size() != 0);
size_t offset = 0;
for (std::string& str : expected) {
ASSERT_STREQ(str.c_str(), actual.substr(offset, str.size()).c_str());
@@ -1512,7 +1513,7 @@
// Call the exit function manually.
debug_finalize();
- exit(0);
+ _exit(0);
}
ASSERT_NE(-1, pid);
ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0)));
@@ -1561,7 +1562,7 @@
// Call the exit function manually.
debug_finalize();
- exit(0);
+ _exit(0);
}
ASSERT_NE(-1, pid);
ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0)));
@@ -1619,7 +1620,7 @@
// Call the exit function manually.
debug_finalize();
- exit(0);
+ _exit(0);
}
ASSERT_NE(-1, pid);
ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0)));
@@ -2429,6 +2430,33 @@
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
+TEST_F(MallocDebugTest, record_allocs_on_exit) {
+ InitRecordAllocs("record_allocs record_allocs_on_exit");
+
+ // The filename created on exit always appends the pid.
+ // Modify the variable so the file is deleted at the end of the test.
+ record_filename += '.' + std::to_string(getpid());
+
+ std::vector<std::string> expected;
+ void* ptr = debug_malloc(100);
+ expected.push_back(android::base::StringPrintf("%d: malloc %p 100", getpid(), ptr));
+ ptr = debug_malloc(200);
+ expected.push_back(android::base::StringPrintf("%d: malloc %p 200", getpid(), ptr));
+ ptr = debug_malloc(400);
+ expected.push_back(android::base::StringPrintf("%d: malloc %p 400", getpid(), ptr));
+
+ // Call the exit function manually.
+ debug_finalize();
+
+ // Read all of the contents.
+ std::string actual;
+ ASSERT_TRUE(android::base::ReadFileToString(record_filename, &actual));
+ VerifyRecords(expected, actual);
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
TEST_F(MallocDebugTest, verify_pointers) {
Init("verify_pointers");
diff --git a/libdl/Android.bp b/libdl/Android.bp
index 95b412b..1bbd902 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -60,33 +60,14 @@
native_bridge_supported: true,
static_ndk_lib: true,
- defaults: ["linux_bionic_supported"],
-
- // 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
- // a) pull symbols from libgcc.a and b) depend on libdl.so will not rely on libdl.so
- // to provide those symbols, but will instead pull them from libgcc.a. Specifically,
- // we use this property to make sure libc.so has its own copy of the code from
- // libgcc.a it uses.
- //
- // DO NOT REMOVE --exclude-libs!
-
- 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-i686-android.a",
- "-Wl,--exclude-libs=libclang_rt.builtins-riscv64-android.a",
- "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
+ defaults: [
+ "linux_bionic_supported",
+ "bug_24465209_workaround",
],
- // for x86, exclude libgcc_eh.a for the same reasons as above
arch: {
arm: {
version_script: ":libdl.arm.map",
- pack_relocations: false,
- ldflags: ["-Wl,--hash-style=both"],
},
arm64: {
version_script: ":libdl.arm64.map",
@@ -95,15 +76,9 @@
version_script: ":libdl.riscv64.map",
},
x86: {
- pack_relocations: false,
- ldflags: [
- "-Wl,--exclude-libs=libgcc_eh.a",
- "-Wl,--hash-style=both",
- ],
version_script: ":libdl.x86.map",
},
x86_64: {
- ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
version_script: ":libdl.x86_64.map",
},
},
@@ -162,37 +137,6 @@
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
- // a) pull symbols from libgcc.a and b) depend on libdl.so will not rely on libdl.so
- // to provide those symbols, but will instead pull them from libgcc.a. Specifically,
- // we use this property to make sure libc.so has its own copy of the code from
- // libgcc.a it uses.
- //
- // DO NOT REMOVE --exclude-libs!
-
- 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-i686-android.a",
- "-Wl,--exclude-libs=libclang_rt.builtins-riscv64-android.a",
- "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
- ],
-
- // for x86, exclude libgcc_eh.a for the same reasons as above
- arch: {
- x86: {
- ldflags: [
- "-Wl,--exclude-libs=libgcc_eh.a",
- ],
- },
- x86_64: {
- ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
- },
- },
-
srcs: ["libdl_android.cpp"],
version_script: "libdl_android.map.txt",
diff --git a/libm/Android.bp b/libm/Android.bp
index cc37fb7..00d90a0 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -21,7 +21,10 @@
cc_library {
name: "libm",
- defaults: ["linux_bionic_supported"],
+ defaults: [
+ "linux_bionic_supported",
+ "bug_24465209_workaround",
+ ],
ramdisk_available: true,
vendor_ramdisk_available: true,
recovery_available: true,
@@ -196,11 +199,6 @@
"upstream-netbsd/lib/libm/complex/ctanhl.c",
"upstream-netbsd/lib/libm/complex/ctanl.c",
- // TODO: this comes from from upstream's libc, not libm, but it's an
- // implementation detail that should have hidden visibility, so it needs
- // to be in whatever library the math code is in.
- "digittoint.c",
-
// Functionality not in the BSDs.
"significandl.c",
"fake_long_double.c",
@@ -282,8 +280,6 @@
"upstream-freebsd/lib/msun/src/s_ceilf.c",
],
instruction_set: "arm",
- pack_relocations: false,
- ldflags: ["-Wl,--hash-style=both"],
version_script: ":libm.arm.map",
no_libcrt: true,
shared: {
@@ -368,11 +364,9 @@
"upstream-freebsd/lib/msun/src/s_truncf.c",
],
local_include_dirs: ["i387"],
- pack_relocations: false,
// The x86 ABI doesn't include this, which is needed for the
// roundss/roundsd instructions that we've used since Android M.
cflags: ["-msse4.1"],
- ldflags: ["-Wl,--hash-style=both"],
version_script: ":libm.x86.map",
},
diff --git a/libm/digittoint.c b/libm/digittoint.c
deleted file mode 100644
index 1824788..0000000
--- a/libm/digittoint.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*-
- * Copyright (c) 2007 David Schultz
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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 AUTHOR 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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#include <sys/cdefs.h>
-
-/* digittoint is in the FreeBSD C library, but implemented in terms of locale stuff. */
-__LIBC_HIDDEN__ int digittoint(char ch) {
- int d = ch - '0';
- if ((unsigned) d < 10) {
- return d;
- }
- d = ch - 'a';
- if ((unsigned) d < 6) {
- return d + 10;
- }
- d = ch - 'A';
- if ((unsigned) d < 6) {
- return d + 10;
- }
- return -1;
-}
diff --git a/libm/freebsd-compat.h b/libm/freebsd-compat.h
index 7accc55..a3c7cd4 100644
--- a/libm/freebsd-compat.h
+++ b/libm/freebsd-compat.h
@@ -27,18 +27,12 @@
#define __strong_reference(sym,aliassym) \
extern __typeof (sym) aliassym __attribute__ ((__alias__ (#sym)))
-#define __warn_references(sym,msg) /* ignored */
-
-// digittoint is in BSD's <ctype.h>, but not ours, so we have a secret
-// implementation in libm. We reuse parts of libm in the NDK's
-// libandroid_support, where it's a static library, so we want all our
-// "hidden" functions start with a double underscore --- being HIDDEN
-// in the ELF sense is not sufficient.
-#define digittoint __libm_digittoint
-int digittoint(char ch);
-
-// Similarly rename _scan_nan.
-#define _scan_nan __libm_scan_nan
+// digittoint is in BSD's <ctype.h> but not ours.
+#include <ctype.h>
+static inline int digittoint(char ch) {
+ if (!isxdigit(ch)) return -1;
+ return isdigit(ch) ? (ch - '0') : (_tolower(ch) - 'a');
+}
// FreeBSD exports these in <math.h> but we don't.
double cospi(double);
diff --git a/linker/Android.bp b/linker/Android.bp
index 78109e8..da57f7a 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -1,14 +1,3 @@
-// ========================================================
-// linker_wrapper - Linux Bionic (on the host)
-// ========================================================
-
-// This is used for bionic on (host) Linux to bootstrap our linker embedded into
-// a binary.
-//
-// Host bionic binaries do not have a PT_INTERP section, instead this gets
-// embedded as the entry point, and the linker is embedded as ELF sections in
-// each binary. There's a linker script that sets all of that up (generated by
-// extract_linker), and defines the extern symbols used in this file.
package {
default_team: "trendy_team_native_tools_libraries",
default_applicable_licenses: ["bionic_linker_license"],
@@ -25,6 +14,17 @@
],
}
+// ========================================================
+// linker_wrapper - Linux Bionic (on the host)
+// ========================================================
+
+// This is used for bionic on (host) Linux to bootstrap our linker embedded into
+// a binary.
+//
+// Host bionic binaries do not have a PT_INTERP section, instead this gets
+// embedded as the entry point, and the linker is embedded as ELF sections in
+// each binary. There's a linker script that sets all of that up (generated by
+// extract_linker), and defines the extern symbols used in this file.
cc_object {
name: "linker_wrapper",
host_supported: true,
@@ -327,8 +327,10 @@
},
},
+ static_executable: true,
+
// -shared is used to overwrite the -Bstatic and -static flags triggered by enabling
- // static_executable. This dynamic linker is actually a shared object linked with static
+ // static_executable. The dynamic linker is actually a shared object linked with static
// libraries.
ldflags: [
"-shared",
@@ -344,18 +346,14 @@
"-Wl,--pack-dyn-relocs=relr",
],
- // we are going to link libc++_static manually because
- // when stl is not set to "none" build system adds libdl
- // to the list of static libraries which needs to be
- // avoided in the case of building loader.
+ // We link libc++_static manually because otherwise the build system will
+ // automatically add libdl to the list of static libraries.
stl: "none",
- // we don't want crtbegin.o (because we have begin.o), so unset it
- // just for this module
+ // We don't want crtbegin.o (because we have our own arch/*/begin.o),
+ // so unset it just for this module.
nocrt: true,
- static_executable: true,
-
// Insert an extra objcopy step to add prefix to symbols. This is needed to prevent gdb
// looking up symbols in the linker by mistake.
prefix_symbols: "__dl_",
@@ -368,26 +366,17 @@
"liblinker_main",
"liblinker_malloc",
- // Use a version of libc++ built without exceptions, because accessing EH globals uses
- // ELF TLS, which is not supported in the loader.
+ // We use a version of libc++ built without exceptions,
+ // because accessing EH globals uses ELF TLS,
+ // which is not supported in the loader.
"libc++_static_noexcept",
+
"libc_nomalloc",
"libc_dynamic_dispatch",
"libm",
"libunwind",
],
- // Ensure that if the linker needs __gnu_Unwind_Find_exidx, then the linker will have a
- // definition of the symbol. The linker links against libgcc.a, whose arm32 unwinder has a weak
- // reference to __gnu_Unwind_Find_exidx, which isn't sufficient to pull in the strong definition
- // of __gnu_Unwind_Find_exidx from libc. An unresolved weak reference would create a
- // non-relative dynamic relocation in the linker binary, which complicates linker startup.
- //
- // This line should be unnecessary because the linker's dependency on libunwind_llvm.a should
- // override libgcc.a, but this line provides a simpler guarantee. It can be removed once the
- // linker stops linking against libgcc.a's arm32 unwinder.
- whole_static_libs: ["libc_unwind_static"],
-
system_shared_libs: [],
// Opt out of native_coverage when opting out of system_shared_libs
@@ -474,35 +463,6 @@
}
cc_library {
- // NOTE: --exclude-libs=libgcc.a makes sure that any symbols ld-android.so pulls from
- // libgcc.a are made static to ld-android.so. This in turn ensures that libraries that
- // a) pull symbols from libgcc.a and b) depend on ld-android.so will not rely on ld-android.so
- // to provide those symbols, but will instead pull them from libgcc.a. Specifically,
- // we use this property to make sure libc.so has its own copy of the code from
- // libgcc.a it uses.
- //
- // DO NOT REMOVE --exclude-libs!
-
- 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-riscv64-android.a",
- "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
- "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
- ],
-
- // for x86, exclude libgcc_eh.a for the same reasons as above
- arch: {
- x86: {
- ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
- },
- x86_64: {
- ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
- },
- },
-
srcs: ["ld_android.cpp"],
cflags: [
"-Wall",
diff --git a/tests/math_test.cpp b/tests/math_test.cpp
index 493f3af..273ef97 100644
--- a/tests/math_test.cpp
+++ b/tests/math_test.cpp
@@ -17,36 +17,37 @@
#define _GNU_SOURCE 1
#include <math.h>
-// This include (and the associated definition of __test_capture_signbit)
-// must be placed before any files that include <cmath> (gtest.h in this case).
+// <math.h> is required to define type-generic macros: fpclassify, signbit,
+// isfinite, isinf, isnan, isnormal, isgreater, isgreaterequal, isless,
+// islessequal, islessgreater, and isunordered.
//
-// <math.h> is required to define generic macros signbit, isfinite and
-// several other such functions.
+// <cmath> is required to #undef these macros and make equivalent sets of
+// _overloaded_ functions available in namespace std. So the isnan() macro,
+// for example, is replaced by std::isnan(float), std::isnan(double),
+// and std::isnan(long double).
//
-// <cmath> is required to undef declarations of these macros in the global
-// namespace and make equivalent functions available in namespace std. Our
-// stlport implementation does this only for signbit, isfinite, isinf and
-// isnan.
-//
-// NOTE: We don't write our test using std::signbit because we want to be
-// sure that we're testing the bionic version of signbit. The C++ libraries
-// are free to reimplement signbit or delegate to compiler builtins if they
-// please.
+// We're trying to test the bionic macros rather than whatever libc++'s
+// implementation happens to be, so we #include <math.h> and "capture" the
+// macros in our own _template_ functions in the global namespace before
+// we #include any files that include <cmath>, such as <gtest.h>.
-namespace {
-template<typename T> inline int test_capture_signbit(const T in) {
- return signbit(in);
-}
-template<typename T> inline int test_capture_isfinite(const T in) {
- return isfinite(in);
-}
-template<typename T> inline int test_capture_isnan(const T in) {
- return isnan(in);
-}
-template<typename T> inline int test_capture_isinf(const T in) {
- return isinf(in);
-}
-}
+#define capture_generic_macro(capture_function_name, generic_macro_name) \
+ template <typename T> inline int capture_function_name(const T in) { \
+ return generic_macro_name(in); \
+ }
+
+capture_generic_macro(test_capture_fpclassify, fpclassify)
+capture_generic_macro(test_capture_signbit, signbit)
+capture_generic_macro(test_capture_isfinite, isfinite)
+capture_generic_macro(test_capture_isinf, isinf)
+capture_generic_macro(test_capture_isnan, isnan)
+capture_generic_macro(test_capture_isnormal, isnormal)
+capture_generic_macro(test_capture_isgreater, isgreater)
+capture_generic_macro(test_capture_isgreaterequal, isgreaterequal)
+capture_generic_macro(test_capture_isless, isless)
+capture_generic_macro(test_capture_islessequal, islessequal)
+capture_generic_macro(test_capture_islessgreater, islessgreater)
+capture_generic_macro(test_capture_isunordered, isunordered)
#include "math_data_test.h"
@@ -60,6 +61,22 @@
#include <android-base/scopeguard.h>
+// Now we've included all the headers we need, we can redefine the generic
+// function-like macros to point to the bionic <math.h> versions we captured
+// earlier.
+#define fpclassify test_capture_fpclassify
+#define signbit test_capture_signbit
+#define isfinite test_capture_isfinite
+#define isinf test_capture_isinf
+#define isnan test_capture_isnan
+#define isnormal test_capture_isnormal
+#define isgreater test_capture_isgreater
+#define isgreaterequal test_capture_isgreaterequal
+#define isless test_capture_isless
+#define islessequal test_capture_islessequal
+#define islessgreater test_capture_islessgreater
+#define isunordered test_capture_isunordered
+
static float float_subnormal() {
union {
float f;
@@ -124,36 +141,36 @@
}
TEST(math_h, isfinite) {
- ASSERT_TRUE(test_capture_isfinite(123.0f));
- ASSERT_TRUE(test_capture_isfinite(123.0));
- ASSERT_TRUE(test_capture_isfinite(123.0L));
- ASSERT_FALSE(test_capture_isfinite(HUGE_VALF));
- ASSERT_FALSE(test_capture_isfinite(-HUGE_VALF));
- ASSERT_FALSE(test_capture_isfinite(HUGE_VAL));
- ASSERT_FALSE(test_capture_isfinite(-HUGE_VAL));
- ASSERT_FALSE(test_capture_isfinite(HUGE_VALL));
- ASSERT_FALSE(test_capture_isfinite(-HUGE_VALL));
+ ASSERT_TRUE(isfinite(123.0f));
+ ASSERT_TRUE(isfinite(123.0));
+ ASSERT_TRUE(isfinite(123.0L));
+ ASSERT_FALSE(isfinite(HUGE_VALF));
+ ASSERT_FALSE(isfinite(-HUGE_VALF));
+ ASSERT_FALSE(isfinite(HUGE_VAL));
+ ASSERT_FALSE(isfinite(-HUGE_VAL));
+ ASSERT_FALSE(isfinite(HUGE_VALL));
+ ASSERT_FALSE(isfinite(-HUGE_VALL));
}
TEST(math_h, isinf) {
- ASSERT_FALSE(test_capture_isinf(123.0f));
- ASSERT_FALSE(test_capture_isinf(123.0));
- ASSERT_FALSE(test_capture_isinf(123.0L));
- ASSERT_TRUE(test_capture_isinf(HUGE_VALF));
- ASSERT_TRUE(test_capture_isinf(-HUGE_VALF));
- ASSERT_TRUE(test_capture_isinf(HUGE_VAL));
- ASSERT_TRUE(test_capture_isinf(-HUGE_VAL));
- ASSERT_TRUE(test_capture_isinf(HUGE_VALL));
- ASSERT_TRUE(test_capture_isinf(-HUGE_VALL));
+ ASSERT_FALSE(isinf(123.0f));
+ ASSERT_FALSE(isinf(123.0));
+ ASSERT_FALSE(isinf(123.0L));
+ ASSERT_TRUE(isinf(HUGE_VALF));
+ ASSERT_TRUE(isinf(-HUGE_VALF));
+ ASSERT_TRUE(isinf(HUGE_VAL));
+ ASSERT_TRUE(isinf(-HUGE_VAL));
+ ASSERT_TRUE(isinf(HUGE_VALL));
+ ASSERT_TRUE(isinf(-HUGE_VALL));
}
TEST(math_h, isnan) {
- ASSERT_FALSE(test_capture_isnan(123.0f));
- ASSERT_FALSE(test_capture_isnan(123.0));
- ASSERT_FALSE(test_capture_isnan(123.0L));
- ASSERT_TRUE(test_capture_isnan(nanf("")));
- ASSERT_TRUE(test_capture_isnan(nan("")));
- ASSERT_TRUE(test_capture_isnan(nanl("")));
+ ASSERT_FALSE(isnan(123.0f));
+ ASSERT_FALSE(isnan(123.0));
+ ASSERT_FALSE(isnan(123.0L));
+ ASSERT_TRUE(isnan(nanf("")));
+ ASSERT_TRUE(isnan(nan("")));
+ ASSERT_TRUE(isnan(nanl("")));
}
TEST(math_h, isnormal) {
@@ -167,17 +184,17 @@
// TODO: isgreater, isgreaterequals, isless, islessequal, islessgreater, isunordered
TEST(math_h, signbit) {
- ASSERT_EQ(0, test_capture_signbit(0.0f));
- ASSERT_EQ(0, test_capture_signbit(0.0));
- ASSERT_EQ(0, test_capture_signbit(0.0L));
+ ASSERT_EQ(0, signbit(0.0f));
+ ASSERT_EQ(0, signbit(0.0));
+ ASSERT_EQ(0, signbit(0.0L));
- ASSERT_EQ(0, test_capture_signbit(1.0f));
- ASSERT_EQ(0, test_capture_signbit(1.0));
- ASSERT_EQ(0, test_capture_signbit(1.0L));
+ ASSERT_EQ(0, signbit(1.0f));
+ ASSERT_EQ(0, signbit(1.0));
+ ASSERT_EQ(0, signbit(1.0L));
- ASSERT_NE(0, test_capture_signbit(-1.0f));
- ASSERT_NE(0, test_capture_signbit(-1.0));
- ASSERT_NE(0, test_capture_signbit(-1.0L));
+ ASSERT_NE(0, signbit(-1.0f));
+ ASSERT_NE(0, signbit(-1.0));
+ ASSERT_NE(0, signbit(-1.0L));
}
// Historical BSD cruft that isn't exposed in <math.h> any more.
@@ -309,9 +326,7 @@
// Historical BSD cruft that isn't exposed in <math.h> any more.
extern "C" int __isinf(double);
extern "C" int __isinff(float);
-extern "C" int isinff(float);
extern "C" int __isinfl(long double);
-extern "C" int isinfl(long double);
TEST(math_h, __isinf) {
#if defined(ANDROID_HOST_MUSL)
@@ -367,9 +382,7 @@
// Historical BSD cruft that isn't exposed in <math.h> any more.
extern "C" int __isnan(double);
extern "C" int __isnanf(float);
-extern "C" int isnanf(float);
extern "C" int __isnanl(long double);
-extern "C" int isnanl(long double);
TEST(math_h, __isnan) {
#if defined(ANDROID_HOST_MUSL)