Merge "linker: changes to init work arounds"
diff --git a/benchmarks/property_benchmark.cpp b/benchmarks/property_benchmark.cpp
index 9251a05..77814bf 100644
--- a/benchmarks/property_benchmark.cpp
+++ b/benchmarks/property_benchmark.cpp
@@ -21,7 +21,7 @@
#include <string>
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
using namespace std::literals;
diff --git a/benchmarks/stdio_benchmark.cpp b/benchmarks/stdio_benchmark.cpp
index 21d9dc0..037bbd9 100644
--- a/benchmarks/stdio_benchmark.cpp
+++ b/benchmarks/stdio_benchmark.cpp
@@ -20,7 +20,7 @@
#include <stdio_ext.h>
#include <stdlib.h>
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
#include <benchmark/benchmark.h>
#include "util.h"
diff --git a/benchmarks/tests/interface_test.cpp b/benchmarks/tests/interface_test.cpp
index ff4b255..301c294 100644
--- a/benchmarks/tests/interface_test.cpp
+++ b/benchmarks/tests/interface_test.cpp
@@ -63,7 +63,7 @@
void SystemTests::SanitizeOutput() {
// Cut off anything after the arguments, since that varies with time.
- sanitized_output_ = std::regex_replace(raw_output_, std::regex(".+(BM_\\S+) +.+"), "$1");
+ sanitized_output_ = std::regex_replace(raw_output_, std::regex(".*(BM_\\S+)\\s+.+"), "$1");
// Remove everything before the header.
sanitized_output_.erase(0, sanitized_output_.find("------------------------------------------------"));
@@ -165,7 +165,8 @@
" [--benchmark_filter=<regex>]\n"
" [--benchmark_min_time=<min_time>]\n"
" [--benchmark_repetitions=<num_repetitions>]\n"
- " [--benchmark_report_aggregates_only={true|false}\n"
+ " [--benchmark_report_aggregates_only={true|false}]\n"
+ " [--benchmark_display_aggregates_only={true|false}]\n"
" [--benchmark_format=<console|json|csv>]\n"
" [--benchmark_out=<filename>]\n"
" [--benchmark_out_format=<json|console|csv>]\n"
diff --git a/docs/elf-tls.md b/docs/elf-tls.md
new file mode 100644
index 0000000..4a62793
--- /dev/null
+++ b/docs/elf-tls.md
@@ -0,0 +1,882 @@
+# 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
+
+[TOC]
+
+# Overview
+
+ELF TLS is a system for automatically allocating thread-local variables with cooperation among the
+compiler, linker, dynamic loader, and libc.
+
+Thread-local variables are declared in C and C++ with a specifier, e.g.:
+
+```cpp
+thread_local int tls_var;
+```
+
+At run-time, TLS variables are allocated on a module-by-module basis, where a module is a shared
+object or executable. At program startup, TLS for all initially-loaded modules comprises the "Static
+TLS Block". TLS variables within the Static TLS Block exist at fixed offsets from an
+architecture-specific thread pointer (TP) and can be accessed very efficiently -- typically just a
+few instructions. TLS variables belonging to dlopen'ed shared objects, on the other hand, may be
+allocated lazily, and accessing them typically requires a function call.
+
+# Thread-Specific Memory Layout
+
+Ulrich Drepper's ELF TLS document specifies two ways of organizing memory pointed at by the
+architecture-specific thread-pointer ([`__get_tls()`] in Bionic):
+
+
+
+
+
+Variant 1 places the static TLS block after the TP, whereas variant 2 places it before the TP.
+According to Drepper, variant 2 was motivated by backwards compatibility, and variant 1 was designed
+for Itanium. The choice has effects on the toolchain, loader, and libc. In particular, when linking
+an executable, the linker needs to know where an executable's TLS segment is relative to the TP so
+it can correctly relocate TLS accesses. Both variants are incompatible with Bionic's current
+thread-specific data layout, but variant 1 is more problematic than variant 2.
+
+Each thread has a "Dynamic Thread Vector" (DTV) with a pointer to each module's TLS block (or NULL
+if it hasn't been allocated yet). If the executable has a TLS segment, then it will always be module
+1, and its storage will always be immediately after (or before) the TP. In variant 1, the TP is
+expected to point immediately at the DTV pointer, whereas in variant 2, the DTV pointer's offset
+from TP is implementation-defined.
+
+The DTV's "generation" field is used to lazily update/reallocate the DTV when new modules are loaded
+or unloaded.
+
+[`__get_tls()`]: https://android.googlesource.com/platform/bionic/+/7245c082658182c15d2a423fe770388fec707cbc/libc/private/__get_tls.h
+
+# Access Models
+
+When a C/C++ file references a TLS variable, the toolchain generates instructions to find its
+address using a TLS "access model". The access models trade generality against efficiency. The four
+models are:
+
+ * GD: General Dynamic (aka Global Dynamic)
+ * LD: Local Dynamic
+ * IE: Initial Exec
+ * LE: Local Exec
+
+A TLS variable may be in a different module than the reference.
+
+## General Dynamic (or Global Dynamic) (GD)
+
+A GD access can refer to a TLS variable anywhere. To access a variable `tls_var` using the
+"traditional" non-TLSDESC design described in Drepper's TLS document, the toolchain compiler emits a
+call to a `__tls_get_addr` function provided by libc.
+
+For example, if we have this C code in a shared object:
+
+```cpp
+extern thread_local char tls_var;
+char* get_tls_var() {
+ return &tls_var;
+}
+```
+
+The toolchain generates code like this:
+
+```cpp
+struct TlsIndex {
+ long module; // starts counting at 1
+ long offset;
+};
+
+char* get_tls_var() {
+ static TlsIndex tls_var_idx = { // allocated in the .got
+ R_TLS_DTPMOD(tls_var), // dynamic TP module ID
+ R_TLS_DTPOFF(tls_var), // dynamic TP offset
+ };
+ return __tls_get_addr(&tls_var_idx);
+}
+```
+
+`R_TLS_DTPMOD` is a dynamic relocation to the index of the module containing `tls_var`, and
+`R_TLS_DTPOFF` is a dynamic relocation to the offset of `tls_var` within its module's `PT_TLS`
+segment.
+
+`__tls_get_addr` looks up `TlsIndex::module`'s entry in the DTV and adds `TlsIndex::offset` to the
+module's TLS block. Before it can do this, it ensures that the module's TLS block is allocated. A
+simple approach is to allocate memory lazily:
+
+1. If the current thread's DTV generation count is less than the current global TLS generation, then
+ `__tls_get_addr` may reallocate the DTV or free blocks for unloaded modules.
+
+2. If the DTV's entry for the given module is `NULL`, then `__tls_get_addr` allocates the module's
+ memory.
+
+If an allocation fails, `__tls_get_addr` calls `abort` (like emutls).
+
+musl, on the other, preallocates TLS memory in `pthread_create` and in `dlopen`, and each can report
+out-of-memory.
+
+## Local Dynamic (LD)
+
+LD is a specialization of GD that's useful when a function has references to two or more TLS
+variables that are both part of the same module as the reference. Instead of a call to
+`__tls_get_addr` for each variable, the compiler calls `__tls_get_addr` once to get the current
+module's TLS block, then adds each variable's DTPOFF to the result.
+
+For example, suppose we have this C code:
+
+```cpp
+static thread_local int x;
+static thread_local int y;
+int sum() {
+ return x + y;
+}
+```
+
+The toolchain generates code like this:
+
+```cpp
+int sum() {
+ static TlsIndex tls_module_idx = { // allocated in the .got
+ // a dynamic relocation against symbol 0 => current module ID
+ R_TLS_DTPMOD(NULL),
+ 0,
+ };
+ char* base = __tls_get_addr(&tls_module_idx);
+ // These R_TLS_DTPOFF() relocations are resolved at link-time.
+ int* px = base + R_TLS_DTPOFF(x);
+ int* py = base + R_TLS_DTPOFF(y);
+ return *px + *py;
+}
+```
+
+(XXX: LD might be important for C++ `thread_local` variables -- even a single `thread_local`
+variable with a dynamic initializer has an associated TLS guard variable.)
+
+## Initial Exec (IE)
+
+If the variable is part of the Static TLS Block (i.e. the executable or an initially-loaded shared
+object), then its offset from the TP is known at load-time. The variable can be accessed with a few
+loads.
+
+Example: a C file for an executable:
+
+```cpp
+// tls_var could be defined in the executable, or it could be defined
+// in a shared object the executable links against.
+extern thread_local char tls_var;
+char* get_addr() { return &tls_var; }
+```
+
+Compiles to:
+
+```cpp
+// allocated in the .got, resolved at load-time with a dynamic reloc.
+// Unlike DTPOFF, which is relative to the start of the module’s block,
+// TPOFF is directly relative to the thread pointer.
+static long tls_var_gotoff = R_TLS_TPOFF(tls_var);
+
+char* get_addr() {
+ return (char*)__get_tls() + tls_var_gotoff;
+}
+```
+
+## Local Exec (LE)
+
+LE is a specialization of IE. If the variable is not just part of the Static TLS Block, but is also
+part of the executable (and referenced from the executable), then a GOT access can be avoided. The
+IE example compiles to:
+
+```cpp
+char* get_addr() {
+ // R_TLS_TPOFF() is resolved at (static) link-time
+ return (char*)__get_tls() + R_TLS_TPOFF(tls_var);
+}
+```
+
+## Selecting an Access Model
+
+The compiler selects an access model for each variable reference using these factors:
+ * The absence of `-fpic` implies an executable, so use IE/LE.
+ * Code compiled with `-fpic` could be in a shared object, so use GD/LD.
+ * The per-file default can be overridden with `-ftls-model=<model>`.
+ * Specifiers on the variable (`static`, `extern`, ELF visibility attributes).
+ * A variable can be annotated with `__attribute__((tls_model(...)))`. Clang may still use a more
+ efficient model than the one specified.
+
+# Shared Objects with Static TLS
+
+Shared objects are sometimes compiled with `-ftls-model=initial-exec` (i.e. "static TLS") for better
+performance. On Ubuntu, for example, `libc.so.6` and `libOpenGL.so.0` are compiled this way. Shared
+objects using static TLS can't be loaded with `dlopen` unless libc has reserved enough surplus
+memory in the static TLS block. glibc reserves a kilobyte or two (`TLS_STATIC_SURPLUS`) with the
+intent that only a few core system libraries would use static TLS. Non-core libraries also sometimes
+use it, which can break `dlopen` if the surplus area is exhausted. See:
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1124987
+ * web search: [`"dlopen: cannot load any more object with static TLS"`][glibc-static-tls-error]
+
+Neither musl nor the Bionic TLS prototype currently allocate any surplus TLS memory.
+
+In general, supporting surplus TLS memory probably requires maintaining a thread list so that
+`dlopen` can initialize the new static TLS memory in all existing threads. A thread list could be
+omitted if the loader only allowed zero-initialized TLS segments and didn't reclaim memory on
+`dlclose`.
+
+As long as a shared object is one of the initially-loaded modules, a better option is to use
+TLSDESC.
+
+[glibc-static-tls-error]: https://www.google.com/search?q=%22dlopen:+cannot+load+any+more+object+with+static+TLS%22
+
+# TLS Descriptors (TLSDESC)
+
+The code fragments above match the "traditional" TLS design from Drepper's document. For the GD and
+LD models, there is a newer, more efficient design that uses "TLS descriptors". Each TLS variable
+reference has a corresponding descriptor, which contains a resolver function address and an argument
+to pass to the resolver.
+
+For example, if we have this C code in a shared object:
+
+```cpp
+extern thread_local char tls_var;
+char* get_tls_var() {
+ return &tls_var;
+}
+```
+
+The toolchain generates code like this:
+
+```cpp
+struct TlsDescriptor { // NB: arm32 reverses these fields
+ long (*resolver)(long);
+ long arg;
+};
+
+char* get_tls_var() {
+ // allocated in the .got, uses a dynamic relocation
+ static TlsDescriptor desc = R_TLS_DESC(tls_var);
+ return (char*)__get_tls() + desc.resolver(desc.arg);
+}
+```
+
+The dynamic loader fills in the TLS descriptors. For a reference to a variable allocated in the
+Static TLS Block, it can use a simple resolver function:
+
+```cpp
+long static_tls_resolver(long arg) {
+ return arg;
+}
+```
+
+The loader writes `tls_var@TPOFF` into the descriptor's argument.
+
+To support modules loaded with `dlopen`, the loader must use a resolver function that calls
+`__tls_get_addr`. In principle, this simple implementation would work:
+
+```cpp
+long dynamic_tls_resolver(TlsIndex* arg) {
+ return (long)__tls_get_addr(arg) - (long)__get_tls();
+}
+```
+
+There are optimizations that complicate the design a little:
+ * Unlike `__tls_get_addr`, the resolver function has a special calling convention that preserves
+ almost all registers, reducing register pressure in the caller
+ ([example](https://godbolt.org/g/gywcxk)).
+ * In general, the resolver function must call `__tls_get_addr`, so it must save and restore all
+ registers.
+ * To keep the fast path fast, the resolver inlines the fast path of `__tls_get_addr`.
+ * By storing the module's initial generation alongside the TlsIndex, the resolver function doesn't
+ need to use an atomic or synchronized access of the global TLS generation counter.
+
+The resolver must be written in assembly, but in C, the function looks like so:
+
+```cpp
+struct TlsDescDynamicArg {
+ unsigned long first_generation;
+ TlsIndex idx;
+};
+
+struct TlsDtv { // DTV == dynamic thread vector
+ unsigned long generation;
+ char* modules[];
+};
+
+long dynamic_tls_resolver(TlsDescDynamicArg* arg) {
+ TlsDtv* dtv = __get_dtv();
+ char* addr;
+ if (dtv->generation >= arg->first_generation &&
+ dtv->modules[arg->idx.module] != nullptr) {
+ addr = dtv->modules[arg->idx.module] + arg->idx.offset;
+ } else {
+ addr = __tls_get_addr(&arg->idx);
+ }
+ return (long)addr - (long)__get_tls();
+}
+```
+
+The loader needs to allocate a table of `TlsDescDynamicArg` objects for each TLS module with dynamic
+TLSDESC relocations.
+
+The static linker can still relax a TLSDESC-based access to an IE/LE access.
+
+The traditional TLS design is implemented everywhere, but the TLSDESC design has less toolchain
+support:
+ * GCC and the BFD linker support both designs on all supported Android architectures (arm32, arm64,
+ x86, x86-64).
+ * GCC can select the design at run-time using `-mtls-dialect=<dialect>` (`trad`-vs-`desc` on arm64,
+ otherwise `gnu`-vs-`gnu2`). Clang always uses the default mode.
+ * GCC and Clang default to TLSDESC on arm64 and the traditional design on other architectures.
+ * Gold and LLD support for TLSDESC is spotty (except when targeting arm64).
+
+# Linker Relaxations
+
+The (static) linker frequently has more information about the location of a referenced TLS variable
+than the compiler, so it can "relax" TLS accesses to more efficient models. For example, if an
+object file compiled with `-fpic` is linked into an executable, the linker could relax GD accesses
+to IE or LE. To relax a TLS access, the linker looks for an expected sequences of instructions and
+static relocations, then replaces the sequence with a different one of equal size. It may need to
+add or remove no-op instructions.
+
+## Current Support for GD->LE Relaxations Across Linkers
+
+Versions tested:
+ * BFD and Gold linkers: version 2.30
+ * LLD version 6.0.0 (upstream)
+
+Linker support for GD->LE relaxation with `-mtls-dialect=gnu/trad` (traditional):
+
+Architecture | BFD | Gold | LLD
+--------------- | --- | ---- | ---
+arm32 | no | no | no
+arm64 (unusual) | yes | yes | no
+x86 | yes | yes | yes
+x86_64 | yes | yes | yes
+
+Linker support for GD->LE relaxation with `-mtls-dialect=gnu2/desc` (TLSDESC):
+
+Architecture | BFD | Gold | LLD
+--------------------- | --- | ------------------ | ------------------
+arm32 (experimental) | yes | unsupported relocs | unsupported relocs
+arm64 | yes | yes | yes
+x86 (experimental) | yes | yes | unsupported relocs
+X86_64 (experimental) | yes | yes | unsupported relocs
+
+arm32 linkers can't relax traditional TLS accesses. BFD can relax an arm32 TLSDESC access, but LLD
+can't link code using TLSDESC at all, except on arm64, where it's used by default.
+
+# dlsym
+
+Calling `dlsym` on a TLS variable returns the address of the current thread's variable.
+
+# Debugger Support
+
+## gdb
+
+gdb uses a libthread_db plugin library to retrieve thread-related information from a target. This
+library is typically a shared object, but for Android, we link our own `libthread_db.a` into
+gdbserver. We will need to implement at least 2 APIs in `libthread_db.a` to find TLS variables, and
+gdb provides APIs for looking up symbols, reading or writing memory, and retrieving the current
+thread pointer (e.g. `ps_get_thread_area`).
+ * Reference: [gdb_proc_service.h]: APIs gdb provides to libthread_db
+ * Reference: [Currently unimplemented TLS functions in Android's libthread_tb][libthread_db.c]
+
+[gdb_proc_service.h]: https://android.googlesource.com/toolchain/gdb/+/a7e49fd02c21a496095c828841f209eef8ae2985/gdb-8.0.1/gdb/gdb_proc_service.h#41
+[libthread_db.c]: https://android.googlesource.com/platform/ndk/+/e1f0ad12fc317c0ca3183529cc9625d3f084d981/sources/android/libthread_db/libthread_db.c#115
+
+## LLDB
+
+LLDB more-or-less implemented Linux TLS debugging in [r192922][rL192922] ([D1944]) for x86 and
+x86-64. [arm64 support came later][D5073]. However, the Linux TLS functionality no longer does
+anything: the `GetThreadPointer` function is no longer implemented. Code for reading the thread
+pointer was removed in [D10661] ([this function][r240543]). (arm32 was apparently never supported.)
+
+[rL192922]: https://reviews.llvm.org/rL192922
+[D1944]: https://reviews.llvm.org/D1944
+[D5073]: https://reviews.llvm.org/D5073
+[D10661]: https://reviews.llvm.org/D10661
+[r240543]: https://github.com/llvm-mirror/lldb/commit/79246050b0f8d6b54acb5366f153d07f235d2780#diff-52dee3d148892cccfcdab28bc2165548L962
+
+## Threading Library Metadata
+
+Both debuggers need metadata from the threading library (`libc.so` / `libpthread.so`) to find TLS
+variables. From [LLDB r192922][rL192922]'s commit message:
+
+> ... All OSes use basically the same algorithm (a per-module lookup table) as detailed in Ulrich
+> Drepper's TLS ELF ABI document, so we can easily write code to decode it ourselves. The only
+> question therefore is the exact field layouts required. Happily, the implementors of libpthread
+> expose the structure of the DTV via metadata exported as symbols from the .so itself, designed
+> exactly for this kind of thing. So this patch simply reads that metadata in, and re-implements
+> libthread_db's algorithm itself. We thereby get cross-platform TLS lookup without either requiring
+> third-party libraries, while still being independent of the version of libpthread being used.
+
+ LLDB uses these variables:
+
+Name | Notes
+--------------------------------- | ---------------------------------------------------------------------------------------
+`_thread_db_pthread_dtvp` | Offset from TP to DTV pointer (0 for variant 1, implementation-defined for variant 2)
+`_thread_db_dtv_dtv` | Size of a DTV slot (typically/always sizeof(void*))
+`_thread_db_dtv_t_pointer_val` | Offset within a DTV slot to the pointer to the allocated TLS block (typically/always 0)
+`_thread_db_link_map_l_tls_modid` | Offset of a `link_map` field containing the module's 1-based TLS module ID
+
+The metadata variables are local symbols in glibc's `libpthread.so` symbol table (but not its
+dynamic symbol table). Debuggers can access them, but applications can't.
+
+The debugger lookup process is straightforward:
+ * Find the `link_map` object and module-relative offset for a TLS variable.
+ * Use `_thread_db_link_map_l_tls_modid` to find the TLS variable's module ID.
+ * Read the target thread pointer.
+ * Use `_thread_db_pthread_dtvp` to find the thread's DTV.
+ * Use `_thread_db_dtv_dtv` and `_thread_db_dtv_t_pointer_val` to find the desired module's block
+ within the DTV.
+ * Add the module-relative offset to the module pointer.
+
+This process doesn't appear robust in the face of lazy DTV initialization -- presumably it could
+read past the end of an out-of-date DTV or access an unloaded module. To be robust, it needs to
+compare a module's initial generation count against the DTV's generation count. (XXX: Does gdb have
+these sorts of problems with glibc's libpthread?)
+
+## Reading the Thread Pointer with Ptrace
+
+There are ptrace interfaces for reading the thread pointer for each of arm32, arm64, x86, and x86-64
+(XXX: check 32-vs-64-bit for inferiors, debuggers, and kernels):
+ * arm32: `PTRACE_GET_THREAD_AREA`
+ * arm64: `PTRACE_GETREGSET`, `NT_ARM_TLS`
+ * x86_32: `PTRACE_GET_THREAD_AREA`
+ * x86_64: use `PTRACE_PEEKUSER` to read the `{fs,gs}_base` fields of `user_regs_struct`
+
+# C/C++ Specifiers
+
+C/C++ TLS variables are declared with a specifier:
+
+Specifier | Notes
+--------------- | -----------------------------------------------------------------------------------------------------------------------------
+`__thread` | - non-standard, but ubiquitous in GCC and Clang<br/> - cannot have dynamic initialization or destruction
+`_Thread_local` | - a keyword standardized in C11<br/> - cannot have dynamic initialization or destruction
+`thread_local` | - C11: a macro for `_Thread_local` via `threads.h`<br/> - C++11: a keyword, allows dynamic initialization and/or destruction
+
+The dynamic initialization and destruction of C++ `thread_local` variables is layered on top of ELF
+TLS (or emutls), so this design document mostly ignores it. Like emutls, ELF TLS variables either
+have a static initializer or are zero-initialized.
+
+Aside: Because a `__thread` variable cannot have dynamic initialization, `__thread` is more
+efficient in C++ than `thread_local` when the compiler cannot see the definition of a declared TLS
+variable. The compiler assumes the variable could have a dynamic initializer and generates code, at
+each access, to call a function to initialize the variable.
+
+# Graceful Failure on Old Platforms
+
+ELF TLS isn't implemented on older Android platforms, so dynamic executables and shared objects
+using it generally won't work on them. Ideally, the older platforms would reject these binaries
+rather than experience memory corruption at run-time.
+
+Static executables aren't a problem--the necessary runtime support is part of the executable, so TLS
+just works.
+
+XXX: Shared objects are less of a problem.
+ * On arm32, x86, and x86_64, the loader [should reject a TLS relocation]. (XXX: I haven't verified
+ this.)
+ * On arm64, the primary TLS relocation (R_AARCH64_TLSDESC) is [confused with an obsolete
+ R_AARCH64_TLS_DTPREL32 relocation][R_AARCH64_TLS_DTPREL32] and is [quietly ignored].
+ * Android P [added compatibility checks] for TLS symbols and `DT_TLSDESC_{GOT|PLT}` entries.
+
+XXX: A dynamic executable using ELF TLS would have a PT_TLS segment and no other distinguishing
+marks, so running it on an older platform would result in memory corruption. Should we add something
+to these executables that only newer platforms recognize? (e.g. maybe an entry in .dynamic, a
+reference to a symbol only a new libc.so has...)
+
+[should reject a TLS relocation]: https://android.googlesource.com/platform/bionic/+/android-8.1.0_r48/linker/linker.cpp#2852
+[R_AARCH64_TLS_DTPREL32]: https://android-review.googlesource.com/c/platform/bionic/+/723696
+[quietly ignored]: https://android.googlesource.com/platform/bionic/+/android-8.1.0_r48/linker/linker.cpp#2784
+[added compatibility checks]: https://android-review.googlesource.com/c/platform/bionic/+/648760
+
+# Bionic Prototype Notes
+
+There is an [ELF TLS prototype] uploaded on Gerrit. It implements:
+ * Static TLS Block allocation for static and dynamic executables
+ * TLS for dynamically loaded and unloaded modules (`__tls_get_addr`)
+ * TLSDESC for arm64 only
+
+Missing:
+ * `dlsym` of a TLS variable
+ * debugger support
+
+[ELF TLS prototype]: https://android-review.googlesource.com/q/topic:%22elf-tls-prototype%22+(status:open%20OR%20status:merged)
+
+## Loader/libc Communication
+
+The loader exposes a list of TLS modules ([`struct TlsModules`][TlsModules]) to `libc.so` using the
+`__libc_shared_globals` variable (see `tls_modules()` in [linker_tls.cpp][tls_modules-linker] and
+[elf_tls.cpp][tls_modules-libc]). `__tls_get_addr` in libc.so acquires the `TlsModules::mutex` and
+iterates its module list to lazily allocate and free TLS blocks.
+
+[TlsModules]: https://android-review.googlesource.com/c/platform/bionic/+/723698/1/libc/bionic/elf_tls.h#53
+[tls_modules-linker]: https://android-review.googlesource.com/c/platform/bionic/+/723698/1/linker/linker_tls.cpp#45
+[tls_modules-libc]: https://android-review.googlesource.com/c/platform/bionic/+/723698/1/libc/bionic/elf_tls.cpp#49
+
+## TLS Allocator
+
+The prototype currently allocates a `pthread_internal_t` object and static TLS in a single mmap'ed
+region, along with a thread's stack if it needs one allocated. It doesn't place TLS memory on a
+preallocated stack (either the main thread's stack or one provided with `pthread_attr_setstack`).
+
+The DTV and blocks for dlopen'ed modules are instead allocated using the Bionic loader's
+`LinkerMemoryAllocator`, adapted to avoid the STL and to provide `memalign`. The prototype tries to
+achieve async-signal safety by blocking signals and acquiring a lock.
+
+There are three "entry points" to dynamically locate a TLS variable's address:
+ * libc.so: `__tls_get_addr`
+ * loader: TLSDESC dynamic resolver
+ * loader: dlsym
+
+The loader's entry points need to call `__tls_get_addr`, which needs to allocate memory. Currently,
+the prototype uses a [special function pointer] to call libc.so's `__tls_get_addr` from the loader.
+(This should probably be removed.)
+
+The prototype currently allows for arbitrarily-large TLS variable alignment. IIRC, different
+implementations (glibc, musl, FreeBSD) vary in their level of respect for TLS alignment. It looks
+like the Bionic loader ignores segments' alignment and aligns loaded libraries to 256 KiB. See
+`ReserveAligned`.
+
+[special function pointer]: https://android-review.googlesource.com/c/platform/bionic/+/723698/1/libc/private/bionic_globals.h#52
+
+## Async-Signal Safety
+
+The prototype's `__tls_get_addr` might be async-signal safe. Making it AS-safe is a good idea if
+it's feasible. musl's function is AS-safe, but glibc's isn't (or wasn't). Google had a patch to make
+glibc AS-safe back in 2012-2013. See:
+ * https://sourceware.org/glibc/wiki/TLSandSignals
+ * https://sourceware.org/ml/libc-alpha/2012-06/msg00335.html
+ * https://sourceware.org/ml/libc-alpha/2013-09/msg00563.html
+
+## Out-of-Memory Handling (abort)
+
+The prototype lazily allocates TLS memory for dlopen'ed modules (see `__tls_get_addr`), and an
+out-of-memory error on a TLS access aborts the process. musl, on the other hand, preallocates TLS
+memory on `pthread_create` and `dlopen`, so either function can return out-of-memory. Both functions
+probably need to acquire the same lock.
+
+Maybe Bionic should do the same as musl? Perhaps musl's robustness argument holds for Bionic,
+though, because Bionic (at least the linker) probably already aborts on OOM. musl doesn't support
+`dlclose`/unloading, so it might have an easier time.
+
+On the other hand, maybe lazy allocation is a feature, because not all threads will use a dlopen'ed
+solib's TLS variables. Drepper makes this argument in his TLS document:
+
+> In addition the run-time support should avoid creating the thread-local storage if it is not
+> necessary. For instance, a loaded module might only be used by one thread of the many which make
+> up the process. It would be a waste of memory and time to allocate the storage for all threads. A
+> lazy method is wanted. This is not much extra burden since the requirement to handle dynamically
+> loaded objects already requires recognizing storage which is not yet allocated. This is the only
+> alternative to stopping all threads and allocating storage for all threads before letting them run
+> again.
+
+FWIW: emutls also aborts on out-of-memory.
+
+## ELF TLS Not Usable in libc
+
+The dynamic loader currently can't use ELF TLS, so any part of libc linked into the loader (i.e.
+most of it) also can't use ELF TLS. It might be possible to lift this restriction, perhaps with
+specialized `__tls_get_addr` and TLSDESC resolver functions.
+
+# Open Issues
+
+## Bionic Memory Layout Conflicts with Common TLS Layout
+
+Bionic already allocates thread-specific data in a way that conflicts with TLS variants 1 and 2:
+
+
+TLS variant 1 allocates everything after the TP to ELF TLS (except the first two words), and variant
+2 allocates everything before the TP. Bionic currently allocates memory before and after the TP to
+the `pthread_internal_t` struct.
+
+The `bionic_tls.h` header is marked with a warning:
+
+```cpp
+/** WARNING WARNING WARNING
+ **
+ ** This header file is *NOT* part of the public Bionic ABI/API
+ ** and should not be used/included by user-serviceable parts of
+ ** the system (e.g. applications).
+ **
+ ** It is only provided here for the benefit of the system dynamic
+ ** linker and the OpenGL sub-system (which needs to access the
+ ** pre-allocated slot directly for performance reason).
+ **/
+```
+
+There are issues with rearranging this memory:
+
+ * `TLS_SLOT_STACK_GUARD` is used for `-fstack-protector`. The location (word #5) was initially used
+ by GCC on x86 (and x86-64), where it is compatible with x86's TLS variant 2. We [modified Clang
+ to use this slot for arm64 in 2016][D18632], though, and the slot isn't compatible with ARM's
+ variant 1 layout. This change shipped in NDK r14, and the NDK's build systems (ndk-build and the
+ CMake toolchain file) enable `-fstack-protector-strong` by default.
+
+ * `TLS_SLOT_TSAN` is used for more than just TSAN -- it's also used by [HWASAN and
+ Scudo](https://reviews.llvm.org/D53906#1285002).
+
+ * The Go runtime allocates a thread-local "g" variable on Android by creating a pthread key and
+ searching for its TP-relative offset, which it assumes is nonnegative:
+ * On arm32/arm64, it creates a pthread key, sets it to a magic value, then scans forward from
+ the thread pointer looking for it. [The scan count was bumped to 384 to fix a reported
+ breakage happening with Android N.](https://go-review.googlesource.com/c/go/+/38636) (XXX: I
+ suspect the actual platform breakage happened with Android M's [lock-free pthread key
+ work][bionic-lockfree-keys].)
+ * On x86/x86-64, it uses a fixed offset from the thread pointer (TP+0xf8 or TP+0x1d0) and
+ creates pthread keys until one of them hits the fixed offset.
+ * CLs:
+ * arm32: https://codereview.appspot.com/106380043
+ * arm64: https://go-review.googlesource.com/c/go/+/17245
+ * x86: https://go-review.googlesource.com/c/go/+/16678
+ * x86-64: https://go-review.googlesource.com/c/go/+/15991
+ * Moving the pthread keys before the thread pointer breaks Go-based apps.
+ * It's unclear how many Android apps use Go. There are at least two with 1,000,000+ installs.
+ * [Some motivation for Go's design][golang-post], [runtime/HACKING.md][go-hacking]
+ * [On x86/x86-64 Darwin, Go uses a TLS slot reserved for both Go and Wine][go-darwin-x86] (On
+ [arm32][go-darwin-arm32]/[arm64][go-darwin-arm64] Darwin, Go scans for pthread keys like it
+ does on Android.)
+
+ * Android's "native bridge" system allows the Zygote to load an app solib of a non-native ABI. (For
+ example, it could be used to load an arm32 solib into an x86 Zygote.) The solib is translated
+ into the host architecture. TLS accesses in the app solib (whether ELF TLS, Bionic slots, or
+ `pthread_internal_t` fields) become host accesses. Laying out TLS memory differently across
+ architectures could complicate this translation.
+
+ * A `pthread_t` is practically just a `pthread_internal_t*`, and some apps directly access the
+ `pthread_internal_t::tid` field. Past examples: http://b/17389248, [aosp/107467]. Reorganizing
+ the initial `pthread_internal_t` fields could break those apps.
+
+It seems easy to fix the incompatibility for variant 2 (x86 and x86_64) by splitting out the Bionic
+slots into a new data structure. Variant 1 is a harder problem.
+
+The TLS prototype currently uses a patched LLD that uses a variant 1 TLS layout with a 16-word TCB
+on all architectures.
+
+Aside: gcc's arm64ilp32 target uses a 32-bit unsigned offset for a TLS IE access
+(https://godbolt.org/z/_NIXjF). If Android ever supports this target, and in a configuration with
+variant 2 TLS, we might need to change the compiler to emit a sign-extending load.
+
+[D18632]: https://reviews.llvm.org/D18632
+[bionic-lockfree-keys]: https://android-review.googlesource.com/c/platform/bionic/+/134202
+[golang-post]: https://groups.google.com/forum/#!msg/golang-nuts/EhndTzcPJxQ/i-w7kAMfBQAJ
+[go-hacking]: https://github.com/golang/go/blob/master/src/runtime/HACKING.md
+[go-darwin-x86]: https://github.com/golang/go/issues/23617
+[go-darwin-arm32]: https://github.com/golang/go/blob/15c106d99305411b587ec0d9e80c882e538c9d47/src/runtime/cgo/gcc_darwin_arm.c
+[go-darwin-arm64]: https://github.com/golang/go/blob/15c106d99305411b587ec0d9e80c882e538c9d47/src/runtime/cgo/gcc_darwin_arm64.c
+[aosp/107467]: https://android-review.googlesource.com/c/platform/bionic/+/107467
+
+### Workaround: Use Variant 2 on arm32/arm64
+
+Pros: simplifies Bionic
+
+Cons:
+ * arm64: requires either subtle reinterpretation of a TLS relocation or addition of a new
+ relocation
+ * arm64: a new TLS relocation reduces compiler/assembler compatibility with non-Android
+
+The point of variant 2 was backwards-compatibility, and ARM Android needs to remain
+backwards-compatible, so we could use variant 2 for ARM. Problems:
+
+ * When linking an executable, the static linker needs to know how TLS is allocated because it
+ writes TP-relative offsets for IE/LE-model accesses. Clang doesn't tell the linker to target
+ Android, so it could pass an `--tls-variant2` flag to configure lld.
+
+ * On arm64, there are different sets of static LE relocations accommodating different ranges of
+ offsets from TP:
+
+ Size | TP offset range | Static LE relocation types
+ ---- | ----------------- | ---------------------------------------
+ 12 | 0 <= x < 2^12 | `R_AARCH64_TLSLE_ADD_TPREL_LO12`
+ " | " | `R_AARCH64_TLSLE_LDST8_TPREL_LO12`
+ " | " | `R_AARCH64_TLSLE_LDST16_TPREL_LO12`
+ " | " | `R_AARCH64_TLSLE_LDST32_TPREL_LO12`
+ " | " | `R_AARCH64_TLSLE_LDST64_TPREL_LO12`
+ " | " | `R_AARCH64_TLSLE_LDST128_TPREL_LO12`
+ 16 | -2^16 <= x < 2^16 | `R_AARCH64_TLSLE_MOVW_TPREL_G0`
+ 24 | 0 <= x < 2^24 | `R_AARCH64_TLSLE_ADD_TPREL_HI12`
+ " | " | `R_AARCH64_TLSLE_ADD_TPREL_LO12_NC`
+ " | " | `R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC`
+ " | " | `R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC`
+ " | " | `R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC`
+ " | " | `R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC`
+ " | " | `R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC`
+ 32 | -2^32 <= x < 2^32 | `R_AARCH64_TLSLE_MOVW_TPREL_G1`
+ " | " | `R_AARCH64_TLSLE_MOVW_TPREL_G0_NC`
+ 48 | -2^48 <= x < 2^48 | `R_AARCH64_TLSLE_MOVW_TPREL_G2`
+ " | " | `R_AARCH64_TLSLE_MOVW_TPREL_G1_NC`
+ " | " | `R_AARCH64_TLSLE_MOVW_TPREL_G0_NC`
+
+ GCC for arm64 defaults to the 24-bit model and has an `-mtls-size=SIZE` option for setting other
+ supported sizes. (It supports 12, 24, 32, and 48.) Clang has only implemented the 24-bit model,
+ but that could change. (Clang [briefly used][D44355] load/store relocations, but it was reverted
+ because no linker supported them: [BFD], [Gold], [LLD]).
+
+ The 16-, 32-, and 48-bit models use a `movn/movz` instruction to set the highest 16 bits to a
+ positive or negative value, then `movk` to set the remaining 16 bit chunks. In principle, these
+ relocations should be able to accommodate a negative TP offset.
+
+ The 24-bit model uses `add` to set the high 12 bits, then places the low 12 bits into another
+ `add` or a load/store instruction.
+
+Maybe we could modify the `R_AARCH64_TLSLE_ADD_TPREL_HI12` relocation to allow a negative TP offset
+by converting the relocated `add` instruction to a `sub`. Alternately, we could add a new
+`R_AARCH64_TLSLE_SUB_TPREL_HI12` relocation, and Clang would use a different TLS LE instruction
+sequence when targeting Android/arm64.
+
+ * LLD's arm64 relaxations from GD and IE to LE would need to use `movn` instead of `movk` for
+ Android.
+
+ * Binaries linked with the flag crash on non-Bionic, and binaries without the flag crash on Bionic.
+ We might want to mark the binaries somehow to indicate the non-standard TLS ABI. Suggestion:
+ * Use an `--android-tls-variant2` flag (or `--bionic-tls-variant2`, we're trying to make [Bionic
+ run on the host](http://b/31559095))
+ * Add a `PT_ANDROID_TLS_TPOFF` segment?
+ * Add a [`.note.gnu.property`](https://reviews.llvm.org/D53906#1283425) with a
+ "`GNU_PROPERTY_TLS_TPOFF`" property value?
+
+[D44355]: https://reviews.llvm.org/D44355
+[BFD]: https://sourceware.org/bugzilla/show_bug.cgi?id=22970
+[Gold]: https://sourceware.org/bugzilla/show_bug.cgi?id=22969
+[LLD]: https://bugs.llvm.org/show_bug.cgi?id=36727
+
+### Workaround: Reserve an Extra-Large TCB on ARM
+
+Pros: Minimal linker change, no change to TLS relocations.
+Cons: The reserved amount becomes an arbitrary but immutable part of the Android ABI.
+
+Add an lld option: `--android-tls[-tcb=SIZE]`
+
+As with the first workaround, we'd probably want to mark the binary to indicate the non-standard
+TP-to-TLS-segment offset.
+
+Reservation amount:
+ * We would reserve at least 6 words to cover the stack guard
+ * Reserving 16 covers all the existing Bionic slots and gives a little room for expansion. (If we
+ ever needed more than 16 slots, we could allocate the space before TP.)
+ * 16 isn't enough for the pthread keys, so the Go runtime is still a problem.
+ * Reserving 138 words is enough for existing slots and pthread keys.
+
+### Workaround: Use Variant 1 Everywhere with an Extra-Large TCB
+
+Pros:
+ * memory layout is the same on all architectures, avoids native bridge complications
+ * x86/x86-64 relocations probably handle positive offsets without issue
+
+Cons:
+ * The reserved amount is still arbitrary.
+
+### Workaround: No LE Model in Android Executables
+
+Pros:
+ * Keeps options open. We can allow LE later if we want.
+ * Bionic's existing memory layout doesn't change, and arm32 and 32-bit x86 have the same layout
+ * Fixes everything but static executables
+
+Cons:
+ * more intrusive toolchain changes (affects both Clang and LLD)
+ * statically-linked executables still need another workaround
+ * somewhat larger/slower executables (they must use IE, not LE)
+
+The layout conflict is apparently only a problem because an executable assumes that its TLS segment
+is located at a statically-known offset from the TP (i.e. it uses the LE model). An initially-loaded
+shared object can still use the efficient IE access model, but its TLS segment offset is known at
+load-time, not link-time. If we can guarantee that Android's executables also use the IE model, not
+LE, then the Bionic loader can place the executable's TLS segment at any offset from the TP, leaving
+the existing thread-specific memory layout untouched.
+
+This workaround doesn't help with statically-linked executables, but they're probably less of a
+problem, because the linker and `libc.a` are usually packaged together.
+
+A likely problem: LD is normally relaxed to LE, not to IE. We'd either have to disable LD usage in
+the compiler (bad for performance) or add LD->IE relaxation. This relaxation requires that IE code
+sequences be no larger than LD code sequences, which may not be the case on some architectures.
+(XXX: In some past testing, it looked feasible for TLSDESC but not the traditional design.)
+
+To implement:
+ * Clang would need to stop generating LE accesses.
+ * LLD would need to relax GD and LD to IE instead of LE.
+ * LLD should abort if it sees a TLS LE relocation.
+ * LLD must not statically resolve an executable's IE relocation in the GOT. (It might assume that
+ it knows its value.)
+ * Perhaps LLD should mark executables specially, because a normal ELF linker's output would quietly
+ trample on `pthread_internal_t`. We need something like `DF_STATIC_TLS`, but instead of
+ indicating IE in an solib, we want to indicate the lack of LE in an executable.
+
+### (Non-)workaround for Go: Allocate a Slot with Go's Magic Values
+
+The Go runtime allocates its thread-local "g" variable by searching for a hard-coded magic constant
+(`0x23581321` for arm32 and `0x23581321345589` for arm64). As long as it finds its constant at a
+small positive offset from TP (within the first 384 words), it will think it has found the pthread
+key it allocated.
+
+As a temporary compatibility hack, we might try to keep these programs running by reserving a TLS
+slot with this magic value. This hack doesn't appear to work, however. The runtime finds its pthread
+key, but apps segfault. Perhaps the Go runtime expects its "g" variable to be zero-initialized ([one
+example][go-tlsg-zero]). With this hack, it's never zero, but with its current allocation strategy,
+it is typically zero. After [Bionic's pthread key system was rewritten to be
+lock-free][bionic-lockfree-keys] for Android M, though, it's not guaranteed, because a key could be
+recycled.
+
+[go-tlsg-zero]: https://go.googlesource.com/go/+/5bc1fd42f6d185b8ff0201db09fb82886978908b/src/runtime/asm_arm64.s#980
+
+### Workaround for Go: place pthread keys after the executable's TLS
+
+Most Android executables do not use any `thread_local` variables. In the current prototype, with the
+AOSP hikey960 build, only `/system/bin/netd` has a TLS segment, and it's only 32 bytes. As long as
+`/system/bin/app_process{32,64}` limits its use of TLS memory, then the pthread keys could be
+allocated after `app_process`' TLS segment, and Go will still find them.
+
+Go scans 384 words from the thread pointer. If there are at most 16 Bionic slots and 130 pthread
+keys (2 words per key), then `app_process` can use at most 108 words of TLS memory.
+
+Drawback: In principle, this might make pthread key accesses slower, because Bionic can't assume
+that pthread keys are at a fixed offset from the thread pointer anymore. It must load an offset from
+somewhere (a global variable, another TLS slot, ...). `__get_thread()` already uses a TLS slot to
+find `pthread_internal_t`, though, rather than assume a fixed offset. (XXX: I think it could be
+optimized.)
+
+## TODO: Memory Layout Querying APIs (Proposed)
+
+ * https://sourceware.org/glibc/wiki/ThreadPropertiesAPI
+ * http://b/30609580
+
+## TODO: Sanitizers
+
+XXX: Maybe a sanitizer would want to intercept allocations of TLS memory, and that could be hard if
+the loader is allocating it.
+ * It looks like glibc's ld.so re-relocates itself after loading a program, so a program's symbols
+ can interpose call in the loader: https://sourceware.org/ml/libc-alpha/2014-01/msg00501.html
+
+# References
+
+General (and x86/x86-64)
+ * Ulrich Drepper's TLS document, ["ELF Handling For Thread-Local Storage."][drepper] Describes the
+ overall ELF TLS design and ABI details for x86 and x86-64 (as well as several other architectures
+ that Android doesn't target).
+ * Alexandre Oliva's TLSDESC proposal with details for x86 and x86-64: ["Thread-Local Storage
+ Descriptors for IA32 and AMD64/EM64T."][tlsdesc-x86]
+ * [x86 and x86-64 SystemV psABIs][psabi-x86].
+
+arm32:
+ * Alexandre Oliva's TLSDESC proposal for arm32: ["Thread-Local Storage Descriptors for the ARM
+ platform."][tlsdesc-arm]
+ * ["Addenda to, and Errata in, the ABI for the ARM® Architecture."][arm-addenda] Section 3,
+ "Addendum: Thread Local Storage" has details for arm32 non-TLSDESC ELF TLS.
+ * ["Run-time ABI for the ARM® Architecture."][arm-rtabi] Documents `__aeabi_read_tp`.
+ * ["ELF for the ARM® Architecture."][arm-elf] List TLS relocations (traditional and TLSDESC).
+
+arm64:
+ * [2015 LLVM bugtracker comment][llvm22408] with an excerpt from an unnamed ARM draft specification
+ describing arm64 code sequences necessary for linker relaxation
+ * ["ELF for the ARM® 64-bit Architecture (AArch64)."][arm64-elf] Lists TLS relocations (traditional
+ and TLSDESC).
+
+[drepper]: https://www.akkadia.org/drepper/tls.pdf
+[tlsdesc-x86]: https://www.fsfla.org/~lxoliva/writeups/TLS/RFC-TLSDESC-x86.txt
+[psabi-x86]: https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI
+[tlsdesc-arm]: https://www.fsfla.org/~lxoliva/writeups/TLS/RFC-TLSDESC-ARM.txt
+[arm-addenda]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf
+[arm-rtabi]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0043d/IHI0043D_rtabi.pdf
+[arm-elf]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf
+[llvm22408]: https://bugs.llvm.org/show_bug.cgi?id=22408#c10
+[arm64-elf]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
diff --git a/docs/img/bionic-tls-layout-in-p.png b/docs/img/bionic-tls-layout-in-p.png
new file mode 100644
index 0000000..4c810d6
--- /dev/null
+++ b/docs/img/bionic-tls-layout-in-p.png
Binary files differ
diff --git a/docs/img/tls-variant1.png b/docs/img/tls-variant1.png
new file mode 100644
index 0000000..bd92f16
--- /dev/null
+++ b/docs/img/tls-variant1.png
Binary files differ
diff --git a/docs/img/tls-variant2.png b/docs/img/tls-variant2.png
new file mode 100644
index 0000000..f941af7
--- /dev/null
+++ b/docs/img/tls-variant2.png
Binary files differ
diff --git a/libc/Android.bp b/libc/Android.bp
index 681394f..bc4dd9e 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -65,7 +65,7 @@
cppflags: [],
include_dirs: [
"bionic/libc/async_safe/include",
- "external/jemalloc/include",
+ "external/jemalloc_new/include",
],
stl: "none",
@@ -76,6 +76,9 @@
},
native_coverage: false,
recovery_available: true,
+
+ // TODO(ivanlozano): Remove after b/118321713
+ xom: false,
}
// ANDROIDMK TRANSLATION ERROR: unsupported directive
@@ -268,23 +271,11 @@
"upstream-freebsd/lib/libc/string/wcscmp.c",
"upstream-freebsd/lib/libc/string/wcslen.c",
"upstream-freebsd/lib/libc/string/wcsrchr.c",
+ "upstream-freebsd/lib/libc/string/wmemcmp.c",
+ "upstream-freebsd/lib/libc/string/wcscat.c",
+ "upstream-freebsd/lib/libc/string/wcscpy.c",
+ "upstream-freebsd/lib/libc/string/wmemcmp.c",
],
- atom: {
- exclude_srcs: [
- "upstream-freebsd/lib/libc/string/wmemcmp.c",
- ],
- },
- ssse3: {
- exclude_srcs: [
- "upstream-freebsd/lib/libc/string/wcscat.c",
- "upstream-freebsd/lib/libc/string/wcscpy.c",
- ],
- },
- sse4: {
- exclude_srcs: [
- "upstream-freebsd/lib/libc/string/wmemcmp.c",
- ],
- },
},
},
@@ -563,13 +554,9 @@
arm: {
exclude_srcs: [
"upstream-openbsd/lib/libc/string/strcpy.c",
+ "upstream-openbsd/lib/libc/string/stpcpy.c",
+ "upstream-openbsd/lib/libc/string/strcat.c",
],
- neon: {
- exclude_srcs: [
- "upstream-openbsd/lib/libc/string/stpcpy.c",
- "upstream-openbsd/lib/libc/string/strcat.c",
- ],
- },
},
arm64: {
exclude_srcs: [
@@ -603,14 +590,10 @@
"upstream-openbsd/lib/libc/string/strcpy.c",
"upstream-openbsd/lib/libc/string/strncmp.c",
"upstream-openbsd/lib/libc/string/strncpy.c",
+ "upstream-openbsd/lib/libc/string/strlcat.c",
+ "upstream-openbsd/lib/libc/string/strlcpy.c",
+ "upstream-openbsd/lib/libc/string/strncat.c",
],
- ssse3: {
- exclude_srcs: [
- "upstream-openbsd/lib/libc/string/strlcat.c",
- "upstream-openbsd/lib/libc/string/strlcpy.c",
- "upstream-openbsd/lib/libc/string/strncat.c",
- ],
- },
},
x86_64: {
@@ -708,120 +691,32 @@
arch: {
arm: {
- cflags: ["-DNO___MEMCPY_CHK"],
+ cflags: [
+ "-DNO___MEMCPY_CHK",
+ "-DRENAME___STRCAT_CHK",
+ "-DRENAME___STRCPY_CHK",
+ ],
srcs: [
"arch-arm/generic/bionic/__memcpy_chk.S",
+
+ "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+ "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+
+ "arch-arm/cortex-a7/bionic/__strcat_chk.S",
+ "arch-arm/cortex-a7/bionic/__strcpy_chk.S",
+
+ "arch-arm/cortex-a9/bionic/__strcat_chk.S",
+ "arch-arm/cortex-a9/bionic/__strcpy_chk.S",
+
+ "arch-arm/krait/bionic/__strcat_chk.S",
+ "arch-arm/krait/bionic/__strcpy_chk.S",
+
+ "arch-arm/cortex-a53/bionic/__strcat_chk.S",
+ "arch-arm/cortex-a53/bionic/__strcpy_chk.S",
+
+ "arch-arm/denver/bionic/__strcat_chk.S",
+ "arch-arm/denver/bionic/__strcpy_chk.S",
],
- neon: {
- cflags: [
- "-DNO___STRCAT_CHK",
- "-DNO___STRCPY_CHK",
- ],
- srcs: [
- "arch-arm/cortex-a15/bionic/__strcat_chk.S",
- "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
- ],
- },
- cortex_a7: {
- srcs: [
- "arch-arm/cortex-a7/bionic/__strcat_chk.S",
- "arch-arm/cortex-a7/bionic/__strcpy_chk.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/__strcat_chk.S",
- "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
- ],
- },
- cortex_a9: {
- srcs: [
- "arch-arm/cortex-a9/bionic/__strcat_chk.S",
- "arch-arm/cortex-a9/bionic/__strcpy_chk.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/__strcat_chk.S",
- "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
- ],
- },
- krait: {
- srcs: [
- "arch-arm/krait/bionic/__strcat_chk.S",
- "arch-arm/krait/bionic/__strcpy_chk.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/__strcat_chk.S",
- "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
- ],
- },
- cortex_a53: {
- srcs: [
- "arch-arm/cortex-a53/bionic/__strcat_chk.S",
- "arch-arm/cortex-a53/bionic/__strcpy_chk.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/__strcat_chk.S",
- "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
- ],
- },
- cortex_a55: {
- srcs: [
- "arch-arm/denver/bionic/__strcat_chk.S",
- "arch-arm/denver/bionic/__strcpy_chk.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/__strcat_chk.S",
- "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
- ],
- },
- cortex_a73: {
- srcs: [
- "arch-arm/denver/bionic/__strcat_chk.S",
- "arch-arm/denver/bionic/__strcpy_chk.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/__strcat_chk.S",
- "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
- ],
- },
- cortex_a75: {
- srcs: [
- "arch-arm/denver/bionic/__strcat_chk.S",
- "arch-arm/denver/bionic/__strcpy_chk.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/__strcat_chk.S",
- "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
- ],
- },
- cortex_a76: {
- srcs: [
- "arch-arm/denver/bionic/__strcat_chk.S",
- "arch-arm/denver/bionic/__strcpy_chk.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/__strcat_chk.S",
- "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
- ],
- },
- denver: {
- srcs: [
- "arch-arm/denver/bionic/__strcat_chk.S",
- "arch-arm/denver/bionic/__strcpy_chk.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/__strcat_chk.S",
- "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
- ],
- },
- kryo: {
- srcs: [
- "arch-arm/krait/bionic/__strcat_chk.S",
- "arch-arm/krait/bionic/__strcpy_chk.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/__strcat_chk.S",
- "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
- ],
- },
},
arm64: {
cflags: ["-DNO___MEMCPY_CHK"],
@@ -865,6 +760,8 @@
"arch-arm/generic/bionic/memcmp.S",
"arch-arm/generic/bionic/memmove.S",
"arch-arm/generic/bionic/memset.S",
+ "arch-arm/generic/bionic/stpcpy.c",
+ "arch-arm/generic/bionic/strcat.c",
"arch-arm/generic/bionic/strcmp.S",
"arch-arm/generic/bionic/strcpy.S",
"arch-arm/generic/bionic/strlen.c",
@@ -878,162 +775,44 @@
"arch-arm/bionic/setjmp.S",
"arch-arm/bionic/syscall.S",
"arch-arm/bionic/vfork.S",
+
+ "arch-arm/cortex-a15/bionic/memcpy.S",
+ "arch-arm/cortex-a15/bionic/memmove.S",
+ "arch-arm/cortex-a15/bionic/memset.S",
+ "arch-arm/cortex-a15/bionic/stpcpy.S",
+ "arch-arm/cortex-a15/bionic/strcat.S",
+ "arch-arm/cortex-a15/bionic/strcmp.S",
+ "arch-arm/cortex-a15/bionic/strcpy.S",
+ "arch-arm/cortex-a15/bionic/strlen.S",
+
+ "arch-arm/cortex-a7/bionic/memcpy.S",
+ "arch-arm/cortex-a7/bionic/memmove.S",
+ "arch-arm/cortex-a7/bionic/memset.S",
+
+ "arch-arm/cortex-a9/bionic/memcpy.S",
+ "arch-arm/cortex-a9/bionic/memmove.S",
+ "arch-arm/cortex-a9/bionic/memset.S",
+ "arch-arm/cortex-a9/bionic/stpcpy.S",
+ "arch-arm/cortex-a9/bionic/strcat.S",
+ "arch-arm/cortex-a9/bionic/strcmp.S",
+ "arch-arm/cortex-a9/bionic/strcpy.S",
+ "arch-arm/cortex-a9/bionic/strlen.S",
+
+ "arch-arm/krait/bionic/memcpy.S",
+ "arch-arm/krait/bionic/memmove.S",
+ "arch-arm/krait/bionic/memset.S",
+ "arch-arm/krait/bionic/strcmp.S",
+
+ "arch-arm/cortex-a53/bionic/memcpy.S",
+ "arch-arm/cortex-a53/bionic/memmove.S",
+
+ "arch-arm/denver/bionic/memcpy.S",
+ "arch-arm/denver/bionic/memmove.S",
+ "arch-arm/denver/bionic/memset.S",
+
+ "arch-arm/kryo/bionic/memcpy.S",
+ "arch-arm/kryo/bionic/memmove.S",
],
- cortex_a7: {
- srcs: [
- "arch-arm/cortex-a7/bionic/memcpy.S",
- "arch-arm/cortex-a7/bionic/memset.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/memcpy.S",
- "arch-arm/cortex-a15/bionic/memset.S",
- ],
- },
- cortex_a9: {
- srcs: [
- "arch-arm/cortex-a9/bionic/memcpy.S",
- "arch-arm/cortex-a9/bionic/memset.S",
-
- "arch-arm/cortex-a9/bionic/stpcpy.S",
- "arch-arm/cortex-a9/bionic/strcat.S",
- "arch-arm/cortex-a9/bionic/strcmp.S",
- "arch-arm/cortex-a9/bionic/strcpy.S",
- "arch-arm/cortex-a9/bionic/strlen.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/memcpy.S",
- "arch-arm/cortex-a15/bionic/memset.S",
-
- "arch-arm/cortex-a15/bionic/stpcpy.S",
- "arch-arm/cortex-a15/bionic/strcat.S",
- "arch-arm/cortex-a15/bionic/strcmp.S",
- "arch-arm/cortex-a15/bionic/strcpy.S",
- "arch-arm/cortex-a15/bionic/strlen.S",
- ],
- },
- krait: {
- srcs: [
- "arch-arm/krait/bionic/memcpy.S",
- "arch-arm/krait/bionic/memset.S",
-
- "arch-arm/krait/bionic/strcmp.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/memset.S",
- "arch-arm/cortex-a15/bionic/memcpy.S",
-
- "arch-arm/cortex-a15/bionic/strcmp.S",
- ],
- },
- cortex_a53: {
- srcs: [
- "arch-arm/cortex-a53/bionic/memcpy.S",
- "arch-arm/cortex-a7/bionic/memset.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/memset.S",
- "arch-arm/cortex-a15/bionic/memcpy.S",
- ],
- },
- cortex_a55: {
- srcs: [
- "arch-arm/cortex-a7/bionic/memset.S",
- "arch-arm/denver/bionic/memcpy.S",
-
- "arch-arm/krait/bionic/strcmp.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/memset.S",
- "arch-arm/cortex-a15/bionic/memcpy.S",
- "arch-arm/cortex-a15/bionic/strcmp.S",
- ],
- },
- cortex_a73: {
- srcs: [
- "arch-arm/cortex-a7/bionic/memset.S",
- "arch-arm/denver/bionic/memcpy.S",
-
- "arch-arm/krait/bionic/strcmp.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/memset.S",
- "arch-arm/cortex-a15/bionic/memcpy.S",
- "arch-arm/cortex-a15/bionic/strcmp.S",
- ],
- },
- cortex_a75: {
- srcs: [
- "arch-arm/cortex-a7/bionic/memset.S",
- "arch-arm/denver/bionic/memcpy.S",
-
- "arch-arm/krait/bionic/strcmp.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/memset.S",
- "arch-arm/cortex-a15/bionic/memcpy.S",
- "arch-arm/cortex-a15/bionic/strcmp.S",
- ],
- },
- cortex_a76: {
- srcs: [
- "arch-arm/cortex-a7/bionic/memset.S",
- "arch-arm/denver/bionic/memcpy.S",
-
- "arch-arm/krait/bionic/strcmp.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/memset.S",
- "arch-arm/cortex-a15/bionic/memcpy.S",
- "arch-arm/cortex-a15/bionic/strcmp.S",
- ],
- },
- denver: {
- srcs: [
- "arch-arm/denver/bionic/memcpy.S",
- "arch-arm/denver/bionic/memset.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/memset.S",
- "arch-arm/cortex-a15/bionic/memcpy.S",
- ],
- },
- kryo: {
- srcs: [
- "arch-arm/kryo/bionic/memcpy.S",
- "arch-arm/cortex-a7/bionic/memset.S",
-
- "arch-arm/krait/bionic/strcmp.S",
- ],
- exclude_srcs: [
- "arch-arm/cortex-a15/bionic/memset.S",
- "arch-arm/cortex-a15/bionic/memcpy.S",
- "arch-arm/cortex-a15/bionic/strcmp.S",
- ],
- },
- // Cores not listed above (like cortex-a8, cortex-a15) or
- // "generic" core will use the following implementation.
- neon: {
- srcs: [
- "arch-arm/cortex-a15/bionic/memcpy.S",
- "arch-arm/cortex-a15/bionic/memset.S",
-
- "arch-arm/cortex-a15/bionic/stpcpy.S",
- "arch-arm/cortex-a15/bionic/strcat.S",
- "arch-arm/cortex-a15/bionic/strcmp.S",
- "arch-arm/cortex-a15/bionic/strcpy.S",
- "arch-arm/cortex-a15/bionic/strlen.S",
-
- "arch-arm/denver/bionic/memmove.S",
- ],
- exclude_srcs: [
- "arch-arm/generic/bionic/memcpy.S",
- "arch-arm/generic/bionic/memmove.S",
- "arch-arm/generic/bionic/memset.S",
- "arch-arm/generic/bionic/strcmp.S",
- "arch-arm/generic/bionic/strcpy.S",
- "arch-arm/generic/bionic/strlen.c",
- ],
- },
},
arm64: {
srcs: [
@@ -1136,6 +915,14 @@
"arch-x86/generic/string/strcmp.S",
"arch-x86/generic/string/strncmp.S",
"arch-x86/generic/string/strcat.S",
+
+ "arch-x86/generic/string/strlcat.c",
+ "arch-x86/generic/string/strlcpy.c",
+ "arch-x86/generic/string/strncat.c",
+ "arch-x86/generic/string/wcscat.c",
+ "arch-x86/generic/string/wcscpy.c",
+ "arch-x86/generic/string/wmemcmp.c",
+
"arch-x86/atom/string/sse2-memchr-atom.S",
"arch-x86/atom/string/sse2-memrchr-atom.S",
"arch-x86/atom/string/sse2-strchr-atom.S",
@@ -1160,6 +947,29 @@
"arch-x86/bionic/setjmp.S",
"arch-x86/bionic/syscall.S",
"arch-x86/bionic/vfork.S",
+
+ // ssse3 functions
+ "arch-x86/atom/string/ssse3-strcat-atom.S",
+ "arch-x86/atom/string/ssse3-strcmp-atom.S",
+ "arch-x86/atom/string/ssse3-strlcat-atom.S",
+ "arch-x86/atom/string/ssse3-strlcpy-atom.S",
+ "arch-x86/atom/string/ssse3-strncat-atom.S",
+ "arch-x86/atom/string/ssse3-strncmp-atom.S",
+ "arch-x86/atom/string/ssse3-wcscat-atom.S",
+ "arch-x86/atom/string/ssse3-wcscpy-atom.S",
+
+ // sse4 functions
+ "arch-x86/silvermont/string/sse4-memcmp-slm.S",
+ "arch-x86/silvermont/string/sse4-wmemcmp-slm.S",
+
+ // atom functions
+ "arch-x86/atom/string/sse2-memset-atom.S",
+ "arch-x86/atom/string/sse2-strlen-atom.S",
+ "arch-x86/atom/string/ssse3-memcmp-atom.S",
+ "arch-x86/atom/string/ssse3-memmove-atom.S",
+ "arch-x86/atom/string/ssse3-strcpy-atom.S",
+ "arch-x86/atom/string/ssse3-strncpy-atom.S",
+ "arch-x86/atom/string/ssse3-wmemcmp-atom.S",
],
exclude_srcs: [
@@ -1167,51 +977,6 @@
"bionic/strnlen.c",
"bionic/strrchr.cpp",
],
- atom: {
- srcs: [
- "arch-x86/atom/string/sse2-memset-atom.S",
- "arch-x86/atom/string/sse2-strlen-atom.S",
- "arch-x86/atom/string/ssse3-memcmp-atom.S",
- "arch-x86/atom/string/ssse3-memcpy-atom.S",
- "arch-x86/atom/string/ssse3-strcpy-atom.S",
- "arch-x86/atom/string/ssse3-strncpy-atom.S",
- "arch-x86/atom/string/ssse3-wmemcmp-atom.S",
- ],
- exclude_srcs: [
- "arch-x86/generic/string/memcmp.S",
- "arch-x86/silvermont/string/sse2-memmove-slm.S",
- "arch-x86/silvermont/string/sse2-memset-slm.S",
- "arch-x86/silvermont/string/sse2-strcpy-slm.S",
- "arch-x86/silvermont/string/sse2-strlen-slm.S",
- "arch-x86/silvermont/string/sse2-strncpy-slm.S",
- ],
- },
- ssse3: {
- srcs: [
- "arch-x86/atom/string/ssse3-strncat-atom.S",
- "arch-x86/atom/string/ssse3-strlcat-atom.S",
- "arch-x86/atom/string/ssse3-strlcpy-atom.S",
- "arch-x86/atom/string/ssse3-strcat-atom.S",
- "arch-x86/atom/string/ssse3-strcmp-atom.S",
- "arch-x86/atom/string/ssse3-strncmp-atom.S",
- "arch-x86/atom/string/ssse3-wcscat-atom.S",
- "arch-x86/atom/string/ssse3-wcscpy-atom.S",
- ],
- exclude_srcs: [
- "arch-x86/generic/string/strcmp.S",
- "arch-x86/generic/string/strncmp.S",
- "arch-x86/generic/string/strcat.S",
- ],
- },
- sse4: {
- srcs: [
- "arch-x86/silvermont/string/sse4-memcmp-slm.S",
- "arch-x86/silvermont/string/sse4-wmemcmp-slm.S",
- ],
- exclude_srcs: [
- "arch-x86/generic/string/memcmp.S",
- ],
- },
},
x86_64: {
srcs: [
@@ -1402,9 +1167,7 @@
"bionic/sys_msg.cpp",
"bionic/sys_sem.cpp",
"bionic/sys_shm.cpp",
- "bionic/sys_siglist.c",
"bionic/sys_signalfd.cpp",
- "bionic/sys_signame.c",
"bionic/sys_time.cpp",
"bionic/sysinfo.cpp",
"bionic/syslog.cpp",
@@ -1597,7 +1360,7 @@
"libc_syscalls",
"libc_tzcode",
"libm",
- "libjemalloc",
+ "libjemalloc5",
"libstdc++",
],
}
@@ -1656,6 +1419,52 @@
}
// ========================================================
+// libc_common_static.a For static binaries.
+// ========================================================
+cc_library_static {
+ defaults: ["libc_defaults"],
+ name: "libc_common_static",
+
+ arch: {
+ x86: {
+ srcs: ["arch-x86/static_function_dispatch.S"],
+ },
+ arm: {
+ srcs: ["arch-arm/static_function_dispatch.S"],
+ },
+ },
+
+ whole_static_libs: [
+ "libc_common",
+ ],
+}
+
+// ========================================================
+// libc_common_shared.a For shared libraries.
+// ========================================================
+cc_library_static {
+ defaults: ["libc_defaults"],
+ name: "libc_common_shared",
+
+ cflags: [
+ "-fno-stack-protector",
+ "-fno-jump-tables",
+ ],
+ arch: {
+ x86: {
+ srcs: ["arch-x86/dynamic_function_dispatch.cpp"],
+ },
+ arm: {
+ srcs: ["arch-arm/dynamic_function_dispatch.cpp"],
+ },
+ },
+
+ whole_static_libs: [
+ "libc_common",
+ ],
+}
+
+// ========================================================
// libc_nomalloc.a
// ========================================================
//
@@ -1679,7 +1488,7 @@
cflags: ["-DLIBC_STATIC"],
whole_static_libs: [
- "libc_common",
+ "libc_common_static",
"libc_init_static",
],
}
@@ -1702,6 +1511,7 @@
defaults: ["libc_defaults"],
name: "libc",
static_ndk_lib: true,
+ export_include_dirs: ["include"],
product_variables: {
platform_sdk_version: {
asflags: ["-DPLATFORM_SDK_VERSION=%d"],
@@ -1713,7 +1523,10 @@
"bionic/malloc_common.cpp",
],
cflags: ["-DLIBC_STATIC"],
- whole_static_libs: ["libc_init_static"],
+ whole_static_libs: [
+ "libc_init_static",
+ "libc_common_static",
+ ],
},
shared: {
srcs: [
@@ -1724,7 +1537,10 @@
"bionic/NetdClient.cpp",
"arch-common/bionic/crtend_so.S",
],
- whole_static_libs: ["libc_init_dynamic"],
+ whole_static_libs: [
+ "libc_init_dynamic",
+ "libc_common_shared",
+ ],
},
required: ["tzdata"],
@@ -1751,8 +1567,7 @@
"libdl",
],
whole_static_libs: [
- "libc_common",
- "libjemalloc",
+ "libjemalloc5",
],
nocrt: true,
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 5c63c0f..772f0e7 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -5,7 +5,7 @@
# return_type func_name[|alias_list][:syscall_name[:socketcall_id]]([parameter_list]) arch_list
#
# where:
-# arch_list ::= "all" | arch+
+# arch_list ::= "all" | "lp32" | "lp64" | arch+
# arch ::= "arm" | "arm64" | "mips" | "mips64" | "x86" | "x86_64"
#
# Note:
@@ -68,11 +68,11 @@
# On 32-bit systems we use prlimit64 to implement the rlimit64 functions.
int getrlimit:ugetrlimit(int, struct rlimit*) arm,x86
int getrlimit(int, struct rlimit*) mips
-int getrlimit|getrlimit64(int, struct rlimit*) arm64,mips64,x86_64
-int setrlimit(int, const struct rlimit*) arm,mips,x86
-int setrlimit|setrlimit64(int, const struct rlimit*) arm64,mips64,x86_64
-int prlimit64|prlimit(pid_t, int, struct rlimit64*, const struct rlimit64*) arm64,mips64,x86_64
-int prlimit64(pid_t, int, struct rlimit64*, const struct rlimit64*) arm,mips,x86
+int getrlimit|getrlimit64(int, struct rlimit*) lp64
+int setrlimit(int, const struct rlimit*) lp32
+int setrlimit|setrlimit64(int, const struct rlimit*) lp64
+int prlimit64|prlimit(pid_t, int, struct rlimit64*, const struct rlimit64*) lp64
+int prlimit64(pid_t, int, struct rlimit64*, const struct rlimit64*) lp32
int setgroups:setgroups32(int, const gid_t*) arm,x86
int setgroups:setgroups(int, const gid_t*) arm64,mips,mips64,x86_64
@@ -90,19 +90,19 @@
# file descriptors
ssize_t read(int, void*, size_t) all
ssize_t write(int, const void*, size_t) all
-ssize_t pread64(int, void*, size_t, off64_t) arm,mips,x86
-ssize_t pread64|pread(int, void*, size_t, off_t) arm64,mips64,x86_64
-ssize_t pwrite64(int, void*, size_t, off64_t) arm,mips,x86
-ssize_t pwrite64|pwrite(int, void*, size_t, off_t) arm64,mips64,x86_64
+ssize_t pread64(int, void*, size_t, off64_t) lp32
+ssize_t pread64|pread(int, void*, size_t, off_t) lp64
+ssize_t pwrite64(int, void*, size_t, off64_t) lp32
+ssize_t pwrite64|pwrite(int, void*, size_t, off_t) lp64
# On LP32, preadv/pwritev don't use off64_t --- they use pairs of 32-bit
# arguments to avoid problems on architectures like ARM where 64-bit arguments
# must be in a register pair starting with an even-numbered register.
# See linux/fs/read_write.c and https://lwn.net/Articles/311630/.
-ssize_t __preadv64:preadv(int, const struct iovec*, int, long, long) arm,mips,x86
-ssize_t preadv|preadv64(int, const struct iovec*, int, off_t) arm64,mips64,x86_64
-ssize_t __pwritev64:pwritev(int, const struct iovec*, int, long, long) arm,mips,x86
-ssize_t pwritev|pwritev64(int, const struct iovec*, int, off_t) arm64,mips64,x86_64
+ssize_t __preadv64:preadv(int, const struct iovec*, int, long, long) lp32
+ssize_t preadv|preadv64(int, const struct iovec*, int, off_t) lp64
+ssize_t __pwritev64:pwritev(int, const struct iovec*, int, long, long) lp32
+ssize_t pwritev|pwritev64(int, const struct iovec*, int, off_t) lp64
int ___close:close(int) all
pid_t __getpid:getpid() all
@@ -119,8 +119,8 @@
int __ioctl:ioctl(int, int, void*) all
ssize_t readv(int, const struct iovec*, int) all
ssize_t writev(int, const struct iovec*, int) all
-int __fcntl64:fcntl64(int, int, void*) arm,mips,x86
-int fcntl(int, int, void*) arm64,mips64,x86_64
+int __fcntl64:fcntl64(int, int, void*) lp32
+int fcntl(int, int, void*) lp64
int flock(int, int) all
int ___fchmod:fchmod(int, mode_t) all
int dup(int) all
@@ -143,7 +143,7 @@
int ___faccessat:faccessat(int, const char*, int) all
int ___fchmodat:fchmodat(int, const char*, mode_t) all
int fchownat(int, const char*, uid_t, gid_t, int) all
-int fstatat64|fstatat:fstatat64(int, const char*, struct stat*, int) arm,mips,x86
+int fstatat64|fstatat:fstatat64(int, const char*, struct stat*, int) lp32
int fstatat64|fstatat:newfstatat(int, const char*, struct stat*, int) arm64,x86_64
int linkat(int, const char*, int, const char*, int) all
int mkdirat(int, const char*, mode_t) all
@@ -158,23 +158,23 @@
# sizeof(off_t) == sizeof(off64_t), so there we emit two symbols that are
# aliases. On 32-bit systems, we have two different system calls.
# That means that every system call in this section should take three lines.
-off_t lseek(int, off_t, int) arm,mips,x86
-int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,mips,x86
-off_t lseek|lseek64(int, off_t, int) arm64,mips64,x86_64
-int ftruncate64(int, off64_t) arm,mips,x86
-int ftruncate|ftruncate64(int, off_t) arm64,mips64,x86_64
-ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count) arm,mips,x86
-ssize_t sendfile64(int out_fd, int in_fd, off64_t* offset, size_t count) arm,mips,x86
-ssize_t sendfile|sendfile64(int out_fd, int in_fd, off_t* offset, size_t count) arm64,mips64,x86_64
-int truncate(const char*, off_t) arm,mips,x86
-int truncate64(const char*, off64_t) arm,mips,x86
-int truncate|truncate64(const char*, off_t) arm64,mips64,x86_64
+off_t lseek(int, off_t, int) lp32
+int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) lp32
+off_t lseek|lseek64(int, off_t, int) lp64
+int ftruncate64(int, off64_t) lp32
+int ftruncate|ftruncate64(int, off_t) lp64
+ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count) lp32
+ssize_t sendfile64(int out_fd, int in_fd, off64_t* offset, size_t count) lp32
+ssize_t sendfile|sendfile64(int out_fd, int in_fd, off_t* offset, size_t count) lp64
+int truncate(const char*, off_t) lp32
+int truncate64(const char*, off64_t) lp32
+int truncate|truncate64(const char*, off_t) lp64
# (mmap only gets two lines because we only used the 64-bit variant on 32-bit systems.)
-void* __mmap2:mmap2(void*, size_t, int, int, int, long) arm,mips,x86
-void* mmap|mmap64(void*, size_t, int, int, int, off_t) arm64,mips64,x86_64
+void* __mmap2:mmap2(void*, size_t, int, int, int, long) lp32
+void* mmap|mmap64(void*, size_t, int, int, int, off_t) lp64
# (fallocate only gets two lines because there is no 32-bit variant.)
-int fallocate64:fallocate(int, int, off64_t, off64_t) arm,mips,x86
-int fallocate|fallocate64(int, int, off_t, off_t) arm64,mips64,x86_64
+int fallocate64:fallocate(int, int, off64_t, off64_t) lp32
+int fallocate|fallocate64(int, int, off_t, off_t) lp64
# posix_fadvise64 is awkward: arm has shuffled arguments,
# the POSIX functions don't set errno, and no architecture has posix_fadvise.
@@ -182,12 +182,12 @@
int __fadvise64:fadvise64_64(int, off64_t, off64_t, int) x86
int __fadvise64:fadvise64(int, off64_t, off64_t, int) arm64,mips,mips64,x86_64
-int __fstatfs64:fstatfs64(int, size_t, struct statfs*) arm,mips,x86
-int __fstatfs:fstatfs(int, struct statfs*) arm64,mips64,x86_64
-int __statfs64:statfs64(const char*, size_t, struct statfs*) arm,mips,x86
-int __statfs:statfs(const char*, struct statfs*) arm64,mips64,x86_64
+int __fstatfs64:fstatfs64(int, size_t, struct statfs*) lp32
+int __fstatfs:fstatfs(int, struct statfs*) lp64
+int __statfs64:statfs64(const char*, size_t, struct statfs*) lp32
+int __statfs:statfs(const char*, struct statfs*) lp64
-int fstat64|fstat:fstat64(int, struct stat*) arm,mips,x86
+int fstat64|fstat:fstat64(int, struct stat*) lp32
int fstat64|fstat:fstat(int, struct stat*) arm64,x86_64
# file system
@@ -227,7 +227,7 @@
int clock_adjtime(clockid_t, struct timex*) all
# signals
-int __sigaction:sigaction(int, const struct sigaction*, struct sigaction*) arm,mips,x86
+int __sigaction:sigaction(int, const struct sigaction*, struct sigaction*) lp32
int __rt_sigaction:rt_sigaction(int, const struct sigaction*, struct sigaction*, size_t) all
int __rt_sigpending:rt_sigpending(sigset64_t*, size_t) all
int __rt_sigprocmask:rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t) all
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
index ca29715..69e405f 100644
--- a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
// Get the length of src string, then get the source of the dst string.
// Check that the two lengths together don't exceed the threshold, then
// do a memcpy of the data.
-ENTRY(__strcat_chk)
+ENTRY(__strcat_chk_a15)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -200,4 +200,4 @@
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
-END(__strcat_chk)
+END(__strcat_chk_a15)
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
index 2679c02..ddde30e 100644
--- a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
// Get the length of the source string first, then do a memcpy of the data
// instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_a15)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -162,4 +162,4 @@
#include "memcpy_base.S"
-END(__strcpy_chk)
+END(__strcpy_chk_a15)
diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy.S b/libc/arch-arm/cortex-a15/bionic/memcpy.S
index 0bab6ee..a9dfaff 100644
--- a/libc/arch-arm/cortex-a15/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a15/bionic/memcpy.S
@@ -64,7 +64,7 @@
.arch armv7-a
// Prototype: void *memcpy (void *dst, const void *src, size_t count).
-ENTRY(__memcpy)
+ENTRY(__memcpy_a15)
pld [r1, #64]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -72,4 +72,4 @@
.cfi_rel_offset lr, 4
#include "memcpy_base.S"
-END(__memcpy)
+END(__memcpy_a15)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/cortex-a15/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/cortex-a15/bionic/memmove.S
index b60123c..2b12de0 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/cortex-a15/bionic/memmove.S
@@ -26,13 +26,7 @@
* SUCH DAMAGE.
*/
-#pragma once
+#define MEMMOVE memmove_a15
+#define MEMCPY __memcpy_a15
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <arch-arm/denver/bionic/memmove.S>
diff --git a/libc/arch-arm/cortex-a15/bionic/memset.S b/libc/arch-arm/cortex-a15/bionic/memset.S
index 4b4388e..ead881e 100644
--- a/libc/arch-arm/cortex-a15/bionic/memset.S
+++ b/libc/arch-arm/cortex-a15/bionic/memset.S
@@ -41,7 +41,7 @@
// arch. The code generated is exactly the same.
.arch armv7-a
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_a15)
cmp r2, r3
bls memset
@@ -51,9 +51,9 @@
.cfi_rel_offset lr, 0
bl __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_a15)
-ENTRY(memset)
+ENTRY(memset_a15)
stmfd sp!, {r0}
.cfi_def_cfa_offset 4
.cfi_rel_offset r0, 0
@@ -171,4 +171,4 @@
strbcs r1, [r0], #1
ldmfd sp!, {r0}
bx lr
-END(memset)
+END(memset_a15)
diff --git a/libc/arch-arm/cortex-a15/bionic/strcat.S b/libc/arch-arm/cortex-a15/bionic/strcat.S
index 157cc9f..260926a 100644
--- a/libc/arch-arm/cortex-a15/bionic/strcat.S
+++ b/libc/arch-arm/cortex-a15/bionic/strcat.S
@@ -80,7 +80,7 @@
\cmd \reg, \label
.endm // m_copy_byte
-ENTRY(strcat)
+ENTRY(strcat_a15)
// Quick check to see if src is empty.
ldrb r2, [r1]
pld [r1, #0]
@@ -572,4 +572,4 @@
.L_strcat_sub2:
sub r0, r0, #2
b .L_strcat_r0_scan_done
-END(strcat)
+END(strcat_a15)
diff --git a/libc/arch-arm/cortex-a15/bionic/strcmp.S b/libc/arch-arm/cortex-a15/bionic/strcmp.S
index d8993d5..58dbf17 100644
--- a/libc/arch-arm/cortex-a15/bionic/strcmp.S
+++ b/libc/arch-arm/cortex-a15/bionic/strcmp.S
@@ -61,7 +61,7 @@
// arch. The code generated is exactly the same.
.arch armv7-a
-ENTRY(strcmp)
+ENTRY(strcmp_a15)
/* Use LDRD whenever possible. */
/* The main thing to look out for when comparing large blocks is that
@@ -376,4 +376,4 @@
it ls
sbcls r0, r0, r0
bx lr
-END(strcmp)
+END(strcmp_a15)
diff --git a/libc/arch-arm/cortex-a15/bionic/string_copy.S b/libc/arch-arm/cortex-a15/bionic/string_copy.S
index 92d1c98..affbc3b 100644
--- a/libc/arch-arm/cortex-a15/bionic/string_copy.S
+++ b/libc/arch-arm/cortex-a15/bionic/string_copy.S
@@ -100,9 +100,9 @@
.endm // m_copy_byte
#if defined(STPCPY)
-ENTRY(stpcpy)
+ENTRY(stpcpy_a15)
#else
-ENTRY(strcpy)
+ENTRY(strcpy_a15)
#endif
// For short copies, hard-code checking the first 8 bytes since this
// new code doesn't win until after about 8 bytes.
@@ -514,7 +514,7 @@
strb r4, [r0]
m_pop
#if defined(STPCPY)
-END(stpcpy)
+END(stpcpy_a15)
#else
-END(strcpy)
+END(strcpy_a15)
#endif
diff --git a/libc/arch-arm/cortex-a15/bionic/strlen.S b/libc/arch-arm/cortex-a15/bionic/strlen.S
index 4fd6284..9c5ed29 100644
--- a/libc/arch-arm/cortex-a15/bionic/strlen.S
+++ b/libc/arch-arm/cortex-a15/bionic/strlen.S
@@ -60,7 +60,7 @@
.thumb
.thumb_func
-ENTRY(strlen)
+ENTRY(strlen_a15)
pld [r0, #0]
mov r1, r0
@@ -162,4 +162,4 @@
.L_sub2_and_return:
sub r0, r0, #2
bx lr
-END(strlen)
+END(strlen_a15)
diff --git a/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
index ca29715..72be243 100644
--- a/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
// Get the length of src string, then get the source of the dst string.
// Check that the two lengths together don't exceed the threshold, then
// do a memcpy of the data.
-ENTRY(__strcat_chk)
+ENTRY(__strcat_chk_a53)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -200,4 +200,4 @@
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
-END(__strcat_chk)
+END(__strcat_chk_a53)
diff --git a/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
index 2679c02..4922884 100644
--- a/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
// Get the length of the source string first, then do a memcpy of the data
// instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_a53)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -162,4 +162,4 @@
#include "memcpy_base.S"
-END(__strcpy_chk)
+END(__strcpy_chk_a53)
diff --git a/libc/arch-arm/cortex-a53/bionic/memcpy.S b/libc/arch-arm/cortex-a53/bionic/memcpy.S
index 0bab6ee..ea748bd 100644
--- a/libc/arch-arm/cortex-a53/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a53/bionic/memcpy.S
@@ -64,7 +64,7 @@
.arch armv7-a
// Prototype: void *memcpy (void *dst, const void *src, size_t count).
-ENTRY(__memcpy)
+ENTRY(__memcpy_a53)
pld [r1, #64]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -72,4 +72,4 @@
.cfi_rel_offset lr, 4
#include "memcpy_base.S"
-END(__memcpy)
+END(__memcpy_a53)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/cortex-a53/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/cortex-a53/bionic/memmove.S
index b60123c..741acb3 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/cortex-a53/bionic/memmove.S
@@ -26,13 +26,7 @@
* SUCH DAMAGE.
*/
-#pragma once
+#define MEMMOVE memmove_a53
+#define MEMCPY __memcpy_a53
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <arch-arm/denver/bionic/memmove.S>
diff --git a/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S
index ca29715..36bda6b 100644
--- a/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
// Get the length of src string, then get the source of the dst string.
// Check that the two lengths together don't exceed the threshold, then
// do a memcpy of the data.
-ENTRY(__strcat_chk)
+ENTRY(__strcat_chk_a7)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -200,4 +200,4 @@
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
-END(__strcat_chk)
+END(__strcat_chk_a7)
diff --git a/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S
index 2679c02..edbabc7 100644
--- a/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
// Get the length of the source string first, then do a memcpy of the data
// instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_a7)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -162,4 +162,4 @@
#include "memcpy_base.S"
-END(__strcpy_chk)
+END(__strcpy_chk_a7)
diff --git a/libc/arch-arm/cortex-a7/bionic/memcpy.S b/libc/arch-arm/cortex-a7/bionic/memcpy.S
index 0bab6ee..2f32d2e 100644
--- a/libc/arch-arm/cortex-a7/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a7/bionic/memcpy.S
@@ -64,7 +64,7 @@
.arch armv7-a
// Prototype: void *memcpy (void *dst, const void *src, size_t count).
-ENTRY(__memcpy)
+ENTRY(__memcpy_a7)
pld [r1, #64]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -72,4 +72,4 @@
.cfi_rel_offset lr, 4
#include "memcpy_base.S"
-END(__memcpy)
+END(__memcpy_a7)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/cortex-a7/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/cortex-a7/bionic/memmove.S
index b60123c..17ead5a 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/cortex-a7/bionic/memmove.S
@@ -26,13 +26,7 @@
* SUCH DAMAGE.
*/
-#pragma once
+#define MEMMOVE memmove_a7
+#define MEMCPY __memcpy_a7
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <arch-arm/denver/bionic/memmove.S>
diff --git a/libc/arch-arm/cortex-a7/bionic/memset.S b/libc/arch-arm/cortex-a7/bionic/memset.S
index 72ee613..d7d3b34 100644
--- a/libc/arch-arm/cortex-a7/bionic/memset.S
+++ b/libc/arch-arm/cortex-a7/bionic/memset.S
@@ -41,7 +41,7 @@
// arch. The code generated is exactly the same.
.arch armv7-a
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_a7)
cmp r2, r3
bls memset
@@ -51,9 +51,9 @@
.cfi_rel_offset lr, 0
bl __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_a7)
-ENTRY(memset)
+ENTRY(memset_a7)
mov r3, r0
// At this point only d0, d1 are going to be used below.
vdup.8 q0, r1
@@ -160,4 +160,4 @@
strbcs r1, [r3], #1
strbcs r1, [r3], #1
bx lr
-END(memset)
+END(memset_a7)
diff --git a/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S
index 776c782..d20283e 100644
--- a/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S
@@ -33,10 +33,14 @@
.thumb
.thumb_func
+ // To avoid warning about deprecated instructions, add an explicit
+ // arch. The code generated is exactly the same.
+ .arch armv7-a
+
// Get the length of src string, then get the source of the dst string.
// Check that the two lengths together don't exceed the threshold, then
// do a memcpy of the data.
-ENTRY(__strcat_chk)
+ENTRY(__strcat_chk_a9)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -191,8 +195,8 @@
pop {r4, r5}
// Fall through into the memcpy_base function.
-END(__strcat_chk)
+END(__strcat_chk_a9)
-#define MEMCPY_BASE __strcat_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
+#define MEMCPY_BASE __strcat_chk_a9_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcat_chk_a9_memcpy_base_aligned
#include "memcpy_base.S"
diff --git a/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S
index 1d5e70b..1f0a774 100644
--- a/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S
@@ -33,9 +33,13 @@
.thumb
.thumb_func
+ // To avoid warning about deprecated instructions, add an explicit
+ // arch. The code generated is exactly the same.
+ .arch armv7-a
+
// Get the length of the source string first, then do a memcpy of the data
// instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_a9)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -159,8 +163,8 @@
bhi __strcpy_chk_fail
// Fall through into the memcpy_base function.
-END(__strcpy_chk)
+END(__strcpy_chk_a9)
-#define MEMCPY_BASE __strcpy_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
+#define MEMCPY_BASE __strcpy_chk_a9_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcpy_chk_a9_memcpy_base_aligned
#include "memcpy_base.S"
diff --git a/libc/arch-arm/cortex-a9/bionic/memcpy.S b/libc/arch-arm/cortex-a9/bionic/memcpy.S
index a71c9d2..e78a7da 100644
--- a/libc/arch-arm/cortex-a9/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a9/bionic/memcpy.S
@@ -39,15 +39,15 @@
.thumb
.thumb_func
-ENTRY(__memcpy)
+ENTRY(__memcpy_a9)
pld [r1, #0]
stmfd sp!, {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
pld [r1, #64]
-END(__memcpy)
+END(__memcpy_a9)
-#define MEMCPY_BASE __memcpy_base
-#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
+#define MEMCPY_BASE __memcpy_base_a9
+#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned_a9
#include "memcpy_base.S"
diff --git a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
index 966b9b3..39da7ff 100644
--- a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
+++ b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
@@ -32,6 +32,12 @@
* cache line.
*/
+ .syntax unified
+
+ // To avoid warning about deprecated instructions, add an explicit
+ // arch. The code generated is exactly the same.
+ .arch armv7-a
+
ENTRY_PRIVATE(MEMCPY_BASE)
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/cortex-a9/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/cortex-a9/bionic/memmove.S
index b60123c..a457633 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/cortex-a9/bionic/memmove.S
@@ -26,13 +26,7 @@
* SUCH DAMAGE.
*/
-#pragma once
+#define MEMMOVE memmove_a9
+#define MEMCPY __memcpy_a9
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <arch-arm/denver/bionic/memmove.S>
diff --git a/libc/arch-arm/cortex-a9/bionic/memset.S b/libc/arch-arm/cortex-a9/bionic/memset.S
index d00231b..cf66e86 100644
--- a/libc/arch-arm/cortex-a9/bionic/memset.S
+++ b/libc/arch-arm/cortex-a9/bionic/memset.S
@@ -36,7 +36,7 @@
.fpu neon
.syntax unified
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_a9)
cmp r2, r3
bls memset
@@ -46,10 +46,10 @@
.cfi_rel_offset lr, 0
bl __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_a9)
/* memset() returns its first argument. */
-ENTRY(memset)
+ENTRY(memset_a9)
// The neon memset only wins for less than 132.
cmp r2, #132
bhi .L_memset_large_copy
@@ -158,4 +158,4 @@
movs r2, r2, lsl #2
strbcs r1, [r0]
ldmfd sp!, {r0, r4-r7, pc}
-END(memset)
+END(memset_a9)
diff --git a/libc/arch-arm/cortex-a9/bionic/strcat.S b/libc/arch-arm/cortex-a9/bionic/strcat.S
index 9077a74..430748f 100644
--- a/libc/arch-arm/cortex-a9/bionic/strcat.S
+++ b/libc/arch-arm/cortex-a9/bionic/strcat.S
@@ -57,6 +57,10 @@
.syntax unified
+ // To avoid warning about deprecated instructions, add an explicit
+ // arch. The code generated is exactly the same.
+ .arch armv7-a
+
.thumb
.thumb_func
@@ -80,7 +84,7 @@
\cmd \reg, \label
.endm // m_copy_byte
-ENTRY(strcat)
+ENTRY(strcat_a9)
// Quick check to see if src is empty.
ldrb r2, [r1]
pld [r1, #0]
@@ -552,4 +556,4 @@
.Lstrcat_r0_update:
sub r0, r0, #1
b .Lstrcat_r0_scan_done
-END(strcat)
+END(strcat_a9)
diff --git a/libc/arch-arm/cortex-a9/bionic/strcmp.S b/libc/arch-arm/cortex-a9/bionic/strcmp.S
index ba191d6..ba7ea13 100644
--- a/libc/arch-arm/cortex-a9/bionic/strcmp.S
+++ b/libc/arch-arm/cortex-a9/bionic/strcmp.S
@@ -52,12 +52,16 @@
.syntax unified
+// To avoid warning about deprecated instructions, add an explicit
+// arch. The code generated is exactly the same.
+.arch armv7-a
+
#if defined (__thumb__)
.thumb
.thumb_func
#endif
-ENTRY(strcmp)
+ENTRY(strcmp_a9)
/* Use LDRD whenever possible. */
/* The main thing to look out for when comparing large blocks is that
@@ -544,4 +548,4 @@
adds sp, sp, #16
bx lr
-END(strcmp)
+END(strcmp_a9)
diff --git a/libc/arch-arm/cortex-a9/bionic/string_copy.S b/libc/arch-arm/cortex-a9/bionic/string_copy.S
index 642db0f..3605b7a 100644
--- a/libc/arch-arm/cortex-a9/bionic/string_copy.S
+++ b/libc/arch-arm/cortex-a9/bionic/string_copy.S
@@ -64,6 +64,10 @@
.thumb
.thumb_func
+ // To avoid warning about deprecated instructions, add an explicit
+ // arch. The code generated is exactly the same.
+ .arch armv7-a
+
#if defined(STPCPY)
.macro m_push
push {r4, r5, lr}
@@ -100,9 +104,9 @@
.endm // m_copy_byte
#if defined(STPCPY)
-ENTRY(stpcpy)
+ENTRY(stpcpy_a9)
#else
-ENTRY(strcpy)
+ENTRY(strcpy_a9)
#endif
// Unroll the first 8 bytes that will be copied.
m_push
@@ -536,7 +540,7 @@
#endif
m_ret inst=pop
#if defined(STPCPY)
-END(stpcpy)
+END(stpcpy_a9)
#else
-END(strcpy)
+END(strcpy_a9)
#endif
diff --git a/libc/arch-arm/cortex-a9/bionic/strlen.S b/libc/arch-arm/cortex-a9/bionic/strlen.S
index b92b043..ffebc9d 100644
--- a/libc/arch-arm/cortex-a9/bionic/strlen.S
+++ b/libc/arch-arm/cortex-a9/bionic/strlen.S
@@ -57,10 +57,14 @@
.syntax unified
+ // To avoid warning about deprecated instructions, add an explicit
+ // arch. The code generated is exactly the same.
+ .arch armv7-a
+
.thumb
.thumb_func
-ENTRY(strlen)
+ENTRY(strlen_a9)
pld [r0, #0]
mov r1, r0
@@ -164,4 +168,4 @@
sub r0, r1, r0
sub r0, r0, #1
bx lr
-END(strlen)
+END(strlen_a9)
diff --git a/libc/arch-arm/denver/bionic/__strcat_chk.S b/libc/arch-arm/denver/bionic/__strcat_chk.S
index d4f651c..1899908 100644
--- a/libc/arch-arm/denver/bionic/__strcat_chk.S
+++ b/libc/arch-arm/denver/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
// Get the length of src string, then get the source of the dst string.
// Check that the two lengths together don't exceed the threshold, then
// do a memcpy of the data.
-ENTRY(__strcat_chk)
+ENTRY(__strcat_chk_denver)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -190,9 +190,9 @@
mov r2, r4
add r0, r0, r3
pop {r4, r5}
-END(__strcat_chk)
+END(__strcat_chk_denver)
-#define MEMCPY_BASE __strcat_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
+#define MEMCPY_BASE __strcat_chk_denver_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcat_chk_denver_memcpy_base_aligned
#include "memcpy_base.S"
diff --git a/libc/arch-arm/denver/bionic/__strcpy_chk.S b/libc/arch-arm/denver/bionic/__strcpy_chk.S
index 9295a00..9910c76 100644
--- a/libc/arch-arm/denver/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/denver/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
// Get the length of the source string first, then do a memcpy of the data
// instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_denver)
pld [r0, #0]
push {r0, lr}
.cfi_def_cfa_offset 8
@@ -161,8 +161,8 @@
bhi __strcpy_chk_fail
// Fall through into the memcpy_base function.
-END(__strcpy_chk)
+END(__strcpy_chk_denver)
-#define MEMCPY_BASE __strcpy_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
+#define MEMCPY_BASE __strcpy_chk_denver_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcpy_chk_denver_memcpy_base_aligned
#include "memcpy_base.S"
diff --git a/libc/arch-arm/denver/bionic/memcpy.S b/libc/arch-arm/denver/bionic/memcpy.S
index f082542..5edee1e 100644
--- a/libc/arch-arm/denver/bionic/memcpy.S
+++ b/libc/arch-arm/denver/bionic/memcpy.S
@@ -65,14 +65,14 @@
// arch. The code generated is exactly the same.
.arch armv7-a
-ENTRY(__memcpy)
+ENTRY(__memcpy_denver)
pld [r1, #64]
push {r0, lr}
.cfi_def_cfa_offset 8
.cfi_rel_offset r0, 0
.cfi_rel_offset lr, 4
-END(__memcpy)
+END(__memcpy_denver)
-#define MEMCPY_BASE __memcpy_base
-#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
+#define MEMCPY_BASE __memcpy_base_denver
+#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned_denver
#include "memcpy_base.S"
diff --git a/libc/arch-arm/denver/bionic/memmove.S b/libc/arch-arm/denver/bionic/memmove.S
index 74d2b31..13c90ef 100644
--- a/libc/arch-arm/denver/bionic/memmove.S
+++ b/libc/arch-arm/denver/bionic/memmove.S
@@ -29,6 +29,14 @@
#include <private/bionic_asm.h>
+#ifndef MEMMOVE
+# define MEMMOVE memmove_denver
+#endif
+
+#ifndef MEMCPY
+# define MEMCPY __memcpy_denver
+#endif
+
.text
.syntax unified
.fpu neon
@@ -40,7 +48,7 @@
#define PREFETCH_DISTANCE_MID (CACHE_LINE_SIZE*4)
#define PREFETCH_DISTANCE_FAR (CACHE_LINE_SIZE*16)
-ENTRY(memmove)
+ENTRY(MEMMOVE)
cmp r2, #0
cmpne r0, r1
bxeq lr
@@ -50,7 +58,7 @@
bhi .L_reversed_memcpy
.L_jump_to_memcpy:
- b __memcpy
+ b MEMCPY
.L_reversed_memcpy:
push {r0, lr}
@@ -277,6 +285,4 @@
pop {r0, pc}
-END(memmove)
-
-ALIAS_SYMBOL(memcpy, memmove)
+END(MEMMOVE)
diff --git a/libc/arch-arm/denver/bionic/memset.S b/libc/arch-arm/denver/bionic/memset.S
index 88ffe5c..198ecf3 100644
--- a/libc/arch-arm/denver/bionic/memset.S
+++ b/libc/arch-arm/denver/bionic/memset.S
@@ -39,7 +39,7 @@
.fpu neon
.syntax unified
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_denver)
cmp r2, r3
bls memset
@@ -49,9 +49,9 @@
.cfi_rel_offset lr, 0
bl __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_denver)
-ENTRY(memset)
+ENTRY(memset_denver)
pldw [r0]
mov r3, r0
@@ -183,4 +183,4 @@
strbcs r1, [r3]
2:
bx lr
-END(memset)
+END(memset_denver)
diff --git a/libc/arch-arm/dynamic_function_dispatch.cpp b/libc/arch-arm/dynamic_function_dispatch.cpp
new file mode 100644
index 0000000..90eff56
--- /dev/null
+++ b/libc/arch-arm/dynamic_function_dispatch.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2018 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 <fcntl.h>
+#include <sys/syscall.h>
+
+extern "C" {
+
+enum CpuVariant {
+ kUnknown = 0,
+ kGeneric,
+ kCortexA7,
+ kCortexA9,
+ kCortexA53,
+ kCortexA55,
+ kDenver,
+ kKrait,
+ kKryo,
+};
+
+static constexpr int MAX_CPU_NAME_LEN = 12;
+struct CpuVariantNames {
+ char name[MAX_CPU_NAME_LEN];
+ CpuVariant variant;
+};
+
+static constexpr CpuVariantNames cpu_variant_names[] = {
+ {"cortex-a76", kCortexA55},
+ {"cortex-a75", kCortexA55},
+ {"kryo", kKryo},
+ {"cortex-a73", kCortexA55},
+ {"cortex-a55", kCortexA55},
+ {"cortex-a53", kCortexA53},
+ {"krait", kKrait},
+ {"cortex-a9", kCortexA9},
+ {"cortex-a7", kCortexA7},
+ {"denver", kDenver},
+ // kUnknown indicates the end of this array.
+ {"", kUnknown},
+};
+
+static long ifunc_open(const char* pathname) {
+ register long r0 __asm__("r0") = AT_FDCWD;
+ register long r1 __asm__("r1") = reinterpret_cast<long>(pathname);
+ register long r2 __asm__("r2") = O_RDONLY;
+ register long r3 __asm__("r3") = 0;
+ register long r7 __asm__("r7") = __NR_openat;
+ __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r7));
+ return r0;
+}
+
+static ssize_t ifunc_read(int fd, void* buf, size_t count) {
+ register long r0 __asm__("r0") = fd;
+ register long r1 __asm__("r1") = reinterpret_cast<long>(buf);
+ register long r2 __asm__("r2") = count;
+ register long r7 __asm__("r7") = __NR_read;
+ __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r7) : "memory");
+ return r0;
+}
+
+static int ifunc_close(int fd) {
+ register long r0 __asm__("r0") = fd;
+ register long r7 __asm__("r7") = __NR_close;
+ __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r7));
+ return r0;
+}
+
+#define DEFINE_IFUNC(name) \
+ name##_func name __attribute__((ifunc(#name "_resolver"))); \
+ __attribute__((visibility("hidden"))) \
+ name##_func* name##_resolver()
+
+#define DECLARE_FUNC(type, name) \
+ __attribute__((visibility("hidden"))) \
+ type name
+
+#define RETURN_FUNC(type, name) { \
+ DECLARE_FUNC(type, name); \
+ return name; \
+ }
+
+static CpuVariant init_cpu_variant() {
+ int fd = ifunc_open("/dev/cpu_variant:arm");
+ if (fd < 0) return kGeneric;
+
+ char name[MAX_CPU_NAME_LEN];
+
+ int bytes_read, total_read = 0;
+ while (total_read < MAX_CPU_NAME_LEN - 1 &&
+ (bytes_read = ifunc_read(fd, name + total_read,
+ MAX_CPU_NAME_LEN - 1 - total_read)) > 0) {
+ total_read += bytes_read;
+ }
+ ifunc_close(fd);
+
+ if (bytes_read != 0) {
+ // The file is too big. We haven't reach the end. Or maybe there is an
+ // error when reading.
+ return kGeneric;
+ }
+ name[total_read] = 0;
+
+ typedef int strcmp_func(const char* __lhs, const char* __rhs);
+ DECLARE_FUNC(strcmp_func, strcmp_a15);
+
+ const CpuVariantNames* cpu_variant = cpu_variant_names;
+ while (cpu_variant->variant != kUnknown) {
+ if (strcmp_a15(cpu_variant->name, name) == 0) {
+ return cpu_variant->variant;
+ }
+ cpu_variant++;
+ }
+ return kGeneric;
+}
+
+static CpuVariant get_cpu_variant() {
+ static CpuVariant cpu_variant = kUnknown;
+ if (cpu_variant == kUnknown) {
+ cpu_variant = init_cpu_variant();
+ }
+ return cpu_variant;
+}
+
+typedef void* memmove_func(void* __dst, const void* __src, size_t __n);
+DEFINE_IFUNC(memmove) {
+ switch(get_cpu_variant()) {
+ case kCortexA7:
+ RETURN_FUNC(memmove_func, memmove_a7);
+ case kCortexA9:
+ RETURN_FUNC(memmove_func, memmove_a9);
+ case kKrait:
+ RETURN_FUNC(memmove_func, memmove_krait);
+ case kCortexA53:
+ RETURN_FUNC(memmove_func, memmove_a53);
+ case kCortexA55:
+ case kDenver:
+ RETURN_FUNC(memmove_func, memmove_denver);
+ case kKryo:
+ RETURN_FUNC(memmove_func, memmove_kryo);
+ default:
+ RETURN_FUNC(memmove_func, memmove_a15);
+ }
+}
+
+typedef void* memcpy_func(void*, const void*, size_t);
+DEFINE_IFUNC(memcpy) {
+ return memmove_resolver();
+}
+
+typedef void* __memset_chk_func(void* s, int c, size_t n, size_t n2);
+DEFINE_IFUNC(__memset_chk) {
+ switch(get_cpu_variant()) {
+ case kCortexA7:
+ case kCortexA53:
+ case kCortexA55:
+ case kKryo:
+ RETURN_FUNC(__memset_chk_func, __memset_chk_a7);
+ case kCortexA9:
+ RETURN_FUNC(__memset_chk_func, __memset_chk_a9);
+ case kKrait:
+ RETURN_FUNC(__memset_chk_func, __memset_chk_krait);
+ case kDenver:
+ RETURN_FUNC(__memset_chk_func, __memset_chk_denver);
+ default:
+ RETURN_FUNC(__memset_chk_func, __memset_chk_a15);
+ }
+}
+
+typedef void* memset_func(void* __dst, int __ch, size_t __n);
+DEFINE_IFUNC(memset) {
+ switch(get_cpu_variant()) {
+ case kCortexA7:
+ case kCortexA53:
+ case kCortexA55:
+ case kKryo:
+ RETURN_FUNC(memset_func, memset_a7);
+ case kCortexA9:
+ RETURN_FUNC(memset_func, memset_a9);
+ case kKrait:
+ RETURN_FUNC(memset_func, memset_krait);
+ case kDenver:
+ RETURN_FUNC(memset_func, memset_denver);
+ default:
+ RETURN_FUNC(memset_func, memset_a15);
+ }
+}
+
+typedef char* strcpy_func(char* __dst, const char* __src);
+DEFINE_IFUNC(strcpy) {
+ switch(get_cpu_variant()) {
+ case kCortexA9:
+ RETURN_FUNC(strcpy_func, strcpy_a9);
+ default:
+ RETURN_FUNC(strcpy_func, strcpy_a15);
+ }
+}
+
+typedef char* __strcpy_chk_func(char* dst, const char* src, size_t dst_len);
+DEFINE_IFUNC(__strcpy_chk) {
+ switch(get_cpu_variant()) {
+ case kCortexA7:
+ RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a7);
+ case kCortexA9:
+ RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a9);
+ case kKrait:
+ case kKryo:
+ RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_krait);
+ case kCortexA53:
+ RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a53);
+ case kCortexA55:
+ case kDenver:
+ RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_denver);
+ default:
+ RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a15);
+ }
+}
+
+typedef char* stpcpy_func(char* __dst, const char* __src);
+DEFINE_IFUNC(stpcpy) {
+ switch(get_cpu_variant()) {
+ case kCortexA9:
+ RETURN_FUNC(stpcpy_func, stpcpy_a9);
+ default:
+ RETURN_FUNC(stpcpy_func, stpcpy_a15);
+ }
+}
+
+typedef char* strcat_func(char* __dst, const char* __src);
+DEFINE_IFUNC(strcat) {
+ switch(get_cpu_variant()) {
+ case kCortexA9:
+ RETURN_FUNC(strcat_func, strcat_a9);
+ default:
+ RETURN_FUNC(strcat_func, strcat_a15);
+ }
+}
+
+typedef char* __strcat_chk_func(char* dst, const char* src, size_t dst_buf_size);
+DEFINE_IFUNC(__strcat_chk) {
+ switch(get_cpu_variant()) {
+ case kCortexA7:
+ RETURN_FUNC(__strcat_chk_func, __strcat_chk_a7);
+ case kCortexA9:
+ RETURN_FUNC(__strcat_chk_func, __strcat_chk_a9);
+ case kKrait:
+ case kKryo:
+ RETURN_FUNC(__strcat_chk_func, __strcat_chk_krait);
+ case kCortexA53:
+ RETURN_FUNC(__strcat_chk_func, __strcat_chk_a53);
+ case kCortexA55:
+ case kDenver:
+ RETURN_FUNC(__strcat_chk_func, __strcat_chk_denver);
+ default:
+ RETURN_FUNC(__strcat_chk_func, __strcat_chk_a15);
+ }
+}
+
+typedef int strcmp_func(const char* __lhs, const char* __rhs);
+DEFINE_IFUNC(strcmp) {
+ switch(get_cpu_variant()) {
+ case kCortexA9:
+ RETURN_FUNC(strcmp_func, strcmp_a9);
+ case kCortexA55:
+ case kKrait:
+ case kKryo:
+ RETURN_FUNC(strcmp_func, strcmp_krait);
+ default:
+ RETURN_FUNC(strcmp_func, strcmp_a15);
+ }
+}
+
+typedef size_t strlen_func(const char* __s);
+DEFINE_IFUNC(strlen) {
+ switch(get_cpu_variant()) {
+ case kCortexA9:
+ RETURN_FUNC(strlen_func, strlen_a9);
+ default:
+ RETURN_FUNC(strlen_func, strlen_a15);
+ }
+}
+
+} // extern "C"
diff --git a/libc/arch-arm/generic/bionic/memmove.S b/libc/arch-arm/generic/bionic/memmove.S
index c52e17e..0cf82d1 100644
--- a/libc/arch-arm/generic/bionic/memmove.S
+++ b/libc/arch-arm/generic/bionic/memmove.S
@@ -464,10 +464,8 @@
b .Lmemcpy_bl4
END(bsd_safe_memcpy)
-ENTRY(memmove)
+ENTRY(memmove_generic)
stmfd sp!, {r0, lr}
bl bsd_safe_memcpy
ldmfd sp!, {r0, pc}
-END(memmove)
-
-ALIAS_SYMBOL(memcpy, memmove)
+END(memmove_generic)
diff --git a/libc/arch-arm/generic/bionic/memset.S b/libc/arch-arm/generic/bionic/memset.S
index 1fd0de1..e70002f 100644
--- a/libc/arch-arm/generic/bionic/memset.S
+++ b/libc/arch-arm/generic/bionic/memset.S
@@ -36,14 +36,14 @@
.syntax unified
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_generic)
cmp r2, r3
bls memset
bl __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_generic)
-ENTRY(memset)
+ENTRY(memset_generic)
/* compute the offset to align the destination
* offset = (4-(src&3))&3 = -src & 3
*/
@@ -108,4 +108,4 @@
movs r2, r2, lsl #2
strbcs r1, [r0]
ldmfd sp!, {r0, r4-r7, pc}
-END(memset)
+END(memset_generic)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/generic/bionic/stpcpy.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/generic/bionic/stpcpy.c
index b60123c..0aabaa5 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/generic/bionic/stpcpy.c
@@ -26,13 +26,5 @@
* SUCH DAMAGE.
*/
-#pragma once
-
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define stpcpy stpcpy_generic
+#include <upstream-openbsd/lib/libc/string/stpcpy.c>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/generic/bionic/strcat.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/generic/bionic/strcat.c
index b60123c..8e70531 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/generic/bionic/strcat.c
@@ -26,13 +26,5 @@
* SUCH DAMAGE.
*/
-#pragma once
-
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define strcat strcat_generic
+#include <upstream-openbsd/lib/libc/string/strcat.c>
diff --git a/libc/arch-arm/generic/bionic/strcmp.S b/libc/arch-arm/generic/bionic/strcmp.S
index 10b6704..03225a0 100644
--- a/libc/arch-arm/generic/bionic/strcmp.S
+++ b/libc/arch-arm/generic/bionic/strcmp.S
@@ -31,6 +31,10 @@
.text
+ // To avoid warning about deprecated instructions, add an explicit
+ // arch. The code generated is exactly the same.
+ .arch armv7-a
+
#ifdef __ARMEB__
#define SHFT2LSB lsl
#define SHFT2LSBEQ lsleq
@@ -50,7 +54,7 @@
#define magic1(REG) REG
#define magic2(REG) REG, lsl #7
-ENTRY(strcmp)
+ENTRY(strcmp_generic)
pld [r0, #0]
pld [r1, #0]
eor r2, r0, r1
@@ -313,4 +317,4 @@
ldr r4, [sp], #4
ldr r5, [sp], #4
bx lr
-END(strcmp)
+END(strcmp_generic)
diff --git a/libc/arch-arm/generic/bionic/strcpy.S b/libc/arch-arm/generic/bionic/strcpy.S
index c0ab9e5..89bd699 100644
--- a/libc/arch-arm/generic/bionic/strcpy.S
+++ b/libc/arch-arm/generic/bionic/strcpy.S
@@ -33,7 +33,11 @@
.syntax unified
-ENTRY(strcpy)
+// To avoid warning about deprecated instructions, add an explicit
+// arch. The code generated is exactly the same.
+.arch armv7-a
+
+ENTRY(strcpy_generic)
pld [r1, #0]
eor r2, r0, r1
mov ip, r0
@@ -131,4 +135,4 @@
cmp r2, #0
bne 4b
bx lr
-END(strcpy)
+END(strcpy_generic)
diff --git a/libc/arch-arm/generic/bionic/strlen.c b/libc/arch-arm/generic/bionic/strlen.c
index 44bd72f..43d9e51 100644
--- a/libc/arch-arm/generic/bionic/strlen.c
+++ b/libc/arch-arm/generic/bionic/strlen.c
@@ -29,7 +29,7 @@
#include <string.h>
#include <stdint.h>
-size_t strlen(const char *s)
+size_t strlen_generic(const char *s)
{
__builtin_prefetch(s);
__builtin_prefetch(s+32);
diff --git a/libc/arch-arm/krait/bionic/__strcat_chk.S b/libc/arch-arm/krait/bionic/__strcat_chk.S
index 32fa82d..9d4bffb 100644
--- a/libc/arch-arm/krait/bionic/__strcat_chk.S
+++ b/libc/arch-arm/krait/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
// Get the length of src string, then get the source of the dst string.
// Check that the two lengths together don't exceed the threshold, then
// do a memcpy of the data.
-ENTRY(__strcat_chk)
+ENTRY(__strcat_chk_krait)
pld [r0, #0]
push {r0, lr}
.cfi_adjust_cfa_offset 8
@@ -200,4 +200,4 @@
.cfi_adjust_cfa_offset 8
.cfi_rel_offset r4, 0
.cfi_rel_offset r5, 4
-END(__strcat_chk)
+END(__strcat_chk_krait)
diff --git a/libc/arch-arm/krait/bionic/__strcpy_chk.S b/libc/arch-arm/krait/bionic/__strcpy_chk.S
index ca4cf7f..969e112 100644
--- a/libc/arch-arm/krait/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/krait/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
// Get the length of the source string first, then do a memcpy of the data
// instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_krait)
pld [r0, #0]
push {r0, lr}
.cfi_adjust_cfa_offset 8
@@ -162,4 +162,4 @@
#include "memcpy_base.S"
-END(__strcpy_chk)
+END(__strcpy_chk_krait)
diff --git a/libc/arch-arm/krait/bionic/memcpy.S b/libc/arch-arm/krait/bionic/memcpy.S
index 49fd040..6618b3a 100644
--- a/libc/arch-arm/krait/bionic/memcpy.S
+++ b/libc/arch-arm/krait/bionic/memcpy.S
@@ -42,7 +42,7 @@
.thumb
.thumb_func
-ENTRY(__memcpy)
+ENTRY(__memcpy_krait)
pld [r1, #64]
stmfd sp!, {r0, lr}
.cfi_adjust_cfa_offset 8
@@ -50,4 +50,4 @@
.cfi_rel_offset lr, 4
#include "memcpy_base.S"
-END(__memcpy)
+END(__memcpy_krait)
diff --git a/libc/arch-arm/krait/bionic/memcpy_base.S b/libc/arch-arm/krait/bionic/memcpy_base.S
index dc8ad2c..5b4b70d 100644
--- a/libc/arch-arm/krait/bionic/memcpy_base.S
+++ b/libc/arch-arm/krait/bionic/memcpy_base.S
@@ -41,8 +41,13 @@
#endif
.text
+ .syntax unified
.fpu neon
+ // To avoid warning about deprecated instructions, add an explicit
+ // arch. The code generated is exactly the same.
+ .arch armv7-a
+
.L_memcpy_base:
cmp r2, #4
blt .L_neon_lt4
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/krait/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/krait/bionic/memmove.S
index b60123c..af85ea6 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/krait/bionic/memmove.S
@@ -26,13 +26,7 @@
* SUCH DAMAGE.
*/
-#pragma once
+#define MEMMOVE memmove_krait
+#define MEMCPY __memcpy_krait
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <arch-arm/denver/bionic/memmove.S>
diff --git a/libc/arch-arm/krait/bionic/memset.S b/libc/arch-arm/krait/bionic/memset.S
index 228942c..675ab53 100644
--- a/libc/arch-arm/krait/bionic/memset.S
+++ b/libc/arch-arm/krait/bionic/memset.S
@@ -37,7 +37,7 @@
.fpu neon
.syntax unified
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_krait)
cmp r2, r3
bls memset
@@ -47,10 +47,10 @@
.cfi_rel_offset lr, 0
bl __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_krait)
/* memset() returns its first argument. */
-ENTRY(memset)
+ENTRY(memset_krait)
mov r3, r0
vdup.8 q0, r1
@@ -82,4 +82,4 @@
strbcs r1, [r3], #1
strbcs r1, [r3], #1
bx lr
-END(memset)
+END(memset_krait)
diff --git a/libc/arch-arm/krait/bionic/strcmp.S b/libc/arch-arm/krait/bionic/strcmp.S
index b871c76..ec692e5 100644
--- a/libc/arch-arm/krait/bionic/strcmp.S
+++ b/libc/arch-arm/krait/bionic/strcmp.S
@@ -52,12 +52,16 @@
.syntax unified
+// To avoid warning about deprecated instructions, add an explicit
+// arch. The code generated is exactly the same.
+.arch armv7-a
+
#if defined (__thumb__)
.thumb
.thumb_func
#endif
-ENTRY(strcmp)
+ENTRY(strcmp_krait)
/* Use LDRD whenever possible. */
/* The main thing to look out for when comparing large blocks is that
@@ -482,4 +486,4 @@
.cfi_restore r7
bx lr
-END(strcmp)
+END(strcmp_krait)
diff --git a/libc/arch-arm/kryo/bionic/memcpy.S b/libc/arch-arm/kryo/bionic/memcpy.S
index 74036ef..250f7bc 100644
--- a/libc/arch-arm/kryo/bionic/memcpy.S
+++ b/libc/arch-arm/kryo/bionic/memcpy.S
@@ -33,8 +33,14 @@
#define PLDOFFS (16)
#define PLDSIZE (128) /* L2 cache line size */
+ .syntax unified
+
+ // To avoid warning about deprecated instructions, add an explicit
+ // arch. The code generated is exactly the same.
+ .arch armv7-a
+
.code 32
-ENTRY(__memcpy)
+ENTRY(__memcpy_kryo)
push {r0}
.cfi_def_cfa_offset 4
.cfi_rel_offset r0, 0
@@ -123,4 +129,4 @@
pop {r0}
bx lr
-END(__memcpy)
+END(__memcpy_kryo)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/kryo/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/kryo/bionic/memmove.S
index b60123c..d0fdd8f 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/kryo/bionic/memmove.S
@@ -26,13 +26,7 @@
* SUCH DAMAGE.
*/
-#pragma once
+#define MEMMOVE memmove_kryo
+#define MEMCPY __memcpy_kryo
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <arch-arm/denver/bionic/memmove.S>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/static_function_dispatch.S
similarity index 68%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/static_function_dispatch.S
index b60123c..a8235c2 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/static_function_dispatch.S
@@ -26,13 +26,21 @@
* SUCH DAMAGE.
*/
-#pragma once
+#include <private/bionic_asm.h>
-#include <sys/cdefs.h>
+#define FUNCTION_DELEGATE(name, impl) \
+ENTRY(name); \
+ b impl; \
+END(name)
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+FUNCTION_DELEGATE(memmove, memmove_generic)
+FUNCTION_DELEGATE(memcpy, memmove_generic)
+FUNCTION_DELEGATE(memset, memset_generic)
+FUNCTION_DELEGATE(__memset_chk, __memset_chk_generic)
+FUNCTION_DELEGATE(strcpy, strcpy_generic)
+FUNCTION_DELEGATE(__strcpy_chk, __strcpy_chk_generic)
+FUNCTION_DELEGATE(stpcpy, stpcpy_generic)
+FUNCTION_DELEGATE(strcat, strcat_generic)
+FUNCTION_DELEGATE(__strcat_chk, __strcat_chk_generic)
+FUNCTION_DELEGATE(strcmp, strcmp_generic)
+FUNCTION_DELEGATE(strlen, strlen_generic)
diff --git a/libc/arch-arm64/bionic/setjmp.S b/libc/arch-arm64/bionic/setjmp.S
index 5e62c28..a2b2370 100644
--- a/libc/arch-arm64/bionic/setjmp.S
+++ b/libc/arch-arm64/bionic/setjmp.S
@@ -27,6 +27,7 @@
*/
#include <private/bionic_asm.h>
+#include <private/bionic_constants.h>
// According to AARCH64 PCS document we need to save the following
// registers:
@@ -44,10 +45,12 @@
// word name description
// 0 sigflag/cookie setjmp cookie in top 31 bits, signal mask flag in low bit
// 1 sigmask signal mask (not used with _setjmp / _longjmp)
-// 2 core_base base of core registers (x19-x30, sp)
-// 15 float_base base of float registers (d8-d15)
-// 23 checksum checksum of core registers
-// 24 reserved reserved entries (room to grow)
+// 2 core_base base of core registers (x18-x30, sp)
+// (We only store the low bits of x18 to avoid leaking the
+// shadow call stack address into memory.)
+// 16 float_base base of float registers (d8-d15)
+// 24 checksum checksum of core registers
+// 25 reserved reserved entries (room to grow)
// 32
#define _JB_SIGFLAG 0
@@ -58,18 +61,20 @@
#define _JB_X24_X25 (_JB_X26_X27 + 2)
#define _JB_X22_X23 (_JB_X24_X25 + 2)
#define _JB_X20_X21 (_JB_X22_X23 + 2)
-#define _JB_X19 (_JB_X20_X21 + 2)
-#define _JB_D14_D15 (_JB_X19 + 1)
+#define _JB_SCS_X19 (_JB_X20_X21 + 2)
+#define _JB_D14_D15 (_JB_SCS_X19 + 2)
#define _JB_D12_D13 (_JB_D14_D15 + 2)
#define _JB_D10_D11 (_JB_D12_D13 + 2)
#define _JB_D8_D9 (_JB_D10_D11 + 2)
#define _JB_CHECKSUM (_JB_D8_D9 + 2)
+#define SCS_MASK (SCS_SIZE - 1)
#define MANGLE_REGISTERS 1
#define USE_CHECKSUM 1
.macro m_mangle_registers reg, sp_reg
#if MANGLE_REGISTERS
+ eor x3, x3, \reg
eor x19, x19, \reg
eor x20, x20, \reg
eor x21, x21, \reg
@@ -88,7 +93,7 @@
.macro m_calculate_checksum dst, src, scratch
mov \dst, #0
- .irp i,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22
+ .irp i,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
ldr \scratch, [\src, #(\i * 8)]
eor \dst, \dst, \scratch
.endr
@@ -151,6 +156,9 @@
// Mask off the signal flag bit.
bic x1, x1, #1
+ // Mask off the high bits of the shadow call stack pointer.
+ and x3, x18, #SCS_MASK
+
// Save core registers.
mov x10, sp
m_mangle_registers x1, sp_reg=x10
@@ -160,7 +168,7 @@
stp x24, x25, [x0, #(_JB_X24_X25 * 8)]
stp x22, x23, [x0, #(_JB_X22_X23 * 8)]
stp x20, x21, [x0, #(_JB_X20_X21 * 8)]
- str x19, [x0, #(_JB_X19 * 8)]
+ stp x3, x19, [x0, #(_JB_SCS_X19 * 8)]
m_unmangle_registers x1, sp_reg=x10
// Save floating point registers.
@@ -248,10 +256,14 @@
ldp x24, x25, [x0, #(_JB_X24_X25 * 8)]
ldp x22, x23, [x0, #(_JB_X22_X23 * 8)]
ldp x20, x21, [x0, #(_JB_X20_X21 * 8)]
- ldr x19, [x0, #(_JB_X19 * 8)]
+ ldp x3, x19, [x0, #(_JB_SCS_X19 * 8)]
m_unmangle_registers x2, sp_reg=x10
mov sp, x10
+ // Restore the low bits of the shadow call stack pointer.
+ and x18, x18, #~SCS_MASK
+ orr x18, x3, x18
+
stp x0, x1, [sp, #-16]!
.cfi_adjust_cfa_offset 16
.cfi_rel_offset x0, 0
diff --git a/libc/arch-x86/atom/string/sse2-memset-atom.S b/libc/arch-x86/atom/string/sse2-memset-atom.S
index 4e211ca..016c49e 100644
--- a/libc/arch-x86/atom/string/sse2-memset-atom.S
+++ b/libc/arch-x86/atom/string/sse2-memset-atom.S
@@ -86,7 +86,7 @@
movl (%esp), %ebx
ret
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_atom)
ENTRANCE
movl LEN(%esp), %ecx
@@ -95,11 +95,11 @@
POP(%ebx) // Undo ENTRANCE without returning.
jmp __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_atom)
.section .text.sse2,"ax",@progbits
ALIGN(4)
-ENTRY(memset)
+ENTRY(memset_atom)
ENTRANCE
movl LEN(%esp), %ecx
@@ -839,4 +839,4 @@
SETRTNVAL
RETURN_END
-END(memset)
+END(memset_atom)
diff --git a/libc/arch-x86/atom/string/sse2-strlen-atom.S b/libc/arch-x86/atom/string/sse2-strlen-atom.S
index 81768fb..6a1acfb 100644
--- a/libc/arch-x86/atom/string/sse2-strlen-atom.S
+++ b/libc/arch-x86/atom/string/sse2-strlen-atom.S
@@ -31,7 +31,7 @@
#ifndef USE_AS_STRCAT
# ifndef STRLEN
-# define STRLEN strlen
+# define STRLEN strlen_atom
# endif
# ifndef L
diff --git a/libc/arch-x86/atom/string/ssse3-memcmp-atom.S b/libc/arch-x86/atom/string/ssse3-memcmp-atom.S
index 0387084..be2c4f6 100644
--- a/libc/arch-x86/atom/string/ssse3-memcmp-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-memcmp-atom.S
@@ -76,7 +76,7 @@
#endif
#ifndef MEMCMP
-# define MEMCMP memcmp
+# define MEMCMP memcmp_atom
#endif
#define CFI_PUSH(REG) \
diff --git a/libc/arch-x86/atom/string/ssse3-memcpy-atom.S b/libc/arch-x86/atom/string/ssse3-memcpy-atom.S
index 2b3b7a5..5532e2e 100644
--- a/libc/arch-x86/atom/string/ssse3-memcpy-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-memcpy-atom.S
@@ -31,11 +31,7 @@
#include "cache.h"
#ifndef MEMCPY
-# define MEMCPY memcpy
-#endif
-
-#ifndef USE_AS_MEMMOVE
-# define USE_AS_MEMMOVE
+# define MEMCPY memcpy_atom
#endif
#ifndef L
@@ -71,12 +67,6 @@
cfi_startproc
#endif
-#ifndef ALIAS_SYMBOL
-# define ALIAS_SYMBOL(alias, original) \
- .globl alias; \
- .equ alias, original
-#endif
-
#ifndef END
# define END(name) \
cfi_endproc; \
@@ -3132,5 +3122,3 @@
#endif
END (MEMCPY)
-
-ALIAS_SYMBOL(memmove, MEMCPY)
diff --git a/libc/arch-x86/atom/string/ssse3-memmove-atom.S b/libc/arch-x86/atom/string/ssse3-memmove-atom.S
new file mode 100644
index 0000000..3572eac
--- /dev/null
+++ b/libc/arch-x86/atom/string/ssse3-memmove-atom.S
@@ -0,0 +1,34 @@
+/*
+Copyright (c) 2010, Intel Corporation
+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.
+
+ * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+
+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.
+*/
+
+
+#define MEMCPY memmove_atom
+#define USE_AS_MEMMOVE
+#include "ssse3-memcpy-atom.S"
diff --git a/libc/arch-x86/atom/string/ssse3-strcat-atom.S b/libc/arch-x86/atom/string/ssse3-strcat-atom.S
index d9b6129..8d8e89d 100644
--- a/libc/arch-x86/atom/string/ssse3-strcat-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strcat-atom.S
@@ -87,7 +87,7 @@
#define POP(REG) popl REG; CFI_POP (REG)
#ifndef STRCAT
-# define STRCAT strcat
+# define STRCAT strcat_ssse3
#endif
#define PARMS 4
@@ -617,4 +617,4 @@
RETURN1
#endif
-END (STRCAT)
+END (STRCAT_ssse3)
diff --git a/libc/arch-x86/atom/string/ssse3-strcmp-atom.S b/libc/arch-x86/atom/string/ssse3-strcmp-atom.S
index ee253b9..08f6d4a 100644
--- a/libc/arch-x86/atom/string/ssse3-strcmp-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strcmp-atom.S
@@ -108,7 +108,7 @@
#endif
#ifndef STRCMP
-# define STRCMP strcmp
+# define STRCMP strcmp_ssse3
#endif
.section .text.ssse3,"ax",@progbits
diff --git a/libc/arch-x86/atom/string/ssse3-strcpy-atom.S b/libc/arch-x86/atom/string/ssse3-strcpy-atom.S
index 3690b0d..45b0c02 100644
--- a/libc/arch-x86/atom/string/ssse3-strcpy-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strcpy-atom.S
@@ -81,7 +81,7 @@
# define POP(REG) popl REG; CFI_POP (REG)
# ifndef STRCPY
-# define STRCPY strcpy
+# define STRCPY strcpy_atom
# endif
# ifdef USE_AS_STRNCPY
diff --git a/libc/arch-x86/atom/string/ssse3-strlcat-atom.S b/libc/arch-x86/atom/string/ssse3-strlcat-atom.S
index daaf254..055b489 100644
--- a/libc/arch-x86/atom/string/ssse3-strlcat-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strlcat-atom.S
@@ -82,7 +82,7 @@
#define LEN SRC+4
.text
-ENTRY (strlcat)
+ENTRY (strlcat_ssse3)
mov DST(%esp), %edx
PUSH (%ebx)
mov LEN(%esp), %ebx
diff --git a/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S b/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S
index cdb17cc..1671da6 100644
--- a/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S
@@ -29,8 +29,8 @@
*/
#define USE_AS_STRNCPY
-#define STRCPY strlcpy
-#define STRLEN strlcpy
+#define STRCPY strlcpy_ssse3
+#define STRLEN strlcpy_ssse3
#define USE_AS_STRLCPY
#include "ssse3-strcpy-atom.S"
diff --git a/libc/arch-x86/atom/string/ssse3-strncat-atom.S b/libc/arch-x86/atom/string/ssse3-strncat-atom.S
index 5618771..ccb08a7 100644
--- a/libc/arch-x86/atom/string/ssse3-strncat-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strncat-atom.S
@@ -28,7 +28,7 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define STRCAT strncat
+#define STRCAT strncat_ssse3
#define USE_AS_STRNCAT
#include "ssse3-strcat-atom.S"
diff --git a/libc/arch-x86/atom/string/ssse3-strncmp-atom.S b/libc/arch-x86/atom/string/ssse3-strncmp-atom.S
index 4762d7e..2bf5002 100644
--- a/libc/arch-x86/atom/string/ssse3-strncmp-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strncmp-atom.S
@@ -30,6 +30,6 @@
#define USE_AS_STRNCMP
-#define STRCMP strncmp
+#define STRCMP strncmp_ssse3
#include "ssse3-strcmp-atom.S"
diff --git a/libc/arch-x86/atom/string/ssse3-strncpy-atom.S b/libc/arch-x86/atom/string/ssse3-strncpy-atom.S
index 0948b6d..0c27ffe 100644
--- a/libc/arch-x86/atom/string/ssse3-strncpy-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strncpy-atom.S
@@ -29,5 +29,5 @@
*/
#define USE_AS_STRNCPY
-#define STRCPY strncpy
+#define STRCPY strncpy_atom
#include "ssse3-strcpy-atom.S"
diff --git a/libc/arch-x86/atom/string/ssse3-wcscat-atom.S b/libc/arch-x86/atom/string/ssse3-wcscat-atom.S
index 8a389a3..a307983 100644
--- a/libc/arch-x86/atom/string/ssse3-wcscat-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-wcscat-atom.S
@@ -85,7 +85,7 @@
#define USE_AS_WCSCAT
.text
-ENTRY (wcscat)
+ENTRY (wcscat_ssse3)
PUSH (%edi)
mov STR1(%esp), %edi
mov %edi, %edx
@@ -111,4 +111,4 @@
#define RETURN POP(%edi); ret; CFI_PUSH(%edi)
#include "ssse3-wcscpy-atom.S"
-END (wcscat)
+END (wcscat_ssse3)
diff --git a/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S b/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S
index 27cb61e..80aa15f 100644
--- a/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S
@@ -88,7 +88,7 @@
# define LEN STR2+4
.text
-ENTRY (wcscpy)
+ENTRY (wcscpy_ssse3)
mov STR1(%esp), %edx
mov STR2(%esp), %ecx
@@ -648,5 +648,5 @@
ret
#ifndef USE_AS_WCSCAT
-END (wcscpy)
+END (wcscpy_ssse3)
#endif
diff --git a/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S b/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S
index 2c3fa02..a81b78b 100644
--- a/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S
@@ -28,7 +28,7 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define MEMCMP wmemcmp
+#define MEMCMP wmemcmp_atom
#define USE_WCHAR
#define USE_AS_WMEMCMP 1
diff --git a/libc/arch-x86/dynamic_function_dispatch.cpp b/libc/arch-x86/dynamic_function_dispatch.cpp
new file mode 100644
index 0000000..6624385
--- /dev/null
+++ b/libc/arch-x86/dynamic_function_dispatch.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2008 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 <stddef.h>
+
+extern "C" {
+
+struct __processor_model {
+ unsigned int __cpu_vendor;
+ unsigned int __cpu_type;
+ unsigned int __cpu_subtype;
+ unsigned int __cpu_features[1];
+};
+
+__attribute__((visibility("hidden")))
+extern struct __processor_model __cpu_model;
+
+// These definitions have to match the values in
+// llvm/include/llvm/Support/X86TargetParser.def
+static constexpr int SSSE3 = 6;
+static constexpr int SSE4_1 = 7;
+static constexpr int ATOM = 1;
+
+// __builtin_cpu_supports and __builtin_cpu_is can not be used here. They
+// don't access __cpu_model directly but use GOT.
+// See https://reviews.llvm.org/D53850
+static bool cpu_supports(unsigned int feature) {
+ return (__cpu_model.__cpu_features[0] & (1U << feature)) != 0;
+}
+
+static bool cpu_is(unsigned int type) {
+ return (__cpu_model.__cpu_type == type);
+}
+
+#define DEFINE_IFUNC_FOR(name) \
+ name##_func name __attribute__((ifunc(#name "_resolver"))); \
+ __attribute__((visibility("hidden"))) \
+ name##_func* name##_resolver()
+
+#define DECLARE_FUNC(type, name) \
+ __attribute__((visibility("hidden"))) \
+ type name
+
+#define RETURN_FUNC(type, name) { \
+ DECLARE_FUNC(type, name); \
+ return name; \
+ }
+
+typedef int memcmp_func(const void* __lhs, const void* __rhs, size_t __n);
+DEFINE_IFUNC_FOR(memcmp) {
+ __builtin_cpu_init();
+ if (cpu_is(ATOM)) RETURN_FUNC(memcmp_func, memcmp_atom);
+ if (cpu_supports(SSE4_1)) RETURN_FUNC(memcmp_func, memcmp_sse4);
+ RETURN_FUNC(memcmp_func, memcmp_generic);
+}
+
+typedef void* memset_func(void* __dst, int __ch, size_t __n);
+DEFINE_IFUNC_FOR(memset) {
+ __builtin_cpu_init();
+ if (cpu_is(ATOM)) RETURN_FUNC(memset_func, memset_atom);
+ RETURN_FUNC(memset_func, memset_generic);
+}
+
+typedef void* __memset_chk_func(void *s, int c, size_t n, size_t n2);
+DEFINE_IFUNC_FOR(__memset_chk) {
+ __builtin_cpu_init();
+ if (cpu_is(ATOM)) RETURN_FUNC(__memset_chk_func, __memset_chk_atom);
+ RETURN_FUNC(__memset_chk_func, __memset_chk_generic);
+}
+
+typedef void* memmove_func(void* __dst, const void* __src, size_t __n);
+DEFINE_IFUNC_FOR(memmove) {
+ __builtin_cpu_init();
+ if (cpu_is(ATOM)) RETURN_FUNC(memmove_func, memmove_atom);
+ RETURN_FUNC(memmove_func, memmove_generic);
+}
+
+typedef void* memcpy_func(void*, const void*, size_t);
+DEFINE_IFUNC_FOR(memcpy) {
+ return memmove_resolver();
+}
+
+typedef char* strcpy_func(char* __dst, const char* __src);
+DEFINE_IFUNC_FOR(strcpy) {
+ __builtin_cpu_init();
+ if (cpu_is(ATOM)) RETURN_FUNC(strcpy_func, strcpy_atom);
+ RETURN_FUNC(strcpy_func, strcpy_generic);
+}
+
+typedef char* strncpy_func(char* __dst, const char* __src, size_t __n);
+DEFINE_IFUNC_FOR(strncpy) {
+ __builtin_cpu_init();
+ if (cpu_is(ATOM)) RETURN_FUNC(strncpy_func, strncpy_atom);
+ RETURN_FUNC(strncpy_func, strncpy_generic);
+}
+
+typedef size_t strlen_func(const char* __s);
+DEFINE_IFUNC_FOR(strlen) {
+ __builtin_cpu_init();
+ if (cpu_is(ATOM)) RETURN_FUNC(strlen_func, strlen_atom);
+ RETURN_FUNC(strlen_func, strlen_generic);
+}
+
+typedef int wmemcmp_func(const wchar_t* __lhs, const wchar_t* __rhs, size_t __n);
+DEFINE_IFUNC_FOR(wmemcmp) {
+ __builtin_cpu_init();
+ if (cpu_supports(SSE4_1)) RETURN_FUNC(wmemcmp_func, wmemcmp_sse4);
+ if (cpu_is(ATOM)) RETURN_FUNC(wmemcmp_func, wmemcmp_atom);
+ RETURN_FUNC(wmemcmp_func, wmemcmp_freebsd);
+}
+
+typedef int strcmp_func(const char* __lhs, const char* __rhs);
+DEFINE_IFUNC_FOR(strcmp) {
+ __builtin_cpu_init();
+ if (cpu_supports(SSSE3)) RETURN_FUNC(strcmp_func, strcmp_ssse3);
+ RETURN_FUNC(strcmp_func, strcmp_generic);
+}
+
+typedef int strncmp_func(const char* __lhs, const char* __rhs, size_t __n);
+DEFINE_IFUNC_FOR(strncmp) {
+ __builtin_cpu_init();
+ if (cpu_supports(SSSE3)) RETURN_FUNC(strncmp_func, strncmp_ssse3);
+ RETURN_FUNC(strncmp_func, strncmp_generic);
+}
+
+typedef char* strcat_func(char* __dst, const char* __src);
+DEFINE_IFUNC_FOR(strcat) {
+ __builtin_cpu_init();
+ if (cpu_supports(SSSE3)) RETURN_FUNC(strcat_func, strcat_ssse3);
+ RETURN_FUNC(strcat_func, strcat_generic);
+}
+
+typedef char* strncat_func(char* __dst, const char* __src, size_t __n);
+DEFINE_IFUNC_FOR(strncat) {
+ __builtin_cpu_init();
+ if (cpu_supports(SSSE3)) RETURN_FUNC(strncat_func, strncat_ssse3);
+ RETURN_FUNC(strncat_func, strncat_openbsd);
+}
+
+typedef size_t strlcat_func(char *dst, const char *src, size_t dsize);
+DEFINE_IFUNC_FOR(strlcat) {
+ __builtin_cpu_init();
+ if (cpu_supports(SSSE3)) RETURN_FUNC(strlcat_func, strlcat_ssse3);
+ RETURN_FUNC(strlcat_func, strlcat_openbsd);
+}
+
+typedef size_t strlcpy_func(char *dst, const char *src, size_t dsize);
+DEFINE_IFUNC_FOR(strlcpy) {
+ __builtin_cpu_init();
+ if (cpu_supports(SSSE3)) RETURN_FUNC(strlcpy_func, strlcpy_ssse3);
+ RETURN_FUNC(strlcpy_func, strlcpy_openbsd);
+}
+
+typedef wchar_t* wcscat_func(wchar_t *s1, const wchar_t *s2);
+DEFINE_IFUNC_FOR(wcscat) {
+ __builtin_cpu_init();
+ if (cpu_supports(SSSE3)) RETURN_FUNC(wcscat_func, wcscat_ssse3);
+ RETURN_FUNC(wcscat_func, wcscat_freebsd);
+}
+
+typedef wchar_t* wcscpy_func(wchar_t *s1, const wchar_t *s2);
+DEFINE_IFUNC_FOR(wcscpy) {
+ __builtin_cpu_init();
+ if (cpu_supports(SSSE3)) RETURN_FUNC(wcscpy_func, wcscpy_ssse3);
+ RETURN_FUNC(wcscpy_func, wcscpy_freebsd);
+}
+
+} // extern "C"
diff --git a/libc/arch-x86/generic/string/memcmp.S b/libc/arch-x86/generic/string/memcmp.S
index ef36b4f..1d327c7 100644
--- a/libc/arch-x86/generic/string/memcmp.S
+++ b/libc/arch-x86/generic/string/memcmp.S
@@ -6,7 +6,7 @@
#include <private/bionic_asm.h>
-ENTRY(memcmp)
+ENTRY(memcmp_generic)
pushl %edi
pushl %esi
movl 12(%esp),%edi
@@ -41,4 +41,4 @@
popl %esi
popl %edi
ret
-END(memcmp)
+END(memcmp_generic)
diff --git a/libc/arch-x86/generic/string/strcat.S b/libc/arch-x86/generic/string/strcat.S
index 49e8eee..e2e9623 100644
--- a/libc/arch-x86/generic/string/strcat.S
+++ b/libc/arch-x86/generic/string/strcat.S
@@ -19,7 +19,7 @@
* cache.
*/
-ENTRY(strcat)
+ENTRY(strcat_generic)
pushl %edi /* save edi */
movl 8(%esp),%edi /* dst address */
movl 12(%esp),%edx /* src address */
@@ -71,4 +71,4 @@
L2: popl %eax /* pop destination address */
popl %edi /* restore edi */
ret
-END(strcat)
+END(strcat_generic)
diff --git a/libc/arch-x86/generic/string/strcmp.S b/libc/arch-x86/generic/string/strcmp.S
index 580f4d5..7b003e8 100644
--- a/libc/arch-x86/generic/string/strcmp.S
+++ b/libc/arch-x86/generic/string/strcmp.S
@@ -12,7 +12,7 @@
* cache.
*/
-ENTRY(strcmp)
+ENTRY(strcmp_generic)
movl 0x04(%esp),%eax
movl 0x08(%esp),%edx
jmp L2 /* Jump into the loop! */
@@ -79,4 +79,4 @@
movzbl (%edx),%edx
subl %edx,%eax
ret
-END(strcmp)
+END(strcmp_generic)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/strlcat.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-x86/generic/string/strlcat.c
index b60123c..95c34a3 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/strlcat.c
@@ -26,13 +26,7 @@
* SUCH DAMAGE.
*/
-#pragma once
+#include <upstream-openbsd/android/include/openbsd-compat.h>
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define strlcat strlcat_openbsd
+#include <upstream-openbsd/lib/libc/string/strlcat.c>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/strlcpy.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-x86/generic/string/strlcpy.c
index b60123c..8d4047c 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/strlcpy.c
@@ -26,13 +26,7 @@
* SUCH DAMAGE.
*/
-#pragma once
+#include <upstream-openbsd/android/include/openbsd-compat.h>
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define strlcpy strlcpy_openbsd
+#include <upstream-openbsd/lib/libc/string/strlcpy.c>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/strncat.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-x86/generic/string/strncat.c
index b60123c..687e560 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/strncat.c
@@ -26,13 +26,7 @@
* SUCH DAMAGE.
*/
-#pragma once
+#include <upstream-openbsd/android/include/openbsd-compat.h>
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define strncat strncat_openbsd
+#include <upstream-openbsd/lib/libc/string/strncat.c>
diff --git a/libc/arch-x86/generic/string/strncmp.S b/libc/arch-x86/generic/string/strncmp.S
index 9ba83a1..6d9f23c 100644
--- a/libc/arch-x86/generic/string/strncmp.S
+++ b/libc/arch-x86/generic/string/strncmp.S
@@ -12,7 +12,7 @@
* cache.
*/
-ENTRY(strncmp)
+ENTRY(strncmp_generic)
pushl %ebx
movl 8(%esp),%eax
movl 12(%esp),%ecx
@@ -111,4 +111,4 @@
L4: xorl %eax,%eax
popl %ebx
ret
-END(strncmp)
+END(strncmp_generic)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/wcscat.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-x86/generic/string/wcscat.c
index b60123c..a102551 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/wcscat.c
@@ -26,13 +26,5 @@
* SUCH DAMAGE.
*/
-#pragma once
-
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define wcscat wcscat_freebsd
+#include <upstream-freebsd/lib/libc/string/wcscat.c>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/wcscpy.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-x86/generic/string/wcscpy.c
index b60123c..10fb66d 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/wcscpy.c
@@ -26,13 +26,5 @@
* SUCH DAMAGE.
*/
-#pragma once
-
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define wcscpy wcscpy_freebsd
+#include <upstream-freebsd/lib/libc/string/wcscpy.c>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/wmemcmp.c
similarity index 86%
rename from libc/include/android/legacy_get_device_api_level_inlines.h
rename to libc/arch-x86/generic/string/wmemcmp.c
index b60123c..9d5e929 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/wmemcmp.c
@@ -26,13 +26,5 @@
* SUCH DAMAGE.
*/
-#pragma once
-
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define wmemcmp wmemcmp_freebsd
+#include <upstream-freebsd/lib/libc/string/wmemcmp.c>
diff --git a/libc/arch-x86/silvermont/string/sse2-memmove-slm.S b/libc/arch-x86/silvermont/string/sse2-memmove-slm.S
index ceada1b..da6456c 100644
--- a/libc/arch-x86/silvermont/string/sse2-memmove-slm.S
+++ b/libc/arch-x86/silvermont/string/sse2-memmove-slm.S
@@ -31,7 +31,7 @@
#include "cache.h"
#ifndef MEMMOVE
-# define MEMMOVE memmove
+# define MEMMOVE memmove_generic
#endif
#ifndef L
@@ -67,12 +67,6 @@
cfi_startproc
#endif
-#ifndef ALIAS_SYMBOL
-# define ALIAS_SYMBOL(alias, original) \
- .globl alias; \
- .equ alias, original
-#endif
-
#ifndef END
# define END(name) \
cfi_endproc; \
@@ -543,5 +537,3 @@
jmp L(mm_recalc_len)
END (MEMMOVE)
-
-ALIAS_SYMBOL(memcpy, MEMMOVE)
diff --git a/libc/arch-x86/silvermont/string/sse2-memset-slm.S b/libc/arch-x86/silvermont/string/sse2-memset-slm.S
index 03a552d..adaccae 100644
--- a/libc/arch-x86/silvermont/string/sse2-memset-slm.S
+++ b/libc/arch-x86/silvermont/string/sse2-memset-slm.S
@@ -86,7 +86,7 @@
movl (%esp), %ebx
ret
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_generic)
ENTRANCE
movl LEN(%esp), %ecx
@@ -95,11 +95,11 @@
POP(%ebx) // Undo ENTRANCE without returning.
jmp __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_generic)
.section .text.sse2,"ax",@progbits
ALIGN(4)
-ENTRY(memset)
+ENTRY(memset_generic)
ENTRANCE
movl LEN(%esp), %ecx
@@ -758,4 +758,4 @@
SETRTNVAL
RETURN_END
-END(memset)
+END(memset_generic)
diff --git a/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S b/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S
index b5d84b5..22ceeab 100755
--- a/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S
+++ b/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S
@@ -79,7 +79,7 @@
#define POP(REG) popl REG; CFI_POP (REG)
#ifndef STRCPY
-# define STRCPY strcpy
+# define STRCPY strcpy_generic
#endif
#ifdef USE_AS_STPNCPY
diff --git a/libc/arch-x86/silvermont/string/sse2-strlen-slm.S b/libc/arch-x86/silvermont/string/sse2-strlen-slm.S
index 27cc025..b805ad6 100755
--- a/libc/arch-x86/silvermont/string/sse2-strlen-slm.S
+++ b/libc/arch-x86/silvermont/string/sse2-strlen-slm.S
@@ -29,7 +29,7 @@
*/
#ifndef STRLEN
-# define STRLEN strlen
+# define STRLEN strlen_generic
#endif
#ifndef L
diff --git a/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S b/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S
index 591419f..aff7fb9 100755
--- a/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S
+++ b/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S
@@ -29,5 +29,5 @@
*/
#define USE_AS_STRNCPY
-#define STRCPY strncpy
+#define STRCPY strncpy_generic
#include "sse2-strcpy-slm.S"
diff --git a/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S b/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S
index e5028ff..f151168 100755
--- a/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S
+++ b/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S
@@ -76,7 +76,7 @@
#endif
#ifndef MEMCMP
-# define MEMCMP memcmp
+# define MEMCMP memcmp_sse4
#endif
#define CFI_PUSH(REG) \
diff --git a/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S b/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S
index 2c350bb..2bf92f5 100755
--- a/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S
+++ b/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S
@@ -29,5 +29,5 @@
*/
#define USE_AS_WMEMCMP
-#define MEMCMP wmemcmp
+#define MEMCMP wmemcmp_sse4
#include "sse4-memcmp-slm.S"
diff --git a/libc/include/android/get_device_api_level.h b/libc/arch-x86/static_function_dispatch.S
similarity index 61%
rename from libc/include/android/get_device_api_level.h
rename to libc/arch-x86/static_function_dispatch.S
index 39609da..7e8e63d 100644
--- a/libc/include/android/get_device_api_level.h
+++ b/libc/arch-x86/static_function_dispatch.S
@@ -26,29 +26,27 @@
* SUCH DAMAGE.
*/
-#pragma once
+#include <private/bionic_asm.h>
-/**
- * @file android/get_device_api_level.h
- * @brief Check the API level of the device we're actually running on.
- */
+#define FUNCTION_DELEGATE(name, impl) \
+ENTRY(name); \
+ jmp impl; \
+END(name)
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-#if __ANDROID_API__ >= __ANDROID_API_Q__
-// This file is implemented as static inlines before API level 29.
-
-/**
- * Returns the API level of the device we're actually running on, or -1 on failure.
- * The returned values correspond to the named constants in <android/api-level.h>,
- * and is equivalent to the Java `Build.VERSION.SDK_INT` API.
- */
-int android_get_device_api_level() __INTRODUCED_IN(29);
-
-#endif
-
-__END_DECLS
-
-#include <android/legacy_get_device_api_level_inlines.h>
+FUNCTION_DELEGATE(memcmp, memcmp_generic)
+FUNCTION_DELEGATE(memset, memset_generic)
+FUNCTION_DELEGATE(__memset_chk, __memset_chk_generic)
+FUNCTION_DELEGATE(memcpy, memmove_generic)
+FUNCTION_DELEGATE(memmove, memmove_generic)
+FUNCTION_DELEGATE(strcpy, strcpy_generic)
+FUNCTION_DELEGATE(strncpy, strncpy_generic)
+FUNCTION_DELEGATE(strlen, strlen_generic)
+FUNCTION_DELEGATE(strcmp, strcmp_generic)
+FUNCTION_DELEGATE(strncmp, strncmp_generic)
+FUNCTION_DELEGATE(strcat, strcat_generic)
+FUNCTION_DELEGATE(wmemcmp, wmemcmp_freebsd)
+FUNCTION_DELEGATE(wcscat, wcscat_freebsd)
+FUNCTION_DELEGATE(strncat, strncat_openbsd)
+FUNCTION_DELEGATE(strlcat, strlcat_openbsd)
+FUNCTION_DELEGATE(strlcpy, strlcpy_openbsd)
+FUNCTION_DELEGATE(wcscpy, wcscpy_freebsd)
diff --git a/libc/bionic/NetdClient.cpp b/libc/bionic/NetdClient.cpp
index a5c519e..87eec27 100644
--- a/libc/bionic/NetdClient.cpp
+++ b/libc/bionic/NetdClient.cpp
@@ -58,6 +58,8 @@
netdClientInitFunction(netdClientHandle, "netdClientInitNetIdForResolv",
&__netdClientDispatch.netIdForResolv);
netdClientInitFunction(netdClientHandle, "netdClientInitSocket", &__netdClientDispatch.socket);
+ netdClientInitFunction(netdClientHandle, "netdClientInitDnsOpenProxy",
+ &__netdClientDispatch.dnsOpenProxy);
}
static pthread_once_t netdClientInitOnce = PTHREAD_ONCE_INIT;
diff --git a/libc/bionic/NetdClientDispatch.cpp b/libc/bionic/NetdClientDispatch.cpp
index 67fa197..a873173 100644
--- a/libc/bionic/NetdClientDispatch.cpp
+++ b/libc/bionic/NetdClientDispatch.cpp
@@ -30,6 +30,10 @@
return netId;
}
+static int fallBackDnsOpenProxy() {
+ return -1;
+}
+
// This structure is modified only at startup (when libc.so is loaded) and never
// afterwards, so it's okay that it's read later at runtime without a lock.
__LIBC_HIDDEN__ NetdClientDispatch __netdClientDispatch __attribute__((aligned(32))) = {
@@ -37,4 +41,5 @@
__connect,
__socket,
fallBackNetIdForResolv,
+ fallBackDnsOpenProxy,
};
diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
index 758b295..be9d32e 100644
--- a/libc/bionic/__libc_init_main_thread.cpp
+++ b/libc/bionic/__libc_init_main_thread.cpp
@@ -101,5 +101,5 @@
__init_thread(&main_thread);
- __init_alternate_signal_stack(&main_thread);
+ __init_additional_stacks(&main_thread);
}
diff --git a/libc/bionic/fortify.cpp b/libc/bionic/fortify.cpp
index 4b94573..20e265e 100644
--- a/libc/bionic/fortify.cpp
+++ b/libc/bionic/fortify.cpp
@@ -454,9 +454,14 @@
return write(fd, buf, count);
}
-#if !defined(NO___STRCAT_CHK)
+#if defined(RENAME___STRCAT_CHK)
+#define __STRCAT_CHK __strcat_chk_generic
+#else
+#define __STRCAT_CHK __strcat_chk
+#endif // RENAME___STRCAT_CHK
+
// Runtime implementation of __builtin____strcat_chk (used directly by compiler, not in headers).
-extern "C" char* __strcat_chk(char* dst, const char* src, size_t dst_buf_size) {
+extern "C" char* __STRCAT_CHK(char* dst, const char* src, size_t dst_buf_size) {
char* save = dst;
size_t dst_len = __strlen_chk(dst, dst_buf_size);
@@ -472,17 +477,20 @@
return save;
}
-#endif // NO___STRCAT_CHK
-#if !defined(NO___STRCPY_CHK)
+#if defined(RENAME___STRCPY_CHK)
+#define __STRCPY_CHK __strcpy_chk_generic
+#else
+#define __STRCPY_CHK __strcpy_chk
+#endif // RENAME___STRCPY_CHK
+
// Runtime implementation of __builtin____strcpy_chk (used directly by compiler, not in headers).
-extern "C" char* __strcpy_chk(char* dst, const char* src, size_t dst_len) {
+extern "C" char* __STRCPY_CHK(char* dst, const char* src, size_t dst_len) {
// TODO: optimize so we don't scan src twice.
size_t src_len = strlen(src) + 1;
__check_buffer_access("strcpy", "write into", src_len, dst_len);
return strcpy(dst, src);
}
-#endif // NO___STRCPY_CHK
#if !defined(NO___MEMCPY_CHK)
// Runtime implementation of __memcpy_chk (used directly by compiler, not in headers).
diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp
index 40f2a66..ef0d384 100644
--- a/libc/bionic/jemalloc_wrapper.cpp
+++ b/libc/bionic/jemalloc_wrapper.cpp
@@ -52,11 +52,11 @@
// The only parameter we currently understand is M_DECAY_TIME.
if (param == M_DECAY_TIME) {
// Only support setting the value to 1 or 0.
- ssize_t decay_time;
+ ssize_t decay_time_ms;
if (value) {
- decay_time = 1;
+ decay_time_ms = 1000;
} else {
- decay_time = 0;
+ decay_time_ms = 0;
}
// First get the total number of arenas.
unsigned narenas;
@@ -66,15 +66,22 @@
}
// Set the decay time for any arenas that will be created in the future.
- if (je_mallctl("arenas.decay_time", nullptr, nullptr, &decay_time, sizeof(decay_time)) != 0) {
+ if (je_mallctl("arenas.dirty_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
+ return 0;
+ }
+ if (je_mallctl("arenas.muzzy_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
return 0;
}
// Change the decay on the already existing arenas.
char buffer[100];
for (unsigned i = 0; i < narenas; i++) {
- snprintf(buffer, sizeof(buffer), "arena.%d.decay_time", i);
- if (je_mallctl(buffer, nullptr, nullptr, &decay_time, sizeof(decay_time)) != 0) {
+ snprintf(buffer, sizeof(buffer), "arena.%d.dirty_decay_ms", i);
+ if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
+ break;
+ }
+ snprintf(buffer, sizeof(buffer), "arena.%d.muzzy_decay_ms", i);
+ if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
break;
}
}
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index f943402..a860b98 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -62,13 +62,9 @@
const char* __progname;
void __libc_init_globals(KernelArgumentBlock& args) {
-#if defined(__i386__)
- __libc_init_sysinfo(args);
-#endif
// Initialize libc globals that are needed in both the linker and in libc.
// In dynamic binaries, this is run at least twice for different copies of the
// globals, once for the linker's copy and once for the one in libc.so.
- __libc_auxv = args.auxv;
__libc_globals.initialize();
__libc_globals.mutate([&args](libc_globals* globals) {
__libc_init_vdso(globals, args);
@@ -275,7 +271,6 @@
}
static void __sanitize_environment_variables(char** env) {
- bool is_AT_SECURE = getauxval(AT_SECURE);
char** src = env;
char** dst = env;
for (; src[0] != nullptr; ++src) {
@@ -283,7 +278,7 @@
continue;
}
// Remove various unsafe environment variables if we're loading a setuid program.
- if (is_AT_SECURE && __is_unsafe_environment_variable(src[0])) {
+ if (__is_unsafe_environment_variable(src[0])) {
continue;
}
dst[0] = src[0];
@@ -306,20 +301,14 @@
}
void __libc_init_AT_SECURE(KernelArgumentBlock& args) {
- __libc_auxv = args.auxv;
__abort_message_ptr = args.abort_message_ptr;
// Check that the kernel provided a value for AT_SECURE.
- bool found_AT_SECURE = false;
- for (ElfW(auxv_t)* v = __libc_auxv; v->a_type != AT_NULL; ++v) {
- if (v->a_type == AT_SECURE) {
- found_AT_SECURE = true;
- break;
- }
- }
- if (!found_AT_SECURE) __early_abort(__LINE__);
+ errno = 0;
+ unsigned long is_AT_SECURE = getauxval(AT_SECURE);
+ if (errno != 0) __early_abort(__LINE__);
- if (getauxval(AT_SECURE)) {
+ if (is_AT_SECURE) {
// If this is a setuid/setgid program, close the security hole described in
// https://www.freebsd.org/security/advisories/FreeBSD-SA-02:23.stdio.asc
__nullify_closed_stdio();
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 5f76354..08d3df4 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -51,6 +51,7 @@
#include <elf.h>
#include "libc_init_common.h"
+#include "private/bionic_auxv.h"
#include "private/bionic_globals.h"
#include "private/bionic_macros.h"
#include "private/bionic_ssp.h"
@@ -78,8 +79,12 @@
// protector.
__attribute__((noinline))
static void __libc_preinit_impl(KernelArgumentBlock& args) {
- __libc_shared_globals = args.shared_globals;
+ __libc_auxv = args.auxv;
+#if defined(__i386__)
+ __libc_init_sysinfo(args);
+#endif
+ __libc_shared_globals = args.shared_globals;
__libc_init_globals(args);
__libc_init_common(args);
@@ -137,9 +142,3 @@
args.argv + __libc_shared_globals->initial_linker_arg_count,
args.envp));
}
-
-extern "C" uint32_t android_get_application_target_sdk_version();
-
-uint32_t bionic_get_application_target_sdk_version() {
- return android_get_application_target_sdk_version();
-}
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 38a04f8..ef1c393 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -146,16 +146,12 @@
__real_libc_init(raw_args, onexit, slingshot, structors);
}
-static uint32_t g_target_sdk_version{__ANDROID_API__};
+static int g_target_sdk_version{__ANDROID_API__};
-extern "C" uint32_t android_get_application_target_sdk_version() {
+extern "C" int android_get_application_target_sdk_version() {
return g_target_sdk_version;
}
-uint32_t bionic_get_application_target_sdk_version() {
- return android_get_application_target_sdk_version();
-}
-
-extern "C" void android_set_application_target_sdk_version(uint32_t target) {
+extern "C" void android_set_application_target_sdk_version(int target) {
g_target_sdk_version = target;
}
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 3a94084..9a80767 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -271,6 +271,7 @@
static const char* HEAPPROFD_SHARED_LIB = "heapprofd_client.so";
static const char* HEAPPROFD_PREFIX = "heapprofd";
+static const char* HEAPPROFD_PROPERTY_ENABLE = "heapprofd.enable";
static const int HEAPPROFD_SIGNAL = __SIGRTMIN + 4;
enum FunctionEnum : uint8_t {
@@ -365,12 +366,6 @@
}
static bool InitMallocFunctions(void* impl_handler, MallocDispatch* table, const char* prefix) {
- // We initialize free first to prevent the following situation:
- // Heapprofd's MallocMalloc is installed, and an allocation is observed
- // and logged to the heap dump. The corresponding free happens before
- // heapprofd's MallocFree is installed, and is not logged in the heap
- // dump. This leads to the allocation wrongly being active in the heap
- // dump indefinitely.
if (!InitMallocFunction<MallocFree>(impl_handler, &table->free, prefix, "free")) {
return false;
}
@@ -469,6 +464,39 @@
return true;
}
+static bool CheckLoadHeapprofd() {
+ // First check for heapprofd.enable. If it is set to "all", enable
+ // heapprofd for all processes. Otherwise, check heapprofd.enable.${prog},
+ // if it is set and not 0, enable heap profiling for this process.
+ char property_value[PROP_VALUE_MAX];
+ if (__system_property_get(HEAPPROFD_PROPERTY_ENABLE, property_value) == 0) {
+ return false;
+ }
+ if (strcmp(property_value, "all") == 0) {
+ return true;
+ }
+
+ char program_property[128];
+ int ret = snprintf(program_property, sizeof(program_property), "%s.%s",
+ HEAPPROFD_PROPERTY_ENABLE, getprogname());
+
+ if (ret < 0 || static_cast<size_t>(ret) >= sizeof(program_property)) {
+ if (ret < 0) {
+ error_log("Failed to concatenate heapprofd property %s.%s: %s",
+ HEAPPROFD_PROPERTY_ENABLE, getprogname(), strerror(errno));
+ } else {
+ error_log("Overflow in concatenating heapprofd property");
+ }
+ return false;
+ }
+
+ if (__system_property_get(program_property, property_value) == 0) {
+ return false;
+ }
+
+ return program_property[0] != '\0';
+}
+
static void ClearGlobalFunctions() {
for (size_t i = 0; i < FUNC_LAST; i++) {
g_functions[i] = nullptr;
@@ -538,6 +566,16 @@
}
atomic_store(&g_heapprofd_init_func, init_func);
+ // We assign free first explicitly to prevent the case where we observe a
+ // alloc, but miss the corresponding free because of initialization order.
+ //
+ // This is safer than relying on the declaration order inside
+ // MallocDispatch at the cost of an extra atomic pointer write on
+ // initialization.
+ atomic_store(&globals->malloc_dispatch.free, dispatch_table.free);
+ // The struct gets assigned elementwise and each of the elements is an
+ // _Atomic. Assigning to an _Atomic is an atomic_store operation.
+ // The assignment is done in declaration order.
globals->malloc_dispatch = dispatch_table;
info_log("%s: malloc %s enabled", getprogname(), prefix);
@@ -572,6 +610,9 @@
} else if (CheckLoadMallocHooks(&options)) {
prefix = "hooks";
shared_lib = HOOKS_SHARED_LIB;
+ } else if (CheckLoadHeapprofd()) {
+ prefix = "heapprofd";
+ shared_lib = HEAPPROFD_SHARED_LIB;
} else {
return;
}
@@ -642,7 +683,7 @@
extern "C" void InstallInitHeapprofdHook(int) {
if (!atomic_exchange(&g_heapprofd_init_in_progress, true)) {
__libc_globals.mutate([](libc_globals* globals) {
- globals->malloc_dispatch.malloc = InitHeapprofdHook;
+ atomic_store(&globals->malloc_dispatch.malloc, InitHeapprofdHook);
});
}
}
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index 543fdc5..6f632e8 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -32,12 +32,14 @@
#include <string.h>
#include <sys/mman.h>
#include <sys/prctl.h>
+#include <sys/random.h>
#include <unistd.h>
#include "pthread_internal.h"
#include <async_safe/log.h>
+#include "private/bionic_constants.h"
#include "private/bionic_defs.h"
#include "private/bionic_macros.h"
#include "private/bionic_ssp.h"
@@ -86,7 +88,7 @@
thread->tls[TLS_SLOT_STACK_GUARD] = reinterpret_cast<void*>(__stack_chk_guard);
}
-void __init_alternate_signal_stack(pthread_internal_t* thread) {
+static void __init_alternate_signal_stack(pthread_internal_t* thread) {
// Create and set an alternate signal stack.
void* stack_base = mmap(nullptr, SIGNAL_STACK_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (stack_base != MAP_FAILED) {
@@ -109,6 +111,30 @@
}
}
+static void __init_shadow_call_stack(pthread_internal_t* thread __unused) {
+#ifdef __aarch64__
+ // Allocate the stack and store its address in register x18. The address is aligned to SCS_SIZE so
+ // that we only need to store the lower log2(SCS_SIZE) bits in jmp_buf.
+ // TODO(pcc): We ought to allocate a larger guard region here and then allocate the SCS at a
+ // random location within it. This will provide greater security since it would mean that an
+ // attacker who can read the pthread_internal_t won't be able to discover the address of the SCS.
+ // However, doing so is blocked on a solution to b/118642754.
+ char* scs_guard_region = reinterpret_cast<char*>(
+ mmap(nullptr, SCS_GUARD_REGION_SIZE, 0, MAP_PRIVATE | MAP_ANON, -1, 0));
+ thread->shadow_call_stack_guard_region = scs_guard_region;
+
+ char* scs =
+ reinterpret_cast<char*>(align_up(reinterpret_cast<uintptr_t>(scs_guard_region), SCS_SIZE));
+ mprotect(scs, SCS_SIZE, PROT_READ | PROT_WRITE);
+ __asm__ __volatile__("mov x18, %0" ::"r"(scs));
+#endif
+}
+
+void __init_additional_stacks(pthread_internal_t* thread) {
+ __init_alternate_signal_stack(thread);
+ __init_shadow_call_stack(thread);
+}
+
int __init_thread(pthread_internal_t* thread) {
thread->cleanup_stack = nullptr;
@@ -252,7 +278,7 @@
// accesses previously made by the creating thread are visible to us.
thread->startup_handshake_lock.lock();
- __init_alternate_signal_stack(thread);
+ __init_additional_stacks(thread);
void* result = thread->start_routine(thread->start_routine_arg);
pthread_exit(result);
diff --git a/libc/bionic/pthread_exit.cpp b/libc/bionic/pthread_exit.cpp
index 220f7a0..2d4d6cf 100644
--- a/libc/bionic/pthread_exit.cpp
+++ b/libc/bionic/pthread_exit.cpp
@@ -33,6 +33,7 @@
#include <string.h>
#include <sys/mman.h>
+#include "private/bionic_constants.h"
#include "private/bionic_defs.h"
#include "private/ScopedSignalBlocker.h"
#include "pthread_internal.h"
@@ -103,6 +104,11 @@
thread->alternate_signal_stack = nullptr;
}
+#ifdef __aarch64__
+ // Free the shadow call stack and guard pages.
+ munmap(thread->shadow_call_stack_guard_region, SCS_GUARD_REGION_SIZE);
+#endif
+
ThreadJoinState old_state = THREAD_NOT_JOINED;
while (old_state == THREAD_NOT_JOINED &&
!atomic_compare_exchange_weak(&thread->join_state, &old_state, THREAD_EXITED_NOT_JOINED)) {
diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp
index 92786fe..2b7a99a 100644
--- a/libc/bionic/pthread_internal.cpp
+++ b/libc/bionic/pthread_internal.cpp
@@ -36,7 +36,6 @@
#include <async_safe/log.h>
#include "private/bionic_futex.h"
-#include "private/bionic_sdk_version.h"
#include "private/bionic_tls.h"
static pthread_internal_t* g_thread_list = nullptr;
@@ -114,7 +113,7 @@
}
// Historically we'd return null, but
- if (bionic_get_application_target_sdk_version() >= __ANDROID_API_O__) {
+ if (android_get_application_target_sdk_version() >= __ANDROID_API_O__) {
if (thread == nullptr) {
// This seems to be a common mistake, and it's relatively harmless because
// there will never be a valid thread at address 0, whereas other invalid
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 6dd2f9c..81b885a 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -106,6 +106,29 @@
void* alternate_signal_stack;
+ // The start address of the shadow call stack's guard region (arm64 only).
+ // This address is only used to deallocate the shadow call stack on thread
+ // exit; the address of the stack itself is stored only in the x18 register.
+ // Because the protection offered by SCS relies on the secrecy of the stack
+ // address, storing the address here weakens the protection, but only
+ // slightly, because it is relatively easy for an attacker to discover the
+ // address of the guard region anyway (e.g. it can be discovered by reference
+ // to other allocations), but not the stack itself, which is <0.1% of the size
+ // of the guard region.
+ //
+ // There are at least two other options for discovering the start address of
+ // the guard region on thread exit, but they are not as simple as storing in
+ // TLS.
+ // 1) Derive it from the value of the x18 register. This is only possible in
+ // processes that do not contain legacy code that might clobber x18,
+ // therefore each process must declare early during process startup whether
+ // it might load legacy code.
+ // 2) Mark the guard region as such using prctl(PR_SET_VMA_ANON_NAME) and
+ // discover its address by reading /proc/self/maps. One issue with this is
+ // that reading /proc/self/maps can race with allocations, so we may need
+ // code to handle retries.
+ void* shadow_call_stack_guard_region;
+
Lock startup_handshake_lock;
size_t mmap_size;
@@ -132,7 +155,7 @@
__LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread);
__LIBC_HIDDEN__ bool __init_tls(pthread_internal_t* thread);
__LIBC_HIDDEN__ void __init_thread_stack_guard(pthread_internal_t* thread);
-__LIBC_HIDDEN__ void __init_alternate_signal_stack(pthread_internal_t*);
+__LIBC_HIDDEN__ void __init_additional_stacks(pthread_internal_t*);
__LIBC_HIDDEN__ pthread_t __pthread_internal_add(pthread_internal_t* thread);
__LIBC_HIDDEN__ pthread_internal_t* __pthread_internal_find(pthread_t pthread_id);
@@ -167,9 +190,14 @@
// SIGSTKSZ (8KiB) is not big enough.
// An snprintf to a stack buffer of size PATH_MAX consumes ~7KiB of stack.
-// Also, on 64-bit, logging uses more than 8KiB by itself:
-// https://code.google.com/p/android/issues/detail?id=187064
+// On 64-bit, logging uses more than 8KiB by itself, ucontext is comically
+// large on aarch64, and we have effectively infinite address space, so double
+// the signal stack size.
+#if defined(__LP64__)
+#define SIGNAL_STACK_SIZE_WITHOUT_GUARD (32 * 1024)
+#else
#define SIGNAL_STACK_SIZE_WITHOUT_GUARD (16 * 1024)
+#endif
// Traditionally we gave threads a 1MiB stack. When we started
// allocating per-thread alternate signal stacks to ease debugging of
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index fda0b93..d9ddf10 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -42,7 +42,6 @@
#include "private/bionic_constants.h"
#include "private/bionic_fortify.h"
#include "private/bionic_futex.h"
-#include "private/bionic_sdk_version.h"
#include "private/bionic_systrace.h"
#include "private/bionic_time_conversions.h"
#include "private/bionic_tls.h"
@@ -789,7 +788,7 @@
// ARM64. So make it noinline.
static int __attribute__((noinline)) HandleUsingDestroyedMutex(pthread_mutex_t* mutex,
const char* function_name) {
- if (bionic_get_application_target_sdk_version() >= __ANDROID_API_P__) {
+ if (android_get_application_target_sdk_version() >= __ANDROID_API_P__) {
__fortify_fatal("%s called on a destroyed mutex (%p)", function_name, mutex);
}
return EBUSY;
diff --git a/libc/bionic/semaphore.cpp b/libc/bionic/semaphore.cpp
index d401b66..e0486b4 100644
--- a/libc/bionic/semaphore.cpp
+++ b/libc/bionic/semaphore.cpp
@@ -41,7 +41,6 @@
#include "private/bionic_constants.h"
#include "private/bionic_futex.h"
-#include "private/bionic_sdk_version.h"
#include "private/bionic_time_conversions.h"
// In this implementation, a semaphore contains a
@@ -222,7 +221,7 @@
}
int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, false, nullptr);
- if (bionic_get_application_target_sdk_version() >= __ANDROID_API_N__) {
+ if (android_get_application_target_sdk_version() >= __ANDROID_API_N__) {
if (result ==-EINTR) {
errno = EINTR;
return -1;
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
index 29d902c..326d4b1 100644
--- a/libc/bionic/strerror_r.cpp
+++ b/libc/bionic/strerror_r.cpp
@@ -170,16 +170,6 @@
return __code_string_lookup(_sys_error_strings, error_number);
}
-static const Pair _sys_signal_strings[] = {
-#define __BIONIC_SIGDEF(signal_number, signal_description) { signal_number, signal_description },
-#include "private/bionic_sigdefs.h"
- { 0, nullptr }
-};
-
-extern "C" __LIBC_HIDDEN__ const char* __strsignal_lookup(int signal_number) {
- return __code_string_lookup(_sys_signal_strings, signal_number);
-}
-
int strerror_r(int error_number, char* buf, size_t buf_len) {
ErrnoRestorer errno_restorer;
size_t length;
@@ -203,21 +193,3 @@
strerror_r(error_number, buf, buf_len);
return buf; // ...and just returns whatever fit.
}
-
-extern "C" __LIBC_HIDDEN__ const char* __strsignal(int signal_number, char* buf, size_t buf_len) {
- const char* signal_name = __strsignal_lookup(signal_number);
- if (signal_name != nullptr) {
- return signal_name;
- }
-
- const char* prefix = "Unknown";
- if (signal_number >= SIGRTMIN && signal_number <= SIGRTMAX) {
- prefix = "Real-time";
- signal_number -= SIGRTMIN;
- }
- size_t length = snprintf(buf, buf_len, "%s signal %d", prefix, signal_number);
- if (length >= buf_len) {
- return nullptr;
- }
- return buf;
-}
diff --git a/libc/bionic/strsignal.cpp b/libc/bionic/strsignal.cpp
index 1cdfec1..5637431 100644
--- a/libc/bionic/strsignal.cpp
+++ b/libc/bionic/strsignal.cpp
@@ -26,20 +26,43 @@
* SUCH DAMAGE.
*/
+#include <signal.h>
#include <string.h>
#include "bionic/pthread_internal.h"
-extern "C" const char* __strsignal_lookup(int);
-extern "C" const char* __strsignal(int, char*, size_t);
+const char* const sys_siglist[NSIG] = {
+#define __BIONIC_SIGDEF(signal_number, signal_description) [ signal_number ] = signal_description,
+#include "private/bionic_sigdefs.h"
+};
-char* strsignal(int signal_number) {
- // Just return the original constant in the easy cases.
- char* result = const_cast<char*>(__strsignal_lookup(signal_number));
- if (result != nullptr) {
- return result;
+const char* const sys_signame[NSIG] = {
+#define __BIONIC_SIGDEF(signal_number, unused) [ signal_number ] = #signal_number + 3,
+#include "private/bionic_sigdefs.h"
+};
+
+extern "C" __LIBC_HIDDEN__ const char* __strsignal(int signal_number, char* buf, size_t buf_len) {
+ const char* signal_name = nullptr;
+ if (signal_number >= 0 && signal_number < NSIG) {
+ signal_name = sys_siglist[signal_number];
+ }
+ if (signal_name != nullptr) {
+ return signal_name;
}
+ const char* prefix = "Unknown";
+ if (signal_number >= SIGRTMIN && signal_number <= SIGRTMAX) {
+ prefix = "Real-time";
+ signal_number -= SIGRTMIN;
+ }
+ size_t length = snprintf(buf, buf_len, "%s signal %d", prefix, signal_number);
+ if (length >= buf_len) {
+ return nullptr;
+ }
+ return buf;
+}
+
+char* strsignal(int signal_number) {
bionic_tls& tls = __get_bionic_tls();
return const_cast<char*>(__strsignal(signal_number, tls.strsignal_buf, sizeof(tls.strsignal_buf)));
}
diff --git a/libc/bionic/sys_siglist.c b/libc/bionic/sys_siglist.c
deleted file mode 100644
index 8e33d64..0000000
--- a/libc/bionic/sys_siglist.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2008 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 <signal.h>
-
-const char* const sys_siglist[NSIG] = {
-#define __BIONIC_SIGDEF(signal_number, signal_description) [ signal_number ] = signal_description,
-#include "private/bionic_sigdefs.h"
-};
diff --git a/libc/bionic/sys_signame.c b/libc/bionic/sys_signame.c
deleted file mode 100644
index 5158b83..0000000
--- a/libc/bionic/sys_signame.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2009 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 <signal.h>
-
-const char* const sys_signame[NSIG] = {
-#define __BIONIC_SIGDEF(signal_number, unused) [ signal_number ] = #signal_number + 3,
-#include "private/bionic_sigdefs.h"
-};
diff --git a/libc/dns/include/resolv_netid.h b/libc/dns/include/resolv_netid.h
index c7e2823..aa31596 100644
--- a/libc/dns/include/resolv_netid.h
+++ b/libc/dns/include/resolv_netid.h
@@ -107,7 +107,6 @@
/* Internal use only. */
struct hostent *android_gethostbyaddrfornetcontext_proxy(const void *, socklen_t, int , const struct android_net_context *) __LIBC_HIDDEN__;
int android_getnameinfofornet(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int, unsigned, unsigned) __LIBC_HIDDEN__;
-FILE* android_open_proxy(void) __LIBC_HIDDEN__;
__END_DECLS
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
index f1488a9..4e1aa61 100644
--- a/libc/dns/net/getaddrinfo.c
+++ b/libc/dns/net/getaddrinfo.c
@@ -422,11 +422,10 @@
return EAI_NODATA;
}
- FILE* proxy = android_open_proxy();
+ FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+");
if (proxy == NULL) {
return EAI_SYSTEM;
}
-
netid = __netdClientDispatch.netIdForResolv(netid);
// Send the request.
diff --git a/libc/dns/net/gethnamaddr.c b/libc/dns/net/gethnamaddr.c
index 7589380..7e18840 100644
--- a/libc/dns/net/gethnamaddr.c
+++ b/libc/dns/net/gethnamaddr.c
@@ -565,34 +565,6 @@
return h_errno_to_result(errorp);
}
-__LIBC_HIDDEN__ FILE* android_open_proxy() {
- const char* cache_mode = getenv("ANDROID_DNS_MODE");
- bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
- if (!use_proxy) {
- return NULL;
- }
-
- int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (s == -1) {
- return NULL;
- }
-
- const int one = 1;
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
-
- struct sockaddr_un proxy_addr;
- memset(&proxy_addr, 0, sizeof(proxy_addr));
- proxy_addr.sun_family = AF_UNIX;
- strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
-
- if (TEMP_FAILURE_RETRY(connect(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
- close(s);
- return NULL;
- }
-
- return fdopen(s, "r+");
-}
-
static struct hostent *
android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen, int *he)
{
@@ -816,18 +788,16 @@
return hp;
}
-// very similar in proxy-ness to android_getaddrinfo_proxy
static struct hostent *
gethostbyname_internal(const char *name, int af, res_state res, struct hostent *hp, char *hbuf,
size_t hbuflen, int *errorp, const struct android_net_context *netcontext)
{
- FILE* proxy = android_open_proxy();
+ FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+");
if (proxy == NULL) {
// Either we're not supposed to be using the proxy or the proxy is unavailable.
res_setnetcontext(res, netcontext);
return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen, errorp);
}
-
unsigned netid = __netdClientDispatch.netIdForResolv(netcontext->app_netid);
// This is writing to system/netd/server/DnsProxyListener.cpp and changes
@@ -925,12 +895,11 @@
struct hostent *hp, char *hbuf, size_t hbuflen, int *he,
const struct android_net_context *netcontext)
{
- FILE* proxy = android_open_proxy();
+ FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+");
if (proxy == NULL) {
// Either we're not supposed to be using the proxy or the proxy is unavailable.
return android_gethostbyaddrfornetcontext_real(addr,len, af, hp, hbuf, hbuflen, he, netcontext);
}
-
char buf[INET6_ADDRSTRLEN]; //big enough for IPv4 and IPv6
const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
if (addrStr == NULL) {
diff --git a/libc/dns/net/getnameinfo.c b/libc/dns/net/getnameinfo.c
index 5fa4e37..31d07c5 100644
--- a/libc/dns/net/getnameinfo.c
+++ b/libc/dns/net/getnameinfo.c
@@ -68,6 +68,13 @@
#include <stddef.h>
#include <string.h>
+/* This macro is modelled after the ones in <netinet/in6.h>. */
+/* RFC 6052, section 2.1 */
+#define IN6_IS_ADDR_WKP(a) \
+ ((((a)->s6_addr32[0]) == ntohl(0x0064ff9b)) && \
+ (((a)->s6_addr32[1]) == 0) && \
+ (((a)->s6_addr32[2]) == 0))
+
static const struct afd {
int a_af;
socklen_t a_addrlen;
@@ -248,6 +255,8 @@
;
else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
;
+ else if (IN6_IS_ADDR_WKP(&sin6->sin6_addr))
+ ;
else
flags |= NI_NUMERICHOST;
break;
diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index d0673ef..f4c590f 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -2068,14 +2068,19 @@
// max_samples actually change, in practice the overhead of checking is higher than the
// cost, and overflows are unlikely
++cache_info->revision_id;
- } else if (cache_info->params.max_samples != old_max_samples) {
- // If the maximum number of samples changes, the overhead of keeping the most recent
- // samples around is not considered worth the effort, so they are cleared instead. All
- // other parameters do not affect shared state: Changing these parameters does not
- // invalidate the samples, as they only affect aggregation and the conditions under
- // which servers are considered usable.
- _res_cache_clear_stats_locked(cache_info);
- ++cache_info->revision_id;
+ } else {
+ if (cache_info->params.max_samples != old_max_samples) {
+ // If the maximum number of samples changes, the overhead of keeping the most recent
+ // samples around is not considered worth the effort, so they are cleared instead.
+ // All other parameters do not affect shared state: Changing these parameters does
+ // not invalidate the samples, as they only affect aggregation and the conditions
+ // under which servers are considered usable.
+ _res_cache_clear_stats_locked(cache_info);
+ ++cache_info->revision_id;
+ }
+ for (unsigned j = 0; j < numservers; j++) {
+ freeaddrinfo(nsaddrinfo[j]);
+ }
}
// Always update the search paths, since determining whether they actually changed is
diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h
index 3a8f926..a175857 100644
--- a/libc/include/android/api-level.h
+++ b/libc/include/android/api-level.h
@@ -35,6 +35,8 @@
#include <sys/cdefs.h>
+__BEGIN_DECLS
+
#ifndef __ANDROID_API_FUTURE__
/**
* Magic version number for an Android OS build which has
@@ -97,3 +99,39 @@
/** Names the "Q" API level (29), for comparisons against __ANDROID_API__. */
#define __ANDROID_API_Q__ 29
+
+/**
+ * Returns the `targetSdkVersion` of the caller, or `__ANDROID_API_FUTURE__`
+ * if there is no known target SDK version (for code not running in the
+ * context of an app).
+ *
+ * The returned values correspond to the named constants in `<android/api-level.h>`,
+ * and is equivalent to the AndroidManifest.xml `targetSdkVersion`.
+ *
+ * See also android_get_device_api_level().
+ *
+ * Available since API level 24.
+ */
+int android_get_application_target_sdk_version() __INTRODUCED_IN(24);
+
+#if __ANDROID_API__ < __ANDROID_API_Q__
+
+// android_get_device_api_level is a static inline before API level 29.
+#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
+#include <bits/get_device_api_level_inlines.h>
+#undef __BIONIC_GET_DEVICE_API_LEVEL_INLINE
+
+#else
+
+/**
+ * Returns the API level of the device we're actually running on, or -1 on failure.
+ * The returned values correspond to the named constants in `<android/api-level.h>`,
+ * and is equivalent to the Java `Build.VERSION.SDK_INT` API.
+ *
+ * See also android_get_application_target_sdk_version().
+ */
+int android_get_device_api_level() __INTRODUCED_IN(29);
+
+#endif
+
+__END_DECLS
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index 431e5ce..e78be39 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -100,34 +100,11 @@
*/
ANDROID_DLEXT_FORCE_LOAD = 0x40,
- /**
- * When set, if the minimum `p_vaddr` of the ELF file's `PT_LOAD` segments is non-zero,
- * the dynamic linker will load it at that address.
- *
- * This flag is for ART internal use only.
- */
- ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80,
-
- /**
- * Instructs dlopen to load the library at the address specified by reserved_addr.
- *
- * The difference between `ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS` and
- * `ANDROID_DLEXT_RESERVED_ADDRESS` is that for `ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS` the linker
- * reserves memory at `reserved_addr` whereas for `ANDROID_DLEXT_RESERVED_ADDRESS` the linker
- * relies on the caller to reserve the memory.
- *
- * This flag can be used with `ANDROID_DLEXT_FORCE_FIXED_VADDR`. When
- * `ANDROID_DLEXT_FORCE_FIXED_VADDR` is set and `load_bias` is not 0 (`load_bias` is the
- * minimum `p_vaddr` of all `PT_LOAD` segments) this flag is ignored because the linker has to
- * pick one address over the other and this way is more convenient for ART.
- * Note that `ANDROID_DLEXT_FORCE_FIXED_VADDR` does not generate an error when the minimum
- * `p_vaddr` is 0.
- *
- * Cannot be used with `ANDROID_DLEXT_RESERVED_ADDRESS` or `ANDROID_DLEXT_RESERVED_ADDRESS_HINT`.
- *
- * This flag is for ART internal use only.
- */
- ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS = 0x100,
+ // Historically we had two other options for ART.
+ // They were last available in Android P.
+ // Reuse these bits last!
+ // ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80
+ // ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS = 0x100
/**
* This flag used to load library in a different namespace. The namespace is
@@ -145,8 +122,6 @@
ANDROID_DLEXT_USE_LIBRARY_FD |
ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
ANDROID_DLEXT_FORCE_LOAD |
- ANDROID_DLEXT_FORCE_FIXED_VADDR |
- ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS |
ANDROID_DLEXT_USE_NAMESPACE,
};
diff --git a/libc/include/android/versioning.h b/libc/include/android/versioning.h
index 6e4b8ab..01fa348 100644
--- a/libc/include/android/versioning.h
+++ b/libc/include/android/versioning.h
@@ -14,23 +14,16 @@
* limitations under the License.
*/
-#ifndef ANDROID_VERSIONING_H
-#define ANDROID_VERSIONING_H
+#pragma once
-#ifndef __STRING
-#define __STRING(x) #x
-#endif
-
-#define __INTRODUCED_IN(api_level) __attribute__((annotate("introduced_in=" __STRING(api_level))))
+#define __INTRODUCED_IN(api_level) __attribute__((annotate("introduced_in=" #api_level)))
#define __INTRODUCED_IN_FUTURE __attribute__((annotate("introduced_in_future")))
-#define __DEPRECATED_IN(api_level) __attribute__((annotate("deprecated_in=" __STRING(api_level))))
-#define __REMOVED_IN(api_level) __attribute__((annotate("obsoleted_in=" __STRING(api_level))))
-#define __INTRODUCED_IN_32(api_level) __attribute__((annotate("introduced_in_32=" __STRING(api_level))))
-#define __INTRODUCED_IN_64(api_level) __attribute__((annotate("introduced_in_64=" __STRING(api_level))))
-#define __INTRODUCED_IN_ARM(api_level) __attribute__((annotate("introduced_in_arm=" __STRING(api_level))))
-#define __INTRODUCED_IN_X86(api_level) __attribute__((annotate("introduced_in_x86=" __STRING(api_level))))
-#define __INTRODUCED_IN_MIPS(api_level) __attribute__((annotate("introduced_in_mips=" __STRING(api_level))))
+#define __DEPRECATED_IN(api_level) __attribute__((annotate("deprecated_in=" #api_level)))
+#define __REMOVED_IN(api_level) __attribute__((annotate("obsoleted_in=" #api_level)))
+#define __INTRODUCED_IN_32(api_level) __attribute__((annotate("introduced_in_32=" #api_level)))
+#define __INTRODUCED_IN_64(api_level) __attribute__((annotate("introduced_in_64=" #api_level)))
+#define __INTRODUCED_IN_ARM(api_level) __attribute__((annotate("introduced_in_arm=" #api_level)))
+#define __INTRODUCED_IN_X86(api_level) __attribute__((annotate("introduced_in_x86=" #api_level)))
+#define __INTRODUCED_IN_MIPS(api_level) __attribute__((annotate("introduced_in_mips=" #api_level)))
#define __VERSIONER_NO_GUARD __attribute__((annotate("versioner_no_guard")))
-
-#endif /* ANDROID_VERSIONING_H */
diff --git a/libc/include/bits/get_device_api_level_inlines.h b/libc/include/bits/get_device_api_level_inlines.h
index 8e17814..9c6e243 100644
--- a/libc/include/bits/get_device_api_level_inlines.h
+++ b/libc/include/bits/get_device_api_level_inlines.h
@@ -28,18 +28,20 @@
#pragma once
-#include <stdlib.h>
#include <sys/cdefs.h>
-#include <sys/system_properties.h>
#if !defined(__BIONIC_GET_DEVICE_API_LEVEL_INLINE)
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
+#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static inline /* for versioner */
#endif
__BEGIN_DECLS
+// Avoid circular dependencies since this is exposed from <sys/cdefs.h>.
+int __system_property_get(const char* __name, char* __value);
+int atoi(const char* __s) __attribute_pure__;
+
__BIONIC_GET_DEVICE_API_LEVEL_INLINE int android_get_device_api_level() {
- char value[PROP_VALUE_MAX] = { 0 };
+ char value[92] = { 0 };
if (__system_property_get("ro.build.version.sdk", value) < 1) return -1;
int api_level = atoi(value);
return (api_level > 0) ? api_level : -1;
diff --git a/libc/include/bits/ioctl.h b/libc/include/bits/ioctl.h
index 9ed1292..fd31a58 100644
--- a/libc/include/bits/ioctl.h
+++ b/libc/include/bits/ioctl.h
@@ -54,11 +54,8 @@
* type of the ioctl you prefer, ...), or
* - defining BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD, which will make the
* overloading go away.
- *
- * FIXME: __has_extension is more or less a clang version check. Remove it when
- * we don't need to support old clang code.
*/
-#if __has_extension(overloadable_unmarked) && !defined(BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD)
+#if !defined(BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD)
/* enable_if(1) just exists to break overloading ties. */
int ioctl(int __fd, unsigned __request, ...) __overloadable __enable_if(1, "") __RENAME(ioctl);
#endif
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 42237d0..eba18a8 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -31,12 +31,7 @@
__BEGIN_DECLS
-// Remove this workaround once b/37423073 is fixed.
-#if !__has_attribute(alloc_size)
-#define __BIONIC_ALLOC_SIZE(...)
-#else
#define __BIONIC_ALLOC_SIZE(...) __attribute__((__alloc_size__(__VA_ARGS__)))
-#endif
/**
* [malloc(3)](http://man7.org/linux/man-pages/man3/malloc.3.html) allocates
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 9d1030a..c788ca6 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -114,7 +114,7 @@
int pthread_kill(pthread_t __pthread, int __signal);
#if defined(__USE_GNU)
-int pthread_sigqueue(pthread_t __pthread, int __signal, const union sigval __value) __INTRODUCED_IN(__ANDROID_API_Q__);
+int pthread_sigqueue(pthread_t __pthread, int __signal, const union sigval __value) __INTRODUCED_IN(29);
#endif
int pthread_sigmask(int __how, const sigset_t* __new_set, sigset_t* __old_set);
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 26a05c8..e9d0e4b 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -34,36 +34,10 @@
* @(#)cdefs.h 8.8 (Berkeley) 1/9/95
*/
-#ifndef _SYS_CDEFS_H_
-#define _SYS_CDEFS_H_
-
-#include <android/api-level.h>
+#pragma once
#define __BIONIC__ 1
-/*
- * Testing against Clang-specific extensions.
- */
-#ifndef __has_extension
-#define __has_extension __has_feature
-#endif
-#ifndef __has_feature
-#define __has_feature(x) 0
-#endif
-#ifndef __has_include
-#define __has_include(x) 0
-#endif
-#ifndef __has_builtin
-#define __has_builtin(x) 0
-#endif
-#ifndef __has_attribute
-#define __has_attribute(x) 0
-#endif
-
-#define __strong_alias(alias, sym) \
- __asm__(".global " #alias "\n" \
- #alias " = " #sym);
-
#if defined(__cplusplus)
#define __BEGIN_DECLS extern "C" {
#define __END_DECLS }
@@ -72,6 +46,10 @@
#define __END_DECLS
#endif
+#define __strong_alias(alias, sym) \
+ __asm__(".global " #alias "\n" \
+ #alias " = " #sym);
+
#if defined(__cplusplus)
#define __BIONIC_CAST(_k,_t,_v) (_k<_t>(_v))
#else
@@ -88,22 +66,19 @@
* strings produced by the __STRING macro, but this only works with ANSI C.
*/
-#define ___STRING(x) __STRING(x)
-#define ___CONCAT(x,y) __CONCAT(x,y)
-
#define __P(protos) protos /* full-blown ANSI C */
+
#define __CONCAT1(x,y) x ## y
#define __CONCAT(x,y) __CONCAT1(x,y)
+#define ___CONCAT(x,y) __CONCAT(x,y)
+
#define __STRING(x) #x
+#define ___STRING(x) __STRING(x)
#if defined(__cplusplus)
#define __inline inline /* convert to C++ keyword */
#endif /* !__cplusplus */
-#include <android/versioning.h>
-
-#include <android/versioning.h>
-
#define __always_inline __attribute__((__always_inline__))
#define __attribute_const__ __attribute__((__const__))
#define __attribute_pure__ __attribute__((__pure__))
@@ -359,4 +334,5 @@
*/
#define __unsafe_check_mul_overflow(x, y) ((__SIZE_TYPE__)-1 / (x) < (y))
-#endif /* !_SYS_CDEFS_H_ */
+#include <android/versioning.h>
+#include <android/api-level.h>
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index 01f42b7..0961a94 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -63,11 +63,6 @@
},
},
- // Clang lld link flags do not work with special link rules
- // for libunwind_llvm yet. Linked aosp_arm-eng image failed to
- // boot up in the emulator. http://b/78118944.
- use_clang_lld: false,
-
static_libs: [
"libasync_safe",
"libbase",
diff --git a/libc/private/NetdClientDispatch.h b/libc/private/NetdClientDispatch.h
index 8d8947d..20e7f25 100644
--- a/libc/private/NetdClientDispatch.h
+++ b/libc/private/NetdClientDispatch.h
@@ -27,6 +27,7 @@
int (*connect)(int, const struct sockaddr*, socklen_t);
int (*socket)(int, int, int);
unsigned (*netIdForResolv)(unsigned);
+ int (*dnsOpenProxy)();
};
extern __LIBC_HIDDEN__ struct NetdClientDispatch __netdClientDispatch;
diff --git a/libc/private/bionic_constants.h b/libc/private/bionic_constants.h
index 9ae1c8d..e64c826 100644
--- a/libc/private/bionic_constants.h
+++ b/libc/private/bionic_constants.h
@@ -19,4 +19,14 @@
#define NS_PER_S 1000000000
+// Size of the shadow call stack. This must be a power of 2.
+#define SCS_SIZE (8 * 1024)
+
+// The shadow call stack is allocated at an aligned address within a guard region of this size. The
+// guard region must be large enough that we can allocate an SCS_SIZE-aligned SCS while ensuring
+// that there is at least one guard page after the SCS so that a stack overflow results in a SIGSEGV
+// instead of corrupting the allocation that comes after it.
+// TODO(b/118642754): Use a larger guard region.
+#define SCS_GUARD_REGION_SIZE (SCS_SIZE * 2)
+
#endif // _BIONIC_CONSTANTS_H_
diff --git a/libc/private/bionic_sdk_version.h b/libc/private/bionic_sdk_version.h
deleted file mode 100644
index 871d25c..0000000
--- a/libc/private/bionic_sdk_version.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _BIONIC_SDK_VERSION_H_
-#define _BIONIC_SDK_VERSION_H_
-
-#include <stdint.h>
-
-uint32_t bionic_get_application_target_sdk_version();
-
-#endif // _BIONIC_SDK_VERSION_H_
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index 01c580f..d78a5e7 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -489,6 +489,14 @@
if arch_list == "all":
for arch in all_arches:
t[arch] = True
+ elif arch_list == "lp32":
+ for arch in all_arches:
+ if "64" not in arch:
+ t[arch] = True
+ elif arch_list == "lp64":
+ for arch in all_arches:
+ if "64" in arch:
+ t[arch] = True
else:
for arch in string.split(arch_list, ','):
if arch in all_arches:
diff --git a/libc/tzcode/bionic.cpp b/libc/tzcode/bionic.cpp
index 9b59183..51fd39a 100644
--- a/libc/tzcode/bionic.cpp
+++ b/libc/tzcode/bionic.cpp
@@ -200,11 +200,15 @@
int fd;
#if defined(__ANDROID__)
- // On Android, try the two hard-coded locations.
+ // On Android, try the three hard-coded locations.
fd = __bionic_open_tzdata_path("/data/misc/zoneinfo/current/tzdata",
olson_id, entry_length);
if (fd >= 0) return fd;
+ fd = __bionic_open_tzdata_path("/apex/com.android.tzdata/etc/tzdata",
+ olson_id, entry_length);
+ if (fd >= 0) return fd;
+
fd = __bionic_open_tzdata_path("/system/usr/share/zoneinfo/tzdata",
olson_id, entry_length);
if (fd >= 0) return fd;
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 1fcfc58..28f0601 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -31,6 +31,7 @@
LIBC_N {
global:
+ android_get_application_target_sdk_version; # introduced=24 versioned=29
dlvsym; # introduced=24
} LIBC;
@@ -45,7 +46,6 @@
global:
__cfi_init;
android_dlwarning;
- android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 8d4019c..a03e9e1 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -30,6 +30,7 @@
LIBC_N {
global:
+ android_get_application_target_sdk_version; # introduced=24 versioned=29
dlvsym; # introduced=24
} LIBC;
@@ -44,7 +45,6 @@
global:
__cfi_init;
android_dlwarning;
- android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.cpp b/libdl/libdl.cpp
index 402804e..a468f81 100644
--- a/libdl/libdl.cpp
+++ b/libdl/libdl.cpp
@@ -67,10 +67,10 @@
const void* caller_addr);
__attribute__((__weak__, visibility("default")))
-void __loader_android_set_application_target_sdk_version(uint32_t target);
+void __loader_android_set_application_target_sdk_version(int target);
__attribute__((__weak__, visibility("default")))
-uint32_t __loader_android_get_application_target_sdk_version();
+int __loader_android_get_application_target_sdk_version();
__attribute__((__weak__, visibility("default")))
bool __loader_android_init_anonymous_namespace(const char* shared_libs_sonames,
@@ -165,12 +165,12 @@
}
__attribute__((__weak__))
-void android_set_application_target_sdk_version(uint32_t target) {
+void android_set_application_target_sdk_version(int target) {
__loader_android_set_application_target_sdk_version(target);
}
__attribute__((__weak__))
-uint32_t android_get_application_target_sdk_version() {
+int android_get_application_target_sdk_version() {
return __loader_android_get_application_target_sdk_version();
}
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 002e9f8..c5d1be4 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -30,6 +30,7 @@
LIBC_N {
global:
+ android_get_application_target_sdk_version; # introduced=24 versioned=29
dlvsym; # introduced=24
} LIBC;
@@ -44,7 +45,6 @@
global:
__cfi_init;
android_dlwarning;
- android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 8d4019c..a03e9e1 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -30,6 +30,7 @@
LIBC_N {
global:
+ android_get_application_target_sdk_version; # introduced=24 versioned=29
dlvsym; # introduced=24
} LIBC;
@@ -44,7 +45,6 @@
global:
__cfi_init;
android_dlwarning;
- android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 8d4019c..a03e9e1 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -30,6 +30,7 @@
LIBC_N {
global:
+ android_get_application_target_sdk_version; # introduced=24 versioned=29
dlvsym; # introduced=24
} LIBC;
@@ -44,7 +45,6 @@
global:
__cfi_init;
android_dlwarning;
- android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 8d4019c..a03e9e1 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -30,6 +30,7 @@
LIBC_N {
global:
+ android_get_application_target_sdk_version; # introduced=24 versioned=29
dlvsym; # introduced=24
} LIBC;
@@ -44,7 +45,6 @@
global:
__cfi_init;
android_dlwarning;
- android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 8d4019c..a03e9e1 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -30,6 +30,7 @@
LIBC_N {
global:
+ android_get_application_target_sdk_version; # introduced=24 versioned=29
dlvsym; # introduced=24
} LIBC;
@@ -44,7 +45,6 @@
global:
__cfi_init;
android_dlwarning;
- android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
diff --git a/libm/Android.bp b/libm/Android.bp
index 6d55967..e4ba20d 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -514,6 +514,9 @@
integer_overflow: false,
},
stl: "none",
+
+ // TODO(ivanlozano): Remove after b/118321713
+ xom: false,
}
ndk_library {
diff --git a/linker/Android.bp b/linker/Android.bp
index 779cd3f..a9907ca 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -167,10 +167,6 @@
"-Wl,-soname,ld-android.so",
],
- // lld bug: https://bugs.llvm.org/show_bug.cgi?id=36295
- // error: symbol __aeabi_*@@LIBC_N has undefined version LIBC_N
- use_clang_lld: false,
-
cflags: [
"-fno-stack-protector",
"-Wstrict-overflow=5",
@@ -293,6 +289,7 @@
},
},
compile_multilib: "both",
+ xom: false,
}
cc_library {
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index dfe8e8c..45ae6ed 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -57,7 +57,7 @@
const android_dlextinfo* extinfo,
const void* caller_addr) __LINKER_PUBLIC__;
void __loader_android_dlwarning(void* obj, void (*f)(void*, const char*)) __LINKER_PUBLIC__;
-uint32_t __loader_android_get_application_target_sdk_version() __LINKER_PUBLIC__;
+int __loader_android_get_application_target_sdk_version() __LINKER_PUBLIC__;
void __loader_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) __LINKER_PUBLIC__;
android_namespace_t* __loader_android_get_exported_namespace(const char* name) __LINKER_PUBLIC__;
bool __loader_android_init_anonymous_namespace(const char* shared_libs_sonames,
@@ -67,7 +67,7 @@
const char* shared_libs_sonames) __LINKER_PUBLIC__;
bool __loader_android_link_namespaces_all_libs(android_namespace_t* namespace_from,
android_namespace_t* namespace_to) __LINKER_PUBLIC__;
-void __loader_android_set_application_target_sdk_version(uint32_t target) __LINKER_PUBLIC__;
+void __loader_android_set_application_target_sdk_version(int target) __LINKER_PUBLIC__;
void __loader_android_update_LD_LIBRARY_PATH(const char* ld_library_path) __LINKER_PUBLIC__;
void __loader_cfi_fail(uint64_t CallSiteTypeId,
void* Ptr,
@@ -204,13 +204,13 @@
}
#endif
-void __loader_android_set_application_target_sdk_version(uint32_t target) {
+void __loader_android_set_application_target_sdk_version(int target) {
// lock to avoid modification in the middle of dlopen.
ScopedPthreadMutexLocker locker(&g_dl_mutex);
set_application_target_sdk_version(target);
}
-uint32_t __loader_android_get_application_target_sdk_version() {
+int __loader_android_get_application_target_sdk_version() {
return get_application_target_sdk_version();
}
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 6d646a2..b437f06 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2088,13 +2088,6 @@
return nullptr;
}
- if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
- (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
- DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
- "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
- return nullptr;
- }
-
if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
if (extinfo->library_namespace == nullptr) {
DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
diff --git a/linker/linker.h b/linker/linker.h
index dd45f67..91d3ddf 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -131,8 +131,8 @@
// void ___cfi_slowpath_diag(uint64_t CallSiteTypeId, void *Ptr, void *DiagData, void *Ret);
void ___cfi_fail(uint64_t CallSiteTypeId, void* Ptr, void *DiagData, void *Ret);
-void set_application_target_sdk_version(uint32_t target);
-uint32_t get_application_target_sdk_version();
+void set_application_target_sdk_version(int target);
+int get_application_target_sdk_version();
enum {
/* A regular namespace is the namespace with a custom search path that does
diff --git a/linker/linker_allocator.cpp b/linker/linker_allocator.cpp
index de3309b..8b05a7e 100644
--- a/linker/linker_allocator.cpp
+++ b/linker/linker_allocator.cpp
@@ -222,6 +222,8 @@
first_block->free_blocks_cnt = free_blocks_cnt;
free_blocks_list_ = first_block;
+
+ free_pages_cnt_++;
}
diff --git a/linker/linker_config.h b/linker/linker_config.h
index 24c44f4..49739ee 100644
--- a/linker/linker_config.h
+++ b/linker/linker_config.h
@@ -140,7 +140,7 @@
return it == namespace_configs_map_.end() ? nullptr : it->second;
}
- uint32_t target_sdk_version() const {
+ int target_sdk_version() const {
return target_sdk_version_;
}
@@ -159,7 +159,7 @@
private:
void clear();
- void set_target_sdk_version(uint32_t target_sdk_version) {
+ void set_target_sdk_version(int target_sdk_version) {
target_sdk_version_ = target_sdk_version;
}
@@ -167,7 +167,7 @@
std::vector<std::unique_ptr<NamespaceConfig>> namespace_configs_;
std::unordered_map<std::string, NamespaceConfig*> namespace_configs_map_;
- uint32_t target_sdk_version_;
+ int target_sdk_version_;
DISALLOW_COPY_AND_ASSIGN(Config);
};
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index d88fc75..82b10b7 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -28,6 +28,9 @@
#include "linker_main.h"
+#include <link.h>
+#include <sys/auxv.h>
+
#include "linker_debug.h"
#include "linker_cfi.h"
#include "linker_gdb_support.h"
@@ -35,7 +38,6 @@
#include "linker_phdr.h"
#include "linker_utils.h"
-#include "private/bionic_auxv.h"
#include "private/bionic_globals.h"
#include "private/bionic_tls.h"
#include "private/KernelArgumentBlock.h"
@@ -48,12 +50,10 @@
#endif
#include <async_safe/log.h>
+#include <bionic/libc_init_common.h>
#include <vector>
-extern void __libc_init_globals(KernelArgumentBlock&);
-extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
-
__LIBC_HIDDEN__ extern "C" void _start();
static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 741d4e0..34ac606 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -525,14 +525,10 @@
// Reserve a virtual address range such that if it's limits were extended to the next 2**align
// boundary, it would not overlap with any existing mappings.
-static void* ReserveAligned(void* hint, size_t size, size_t align) {
+static void* ReserveAligned(size_t size, size_t align) {
int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
- // Address hint is only used in Art for the image mapping, and it is pretty important. Don't mess
- // with it.
- // FIXME: try an aligned allocation and fall back to plain mmap() if the former does not provide a
- // mapping at the requested address?
- if (align == PAGE_SIZE || hint != nullptr) {
- void* mmap_ptr = mmap(hint, size, PROT_NONE, mmap_flags, -1, 0);
+ if (align == PAGE_SIZE) {
+ void* mmap_ptr = mmap(nullptr, size, PROT_NONE, mmap_flags, -1, 0);
if (mmap_ptr == MAP_FAILED) {
return nullptr;
}
@@ -575,9 +571,6 @@
void* start;
size_t reserved_size = 0;
bool reserved_hint = true;
- bool strict_hint = false;
- // Assume position independent executable by default.
- void* mmap_hint = nullptr;
if (extinfo != nullptr) {
if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
@@ -586,13 +579,6 @@
} else if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS_HINT) {
reserved_size = extinfo->reserved_size;
}
-
- if (addr != nullptr && (extinfo->flags & ANDROID_DLEXT_FORCE_FIXED_VADDR) != 0) {
- mmap_hint = addr;
- } else if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0) {
- mmap_hint = extinfo->reserved_addr;
- strict_hint = true;
- }
}
if (load_size_ > reserved_size) {
@@ -601,17 +587,11 @@
reserved_size - load_size_, load_size_, name_.c_str());
return false;
}
- start = ReserveAligned(mmap_hint, load_size_, kLibraryAlignment);
+ start = ReserveAligned(load_size_, kLibraryAlignment);
if (start == nullptr) {
DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_.c_str());
return false;
}
- if (strict_hint && (start != mmap_hint)) {
- munmap(start, load_size_);
- DL_ERR("couldn't reserve %zd bytes of address space at %p for \"%s\"",
- load_size_, mmap_hint, name_.c_str());
- return false;
- }
} else {
start = extinfo->reserved_addr;
mapped_by_caller_ = true;
diff --git a/linker/linker_sdk_versions.cpp b/linker/linker_sdk_versions.cpp
index 7bfa26c..b06f3e6 100644
--- a/linker/linker_sdk_versions.cpp
+++ b/linker/linker_sdk_versions.cpp
@@ -30,9 +30,9 @@
#include <android/api-level.h>
#include <atomic>
-static std::atomic<uint32_t> g_target_sdk_version(__ANDROID_API__);
+static std::atomic<int> g_target_sdk_version(__ANDROID_API__);
-void set_application_target_sdk_version(uint32_t target) {
+void set_application_target_sdk_version(int target) {
// translate current sdk_version to platform sdk_version
if (target == 0) {
target = __ANDROID_API__;
@@ -40,7 +40,7 @@
g_target_sdk_version = target;
}
-uint32_t get_application_target_sdk_version() {
+int get_application_target_sdk_version() {
return g_target_sdk_version;
}
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index e630297..93079ca 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -44,7 +44,7 @@
// TODO(dimitry): These functions are currently located in linker.cpp - find a better place for it
bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym);
ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr);
-uint32_t get_application_target_sdk_version();
+int get_application_target_sdk_version();
soinfo::soinfo(android_namespace_t* ns, const char* realpath,
const struct stat* file_stat, off64_t file_offset,
@@ -719,7 +719,7 @@
// This function returns api-level at the time of
// dlopen/load. Note that libraries opened by system
// will always have 'current' api level.
-uint32_t soinfo::get_target_sdk_version() const {
+int soinfo::get_target_sdk_version() const {
if (!has_min_version(2)) {
return __ANDROID_API__;
}
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 7331b2f..44bff28 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -276,7 +276,7 @@
ElfW(Addr) get_verdef_ptr() const;
size_t get_verdef_cnt() const;
- uint32_t get_target_sdk_version() const;
+ int get_target_sdk_version() const;
void set_dt_runpath(const char *);
const std::vector<std::string>& get_dt_runpath() const;
@@ -353,7 +353,7 @@
ElfW(Addr) verneed_ptr_;
size_t verneed_cnt_;
- uint32_t target_sdk_version_;
+ int target_sdk_version_;
// version >= 3
std::vector<std::string> dt_runpath_;
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index 72a8fa8..e926671 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -235,6 +235,13 @@
}
resolved_paths->push_back(std::string(resolved_path) + kZipFileSeparator + entry_path);
+ } else {
+ struct stat s;
+ if (stat(normalized_path.c_str(), &s) == 0 && S_ISDIR(s.st_mode)) {
+ // Path is not a zip path, but an existing directory. Then add it
+ // although we failed to resolve it. b/119656753
+ resolved_paths->push_back(normalized_path);
+ }
}
}
}
diff --git a/linker/tests/Android.mk b/linker/tests/Android.mk
index 8284bea..9268e31 100644
--- a/linker/tests/Android.mk
+++ b/linker/tests/Android.mk
@@ -51,6 +51,6 @@
../linker_config.cpp \
../linker_utils.cpp \
-LOCAL_STATIC_LIBRARIES += libasync_safe libbase
+LOCAL_STATIC_LIBRARIES += libasync_safe libbase liblog
include $(BUILD_NATIVE_TEST)
diff --git a/linker/tests/linker_config_test.cpp b/linker/tests/linker_config_test.cpp
index 9208d9d..14fd132 100644
--- a/linker/tests/linker_config_test.cpp
+++ b/linker/tests/linker_config_test.cpp
@@ -37,10 +37,9 @@
#include <unistd.h>
+#include <android-base/file.h>
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
-#include <android-base/file.h>
-#include <android-base/test_utils.h>
#if defined(__LP64__)
#define ARCH_SUFFIX "64"
@@ -144,7 +143,7 @@
ASSERT_TRUE(config != nullptr);
ASSERT_TRUE(error_msg.empty());
- ASSERT_EQ(113U, config->target_sdk_version());
+ ASSERT_EQ(113, config->target_sdk_version());
const NamespaceConfig* default_ns_config = config->default_namespace_config();
ASSERT_TRUE(default_ns_config != nullptr);
diff --git a/tests/Android.bp b/tests/Android.bp
index 4ad51da..899fc66 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -102,6 +102,7 @@
"limits_test.cpp",
"linux_swab_test.cpp",
"locale_test.cpp",
+ "malloc_iterate_test.cpp",
"malloc_test.cpp",
"math_test.cpp",
"math_force_long_double_test.cpp",
@@ -120,6 +121,7 @@
"regex_test.cpp",
"resolv_test.cpp",
"sched_test.cpp",
+ "scs_test.cpp",
"scsi_sg_test.cpp",
"search_test.cpp",
"semaphore_test.cpp",
@@ -196,6 +198,7 @@
bionic: {
whole_static_libs: [
"libasync_safe",
+ "libprocinfo",
"libsystemproperties",
],
},
@@ -628,6 +631,10 @@
static_executable: true,
stl: "libc++_static",
+
+ // libclang_rt.builtins does not work with libm
+ // http://b/117167374
+ no_libcrt: true,
}
// -----------------------------------------------------------------------------
diff --git a/tests/TemporaryFile.h b/tests/TemporaryFile.h
deleted file mode 100644
index 7853781..0000000
--- a/tests/TemporaryFile.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <android-base/macros.h>
-
-template <typename T = int (*)(char*)>
-class GenericTemporaryFile {
- public:
- explicit GenericTemporaryFile(T mk_fn = mkstemp) : mk_fn(mk_fn) {
- // Since we might be running on the host or the target, and if we're
- // running on the host we might be running under bionic or glibc,
- // let's just try both possible temporary directories and take the
- // first one that works.
- init("/data/local/tmp");
- if (fd == -1) {
- init("/tmp");
- }
- }
-
- explicit GenericTemporaryFile(const char* dirpath, T mk_fn = mkstemp) : mk_fn(mk_fn) {
- init(dirpath);
- }
-
- ~GenericTemporaryFile() {
- close(fd);
- unlink(filename);
- }
-
- void reopen() {
- close(fd);
- fd = open(filename, O_RDWR);
- }
-
- int fd;
- char filename[1024];
-
- private:
- T mk_fn;
-
- void init(const char* tmp_dir) {
- snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
- fd = mk_fn(filename);
- }
-
- DISALLOW_COPY_AND_ASSIGN(GenericTemporaryFile);
-};
-
-typedef GenericTemporaryFile<> TemporaryFile;
-
-class TemporaryDir {
- public:
- TemporaryDir() {
- if (!init("/data/local/tmp")) {
- init("/tmp");
- }
- }
-
- ~TemporaryDir() {
- rmdir(dirname);
- }
-
- char dirname[1024];
-
- private:
- bool init(const char* tmp_dir) {
- snprintf(dirname, sizeof(dirname), "%s/TemporaryDir-XXXXXX", tmp_dir);
- return (mkdtemp(dirname) != nullptr);
- }
-
- DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
-};
diff --git a/tests/android_get_device_api_level.cpp b/tests/android_get_device_api_level.cpp
index 5272a48..0662404 100644
--- a/tests/android_get_device_api_level.cpp
+++ b/tests/android_get_device_api_level.cpp
@@ -29,7 +29,7 @@
#include <gtest/gtest.h>
#if __BIONIC__
-#include <android/get_device_api_level.h>
+#include <android/api-level.h>
#endif
TEST(android_get_device_api_level, smoke) {
diff --git a/tests/buffer_tests.cpp b/tests/buffer_tests.cpp
index a5a0c2a..7563448 100644
--- a/tests/buffer_tests.cpp
+++ b/tests/buffer_tests.cpp
@@ -227,6 +227,18 @@
}
}
+// Malloc can return a tagged pointer, which is not accepted in mm system calls like mprotect.
+// Clear top 8 bits of the address on 64-bit platforms.
+static int MprotectHeap(void* addr, size_t len, int prot) {
+#if defined(__LP64__)
+ constexpr uintptr_t mask = (static_cast<uintptr_t>(1) << 56) - 1;
+ void* untagged_addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & mask);
+#else
+ void* untagged_addr = addr;
+#endif
+ return mprotect(untagged_addr, len, prot);
+}
+
void RunSingleBufferAlignTest(
size_t max_test_size, void (*test_func)(uint8_t*, size_t),
size_t (*set_incr)(size_t)) {
@@ -358,14 +370,14 @@
memset(memory, 0x23, 2*pagesize);
// Make the second page unreadable and unwritable.
- ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_NONE) == 0);
+ ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_NONE) == 0);
for (size_t i = 0; i < pagesize; i++) {
uint8_t* buf = &memory[pagesize-i];
test_func(buf, i);
}
- ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
+ ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
free(memory);
}
@@ -379,7 +391,7 @@
memset(memory, 0x23, 2*pagesize);
// Make the second page unreadable and unwritable.
- ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_NONE) == 0);
+ ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_NONE) == 0);
uint8_t* dst_buffer = new uint8_t[2*pagesize];
// Change the dst alignment as we change the source.
@@ -391,7 +403,7 @@
test_func(src, dst, j);
}
}
- ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
+ ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
free(memory);
delete[] dst_buffer;
}
@@ -409,7 +421,7 @@
memset(memory1, 0x23, 2*pagesize);
// Make the second page unreadable and unwritable.
- ASSERT_TRUE(mprotect(&memory1[pagesize], pagesize, PROT_NONE) == 0);
+ ASSERT_TRUE(MprotectHeap(&memory1[pagesize], pagesize, PROT_NONE) == 0);
uint8_t* memory2;
ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory2), pagesize,
@@ -417,7 +429,7 @@
memset(memory2, 0x23, 2*pagesize);
// Make the second page unreadable and unwritable.
- ASSERT_TRUE(mprotect(&memory2[pagesize], pagesize, PROT_NONE) == 0);
+ ASSERT_TRUE(MprotectHeap(&memory2[pagesize], pagesize, PROT_NONE) == 0);
for (size_t i = 0; i < pagesize; i++) {
uint8_t* buf1 = &memory1[pagesize-i];
@@ -445,8 +457,8 @@
}
}
- ASSERT_TRUE(mprotect(&memory1[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
- ASSERT_TRUE(mprotect(&memory2[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
+ ASSERT_TRUE(MprotectHeap(&memory1[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
+ ASSERT_TRUE(MprotectHeap(&memory2[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
free(memory1);
free(memory2);
}
diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp
index cb98cae..18ba011 100644
--- a/tests/dl_test.cpp
+++ b/tests/dl_test.cpp
@@ -31,7 +31,7 @@
#include <fstream>
#include "gtest_globals.h"
-#include "TemporaryFile.h"
+#include <android-base/file.h>
#include "utils.h"
extern "C" int main_global_default_serial() {
@@ -136,6 +136,7 @@
TEST(dl, preinit_system_calls) {
#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN; // hwasan not initialized in preinit_array
std::string helper = GetTestlibRoot() +
"/preinit_syscall_test_helper/preinit_syscall_test_helper";
chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
@@ -153,6 +154,9 @@
ExecTestHelper eth;
eth.SetArgs({ helper.c_str(), nullptr });
eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, nullptr);
+#else
+ // Force a failure when not compiled for bionic so the test is considered a pass.
+ ASSERT_TRUE(false);
#endif
}
@@ -235,6 +239,7 @@
// whose search paths include the 'ns2/' subdir.
TEST(dl, exec_with_ld_config_file) {
#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN; // libclang_rt.hwasan is not found with custom ld config
if (!is_debuggable_build()) {
// LD_CONFIG_FILE is not supported on user build
return;
@@ -242,8 +247,8 @@
std::string helper = GetTestlibRoot() +
"/ld_config_test_helper/ld_config_test_helper";
TemporaryFile config_file;
- create_ld_config_file(config_file.filename);
- std::string env = std::string("LD_CONFIG_FILE=") + config_file.filename;
+ create_ld_config_file(config_file.path);
+ std::string env = std::string("LD_CONFIG_FILE=") + config_file.path;
chmod(helper.c_str(), 0755);
ExecTestHelper eth;
eth.SetArgs({ helper.c_str(), nullptr });
@@ -257,6 +262,7 @@
// additional namespaces other than the default namespace.
TEST(dl, exec_with_ld_config_file_with_ld_preload) {
#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN; // libclang_rt.hwasan is not found with custom ld config
if (!is_debuggable_build()) {
// LD_CONFIG_FILE is not supported on user build
return;
@@ -264,8 +270,8 @@
std::string helper = GetTestlibRoot() +
"/ld_config_test_helper/ld_config_test_helper";
TemporaryFile config_file;
- create_ld_config_file(config_file.filename);
- std::string env = std::string("LD_CONFIG_FILE=") + config_file.filename;
+ create_ld_config_file(config_file.path);
+ std::string env = std::string("LD_CONFIG_FILE=") + config_file.path;
std::string env2 = std::string("LD_PRELOAD=") + GetTestlibRoot() + "/ld_config_test_helper_lib3.so";
chmod(helper.c_str(), 0755);
ExecTestHelper eth;
@@ -294,8 +300,8 @@
std::string helper = GetTestlibRoot() +
"/ld_config_test_helper/ld_config_test_helper";
TemporaryFile config_file;
- create_ld_config_file(config_file.filename);
- std::string env = std::string("LD_CONFIG_FILE=") + config_file.filename;
+ create_ld_config_file(config_file.path);
+ std::string env = std::string("LD_CONFIG_FILE=") + config_file.path;
chmod(helper.c_str(), 0755);
ExecTestHelper eth;
eth.SetArgs({ helper.c_str(), nullptr });
diff --git a/tests/dlext_private.h b/tests/dlext_private.h
index 2621a68..b338ae0 100644
--- a/tests/dlext_private.h
+++ b/tests/dlext_private.h
@@ -98,7 +98,7 @@
extern bool android_link_namespaces_all_libs(android_namespace_t* from,
android_namespace_t* to);
-extern void android_set_application_target_sdk_version(uint32_t target);
+extern void android_set_application_target_sdk_version(int target);
__END_DECLS
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index b33cf68..34013a7 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -40,7 +40,6 @@
#include <ziparchive/zip_archive.h>
#include "gtest_globals.h"
-#include "TemporaryFile.h"
#include "utils.h"
#include "dlext_private.h"
#include "dlfcn_symlink_support.h"
@@ -367,48 +366,6 @@
EXPECT_EQ(4, f());
}
-TEST_F(DlExtTest, LoadAtFixedAddress) {
- void* start = mmap(nullptr, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- ASSERT_TRUE(start != MAP_FAILED);
- munmap(start, kLibSize);
-
- android_dlextinfo extinfo;
- extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
- extinfo.reserved_addr = start;
-
- handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo);
- ASSERT_DL_NOTNULL(handle_);
- fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
- ASSERT_DL_NOTNULL(f);
- EXPECT_GE(reinterpret_cast<void*>(f), start);
- EXPECT_LT(reinterpret_cast<void*>(f), reinterpret_cast<char*>(start) + kLibSize);
-
- EXPECT_EQ(4, f());
- dlclose(handle_);
- handle_ = nullptr;
-
- // Check that dlclose unmapped the file
- void* addr = mmap(start, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- ASSERT_EQ(start, addr) << "dlclose did not unmap the memory";
-}
-
-TEST_F(DlExtTest, LoadAtFixedAddressTooSmall) {
- void* start = mmap(nullptr, kLibSize + PAGE_SIZE, PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- ASSERT_TRUE(start != MAP_FAILED);
- munmap(start, kLibSize + PAGE_SIZE);
- void* new_addr = mmap(reinterpret_cast<uint8_t*>(start) + PAGE_SIZE, kLibSize, PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- ASSERT_TRUE(new_addr != MAP_FAILED);
-
- android_dlextinfo extinfo;
- extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
- extinfo.reserved_addr = start;
-
- handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo);
- ASSERT_TRUE(handle_ == nullptr);
-}
-
class DlExtRelroSharingTest : public DlExtTest {
protected:
virtual void SetUp() {
@@ -477,7 +434,7 @@
TemporaryFile tf; // Use tf to get an unique filename.
ASSERT_NOERROR(close(tf.fd));
- ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.filename));
+ ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.path));
ASSERT_NO_FATAL_FAILURE(TryUsingRelro(kLibName));
// Use destructor of tf to close and unlink the file.
@@ -488,7 +445,7 @@
TemporaryFile tf; // // Use tf to get an unique filename.
ASSERT_NOERROR(close(tf.fd));
- ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibNameNoRelro, tf.filename));
+ ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibNameNoRelro, tf.path));
ASSERT_NO_FATAL_FAILURE(TryUsingRelro(kLibNameNoRelro));
// Use destructor of tf to close and unlink the file.
@@ -508,14 +465,14 @@
TemporaryFile tf; // Use tf to get an unique filename.
ASSERT_NOERROR(close(tf.fd));
- ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.filename));
+ ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.path));
int pipefd[2];
ASSERT_NOERROR(pipe(pipefd));
size_t without_sharing, with_sharing;
- ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.filename, false, &without_sharing));
- ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.filename, true, &with_sharing));
+ ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.path, false, &without_sharing));
+ ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.path, true, &with_sharing));
ASSERT_LT(with_sharing, without_sharing);
// We expect the sharing to save at least 50% of the library's total PSS.
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index da44fee..d7dce31 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -22,8 +22,7 @@
#include <sys/utsname.h>
#include <sys/vfs.h>
-#include "TemporaryFile.h"
-
+#include <android-base/file.h>
#include <android-base/stringprintf.h>
// Glibc v2.19 doesn't include these in fcntl.h so host builds will fail without.
@@ -307,7 +306,7 @@
// Without O_EXCL, we're allowed to give this a name later.
// (This is unrelated to the O_CREAT interaction with O_EXCL.)
const mode_t perms = S_IRUSR | S_IWUSR;
- int fd = open(dir.dirname, O_TMPFILE | O_RDWR, perms);
+ int fd = open(dir.path, O_TMPFILE | O_RDWR, perms);
// Ignore kernels without O_TMPFILE support (< 3.11).
if (fd == -1 && (errno == EISDIR || errno == EINVAL || errno == EOPNOTSUPP)) return;
@@ -322,7 +321,7 @@
// On Android if we're not root, we won't be able to create links anyway...
if (getuid() != 0) return;
- std::string final_path = android::base::StringPrintf("%s/named_now", dir.dirname);
+ std::string final_path = android::base::StringPrintf("%s/named_now", dir.path);
ASSERT_EQ(0, linkat(AT_FDCWD, android::base::StringPrintf("/proc/self/fd/%d", fd).c_str(),
AT_FDCWD, final_path.c_str(),
AT_SYMLINK_FOLLOW));
@@ -333,11 +332,11 @@
ASSERT_EQ(perms, (sb.st_mode & ~S_IFMT));
// With O_EXCL, you're not allowed to add a name later.
- fd = open(dir.dirname, O_TMPFILE | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
+ fd = open(dir.path, O_TMPFILE | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
ASSERT_TRUE(fd != -1) << strerror(errno);
errno = 0;
ASSERT_EQ(-1, linkat(AT_FDCWD, android::base::StringPrintf("/proc/self/fd/%d", fd).c_str(),
- AT_FDCWD, android::base::StringPrintf("%s/no_chance", dir.dirname).c_str(),
+ AT_FDCWD, android::base::StringPrintf("%s/no_chance", dir.path).c_str(),
AT_SYMLINK_FOLLOW));
ASSERT_EQ(ENOENT, errno);
ASSERT_EQ(0, close(fd));
diff --git a/tests/ftw_test.cpp b/tests/ftw_test.cpp
index 22ab399..dfc4d72 100644
--- a/tests/ftw_test.cpp
+++ b/tests/ftw_test.cpp
@@ -16,6 +16,7 @@
#include <ftw.h>
+#include <fcntl.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -23,8 +24,7 @@
#include <sys/types.h>
#include <unistd.h>
-#include "TemporaryFile.h"
-
+#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <gtest/gtest.h>
@@ -102,26 +102,26 @@
TEST(ftw, ftw) {
TemporaryDir root;
- MakeTree(root.dirname);
- ASSERT_EQ(0, ftw(root.dirname, check_ftw, 128));
+ MakeTree(root.path);
+ ASSERT_EQ(0, ftw(root.path, check_ftw, 128));
}
TEST(ftw, ftw64) {
TemporaryDir root;
- MakeTree(root.dirname);
- ASSERT_EQ(0, ftw64(root.dirname, check_ftw64, 128));
+ MakeTree(root.path);
+ ASSERT_EQ(0, ftw64(root.path, check_ftw64, 128));
}
TEST(ftw, nftw) {
TemporaryDir root;
- MakeTree(root.dirname);
- ASSERT_EQ(0, nftw(root.dirname, check_nftw, 128, 0));
+ MakeTree(root.path);
+ ASSERT_EQ(0, nftw(root.path, check_nftw, 128, 0));
}
TEST(ftw, nftw64) {
TemporaryDir root;
- MakeTree(root.dirname);
- ASSERT_EQ(0, nftw64(root.dirname, check_nftw64, 128, 0));
+ MakeTree(root.path);
+ ASSERT_EQ(0, nftw64(root.path, check_nftw64, 128, 0));
}
template <typename StatT>
@@ -145,13 +145,13 @@
TemporaryDir root;
- std::string path = android::base::StringPrintf("%s/unreadable-directory", root.dirname);
+ std::string path = android::base::StringPrintf("%s/unreadable-directory", root.path);
ASSERT_EQ(0, mkdir(path.c_str(), 0000)) << path;
- ASSERT_EQ(0, ftw(root.dirname, bug_28197840_ftw<struct stat>, 128));
- ASSERT_EQ(0, ftw64(root.dirname, bug_28197840_ftw<struct stat64>, 128));
- ASSERT_EQ(0, nftw(root.dirname, bug_28197840_nftw<struct stat>, 128, FTW_PHYS));
- ASSERT_EQ(0, nftw64(root.dirname, bug_28197840_nftw<struct stat64>, 128, FTW_PHYS));
+ ASSERT_EQ(0, ftw(root.path, bug_28197840_ftw<struct stat>, 128));
+ ASSERT_EQ(0, ftw64(root.path, bug_28197840_ftw<struct stat64>, 128));
+ ASSERT_EQ(0, nftw(root.path, bug_28197840_nftw<struct stat>, 128, FTW_PHYS));
+ ASSERT_EQ(0, nftw64(root.path, bug_28197840_nftw<struct stat64>, 128, FTW_PHYS));
}
template <typename StatT>
diff --git a/tests/getcwd_test.cpp b/tests/getcwd_test.cpp
index f8f205e..791ffae 100644
--- a/tests/getcwd_test.cpp
+++ b/tests/getcwd_test.cpp
@@ -20,6 +20,8 @@
#include <limits.h>
#include <unistd.h>
+#include "utils.h"
+
TEST(getcwd, auto_full) {
// If we let the library do all the work, everything's fine.
errno = 0;
@@ -49,6 +51,7 @@
}
TEST(getcwd, auto_too_large) {
+ SKIP_WITH_HWASAN; // allocation size too large
// If we ask the library to allocate an unreasonably large buffer, ERANGE.
errno = 0;
char* cwd = getcwd(nullptr, static_cast<size_t>(-1));
diff --git a/tests/glob_test.cpp b/tests/glob_test.cpp
index 623a2a3..b48f2af 100644
--- a/tests/glob_test.cpp
+++ b/tests/glob_test.cpp
@@ -22,7 +22,7 @@
#include <string>
#include <vector>
-#include "TemporaryFile.h"
+#include <android-base/file.h>
#if defined(__BIONIC__)
#define ASSERT_MATCH_COUNT(n_,g_) ASSERT_EQ(n_, g_.gl_matchc)
@@ -140,22 +140,22 @@
TEST(glob, glob_GLOB_MARK) {
TemporaryDir td;
// The pattern we're about to pass doesn't have a trailing '/'...
- ASSERT_NE('/', std::string(td.dirname).back());
+ ASSERT_NE('/', std::string(td.path).back());
glob_t g = {};
// Using GLOB_MARK gets you a trailing '/' on a directory...
- ASSERT_EQ(0, glob(td.dirname, GLOB_MARK, nullptr, &g));
+ ASSERT_EQ(0, glob(td.path, GLOB_MARK, nullptr, &g));
ASSERT_EQ(1U, g.gl_pathc);
ASSERT_MATCH_COUNT(1U, g);
- ASSERT_EQ(std::string(td.dirname) + "/", g.gl_pathv[0]);
+ ASSERT_EQ(std::string(td.path) + "/", g.gl_pathv[0]);
ASSERT_EQ(nullptr, g.gl_pathv[1]);
TemporaryFile tf;
// But not on a file...
- ASSERT_EQ(0, glob(tf.filename, GLOB_MARK, nullptr, &g));
+ ASSERT_EQ(0, glob(tf.path, GLOB_MARK, nullptr, &g));
ASSERT_EQ(1U, g.gl_pathc);
ASSERT_MATCH_COUNT(1U, g);
- ASSERT_STREQ(tf.filename, g.gl_pathv[0]);
+ ASSERT_STREQ(tf.path, g.gl_pathv[0]);
ASSERT_EQ(nullptr, g.gl_pathv[1]);
globfree(&g);
diff --git a/tests/grp_pwd_file_test.cpp b/tests/grp_pwd_file_test.cpp
index 8721805..2cbad62 100644
--- a/tests/grp_pwd_file_test.cpp
+++ b/tests/grp_pwd_file_test.cpp
@@ -18,7 +18,7 @@
#include <gtest/gtest.h>
-#include "TemporaryFile.h"
+#include <android-base/file.h>
#if defined(__BIONIC__)
#include "../libc/bionic/grp_pwd_file.cpp"
@@ -94,7 +94,7 @@
static const char test_string[] = "name:password:1:2:user_info:dir:shell\n";
write(file.fd, test_string, sizeof(test_string) - 1);
- PasswdFile passwd_file(file.filename, nullptr);
+ PasswdFile passwd_file(file.path, nullptr);
FileUnmapper unmapper(passwd_file);
FindAndCheckPasswdEntry(&passwd_file, "name", 1, 2, "dir", "shell");
@@ -114,7 +114,7 @@
static const char test_string[] = "name:password:1:one,two,three\n";
write(file.fd, test_string, sizeof(test_string) - 1);
- GroupFile group_file(file.filename, nullptr);
+ GroupFile group_file(file.path, nullptr);
FileUnmapper unmapper(group_file);
FindAndCheckGroupEntry(&group_file, "name", 1);
@@ -150,7 +150,7 @@
write(file.fd, test_string, sizeof(test_string) - 1);
- PasswdFile passwd_file(file.filename, nullptr);
+ PasswdFile passwd_file(file.path, nullptr);
FileUnmapper unmapper(passwd_file);
FindAndCheckPasswdEntry(&passwd_file, "first", 1, 2, "dir", "shell");
@@ -186,7 +186,7 @@
write(file.fd, test_string, sizeof(test_string) - 1);
- GroupFile group_file(file.filename, nullptr);
+ GroupFile group_file(file.path, nullptr);
FileUnmapper unmapper(group_file);
FindAndCheckGroupEntry(&group_file, "first", 1);
@@ -210,7 +210,7 @@
"vendor_name:password:3:4:user_info:dir:shell\n";
write(file.fd, test_string, sizeof(test_string) - 1);
- PasswdFile passwd_file(file.filename, "vendor_");
+ PasswdFile passwd_file(file.path, "vendor_");
FileUnmapper unmapper(passwd_file);
EXPECT_FALSE(passwd_file.FindByName("name", nullptr));
@@ -232,7 +232,7 @@
"vendor_name:password:2:one,two,three\n";
write(file.fd, test_string, sizeof(test_string) - 1);
- GroupFile group_file(file.filename, "vendor_");
+ GroupFile group_file(file.path, "vendor_");
FileUnmapper unmapper(group_file);
EXPECT_FALSE(group_file.FindByName("name", nullptr));
diff --git a/tests/libdl_test.cpp b/tests/libdl_test.cpp
index b162edc..6774f1d 100644
--- a/tests/libdl_test.cpp
+++ b/tests/libdl_test.cpp
@@ -18,17 +18,16 @@
#include <android/api-level.h>
-extern "C" uint32_t android_get_application_target_sdk_version();
-extern "C" void android_set_application_target_sdk_version(uint32_t target);
+extern "C" void android_set_application_target_sdk_version(int target);
TEST(libdl, application_sdk_versions_smoke) {
// Check initial values
- ASSERT_EQ(static_cast<uint32_t>(__ANDROID_API__), android_get_application_target_sdk_version());
+ ASSERT_EQ(__ANDROID_API__, android_get_application_target_sdk_version());
- android_set_application_target_sdk_version(20U);
- ASSERT_EQ(20U, android_get_application_target_sdk_version());
+ android_set_application_target_sdk_version(20);
+ ASSERT_EQ(20, android_get_application_target_sdk_version());
- android_set_application_target_sdk_version(22U);
- ASSERT_EQ(22U, android_get_application_target_sdk_version());
+ android_set_application_target_sdk_version(22);
+ ASSERT_EQ(22, android_get_application_target_sdk_version());
}
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 5c4eb42..79c9a06 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -531,8 +531,6 @@
defaults: ["bionic_testlib_defaults"],
srcs: ["dl_df_1_global.cpp"],
ldflags: ["-Wl,-z,global"],
- // b/80109858, clang lld ignores -z,global
- use_clang_lld: false,
target: {
host: {
@@ -561,8 +559,6 @@
defaults: ["bionic_testlib_defaults"],
srcs: ["dl_df_1_global_dummy.cpp"],
ldflags: ["-Wl,-z,global"],
- // b/80109858, clang lld ignores -z,global
- use_clang_lld: false,
target: {
host: {
diff --git a/tests/libs/cfi_test_helper.cpp b/tests/libs/cfi_test_helper.cpp
index ff313a2..c1a7b6d 100644
--- a/tests/libs/cfi_test_helper.cpp
+++ b/tests/libs/cfi_test_helper.cpp
@@ -27,11 +27,13 @@
static int g_count;
// Mock a CFI-enabled library without relying on the compiler.
-extern "C" __attribute__((aligned(4096))) void __cfi_check(uint64_t /*CallSiteTypeId*/,
- void* /*TargetAddr*/, void* /*Diag*/) {
+extern "C" __attribute__((no_sanitize("hwaddress"))) __attribute__((aligned(4096)))
+void __cfi_check(uint64_t /*CallSiteTypeId*/, void* /*TargetAddr*/, void* /*Diag*/) {
++g_count;
}
+// This code runs before hwasan is initialized.
+__attribute__((no_sanitize("hwaddress")))
void preinit_ctor() {
CHECK(g_count == 0);
__cfi_slowpath(42, reinterpret_cast<void*>(&preinit_ctor));
diff --git a/tests/malloc_iterate_test.cpp b/tests/malloc_iterate_test.cpp
new file mode 100644
index 0000000..5e60a6d
--- /dev/null
+++ b/tests/malloc_iterate_test.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <gtest/gtest.h>
+
+#if defined(__BIONIC__)
+
+#include <vector>
+
+#include <procinfo/process_map.h>
+
+#include "utils.h"
+
+extern "C" void malloc_disable();
+extern "C" void malloc_enable();
+extern "C" int malloc_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t base,
+ size_t size, void* arg), void* arg);
+
+struct AllocDataType {
+ void* ptr;
+ size_t size;
+ size_t size_reported;
+ size_t count;
+};
+
+struct TestDataType {
+ size_t total_allocated_bytes;
+ std::vector<AllocDataType> allocs;
+};
+
+static void AllocPtr(TestDataType* test_data, size_t size) {
+ test_data->allocs.resize(test_data->allocs.size() + 1);
+ AllocDataType* alloc = &test_data->allocs.back();
+ void* ptr = malloc(size);
+ ASSERT_TRUE(ptr != nullptr);
+ alloc->ptr = ptr;
+ alloc->size = malloc_usable_size(ptr);
+ alloc->size_reported = 0;
+ alloc->count = 0;
+}
+
+static void FreePtrs(TestDataType* test_data) {
+ for (size_t i = 0; i < test_data->allocs.size(); i++) {
+ free(test_data->allocs[i].ptr);
+ }
+}
+
+static void SavePointers(uintptr_t base, size_t size, void* data) {
+ TestDataType* test_data = reinterpret_cast<TestDataType*>(data);
+
+ test_data->total_allocated_bytes += size;
+
+ uintptr_t end;
+ if (__builtin_add_overflow(base, size, &end)) {
+ // Skip this entry.
+ return;
+ }
+
+ for (size_t i = 0; i < test_data->allocs.size(); i++) {
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(test_data->allocs[i].ptr);
+ if (ptr >= base && ptr < end) {
+ test_data->allocs[i].count++;
+
+ uintptr_t max_size = end - ptr;
+ if (max_size > test_data->allocs[i].size) {
+ test_data->allocs[i].size_reported = test_data->allocs[i].size;
+ } else {
+ test_data->allocs[i].size_reported = max_size;
+ }
+ }
+ }
+}
+
+static void VerifyPtrs(TestDataType* test_data) {
+ test_data->total_allocated_bytes = 0;
+
+ // Find all of the maps that are [anon:libc_malloc].
+ ASSERT_TRUE(android::procinfo::ReadMapFile("/proc/self/maps",
+ [&](uint64_t start, uint64_t end, uint16_t, uint64_t, const char* name) {
+ if (std::string(name) == "[anon:libc_malloc]") {
+ malloc_disable();
+ malloc_iterate(start, end - start, SavePointers, test_data);
+ malloc_enable();
+ }
+ }));
+
+ for (size_t i = 0; i < test_data->allocs.size(); i++) {
+ EXPECT_EQ(1UL, test_data->allocs[i].count) << "Failed on size " << test_data->allocs[i].size;
+ if (test_data->allocs[i].count == 1) {
+ EXPECT_EQ(test_data->allocs[i].size, test_data->allocs[i].size_reported);
+ }
+ }
+}
+
+static void AllocateSizes(TestDataType* test_data, const std::vector<size_t>& sizes) {
+ static constexpr size_t kInitialAllocations = 40;
+ static constexpr size_t kNumAllocs = 50;
+ for (size_t size : sizes) {
+ // Verify that if the tcache is enabled, that tcache pointers
+ // are found by allocating and freeing 20 pointers (should be larger
+ // than the total number of cache entries).
+ for (size_t i = 0; i < kInitialAllocations; i++) {
+ void* ptr = malloc(size);
+ ASSERT_TRUE(ptr != nullptr);
+ memset(ptr, 0, size);
+ free(ptr);
+ }
+ for (size_t i = 0; i < kNumAllocs; i++) {
+ AllocPtr(test_data, size);
+ }
+ }
+}
+#endif
+
+// Verify that small allocs can be found properly.
+TEST(malloc_iterate, small_allocs) {
+#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN;
+ TestDataType test_data;
+
+ // Try to cycle through all of the different small bins.
+ // This is specific to the implementation of jemalloc and should be
+ // adjusted if a different native memory allocator is used.
+ std::vector<size_t> sizes{8, 16, 32, 48, 64, 80, 96, 112, 128, 160,
+ 192, 224, 256, 320, 384, 448, 512, 640, 768, 896,
+ 1024, 1280, 1536, 1792, 2048, 2560, 3072, 3584, 4096, 5120,
+ 6144, 7168, 8192, 10240, 12288, 14336, 16384, 32768, 65536};
+ AllocateSizes(&test_data, sizes);
+
+ SCOPED_TRACE("");
+ VerifyPtrs(&test_data);
+
+ FreePtrs(&test_data);
+#else
+ GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+#endif
+}
+
+// Verify that large allocs can be found properly.
+TEST(malloc_iterate, large_allocs) {
+#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN;
+ TestDataType test_data;
+
+ // Try some larger sizes.
+ std::vector<size_t> sizes{131072, 262144, 524288, 1048576, 2097152};
+ AllocateSizes(&test_data, sizes);
+
+ SCOPED_TRACE("");
+ VerifyPtrs(&test_data);
+
+ FreePtrs(&test_data);
+#else
+ GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+#endif
+}
+
+// Verify that there are no crashes attempting to get pointers from
+// non-allocated pointers.
+TEST(malloc_iterate, invalid_pointers) {
+#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN;
+ TestDataType test_data = {};
+
+ // Find all of the maps that are not [anon:libc_malloc].
+ ASSERT_TRUE(android::procinfo::ReadMapFile("/proc/self/maps",
+ [&](uint64_t start, uint64_t end, uint16_t, uint64_t, const char* name) {
+ if (std::string(name) != "[anon:libc_malloc]") {
+ malloc_disable();
+ malloc_iterate(start, end - start, SavePointers, &test_data);
+ malloc_enable();
+ }
+ }));
+
+ ASSERT_EQ(0UL, test_data.total_allocated_bytes);
+#else
+ GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+#endif
+}
+
+TEST(malloc_iterate, malloc_disable_prevents_allocs) {
+#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN;
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ malloc_disable();
+ void* ptr = malloc(1024);
+ if (ptr == nullptr) {
+ exit(1);
+ }
+ memset(ptr, 0, 1024);
+ exit(0);
+ }
+ ASSERT_NE(-1, pid);
+
+ // Expect that the malloc will hang forever, and that if the process
+ // does not return for two seconds, it is hung.
+ sleep(2);
+ pid_t wait_pid = TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG));
+ if (wait_pid <= 0) {
+ kill(pid, SIGKILL);
+ }
+ ASSERT_NE(-1, wait_pid) << "Unknown failure in waitpid.";
+ ASSERT_EQ(0, wait_pid) << "malloc_disable did not prevent allocation calls.";
+#else
+ GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+#endif
+}
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index c4f13f6..4a01278 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -25,6 +25,7 @@
#include <tinyxml2.h>
#include "private/bionic_config.h"
+#include "utils.h"
#if defined(__BIONIC__)
#define HAVE_REALLOCARRAY 1
@@ -41,6 +42,7 @@
}
TEST(malloc, malloc_overflow) {
+ SKIP_WITH_HWASAN;
errno = 0;
ASSERT_EQ(nullptr, malloc(SIZE_MAX));
ASSERT_EQ(ENOMEM, errno);
@@ -59,12 +61,14 @@
}
TEST(malloc, calloc_illegal) {
+ SKIP_WITH_HWASAN;
errno = 0;
ASSERT_EQ(nullptr, calloc(-1, 100));
ASSERT_EQ(ENOMEM, errno);
}
TEST(malloc, calloc_overflow) {
+ SKIP_WITH_HWASAN;
errno = 0;
ASSERT_EQ(nullptr, calloc(1, SIZE_MAX));
ASSERT_EQ(ENOMEM, errno);
@@ -80,6 +84,7 @@
}
TEST(malloc, memalign_multiple) {
+ SKIP_WITH_HWASAN; // hwasan requires power of 2 alignment.
// Memalign test where the alignment is any value.
for (size_t i = 0; i <= 12; i++) {
for (size_t alignment = 1 << i; alignment < (1U << (i+1)); alignment++) {
@@ -94,10 +99,12 @@
}
TEST(malloc, memalign_overflow) {
+ SKIP_WITH_HWASAN;
ASSERT_EQ(nullptr, memalign(4096, SIZE_MAX));
}
TEST(malloc, memalign_non_power2) {
+ SKIP_WITH_HWASAN;
void* ptr;
for (size_t align = 0; align <= 256; align++) {
ptr = memalign(align, 1024);
@@ -280,6 +287,7 @@
}
TEST(malloc, realloc_overflow) {
+ SKIP_WITH_HWASAN;
errno = 0;
ASSERT_EQ(nullptr, realloc(nullptr, SIZE_MAX));
ASSERT_EQ(ENOMEM, errno);
@@ -504,6 +512,27 @@
ASSERT_EQ(0, errno);
}
+TEST(malloc, mallopt_decay) {
+#if defined(__BIONIC__)
+ errno = 0;
+ ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1));
+ ASSERT_EQ(1, mallopt(M_DECAY_TIME, 0));
+ ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1));
+ ASSERT_EQ(1, mallopt(M_DECAY_TIME, 0));
+#else
+ GTEST_LOG_(INFO) << "This tests a bionic implementation detail.\n";
+#endif
+}
+
+TEST(malloc, mallopt_purge) {
+#if defined(__BIONIC__)
+ errno = 0;
+ ASSERT_EQ(1, mallopt(M_PURGE, 0));
+#else
+ GTEST_LOG_(INFO) << "This tests a bionic implementation detail.\n";
+#endif
+}
+
TEST(malloc, reallocarray_overflow) {
#if HAVE_REALLOCARRAY
// Values that cause overflow to a result small enough (8 on LP64) that malloc would "succeed".
@@ -531,3 +560,44 @@
GTEST_LOG_(INFO) << "This test requires a C library with reallocarray.\n";
#endif
}
+
+TEST(malloc, mallinfo) {
+#if defined(__BIONIC__)
+ static size_t sizes[] = {
+ 8, 32, 128, 4096, 32768, 131072, 1024000, 10240000, 20480000, 300000000
+ };
+
+ constexpr static size_t kMaxAllocs = 50;
+
+ for (size_t size : sizes) {
+ // If some of these allocations are stuck in a thread cache, then keep
+ // looping until we make an allocation that changes the total size of the
+ // memory allocated.
+ // jemalloc implementations counts the thread cache allocations against
+ // total memory allocated.
+ void* ptrs[kMaxAllocs] = {};
+ bool pass = false;
+ for (size_t i = 0; i < kMaxAllocs; i++) {
+ size_t allocated = mallinfo().uordblks;
+ ptrs[i] = malloc(size);
+ ASSERT_TRUE(ptrs[i] != nullptr);
+ size_t new_allocated = mallinfo().uordblks;
+ if (allocated != new_allocated) {
+ size_t usable_size = malloc_usable_size(ptrs[i]);
+ ASSERT_GE(new_allocated, allocated + usable_size)
+ << "Failed at size " << size << " usable size " << usable_size;
+ pass = true;
+ break;
+ }
+ }
+ for (void* ptr : ptrs) {
+ free(ptr);
+ }
+ ASSERT_TRUE(pass)
+ << "For size " << size << " allocated bytes did not increase after "
+ << kMaxAllocs << " allocations.";
+ }
+#else
+ GTEST_LOG_(INFO) << "Host glibc does not pass this test, skipping.\n";
+#endif
+}
diff --git a/tests/scs_test.cpp b/tests/scs_test.cpp
new file mode 100644
index 0000000..24cb347
--- /dev/null
+++ b/tests/scs_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#if __has_feature(shadow_call_stack)
+
+#include <gtest/gtest.h>
+
+#include "private/bionic_constants.h"
+
+int recurse2(int count);
+
+__attribute__((weak, noinline)) int recurse1(int count) {
+ if (count != 0) return recurse2(count - 1) + 1;
+ return 0;
+}
+
+__attribute__((weak, noinline)) int recurse2(int count) {
+ if (count != 0) return recurse1(count - 1) + 1;
+ return 0;
+}
+
+TEST(scs_test, stack_overflow) {
+ ASSERT_EXIT(recurse1(SCS_SIZE), testing::KilledBySignal(SIGSEGV), "");
+}
+
+#endif
diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp
index 10d99ea..690e886 100644
--- a/tests/semaphore_test.cpp
+++ b/tests/semaphore_test.cpp
@@ -174,7 +174,7 @@
ASSERT_EQ(1, i);
}
-extern "C" void android_set_application_target_sdk_version(uint32_t target);
+extern "C" void android_set_application_target_sdk_version(int target);
static void sem_wait_test_signal_handler(int) {
}
diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp
index dde0be1..44d8af1 100644
--- a/tests/setjmp_test.cpp
+++ b/tests/setjmp_test.cpp
@@ -264,3 +264,14 @@
fprintf(stderr, "setjmp_cookie_checksum: longjmp succeeded?");
}
}
+
+__attribute__((noinline)) void call_longjmp(jmp_buf buf) {
+ longjmp(buf, 123);
+}
+
+TEST(setjmp, setjmp_stack) {
+ jmp_buf buf;
+ int value = setjmp(buf);
+ if (value == 0) call_longjmp(buf);
+ EXPECT_EQ(123, value);
+}
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
index d4616ef..d84fda0 100644
--- a/tests/stdio_ext_test.cpp
+++ b/tests/stdio_ext_test.cpp
@@ -29,7 +29,8 @@
#include <wchar.h>
#include <locale.h>
-#include "TemporaryFile.h"
+#include <android-base/file.h>
+
#include "utils.h"
TEST(stdio_ext, __fbufsize) {
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 54b913a..e9ec499 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -31,8 +31,9 @@
#include <string>
#include <vector>
+#include <android-base/file.h>
+
#include "BionicDeathTest.h"
-#include "TemporaryFile.h"
#include "utils.h"
#if defined(NOFORTIFY)
@@ -1412,7 +1413,7 @@
fflush(fp);
fclose(fp);
- fp = fopen(tf.filename, "r");
+ fp = fopen(tf.path, "r");
ASSERT_TRUE(fp != nullptr);
// Store a valid position.
@@ -2041,7 +2042,7 @@
TEST(STDIO_TEST, fread_after_fseek) {
TemporaryFile tf;
- FILE* fp = fopen(tf.filename, "w+");
+ FILE* fp = fopen(tf.path, "w+");
ASSERT_TRUE(fp != nullptr);
char file_data[12288];
@@ -2051,7 +2052,7 @@
ASSERT_EQ(12288U, fwrite(file_data, 1, 12288, fp));
fclose(fp);
- fp = fopen(tf.filename, "r");
+ fp = fopen(tf.path, "r");
ASSERT_TRUE(fp != nullptr);
char buffer[8192];
@@ -2080,10 +2081,10 @@
TemporaryFile tf;
char buf[6] = {0};
- FILE* fw = fopen(tf.filename, "w");
+ FILE* fw = fopen(tf.path, "w");
ASSERT_TRUE(fw != nullptr);
- FILE* fr = fopen(tf.filename, "r");
+ FILE* fr = fopen(tf.path, "r");
ASSERT_TRUE(fr != nullptr);
fwrite("a", 1, 1, fw);
@@ -2197,7 +2198,7 @@
for (size_t i = 0; i < 256; ++i) {
TemporaryFile* tf = new TemporaryFile;
tfs.push_back(tf);
- FILE* fp = fopen(tf->filename, "w+");
+ FILE* fp = fopen(tf->path, "w+");
fps.push_back(fp);
fprintf(fp, "hello %zu!\n", i);
fflush(fp);
@@ -2313,21 +2314,21 @@
struct stat sb;
TemporaryFile tf;
- ASSERT_EQ(0, remove(tf.filename));
- ASSERT_EQ(-1, lstat(tf.filename, &sb));
+ ASSERT_EQ(0, remove(tf.path));
+ ASSERT_EQ(-1, lstat(tf.path, &sb));
ASSERT_EQ(ENOENT, errno);
TemporaryDir td;
- ASSERT_EQ(0, remove(td.dirname));
- ASSERT_EQ(-1, lstat(td.dirname, &sb));
+ ASSERT_EQ(0, remove(td.path));
+ ASSERT_EQ(-1, lstat(td.path, &sb));
ASSERT_EQ(ENOENT, errno);
errno = 0;
- ASSERT_EQ(-1, remove(tf.filename));
+ ASSERT_EQ(-1, remove(tf.path));
ASSERT_EQ(ENOENT, errno);
errno = 0;
- ASSERT_EQ(-1, remove(td.dirname));
+ ASSERT_EQ(-1, remove(td.path));
ASSERT_EQ(ENOENT, errno);
}
@@ -2404,8 +2405,8 @@
TEST(STDIO_TEST, fopen_append_mode_and_ftell) {
TemporaryFile tf;
- SetFileTo(tf.filename, "0123456789");
- FILE* fp = fopen(tf.filename, "a");
+ SetFileTo(tf.path, "0123456789");
+ FILE* fp = fopen(tf.path, "a");
EXPECT_EQ(10, ftell(fp));
ASSERT_EQ(0, fseek(fp, 2, SEEK_SET));
EXPECT_EQ(2, ftell(fp));
@@ -2415,13 +2416,13 @@
ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
EXPECT_EQ(13, ftell(fp));
ASSERT_EQ(0, fclose(fp));
- AssertFileIs(tf.filename, "0123456789xxx");
+ AssertFileIs(tf.path, "0123456789xxx");
}
TEST(STDIO_TEST, fdopen_append_mode_and_ftell) {
TemporaryFile tf;
- SetFileTo(tf.filename, "0123456789");
- int fd = open(tf.filename, O_RDWR);
+ SetFileTo(tf.path, "0123456789");
+ int fd = open(tf.path, O_RDWR);
ASSERT_NE(-1, fd);
// POSIX: "The file position indicator associated with the new stream is set to the position
// indicated by the file offset associated with the file descriptor."
@@ -2436,14 +2437,14 @@
ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
EXPECT_EQ(13, ftell(fp));
ASSERT_EQ(0, fclose(fp));
- AssertFileIs(tf.filename, "0123456789xxx");
+ AssertFileIs(tf.path, "0123456789xxx");
}
TEST(STDIO_TEST, freopen_append_mode_and_ftell) {
TemporaryFile tf;
- SetFileTo(tf.filename, "0123456789");
+ SetFileTo(tf.path, "0123456789");
FILE* other_fp = fopen("/proc/version", "r");
- FILE* fp = freopen(tf.filename, "a", other_fp);
+ FILE* fp = freopen(tf.path, "a", other_fp);
EXPECT_EQ(10, ftell(fp));
ASSERT_EQ(0, fseek(fp, 2, SEEK_SET));
EXPECT_EQ(2, ftell(fp));
@@ -2453,7 +2454,7 @@
ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
EXPECT_EQ(13, ftell(fp));
ASSERT_EQ(0, fclose(fp));
- AssertFileIs(tf.filename, "0123456789xxx");
+ AssertFileIs(tf.path, "0123456789xxx");
}
TEST(STDIO_TEST, constants) {
@@ -2476,7 +2477,7 @@
TEST(STDIO_TEST, unlocked) {
TemporaryFile tf;
- FILE* fp = fopen(tf.filename, "w+");
+ FILE* fp = fopen(tf.path, "w+");
ASSERT_TRUE(fp != nullptr);
clearerr_unlocked(fp);
@@ -2521,7 +2522,7 @@
TEST(STDIO_TEST, fseek_64bit) {
TemporaryFile tf;
- FILE* fp = fopen64(tf.filename, "w+");
+ FILE* fp = fopen64(tf.path, "w+");
ASSERT_TRUE(fp != nullptr);
ASSERT_EQ(0, fseeko64(fp, 0x2'0000'0000, SEEK_SET));
ASSERT_EQ(0x2'0000'0000, ftello64(fp));
@@ -2534,7 +2535,7 @@
// isn't representable in long/off_t.
TEST(STDIO_TEST, fseek_overflow_32bit) {
TemporaryFile tf;
- FILE* fp = fopen64(tf.filename, "w+");
+ FILE* fp = fopen64(tf.path, "w+");
ASSERT_EQ(0, ftruncate64(fileno(fp), 0x2'0000'0000));
// Bionic implements overflow checking for SEEK_CUR, but glibc doesn't.
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index 1c3e1d1..00850f6 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -14,13 +14,6 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
-#include "BionicDeathTest.h"
-#include "math_data_test.h"
-#include "TemporaryFile.h"
-#include "utils.h"
-
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
@@ -31,10 +24,18 @@
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <unistd.h>
#include <limits>
#include <string>
+#include <android-base/macros.h>
+#include <gtest/gtest.h>
+
+#include "BionicDeathTest.h"
+#include "math_data_test.h"
+#include "utils.h"
+
#if defined(__BIONIC__)
#define ALIGNED_ALLOC_AVAILABLE 1
#elif defined(__GLIBC_PREREQ)
@@ -43,6 +44,41 @@
#endif
#endif
+template <typename T = int (*)(char*)>
+class GenericTemporaryFile {
+ public:
+ explicit GenericTemporaryFile(T mk_fn = mkstemp) : mk_fn_(mk_fn) {
+ // Since we might be running on the host or the target, and if we're
+ // running on the host we might be running under bionic or glibc,
+ // let's just try both possible temporary directories and take the
+ // first one that works.
+ init("/data/local/tmp");
+ if (fd == -1) {
+ init("/tmp");
+ }
+ }
+
+ ~GenericTemporaryFile() {
+ close(fd);
+ unlink(path);
+ }
+
+ int fd;
+ char path[1024];
+
+ private:
+ T mk_fn_;
+
+ void init(const char* tmp_dir) {
+ snprintf(path, sizeof(path), "%s/TemporaryFile-XXXXXX", tmp_dir);
+ fd = mk_fn_(path);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(GenericTemporaryFile);
+};
+
+typedef GenericTemporaryFile<> MyTemporaryFile;
+
// The random number generator tests all set the seed, get four values, reset the seed and check
// that they get the first two values repeated, and then reset the seed and check two more values
// to rule out the possibility that we're just going round a cycle of four values.
@@ -191,6 +227,7 @@
}
TEST(stdlib, posix_memalign_sweep) {
+ SKIP_WITH_HWASAN;
void* ptr;
// These should all fail.
@@ -230,11 +267,13 @@
}
TEST(stdlib, posix_memalign_overflow) {
+ SKIP_WITH_HWASAN;
void* ptr;
ASSERT_NE(0, posix_memalign(&ptr, 16, SIZE_MAX));
}
TEST(stdlib, aligned_alloc_sweep) {
+ SKIP_WITH_HWASAN;
#if defined(ALIGNED_ALLOC_AVAILABLE)
// Verify powers of 2 up to 2048 allocate, and verify that all other
// alignment values between the powers of 2 fail.
@@ -259,6 +298,7 @@
}
TEST(stdlib, aligned_alloc_overflow) {
+ SKIP_WITH_HWASAN;
#if defined(ALIGNED_ALLOC_AVAILABLE)
ASSERT_TRUE(aligned_alloc(16, SIZE_MAX) == nullptr);
#else
@@ -267,6 +307,7 @@
}
TEST(stdlib, aligned_alloc_size_not_multiple_of_alignment) {
+ SKIP_WITH_HWASAN;
#if defined(ALIGNED_ALLOC_AVAILABLE)
for (size_t size = 1; size <= 2048; size++) {
void* ptr = aligned_alloc(2048, size);
@@ -379,24 +420,24 @@
}
TEST(stdlib, mkostemp64) {
- TemporaryFile tf([](char* path) { return mkostemp64(path, O_CLOEXEC); });
+ MyTemporaryFile tf([](char* path) { return mkostemp64(path, O_CLOEXEC); });
AssertCloseOnExec(tf.fd, true);
}
TEST(stdlib, mkostemp) {
- TemporaryFile tf([](char* path) { return mkostemp(path, O_CLOEXEC); });
+ MyTemporaryFile tf([](char* path) { return mkostemp(path, O_CLOEXEC); });
AssertCloseOnExec(tf.fd, true);
}
TEST(stdlib, mkstemp64) {
- TemporaryFile tf(mkstemp64);
+ MyTemporaryFile tf(mkstemp64);
struct stat64 sb;
ASSERT_EQ(0, fstat64(tf.fd, &sb));
ASSERT_EQ(O_LARGEFILE, fcntl(tf.fd, F_GETFL) & O_LARGEFILE);
}
TEST(stdlib, mkstemp) {
- TemporaryFile tf;
+ MyTemporaryFile tf(mkstemp);
struct stat sb;
ASSERT_EQ(0, fstat(tf.fd, &sb));
}
diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp
index 22dc383..0b98198 100644
--- a/tests/sys_mman_test.cpp
+++ b/tests/sys_mman_test.cpp
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
+#include <fcntl.h>
#include <sys/mman.h>
#include <sys/user.h>
#include <sys/types.h>
#include <unistd.h>
-#include "TemporaryFile.h"
+#include <android-base/file.h>
+#include <gtest/gtest.h>
TEST(sys_mman, mmap_std) {
void* map = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
@@ -82,7 +82,7 @@
ASSERT_EQ(0, munmap(map, sizeof(STRING_MSG)));
- tf.reopen();
+ tf.fd = open(tf.path, O_RDWR);
char buf[sizeof(STRING_MSG)];
memset(buf, 0, sizeof(STRING_MSG));
ASSERT_EQ(STR_SSIZE(STRING_MSG), read(tf.fd, buf, sizeof(STRING_MSG)));
@@ -153,7 +153,7 @@
memcpy(map, NEWPAGE1_MSG, sizeof(NEWPAGE1_MSG));
ASSERT_EQ(0, munmap(map, pagesize));
- tf.reopen();
+ tf.fd = open(tf.path, O_RDWR);
map = mmap(nullptr, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, 2 * pagesize);
ASSERT_NE(MAP_FAILED, map);
close(tf.fd);
@@ -161,7 +161,7 @@
memcpy(map, NEWPAGE2_MSG, sizeof(NEWPAGE2_MSG));
ASSERT_EQ(0, munmap(map, pagesize));
- tf.reopen();
+ tf.fd = open(tf.path, O_RDWR);
char buf[pagesize];
ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize));
ASSERT_STREQ(PAGE0_MSG, buf);
diff --git a/tests/sys_msg_test.cpp b/tests/sys_msg_test.cpp
index 4eb5a14..8b3623e 100644
--- a/tests/sys_msg_test.cpp
+++ b/tests/sys_msg_test.cpp
@@ -31,7 +31,7 @@
#include <errno.h>
#include <sys/msg.h>
-#include "TemporaryFile.h"
+#include <android-base/file.h>
TEST(sys_msg, smoke) {
if (msgctl(-1, IPC_STAT, nullptr) == -1 && errno == ENOSYS) {
@@ -41,7 +41,7 @@
// Create a queue.
TemporaryDir dir;
- key_t key = ftok(dir.dirname, 1);
+ key_t key = ftok(dir.path, 1);
int id = msgget(key, IPC_CREAT|0666);
ASSERT_NE(id, -1);
diff --git a/tests/sys_sem_test.cpp b/tests/sys_sem_test.cpp
index eaf2b8f..dff34c8 100644
--- a/tests/sys_sem_test.cpp
+++ b/tests/sys_sem_test.cpp
@@ -31,7 +31,7 @@
#include <errno.h>
#include <sys/sem.h>
-#include "TemporaryFile.h"
+#include <android-base/file.h>
TEST(sys_sem, smoke) {
if (semctl(-1, 0, IPC_RMID) == -1 && errno == ENOSYS) {
@@ -41,7 +41,7 @@
// Create a semaphore.
TemporaryDir dir;
- key_t key = ftok(dir.dirname, 1);
+ key_t key = ftok(dir.path, 1);
int id = semget(key, 1, IPC_CREAT|0666);
ASSERT_NE(id, -1);
diff --git a/tests/sys_sendfile_test.cpp b/tests/sys_sendfile_test.cpp
index 3d6b5cc..4cddd0d 100644
--- a/tests/sys_sendfile_test.cpp
+++ b/tests/sys_sendfile_test.cpp
@@ -14,14 +14,15 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-#include "TemporaryFile.h"
-#include <sys/sendfile.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <errno.h>
+#include <fcntl.h>
+#include <sys/sendfile.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/file.h>
+#include <gtest/gtest.h>
TEST(sys_sendfile, sendfile) {
TemporaryFile src_file;
diff --git a/tests/sys_shm_test.cpp b/tests/sys_shm_test.cpp
index ca2d01a..15abe05 100644
--- a/tests/sys_shm_test.cpp
+++ b/tests/sys_shm_test.cpp
@@ -26,12 +26,11 @@
* SUCH DAMAGE.
*/
-#include <gtest/gtest.h>
-
#include <errno.h>
#include <sys/shm.h>
-#include "TemporaryFile.h"
+#include <android-base/file.h>
+#include <gtest/gtest.h>
TEST(sys_shm, smoke) {
if (shmctl(-1, IPC_STAT, nullptr) == -1 && errno == ENOSYS) {
@@ -41,7 +40,7 @@
// Create a segment.
TemporaryDir dir;
- key_t key = ftok(dir.dirname, 1);
+ key_t key = ftok(dir.path, 1);
int id = shmget(key, 1234, IPC_CREAT|0666);
ASSERT_NE(id, -1);
diff --git a/tests/sys_stat_test.cpp b/tests/sys_stat_test.cpp
index c0a576d..70ad451 100644
--- a/tests/sys_stat_test.cpp
+++ b/tests/sys_stat_test.cpp
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
-#include "TemporaryFile.h"
+#include <android-base/file.h>
+#include <gtest/gtest.h>
TEST(sys_stat, futimens) {
FILE* fp = tmpfile();
@@ -73,7 +72,7 @@
std::string path;
{
TemporaryFile tf;
- path = tf.filename;
+ path = tf.path;
}
ASSERT_EQ(0, mkfifo(path.c_str(), 0666));
@@ -148,19 +147,19 @@
TEST(sys_stat, fchmodat_file) {
TemporaryFile tf;
- ASSERT_EQ(0, fchmodat(AT_FDCWD, tf.filename, 0751, 0));
- AssertFileModeEquals(0751, tf.filename);
+ ASSERT_EQ(0, fchmodat(AT_FDCWD, tf.path, 0751, 0));
+ AssertFileModeEquals(0751, tf.path);
}
TEST(sys_stat, fchmodat_AT_SYMLINK_NOFOLLOW_file) {
TemporaryFile tf;
errno = 0;
- int result = fchmodat(AT_FDCWD, tf.filename, 0751, AT_SYMLINK_NOFOLLOW);
+ int result = fchmodat(AT_FDCWD, tf.path, 0751, AT_SYMLINK_NOFOLLOW);
#if defined(__BIONIC__)
ASSERT_EQ(0, result);
ASSERT_EQ(0, errno);
- AssertFileModeEquals(0751, tf.filename);
+ AssertFileModeEquals(0751, tf.path);
#else
// glibc 2.19 does not implement AT_SYMLINK_NOFOLLOW and always
// returns ENOTSUP
@@ -173,11 +172,11 @@
TemporaryFile tf;
char linkname[255];
- snprintf(linkname, sizeof(linkname), "%s.link", tf.filename);
+ snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
- ASSERT_EQ(0, symlink(tf.filename, linkname));
+ ASSERT_EQ(0, symlink(tf.path, linkname));
ASSERT_EQ(0, fchmodat(AT_FDCWD, linkname, 0751, 0));
- AssertFileModeEquals(0751, tf.filename);
+ AssertFileModeEquals(0751, tf.path);
unlink(linkname);
}
@@ -186,8 +185,8 @@
char linkname[255];
char target[255];
- snprintf(linkname, sizeof(linkname), "%s.link", tf.filename);
- snprintf(target, sizeof(target), "%s.doesnotexist", tf.filename);
+ snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
+ snprintf(target, sizeof(target), "%s.doesnotexist", tf.path);
ASSERT_EQ(0, symlink(target, linkname));
ASSERT_EQ(-1, fchmodat(AT_FDCWD, linkname, 0751, 0));
@@ -205,12 +204,12 @@
TEST(sys_stat, fchmodat_AT_SYMLINK_NOFOLLOW_with_symlink) {
TemporaryFile tf;
struct stat tf_sb;
- ASSERT_EQ(0, stat(tf.filename, &tf_sb));
+ ASSERT_EQ(0, stat(tf.path, &tf_sb));
char linkname[255];
- snprintf(linkname, sizeof(linkname), "%s.link", tf.filename);
+ snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
- ASSERT_EQ(0, symlink(tf.filename, linkname));
+ ASSERT_EQ(0, symlink(tf.path, linkname));
int result = fchmodat(AT_FDCWD, linkname, 0751, AT_SYMLINK_NOFOLLOW);
// It depends on the kernel whether chmod operation on symlink is allowed.
if (result == 0) {
@@ -221,7 +220,7 @@
}
// Target file mode shouldn't be modified.
- AssertFileModeEquals(tf_sb.st_mode, tf.filename);
+ AssertFileModeEquals(tf_sb.st_mode, tf.path);
unlink(linkname);
}
@@ -230,8 +229,8 @@
char linkname[255];
char target[255];
- snprintf(linkname, sizeof(linkname), "%s.link", tf.filename);
- snprintf(target, sizeof(target), "%s.doesnotexist", tf.filename);
+ snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
+ snprintf(target, sizeof(target), "%s.doesnotexist", tf.path);
ASSERT_EQ(0, symlink(target, linkname));
int result = fchmodat(AT_FDCWD, linkname, 0751, AT_SYMLINK_NOFOLLOW);
diff --git a/tests/sys_time_test.cpp b/tests/sys_time_test.cpp
index b3ec161..16187eb 100644
--- a/tests/sys_time_test.cpp
+++ b/tests/sys_time_test.cpp
@@ -17,15 +17,16 @@
#include <gtest/gtest.h>
#include <errno.h>
+#include <fcntl.h>
#include <sys/syscall.h>
#include <sys/time.h>
-#include "TemporaryFile.h"
+#include <android-base/file.h>
// http://b/11383777
TEST(sys_time, utimes_nullptr) {
TemporaryFile tf;
- ASSERT_EQ(0, utimes(tf.filename, nullptr));
+ ASSERT_EQ(0, utimes(tf.path, nullptr));
}
TEST(sys_time, utimes_EINVAL) {
@@ -34,19 +35,19 @@
timeval tv[2] = {};
tv[0].tv_usec = -123;
- ASSERT_EQ(-1, utimes(tf.filename, tv));
+ ASSERT_EQ(-1, utimes(tf.path, tv));
ASSERT_EQ(EINVAL, errno);
tv[0].tv_usec = 1234567;
- ASSERT_EQ(-1, utimes(tf.filename, tv));
+ ASSERT_EQ(-1, utimes(tf.path, tv));
ASSERT_EQ(EINVAL, errno);
tv[0].tv_usec = 0;
tv[1].tv_usec = -123;
- ASSERT_EQ(-1, utimes(tf.filename, tv));
+ ASSERT_EQ(-1, utimes(tf.path, tv));
ASSERT_EQ(EINVAL, errno);
tv[1].tv_usec = 1234567;
- ASSERT_EQ(-1, utimes(tf.filename, tv));
+ ASSERT_EQ(-1, utimes(tf.path, tv));
ASSERT_EQ(EINVAL, errno);
}
@@ -79,7 +80,7 @@
TEST(sys_time, futimesat_nullptr) {
TemporaryFile tf;
- ASSERT_EQ(0, futimesat(AT_FDCWD, tf.filename, nullptr));
+ ASSERT_EQ(0, futimesat(AT_FDCWD, tf.path, nullptr));
}
TEST(sys_time, futimesat_EINVAL) {
@@ -88,25 +89,25 @@
timeval tv[2] = {};
tv[0].tv_usec = -123;
- ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+ ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
ASSERT_EQ(EINVAL, errno);
tv[0].tv_usec = 1234567;
- ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+ ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
ASSERT_EQ(EINVAL, errno);
tv[0].tv_usec = 0;
tv[1].tv_usec = -123;
- ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+ ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
ASSERT_EQ(EINVAL, errno);
tv[1].tv_usec = 1234567;
- ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+ ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
ASSERT_EQ(EINVAL, errno);
}
TEST(sys_time, lutimes_nullptr) {
TemporaryFile tf;
- ASSERT_EQ(0, lutimes(tf.filename, nullptr));
+ ASSERT_EQ(0, lutimes(tf.path, nullptr));
}
TEST(sys_time, lutimes_EINVAL) {
@@ -115,19 +116,19 @@
timeval tv[2] = {};
tv[0].tv_usec = -123;
- ASSERT_EQ(-1, lutimes(tf.filename, tv));
+ ASSERT_EQ(-1, lutimes(tf.path, tv));
ASSERT_EQ(EINVAL, errno);
tv[0].tv_usec = 1234567;
- ASSERT_EQ(-1, lutimes(tf.filename, tv));
+ ASSERT_EQ(-1, lutimes(tf.path, tv));
ASSERT_EQ(EINVAL, errno);
tv[0].tv_usec = 0;
tv[1].tv_usec = -123;
- ASSERT_EQ(-1, lutimes(tf.filename, tv));
+ ASSERT_EQ(-1, lutimes(tf.path, tv));
ASSERT_EQ(EINVAL, errno);
tv[1].tv_usec = 1234567;
- ASSERT_EQ(-1, lutimes(tf.filename, tv));
+ ASSERT_EQ(-1, lutimes(tf.path, tv));
ASSERT_EQ(EINVAL, errno);
}
diff --git a/tests/sys_uio_test.cpp b/tests/sys_uio_test.cpp
index 60bd224..8460041 100644
--- a/tests/sys_uio_test.cpp
+++ b/tests/sys_uio_test.cpp
@@ -18,7 +18,7 @@
#include <sys/uio.h>
-#include "TemporaryFile.h"
+#include <android-base/file.h>
TEST(sys_uio, readv_writev) {
TemporaryFile tf;
diff --git a/tests/sys_xattr_test.cpp b/tests/sys_xattr_test.cpp
index 006e840..8f4a336 100644
--- a/tests/sys_xattr_test.cpp
+++ b/tests/sys_xattr_test.cpp
@@ -14,21 +14,21 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
+#include <fcntl.h>
#include <sys/types.h>
#include <sys/xattr.h>
-#include "TemporaryFile.h"
+#include <android-base/file.h>
+#include <gtest/gtest.h>
TEST(sys_xattr, setxattr) {
TemporaryFile tf;
char buf[10];
- ASSERT_EQ(0, setxattr(tf.filename, "user.foo", "bar", 4, 0));
- ASSERT_EQ(4, getxattr(tf.filename, "user.foo", buf, sizeof(buf)));
+ ASSERT_EQ(0, setxattr(tf.path, "user.foo", "bar", 4, 0));
+ ASSERT_EQ(4, getxattr(tf.path, "user.foo", buf, sizeof(buf)));
ASSERT_STREQ("bar", buf);
buf[0] = '\0';
- ASSERT_EQ(4, lgetxattr(tf.filename, "user.foo", buf, sizeof(buf)));
+ ASSERT_EQ(4, lgetxattr(tf.path, "user.foo", buf, sizeof(buf)));
ASSERT_STREQ("bar", buf);
}
@@ -67,7 +67,7 @@
TEST(sys_xattr, fsetxattr_with_opath) {
TemporaryFile tf;
- int fd = open(tf.filename, O_PATH);
+ int fd = open(tf.path, O_PATH);
ASSERT_NE(-1, fd);
int res = fsetxattr(fd, "user.foo", "bar", 4, 0);
@@ -85,7 +85,7 @@
TEST(sys_xattr, fsetxattr_with_opath_toosmall) {
TemporaryFile tf;
- int fd = open(tf.filename, O_PATH);
+ int fd = open(tf.path, O_PATH);
ASSERT_NE(-1, fd);
int res = fsetxattr(fd, "user.foo", "01234567890123456789", 21, 0);
@@ -114,7 +114,7 @@
TemporaryFile tf;
char buf[65536]; // 64kB is max possible xattr list size. See "man 7 xattr".
ASSERT_EQ(0, fsetxattr(tf.fd, "user.foo", "bar", 4, 0));
- int fd = open(tf.filename, O_PATH);
+ int fd = open(tf.path, O_PATH);
ASSERT_NE(-1, fd);
ssize_t res = flistxattr(fd, buf, sizeof(buf));
#if defined(__BIONIC__)
diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp
index 949019f..3b50896 100644
--- a/tests/system_properties_test.cpp
+++ b/tests/system_properties_test.cpp
@@ -24,7 +24,7 @@
#include <string>
#include <thread>
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
using namespace std::literals;
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index e82f15d..4ec5976 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -488,23 +488,6 @@
ASSERT_EQ(EINVAL, errno);
}
-TEST(time, timer_delete_multiple) {
- timer_t timer_id;
- ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, nullptr, &timer_id));
- ASSERT_EQ(0, timer_delete(timer_id));
- ASSERT_EQ(-1, timer_delete(timer_id));
- ASSERT_EQ(EINVAL, errno);
-
- sigevent_t se;
- memset(&se, 0, sizeof(se));
- se.sigev_notify = SIGEV_THREAD;
- se.sigev_notify_function = NoOpNotifyFunction;
- ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
- ASSERT_EQ(0, timer_delete(timer_id));
- ASSERT_EQ(-1, timer_delete(timer_id));
- ASSERT_EQ(EINVAL, errno);
-}
-
TEST(time, timer_create_multiple) {
Counter counter1(Counter::CountNotifyFunction);
Counter counter2(Counter::CountNotifyFunction);
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index da083de..f4a7f1f 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -18,7 +18,6 @@
#include "BionicDeathTest.h"
#include "SignalUtils.h"
-#include "TemporaryFile.h"
#include "utils.h"
#include <errno.h>
@@ -166,20 +165,20 @@
TEST(UNISTD_TEST, truncate) {
TemporaryFile tf;
ASSERT_EQ(0, close(tf.fd));
- ASSERT_EQ(0, truncate(tf.filename, 123));
+ ASSERT_EQ(0, truncate(tf.path, 123));
struct stat sb;
- ASSERT_EQ(0, stat(tf.filename, &sb));
+ ASSERT_EQ(0, stat(tf.path, &sb));
ASSERT_EQ(123, sb.st_size);
}
TEST(UNISTD_TEST, truncate64) {
TemporaryFile tf;
ASSERT_EQ(0, close(tf.fd));
- ASSERT_EQ(0, truncate64(tf.filename, 123));
+ ASSERT_EQ(0, truncate64(tf.path, 123));
struct stat sb;
- ASSERT_EQ(0, stat(tf.filename, &sb));
+ ASSERT_EQ(0, stat(tf.path, &sb));
ASSERT_EQ(123, sb.st_size);
}
@@ -189,7 +188,7 @@
ASSERT_EQ(0, close(tf.fd));
struct stat sb;
- ASSERT_EQ(0, stat(tf.filename, &sb));
+ ASSERT_EQ(0, stat(tf.path, &sb));
ASSERT_EQ(123, sb.st_size);
}
@@ -199,7 +198,7 @@
ASSERT_EQ(0, close(tf.fd));
struct stat sb;
- ASSERT_EQ(0, stat(tf.filename, &sb));
+ ASSERT_EQ(0, stat(tf.path, &sb));
ASSERT_EQ(123, sb.st_size);
}
@@ -389,11 +388,11 @@
EXPECT_EQ(0, fn(tf.fd));
- ASSERT_NE(-1, fd = open(tf.filename, O_RDONLY));
+ ASSERT_NE(-1, fd = open(tf.path, O_RDONLY));
EXPECT_EQ(0, fn(fd));
close(fd);
- ASSERT_NE(-1, fd = open(tf.filename, O_RDWR));
+ ASSERT_NE(-1, fd = open(tf.path, O_RDWR));
EXPECT_EQ(0, fn(fd));
close(fd);
@@ -671,11 +670,11 @@
long rc = 0L;
// As a file system's block size is always power of 2, the configure values
// for ALLOC and XFER should be power of 2 as well.
- rc = pathconf(tf.filename, _PC_ALLOC_SIZE_MIN);
+ rc = pathconf(tf.path, _PC_ALLOC_SIZE_MIN);
ASSERT_TRUE(rc > 0 && powerof2(rc));
- rc = pathconf(tf.filename, _PC_REC_MIN_XFER_SIZE);
+ rc = pathconf(tf.path, _PC_REC_MIN_XFER_SIZE);
ASSERT_TRUE(rc > 0 && powerof2(rc));
- rc = pathconf(tf.filename, _PC_REC_XFER_ALIGN);
+ rc = pathconf(tf.path, _PC_REC_XFER_ALIGN);
ASSERT_TRUE(rc > 0 && powerof2(rc));
rc = fpathconf(tf.fd, _PC_ALLOC_SIZE_MIN);
@@ -1343,38 +1342,38 @@
TEST(UNISTD_TEST, execvpe_ENOEXEC) {
// Create a shell script with #!.
TemporaryFile tf;
- ASSERT_TRUE(android::base::WriteStringToFile("#!" BIN_DIR "sh\necho script\n", tf.filename));
+ ASSERT_TRUE(android::base::WriteStringToFile("#!" BIN_DIR "sh\necho script\n", tf.path));
// Set $PATH so we can find it.
- setenv("PATH", dirname(tf.filename), 1);
+ setenv("PATH", dirname(tf.path), 1);
ExecTestHelper eth;
- eth.SetArgs({basename(tf.filename), nullptr});
+ eth.SetArgs({basename(tf.path), nullptr});
// It's not inherently executable.
errno = 0;
- ASSERT_EQ(-1, execvpe(basename(tf.filename), eth.GetArgs(), eth.GetEnv()));
+ ASSERT_EQ(-1, execvpe(basename(tf.path), eth.GetArgs(), eth.GetEnv()));
ASSERT_EQ(EACCES, errno);
// Make it executable (and keep it writable because we're going to rewrite it below).
- ASSERT_EQ(0, chmod(tf.filename, 0777));
+ ASSERT_EQ(0, chmod(tf.path, 0777));
// TemporaryFile will have a writable fd, so we can test ETXTBSY while we're here...
errno = 0;
- ASSERT_EQ(-1, execvpe(basename(tf.filename), eth.GetArgs(), eth.GetEnv()));
+ ASSERT_EQ(-1, execvpe(basename(tf.path), eth.GetArgs(), eth.GetEnv()));
ASSERT_EQ(ETXTBSY, errno);
// 1. The simplest test: the kernel should handle this.
ASSERT_EQ(0, close(tf.fd));
- eth.Run([&]() { execvpe(basename(tf.filename), eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
+ eth.Run([&]() { execvpe(basename(tf.path), eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
// 2. Try again without a #!. We should have to handle this ourselves.
- ASSERT_TRUE(android::base::WriteStringToFile("echo script\n", tf.filename));
- eth.Run([&]() { execvpe(basename(tf.filename), eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
+ ASSERT_TRUE(android::base::WriteStringToFile("echo script\n", tf.path));
+ eth.Run([&]() { execvpe(basename(tf.path), eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
// 3. Again without a #!, but also with a leading '/', since that's a special case in the
// implementation.
- eth.Run([&]() { execvpe(tf.filename, eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
+ eth.Run([&]() { execvpe(tf.path, eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
}
TEST(UNISTD_TEST, execvp_libcore_test_55017) {
diff --git a/tests/utils.h b/tests/utils.h
index c8656dc..5fc1d93 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -58,6 +58,14 @@
return (dlopen("libc.so", 0) != nullptr);
}
+extern "C" void __hwasan_init() __attribute__((weak));
+
+static inline bool running_with_hwasan() {
+ return &__hwasan_init != 0;
+}
+
+#define SKIP_WITH_HWASAN if (running_with_hwasan()) { return; }
+
#if defined(__linux__)
#include <sys/sysmacros.h>
diff --git a/tools/versioner/src/Driver.cpp b/tools/versioner/src/Driver.cpp
index 7c4aa23..8ba3d42 100644
--- a/tools/versioner/src/Driver.cpp
+++ b/tools/versioner/src/Driver.cpp
@@ -29,7 +29,6 @@
#include <clang/AST/ASTConsumer.h>
#include <clang/Basic/Diagnostic.h>
#include <clang/Basic/TargetInfo.h>
-#include <clang/Basic/VirtualFileSystem.h>
#include <clang/Driver/Compilation.h>
#include <clang/Driver/Driver.h>
#include <clang/Frontend/CompilerInstance.h>
@@ -42,6 +41,7 @@
#include <llvm/ADT/IntrusiveRefCntPtr.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/VirtualFileSystem.h>
#include "Arch.h"
#include "DeclarationDatabase.h"
@@ -93,7 +93,7 @@
// Run it once to generate flags for each target, and memoize the results.
static std::unordered_map<CompilationType, std::vector<std::string>> cc1_flags;
static const char* filename_placeholder = "__VERSIONER_PLACEHOLDER__";
-static void generateTargetCC1Flags(llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> vfs,
+static void generateTargetCC1Flags(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
CompilationType type,
const std::vector<std::string>& include_dirs) {
std::vector<std::string> cmd = { "versioner" };
@@ -207,7 +207,7 @@
return result;
}
-void initializeTargetCC1FlagCache(llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> vfs,
+void initializeTargetCC1FlagCache(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
const std::set<CompilationType>& types,
const std::unordered_map<Arch, CompilationRequirements>& reqs) {
if (!cc1_flags.empty()) {
@@ -242,7 +242,7 @@
}
}
-void compileHeader(llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> vfs,
+void compileHeader(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
HeaderDatabase* header_database, CompilationType type,
const std::string& filename) {
auto diags = constructDiags();
diff --git a/tools/versioner/src/Driver.h b/tools/versioner/src/Driver.h
index 48683e4..99e57ae 100644
--- a/tools/versioner/src/Driver.h
+++ b/tools/versioner/src/Driver.h
@@ -31,10 +31,10 @@
std::vector<std::string> dependencies;
};
-void initializeTargetCC1FlagCache(llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> vfs,
+void initializeTargetCC1FlagCache(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
const std::set<CompilationType>& types,
const std::unordered_map<Arch, CompilationRequirements>& reqs);
-void compileHeader(llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> vfs,
+void compileHeader(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
HeaderDatabase* header_database, CompilationType type,
const std::string& filename);
diff --git a/tools/versioner/src/VFS.cpp b/tools/versioner/src/VFS.cpp
index 8f9de88..d797f82 100644
--- a/tools/versioner/src/VFS.cpp
+++ b/tools/versioner/src/VFS.cpp
@@ -25,14 +25,14 @@
#include <string>
#include <android-base/unique_fd.h>
-#include <clang/Basic/VirtualFileSystem.h>
#include <llvm/ADT/IntrusiveRefCntPtr.h>
#include <llvm/Support/MemoryBuffer.h>
+#include <llvm/Support/VirtualFileSystem.h>
#include "Utils.h"
using android::base::unique_fd;
-using namespace clang::vfs;
+using namespace llvm::vfs;
static void addDirectoryToVFS(InMemoryFileSystem* vfs, const std::string& path) {
char* paths[] = { const_cast<char*>(path.c_str()), nullptr };
diff --git a/tools/versioner/src/VFS.h b/tools/versioner/src/VFS.h
index e2ab002..e4aac75 100644
--- a/tools/versioner/src/VFS.h
+++ b/tools/versioner/src/VFS.h
@@ -20,8 +20,8 @@
#include <string>
#include <llvm/ADT/IntrusiveRefCntPtr.h>
-#include <clang/Basic/VirtualFileSystem.h>
+#include <llvm/Support/VirtualFileSystem.h>
-llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> createCommonVFS(const std::string& header_dir,
- const std::string& dependency_dir,
- bool add_versioning_header);
+llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> createCommonVFS(const std::string& header_dir,
+ const std::string& dependency_dir,
+ bool add_versioning_header);