Merge "Eliminate ICU's .dat lookup from bionic"
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..376c250
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,52 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+bionic_mountpoint {
+ name: "libc.mountpoint",
+ stem: "libc.so",
+ src: "dummy_mountpoint",
+ library: true,
+ symlinks: ["libc.so"],
+}
+
+bionic_mountpoint {
+ name: "libdl.mountpoint",
+ stem: "libdl.so",
+ src: "dummy_mountpoint",
+ library: true,
+ symlinks: ["libdl.so"],
+}
+
+bionic_mountpoint {
+ name: "libm.mountpoint",
+ stem: "libm.so",
+ src: "dummy_mountpoint",
+ library: true,
+ symlinks: ["libm.so"],
+}
+
+bionic_mountpoint {
+ name: "linker.mountpoint",
+ stem: "linker",
+ multilib: {
+ lib64: {
+ suffix: "64",
+ },
+ },
+ src: "dummy_mountpoint",
+ binary: true,
+ symlinks: ["linker", "linker_asan"],
+}
diff --git a/build/Android.bp b/build/Android.bp
new file mode 100644
index 0000000..6cc160a
--- /dev/null
+++ b/build/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+bootstrap_go_package {
+ name: "soong-bionic",
+ pkgPath: "android/soong/bionic",
+ deps: [
+ "blueprint",
+ "blueprint-pathtools",
+ "blueprint-proptools",
+ "soong",
+ "soong-android",
+ ],
+ srcs: [
+ "bionic.go",
+ ],
+ pluginFor: ["soong_build"],
+}
diff --git a/build/bionic.go b/build/bionic.go
new file mode 100644
index 0000000..3522aca
--- /dev/null
+++ b/build/bionic.go
@@ -0,0 +1,164 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bionic
+
+import (
+ "fmt"
+ "io"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+)
+
+// bionic_mountpoint is a module type that is specialized to create
+// mount points for Bionic files (libc, libdl, libm, and linker).
+//
+// With following description,
+//
+// bionic_mountpoint {
+// name: "libc.mountpoint",
+// stem: "libc.so",
+// src: "dummy_mountpoint",
+// library: true,
+// symlinks: ["libc.so"],
+// }
+//
+// , the build system does following jobs:
+//
+// A mount point /bionic/lib[64]/libc.so is created. Its content
+// is from the file 'dummy_mountpoint'.
+//
+// Then a symlink is created at /system/lib[64]/libc.so which points to
+// the created mountpoint.
+//
+// At runtime, on the mount point, either bootstrap Bionic or default Bionic
+// (which is from the runtime APEX) is mounted by the init process. The
+// symlink exists to provide consistent legacy path for compatibility
+// reason.
+func init() {
+ android.RegisterModuleType("bionic_mountpoint", bionicMountpointFactory)
+}
+
+type bionicMountpoint struct {
+ android.ModuleBase
+ properties bionicMountpointProperties
+
+ outputFile android.Path
+ pathInPartition string
+ stem string
+}
+
+type bionicMountpointProperties struct {
+ // The file that is installed as the mount point
+ Src *string
+
+ // True if the mount point is for a Bionic library such libc.so
+ Library *bool
+ // True if the mount point is for a Bionic binary such as linker
+ Binary *bool
+
+ // Base name of the mount point
+ Stem *string `android:"arch_variant"`
+
+ // Append to the name of the output
+ Suffix *string `android:"arch_variant"`
+
+ // Symlinks to the mountpoints from the system and recovery partitions
+ // Symlinks names will have the same suffix as the mount point
+ Symlinks []string
+}
+
+func (m *bionicMountpoint) DepsMutator(ctx android.BottomUpMutatorContext) {
+ if Bool(m.properties.Library) == Bool(m.properties.Binary) {
+ ctx.ModuleErrorf("either binary or library must be set to true")
+ return
+ }
+ if m.properties.Stem == nil {
+ ctx.PropertyErrorf("stem", "stem must be set")
+ return
+ }
+ if m.properties.Src == nil {
+ ctx.PropertyErrorf("src", "src must be set")
+ }
+ android.ExtractSourceDeps(ctx, m.properties.Src)
+}
+
+func (m *bionicMountpoint) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if Bool(m.properties.Library) {
+ m.pathInPartition = "lib"
+ if m.Arch().ArchType.Multilib == "lib64" {
+ m.pathInPartition = "lib64"
+ }
+ } else if Bool(m.properties.Binary) {
+ m.pathInPartition = "bin"
+ }
+
+ m.stem = String(m.properties.Stem) + String(m.properties.Suffix)
+
+ m.outputFile = ctx.ExpandSource(String(m.properties.Src), "src")
+}
+
+func (m *bionicMountpoint) AndroidMk() android.AndroidMkData {
+ return android.AndroidMkData {
+ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+ if !m.Arch().Native {
+ return
+ }
+ fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
+ fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
+ fmt.Fprintln(w, "LOCAL_MODULE :=", name)
+ fmt.Fprintln(w, "LOCAL_USE_CLANG_LLD := false")
+ fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false")
+ if Bool(m.properties.Library) {
+ fmt.Fprintln(w, "LOCAL_MODULE_CLASS := SHARED_LIBRARIES")
+ } else if Bool(m.properties.Binary) {
+ fmt.Fprintln(w, "LOCAL_MODULE_CLASS := EXECUTABLES")
+ }
+ fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
+ fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", m.outputFile.String())
+ fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", m.Arch().ArchType.String())
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", "$(TARGET_ROOT_OUT)/bionic/" + m.pathInPartition)
+ fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", m.stem)
+
+ if len(m.properties.Symlinks) > 0 {
+ symlink_dir_in_system := "$(TARGET_OUT)/" + m.pathInPartition + "/"
+ symlink_dir_in_recovery := "$(TARGET_RECOVERY_ROOT_OUT)/system/" + m.pathInPartition + "/"
+ symlink_target := "/bionic/" + m.pathInPartition + "/" + m.stem
+ cmds := []string{}
+ cmds = append(cmds, "$(hide) mkdir -p " + symlink_dir_in_system)
+ cmds = append(cmds, "mkdir -p " + symlink_dir_in_recovery)
+ for _, s := range m.properties.Symlinks {
+ symlink := s + String(m.properties.Suffix)
+ cmds = append(cmds, "ln -sf " + symlink_target + " " + symlink_dir_in_system + symlink)
+ cmds = append(cmds, "ln -sf " + symlink_target + " " + symlink_dir_in_recovery + symlink)
+ }
+ fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := " + strings.Join(cmds, " && "))
+ }
+ fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+ },
+ }
+}
+
+func bionicMountpointFactory() android.Module {
+ m := &bionicMountpoint{}
+ m.AddProperties(&m.properties)
+ android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibBoth)
+ return m
+}
+
+var Bool = proptools.Bool
+var String = proptools.String
diff --git a/dummy_mountpoint b/dummy_mountpoint
new file mode 100644
index 0000000..2d13c55
--- /dev/null
+++ b/dummy_mountpoint
@@ -0,0 +1 @@
+This file serves as a mount point for bionic files either from /system partition or from /apex/com.android.runtime. This file is never meant to be accessed directly.
diff --git a/libc/Android.bp b/libc/Android.bp
index 226a81f..dc437d8 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -328,13 +328,10 @@
"upstream-netbsd/lib/libc/regex/regexec.c",
"upstream-netbsd/lib/libc/regex/regfree.c",
"upstream-netbsd/lib/libc/stdlib/bsearch.c",
- "upstream-netbsd/lib/libc/stdlib/div.c",
"upstream-netbsd/lib/libc/stdlib/drand48.c",
"upstream-netbsd/lib/libc/stdlib/erand48.c",
"upstream-netbsd/lib/libc/stdlib/jrand48.c",
"upstream-netbsd/lib/libc/stdlib/lcong48.c",
- "upstream-netbsd/lib/libc/stdlib/ldiv.c",
- "upstream-netbsd/lib/libc/stdlib/lldiv.c",
"upstream-netbsd/lib/libc/stdlib/lrand48.c",
"upstream-netbsd/lib/libc/stdlib/mrand48.c",
"upstream-netbsd/lib/libc/stdlib/nrand48.c",
@@ -343,10 +340,6 @@
"upstream-netbsd/lib/libc/stdlib/reallocarr.c",
"upstream-netbsd/lib/libc/stdlib/seed48.c",
"upstream-netbsd/lib/libc/stdlib/srand48.c",
- "upstream-netbsd/lib/libc/string/memccpy.c",
- "upstream-netbsd/lib/libc/string/strcasestr.c",
- "upstream-netbsd/lib/libc/string/strcoll.c",
- "upstream-netbsd/lib/libc/string/strxfrm.c",
],
multilib: {
lib32: {
@@ -456,19 +449,25 @@
"upstream-openbsd/lib/libc/stdio/wbuf.c",
"upstream-openbsd/lib/libc/stdio/wsetup.c",
"upstream-openbsd/lib/libc/stdlib/abs.c",
+ "upstream-openbsd/lib/libc/stdlib/div.c",
"upstream-openbsd/lib/libc/stdlib/getenv.c",
"upstream-openbsd/lib/libc/stdlib/getsubopt.c",
"upstream-openbsd/lib/libc/stdlib/insque.c",
"upstream-openbsd/lib/libc/stdlib/imaxabs.c",
"upstream-openbsd/lib/libc/stdlib/imaxdiv.c",
"upstream-openbsd/lib/libc/stdlib/labs.c",
+ "upstream-openbsd/lib/libc/stdlib/ldiv.c",
"upstream-openbsd/lib/libc/stdlib/llabs.c",
+ "upstream-openbsd/lib/libc/stdlib/lldiv.c",
"upstream-openbsd/lib/libc/stdlib/lsearch.c",
"upstream-openbsd/lib/libc/stdlib/remque.c",
"upstream-openbsd/lib/libc/stdlib/setenv.c",
"upstream-openbsd/lib/libc/stdlib/tfind.c",
"upstream-openbsd/lib/libc/stdlib/tsearch.c",
+ "upstream-openbsd/lib/libc/string/memccpy.c",
"upstream-openbsd/lib/libc/string/strcasecmp.c",
+ "upstream-openbsd/lib/libc/string/strcasestr.c",
+ "upstream-openbsd/lib/libc/string/strcoll.c",
"upstream-openbsd/lib/libc/string/strcspn.c",
"upstream-openbsd/lib/libc/string/strdup.c",
"upstream-openbsd/lib/libc/string/strndup.c",
@@ -477,6 +476,7 @@
"upstream-openbsd/lib/libc/string/strspn.c",
"upstream-openbsd/lib/libc/string/strstr.c",
"upstream-openbsd/lib/libc/string/strtok.c",
+ "upstream-openbsd/lib/libc/string/strxfrm.c",
"upstream-openbsd/lib/libc/string/wcslcpy.c",
"upstream-openbsd/lib/libc/string/wcswidth.c",
],
@@ -1548,7 +1548,7 @@
],
},
- required: ["tzdata"],
+ required: ["tzdata", "libc.mountpoint"],
// Leave the symbols in the shared library so that stack unwinders can produce
// meaningful name resolution.
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 514423d..3219239 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -66,6 +66,30 @@
}
}
+#if defined(__aarch64__) || defined(__x86_64__)
+extern __LIBC_HIDDEN__ ElfW(Rela) __rela_iplt_start[], __rela_iplt_end[];
+
+static void call_ifunc_resolvers() {
+ typedef ElfW(Addr) (*ifunc_resolver_t)(void);
+ for (ElfW(Rela) *r = __rela_iplt_start; r != __rela_iplt_end; ++r) {
+ ElfW(Addr)* offset = reinterpret_cast<ElfW(Addr)*>(r->r_offset);
+ ElfW(Addr) resolver = r->r_addend;
+ *offset = reinterpret_cast<ifunc_resolver_t>(resolver)();
+ }
+}
+#else
+extern __LIBC_HIDDEN__ ElfW(Rel) __rel_iplt_start[], __rel_iplt_end[];
+
+static void call_ifunc_resolvers() {
+ typedef ElfW(Addr) (*ifunc_resolver_t)(void);
+ for (ElfW(Rel) *r = __rel_iplt_start; r != __rel_iplt_end; ++r) {
+ ElfW(Addr)* offset = reinterpret_cast<ElfW(Addr)*>(r->r_offset);
+ ElfW(Addr) resolver = *offset;
+ *offset = reinterpret_cast<ifunc_resolver_t>(resolver)();
+ }
+}
+#endif
+
static void apply_gnu_relro() {
ElfW(Phdr)* phdr_start = reinterpret_cast<ElfW(Phdr)*>(getauxval(AT_PHDR));
unsigned long int phdr_ct = getauxval(AT_PHNUM);
@@ -137,6 +161,7 @@
__libc_init_main_thread_final();
__libc_init_common();
+ call_ifunc_resolvers();
apply_gnu_relro();
// Several Linux ABIs don't pass the onexit pointer, and the ones that
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index fc65e15..50c2fec 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -604,9 +604,8 @@
return impl_handle;
}
-// A function pointer to heapprofds init function. Used to re-initialize
-// heapprofd. This will start a new profiling session and tear down the old
-// one in case it is still active.
+// The handle returned by dlopen when previously loading the heapprofd
+// hooks. nullptr if they had not been loaded before.
static _Atomic (void*) g_heapprofd_handle = nullptr;
static void install_hooks(libc_globals* globals, const char* options,
@@ -614,7 +613,8 @@
MallocDispatch dispatch_table;
void* impl_handle = atomic_load(&g_heapprofd_handle);
- if (impl_handle != nullptr) {
+ bool reusing_handle = impl_handle != nullptr;
+ if (reusing_handle) {
if (!InitSharedLibrary(impl_handle, shared_lib, prefix, &dispatch_table)) {
return;
}
@@ -627,7 +627,11 @@
init_func_t init_func = reinterpret_cast<init_func_t>(g_functions[FUNC_INITIALIZE]);
if (!init_func(&__libc_malloc_default_dispatch, &gMallocLeakZygoteChild, options)) {
error_log("%s: failed to enable malloc %s", getprogname(), prefix);
- dlclose(impl_handle);
+ if (!reusing_handle) {
+ // We should not close if we are re-using an old handle, as we cannot be
+ // sure other threads are not currently in the hooks.
+ dlclose(impl_handle);
+ }
ClearGlobalFunctions();
return;
}
diff --git a/libc/bionic/pthread_detach.cpp b/libc/bionic/pthread_detach.cpp
index c2e4127..6b22039 100644
--- a/libc/bionic/pthread_detach.cpp
+++ b/libc/bionic/pthread_detach.cpp
@@ -34,7 +34,7 @@
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int pthread_detach(pthread_t t) {
- pthread_internal_t* thread = __pthread_internal_find(t);
+ pthread_internal_t* thread = __pthread_internal_find(t, "pthread_detach");
if (thread == nullptr) {
return ESRCH;
}
diff --git a/libc/bionic/pthread_getcpuclockid.cpp b/libc/bionic/pthread_getcpuclockid.cpp
index f641e4c..0b35998 100644
--- a/libc/bionic/pthread_getcpuclockid.cpp
+++ b/libc/bionic/pthread_getcpuclockid.cpp
@@ -31,7 +31,7 @@
#include "pthread_internal.h"
int pthread_getcpuclockid(pthread_t t, clockid_t* clockid) {
- pid_t tid = pthread_gettid_np(t);
+ pid_t tid = __pthread_internal_gettid(t, "pthread_getcpuclockid");
if (tid == -1) return ESRCH;
// The tid is stored in the top bits, but negated.
diff --git a/libc/bionic/pthread_getschedparam.cpp b/libc/bionic/pthread_getschedparam.cpp
index cc1ece8..ed1853b 100644
--- a/libc/bionic/pthread_getschedparam.cpp
+++ b/libc/bionic/pthread_getschedparam.cpp
@@ -34,7 +34,7 @@
int pthread_getschedparam(pthread_t t, int* policy, sched_param* param) {
ErrnoRestorer errno_restorer;
- pid_t tid = pthread_gettid_np(t);
+ pid_t tid = __pthread_internal_gettid(t, "pthread_getschedparam");
if (tid == -1) return ESRCH;
if (sched_getparam(tid, param) == -1) return errno;
diff --git a/libc/bionic/pthread_gettid_np.cpp b/libc/bionic/pthread_gettid_np.cpp
index 1beddc9..d14900b 100644
--- a/libc/bionic/pthread_gettid_np.cpp
+++ b/libc/bionic/pthread_gettid_np.cpp
@@ -31,6 +31,5 @@
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
pid_t pthread_gettid_np(pthread_t t) {
- pthread_internal_t* thread = __pthread_internal_find(t);
- return thread ? thread->tid : -1;
+ return __pthread_internal_gettid(t, "pthread_gettid_np");
}
diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp
index 46fa630..6fddefe 100644
--- a/libc/bionic/pthread_internal.cpp
+++ b/libc/bionic/pthread_internal.cpp
@@ -80,7 +80,12 @@
__pthread_internal_free(thread);
}
-pthread_internal_t* __pthread_internal_find(pthread_t thread_id) {
+pid_t __pthread_internal_gettid(pthread_t thread_id, const char* caller) {
+ pthread_internal_t* thread = __pthread_internal_find(thread_id, caller);
+ return thread ? thread->tid : -1;
+}
+
+pthread_internal_t* __pthread_internal_find(pthread_t thread_id, const char* caller) {
pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(thread_id);
// Check if we're looking for ourselves before acquiring the lock.
@@ -103,9 +108,9 @@
// addresses might sometimes contain threads or things that look enough like
// threads for us to do some real damage by continuing.
// TODO: try getting rid of this when Treble lets us keep vendor blobs on an old API level.
- async_safe_format_log(ANDROID_LOG_WARN, "libc", "invalid pthread_t (0) passed to libc");
+ async_safe_format_log(ANDROID_LOG_WARN, "libc", "invalid pthread_t (0) passed to %s", caller);
} else {
- async_safe_fatal("invalid pthread_t %p passed to libc", thread);
+ async_safe_fatal("invalid pthread_t %p passed to %s", thread, caller);
}
}
return nullptr;
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index cbcdadf..a1e0c45 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -163,10 +163,11 @@
__LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread);
__LIBC_HIDDEN__ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_size);
-__LIBC_HIDDEN__ pthread_t __pthread_internal_add(pthread_internal_t* thread);
-__LIBC_HIDDEN__ pthread_internal_t* __pthread_internal_find(pthread_t pthread_id);
-__LIBC_HIDDEN__ void __pthread_internal_remove(pthread_internal_t* thread);
-__LIBC_HIDDEN__ void __pthread_internal_remove_and_free(pthread_internal_t* thread);
+__LIBC_HIDDEN__ pthread_t __pthread_internal_add(pthread_internal_t* thread);
+__LIBC_HIDDEN__ pthread_internal_t* __pthread_internal_find(pthread_t pthread_id, const char* caller);
+__LIBC_HIDDEN__ pid_t __pthread_internal_gettid(pthread_t pthread_id, const char* caller);
+__LIBC_HIDDEN__ void __pthread_internal_remove(pthread_internal_t* thread);
+__LIBC_HIDDEN__ void __pthread_internal_remove_and_free(pthread_internal_t* thread);
static inline __always_inline bionic_tcb* __get_bionic_tcb() {
return reinterpret_cast<bionic_tcb*>(&__get_tls()[MIN_TLS_SLOT]);
diff --git a/libc/bionic/pthread_join.cpp b/libc/bionic/pthread_join.cpp
index 8e4ca59..e230fab 100644
--- a/libc/bionic/pthread_join.cpp
+++ b/libc/bionic/pthread_join.cpp
@@ -40,7 +40,7 @@
return EDEADLK;
}
- pthread_internal_t* thread = __pthread_internal_find(t);
+ pthread_internal_t* thread = __pthread_internal_find(t, "pthread_join");
if (thread == nullptr) {
return ESRCH;
}
diff --git a/libc/bionic/pthread_kill.cpp b/libc/bionic/pthread_kill.cpp
index 1531574..8b38f4c 100644
--- a/libc/bionic/pthread_kill.cpp
+++ b/libc/bionic/pthread_kill.cpp
@@ -35,7 +35,7 @@
int pthread_kill(pthread_t t, int sig) {
ErrnoRestorer errno_restorer;
- pid_t tid = pthread_gettid_np(t);
+ pid_t tid = __pthread_internal_gettid(t, "pthread_kill");
// tid gets reset to 0 on thread exit by CLONE_CHILD_CLEARTID.
if (tid == 0 || tid == -1) return ESRCH;
diff --git a/libc/bionic/pthread_setname_np.cpp b/libc/bionic/pthread_setname_np.cpp
index f582d53..f673983 100644
--- a/libc/bionic/pthread_setname_np.cpp
+++ b/libc/bionic/pthread_setname_np.cpp
@@ -42,9 +42,10 @@
// This value is not exported by kernel headers.
#define MAX_TASK_COMM_LEN 16
-static int __open_task_comm_fd(pthread_t t, int flags) {
+static int __open_task_comm_fd(pthread_t t, int flags, const char* caller) {
char comm_name[64];
- snprintf(comm_name, sizeof(comm_name), "/proc/self/task/%d/comm", pthread_gettid_np(t));
+ snprintf(comm_name, sizeof(comm_name), "/proc/self/task/%d/comm",
+ __pthread_internal_gettid(t, caller));
return open(comm_name, O_CLOEXEC | flags);
}
@@ -59,7 +60,7 @@
}
// We have to get another thread's name.
- int fd = __open_task_comm_fd(t, O_RDONLY);
+ int fd = __open_task_comm_fd(t, O_RDONLY, "pthread_getname_np");
if (fd == -1) return errno;
ssize_t n = TEMP_FAILURE_RETRY(read(fd, buf, buf_size));
@@ -91,7 +92,7 @@
}
// We have to set another thread's name.
- int fd = __open_task_comm_fd(t, O_WRONLY);
+ int fd = __open_task_comm_fd(t, O_WRONLY, "pthread_setname_np");
if (fd == -1) return errno;
ssize_t n = TEMP_FAILURE_RETRY(write(fd, thread_name, thread_name_len));
diff --git a/libc/bionic/pthread_setschedparam.cpp b/libc/bionic/pthread_setschedparam.cpp
index 10826d1..8a02728 100644
--- a/libc/bionic/pthread_setschedparam.cpp
+++ b/libc/bionic/pthread_setschedparam.cpp
@@ -31,11 +31,12 @@
#include <sched.h>
#include "private/ErrnoRestorer.h"
+#include "pthread_internal.h"
int pthread_setschedparam(pthread_t t, int policy, const sched_param* param) {
ErrnoRestorer errno_restorer;
- pid_t tid = pthread_gettid_np(t);
+ pid_t tid = __pthread_internal_gettid(t, "pthread_setschedparam");
if (tid == -1) return ESRCH;
return (sched_setscheduler(tid, policy, param) == -1) ? errno : 0;
@@ -44,7 +45,7 @@
int pthread_setschedprio(pthread_t t, int priority) {
ErrnoRestorer errno_restorer;
- pid_t tid = pthread_gettid_np(t);
+ pid_t tid = __pthread_internal_gettid(t, "pthread_setschedprio");
if (tid == -1) return ESRCH;
sched_param param = { .sched_priority = priority };
diff --git a/libc/bionic/pthread_sigqueue.cpp b/libc/bionic/pthread_sigqueue.cpp
index 34bda38..5d13ed5 100644
--- a/libc/bionic/pthread_sigqueue.cpp
+++ b/libc/bionic/pthread_sigqueue.cpp
@@ -38,7 +38,7 @@
int pthread_sigqueue(pthread_t t, int sig, const union sigval value) {
ErrnoRestorer errno_restorer;
- pid_t tid = pthread_gettid_np(t);
+ pid_t tid = __pthread_internal_gettid(t, "pthread_sigqueue");
if (tid == -1) return ESRCH;
siginfo_t siginfo;
diff --git a/libc/stdio/fmemopen.cpp b/libc/stdio/fmemopen.cpp
index 9d8c41f..6e333ba 100644
--- a/libc/stdio/fmemopen.cpp
+++ b/libc/stdio/fmemopen.cpp
@@ -149,7 +149,9 @@
} else if (mode[0] == 'w') {
ck->size = 0;
ck->offset = 0;
- ck->buf[0] = '\0';
+ if (capacity > 0) {
+ ck->buf[0] = '\0';
+ }
}
return fp;
diff --git a/libc/upstream-netbsd/lib/libc/stdlib/lldiv.c b/libc/upstream-netbsd/lib/libc/stdlib/lldiv.c
deleted file mode 100644
index 47104b3..0000000
--- a/libc/upstream-netbsd/lib/libc/stdlib/lldiv.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* $NetBSD: lldiv.c,v 1.4 2012/06/25 22:32:45 abs Exp $ */
-
-/*
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "from: @(#)ldiv.c 8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: lldiv.c,v 1.4 2012/06/25 22:32:45 abs Exp $");
-#endif
-#endif /* LIBC_SCCS and not lint */
-
-#include "namespace.h"
-#include <stdlib.h> /* lldiv_t */
-
-#ifdef __weak_alias
-__weak_alias(lldiv, _lldiv)
-#endif
-
-/* LONGLONG */
-lldiv_t
-lldiv(long long int num, long long int denom)
-{
- lldiv_t r;
-
- /* see div.c for comments */
-
- r.quot = num / denom;
- r.rem = num % denom;
- if (num >= 0 && r.rem < 0) {
- r.quot++;
- r.rem -= denom;
- }
- return (r);
-}
diff --git a/libc/upstream-netbsd/lib/libc/stdlib/div.c b/libc/upstream-openbsd/lib/libc/stdlib/div.c
similarity index 86%
rename from libc/upstream-netbsd/lib/libc/stdlib/div.c
rename to libc/upstream-openbsd/lib/libc/stdlib/div.c
index f3bd32f..beaa428 100644
--- a/libc/upstream-netbsd/lib/libc/stdlib/div.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/div.c
@@ -1,8 +1,7 @@
-/* $NetBSD: div.c,v 1.8 2012/06/25 22:32:45 abs Exp $ */
-
+/* $OpenBSD: div.c,v 1.6 2015/09/13 08:31:47 guenther Exp $ */
/*
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
@@ -32,15 +31,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)div.c 8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: div.c,v 1.8 2012/06/25 22:32:45 abs Exp $");
-#endif
-#endif /* LIBC_SCCS and not lint */
-
#include <stdlib.h> /* div_t */
div_t
@@ -79,3 +69,4 @@
}
return (r);
}
+DEF_STRONG(div);
diff --git a/libc/upstream-netbsd/lib/libc/stdlib/ldiv.c b/libc/upstream-openbsd/lib/libc/stdlib/ldiv.c
similarity index 81%
rename from libc/upstream-netbsd/lib/libc/stdlib/ldiv.c
rename to libc/upstream-openbsd/lib/libc/stdlib/ldiv.c
index 507c831..775065f 100644
--- a/libc/upstream-netbsd/lib/libc/stdlib/ldiv.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/ldiv.c
@@ -1,8 +1,7 @@
-/* $NetBSD: ldiv.c,v 1.8 2012/06/25 22:32:45 abs Exp $ */
-
+/* $OpenBSD: ldiv.c,v 1.5 2005/08/08 08:05:36 espie Exp $ */
/*
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
@@ -32,15 +31,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)ldiv.c 8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: ldiv.c,v 1.8 2012/06/25 22:32:45 abs Exp $");
-#endif
-#endif /* LIBC_SCCS and not lint */
-
#include <stdlib.h> /* ldiv_t */
ldiv_t
diff --git a/libc/upstream-netbsd/lib/libc/stdlib/ldiv.c b/libc/upstream-openbsd/lib/libc/stdlib/lldiv.c
similarity index 78%
copy from libc/upstream-netbsd/lib/libc/stdlib/ldiv.c
copy to libc/upstream-openbsd/lib/libc/stdlib/lldiv.c
index 507c831..59c37b8 100644
--- a/libc/upstream-netbsd/lib/libc/stdlib/ldiv.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/lldiv.c
@@ -1,8 +1,7 @@
-/* $NetBSD: ldiv.c,v 1.8 2012/06/25 22:32:45 abs Exp $ */
-
+/* $OpenBSD: lldiv.c,v 1.2 2016/08/14 23:18:03 guenther Exp $ */
/*
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
@@ -32,21 +31,12 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)ldiv.c 8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: ldiv.c,v 1.8 2012/06/25 22:32:45 abs Exp $");
-#endif
-#endif /* LIBC_SCCS and not lint */
+#include <stdlib.h> /* lldiv_t */
-#include <stdlib.h> /* ldiv_t */
-
-ldiv_t
-ldiv(long num, long denom)
+lldiv_t
+lldiv(long long num, long long denom)
{
- ldiv_t r;
+ lldiv_t r;
/* see div.c for comments */
@@ -58,3 +48,5 @@
}
return (r);
}
+
+__weak_alias(qdiv, lldiv);
diff --git a/libc/upstream-netbsd/lib/libc/string/memccpy.c b/libc/upstream-openbsd/lib/libc/string/memccpy.c
similarity index 83%
rename from libc/upstream-netbsd/lib/libc/string/memccpy.c
rename to libc/upstream-openbsd/lib/libc/string/memccpy.c
index c086241..635061b 100644
--- a/libc/upstream-netbsd/lib/libc/string/memccpy.c
+++ b/libc/upstream-openbsd/lib/libc/string/memccpy.c
@@ -1,4 +1,4 @@
-/* $NetBSD: memccpy.c,v 1.13 2012/06/25 22:32:46 abs Exp $ */
+/* $OpenBSD: memccpy.c,v 1.7 2015/08/31 02:53:57 guenther Exp $ */
/*-
* Copyright (c) 1990, 1993
@@ -29,25 +29,12 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)memccpy.c 8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: memccpy.c,v 1.13 2012/06/25 22:32:46 abs Exp $");
-#endif
-#endif /* LIBC_SCCS and not lint */
-
-#include <assert.h>
#include <string.h>
void *
memccpy(void *t, const void *f, int c, size_t n)
{
- _DIAGASSERT(t != 0);
- _DIAGASSERT(f != 0);
-
if (n) {
unsigned char *tp = t;
const unsigned char *fp = f;
@@ -59,3 +46,4 @@
}
return (0);
}
+DEF_WEAK(memccpy);
diff --git a/libc/upstream-netbsd/lib/libc/string/strcasestr.c b/libc/upstream-openbsd/lib/libc/string/strcasestr.c
similarity index 83%
rename from libc/upstream-netbsd/lib/libc/string/strcasestr.c
rename to libc/upstream-openbsd/lib/libc/string/strcasestr.c
index f8a9444..abb3e15 100644
--- a/libc/upstream-netbsd/lib/libc/string/strcasestr.c
+++ b/libc/upstream-openbsd/lib/libc/string/strcasestr.c
@@ -1,4 +1,5 @@
-/* $NetBSD: strcasestr.c,v 1.3 2005/11/29 03:12:00 christos Exp $ */
+/* $OpenBSD: strcasestr.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
+/* $NetBSD: strcasestr.c,v 1.2 2005/02/09 21:35:47 kleink Exp $ */
/*-
* Copyright (c) 1990, 1993
@@ -32,13 +33,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: strcasestr.c,v 1.3 2005/11/29 03:12:00 christos Exp $");
-#endif /* LIBC_SCCS and not lint */
-
-#include "namespace.h"
-#include <assert.h>
#include <ctype.h>
#include <string.h>
@@ -51,11 +45,8 @@
char c, sc;
size_t len;
- _DIAGASSERT(s != NULL);
- _DIAGASSERT(find != NULL);
-
if ((c = *find++) != 0) {
- c = tolower((unsigned char)c);
+ c = (char)tolower((unsigned char)c);
len = strlen(find);
do {
do {
@@ -65,5 +56,6 @@
} while (strncasecmp(s, find, len) != 0);
s--;
}
- return __UNCONST(s);
+ return ((char *)s);
}
+DEF_WEAK(strcasestr);
diff --git a/libc/upstream-netbsd/lib/libc/string/strcoll.c b/libc/upstream-openbsd/lib/libc/string/strcoll.c
similarity index 78%
rename from libc/upstream-netbsd/lib/libc/string/strcoll.c
rename to libc/upstream-openbsd/lib/libc/string/strcoll.c
index 77a0942..47a6ea4 100644
--- a/libc/upstream-netbsd/lib/libc/string/strcoll.c
+++ b/libc/upstream-openbsd/lib/libc/string/strcoll.c
@@ -1,8 +1,7 @@
-/* $NetBSD: strcoll.c,v 1.10 2012/06/25 22:32:46 abs Exp $ */
-
+/* $OpenBSD: strcoll.c,v 1.6 2015/08/31 02:53:57 guenther Exp $ */
/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
@@ -32,16 +31,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)strcoll.c 8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: strcoll.c,v 1.10 2012/06/25 22:32:46 abs Exp $");
-#endif
-#endif /* LIBC_SCCS and not lint */
-
-#include <assert.h>
#include <string.h>
/*
@@ -50,10 +39,7 @@
int
strcoll(const char *s1, const char *s2)
{
-
- _DIAGASSERT(s1 != NULL);
- _DIAGASSERT(s2 != NULL);
-
/* LC_COLLATE is unimplemented, hence always "C" */
return (strcmp(s1, s2));
}
+DEF_STRONG(strcoll);
diff --git a/libc/upstream-netbsd/lib/libc/string/strxfrm.c b/libc/upstream-openbsd/lib/libc/string/strxfrm.c
similarity index 73%
rename from libc/upstream-netbsd/lib/libc/string/strxfrm.c
rename to libc/upstream-openbsd/lib/libc/string/strxfrm.c
index 42c2a24..97df097 100644
--- a/libc/upstream-netbsd/lib/libc/string/strxfrm.c
+++ b/libc/upstream-openbsd/lib/libc/string/strxfrm.c
@@ -1,8 +1,7 @@
-/* $NetBSD: strxfrm.c,v 1.12 2012/06/25 22:32:46 abs Exp $ */
-
+/* $OpenBSD: strxfrm.c,v 1.7 2015/08/31 02:53:57 guenther Exp $ */
/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
@@ -32,16 +31,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)strxfrm.c 8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: strxfrm.c,v 1.12 2012/06/25 22:32:46 abs Exp $");
-#endif
-#endif /* LIBC_SCCS and not lint */
-
-#include <assert.h>
#include <string.h>
/*
@@ -52,19 +41,12 @@
size_t
strxfrm(char *dst, const char *src, size_t n)
{
- size_t srclen, copysize;
-
- _DIAGASSERT(src != NULL);
/*
* Since locales are unimplemented, this is just a copy.
*/
- srclen = strlen(src);
- if (n != 0) {
- _DIAGASSERT(dst != NULL);
- copysize = srclen < n ? srclen : n - 1;
- (void)memcpy(dst, src, copysize);
- dst[copysize] = 0;
- }
- return (srclen);
+ if (n == 0)
+ return (strlen(src));
+ return (strlcpy(dst, src, n));
}
+DEF_STRONG(strxfrm);
diff --git a/libdl/Android.bp b/libdl/Android.bp
index 262da6c..c17e72e 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -105,6 +105,7 @@
symbol_file: "libdl.map.txt",
versions: ["10000"],
},
+ required: ["libdl.mountpoint"],
}
ndk_library {
diff --git a/libm/Android.bp b/libm/Android.bp
index 28cf1fd..079220b 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -515,6 +515,7 @@
symbol_file: "libm.map.txt",
versions: ["10000"],
},
+ required: ["libm.mountpoint"],
}
ndk_library {
diff --git a/libm/upstream-freebsd/lib/msun/ld128/e_powl.c b/libm/upstream-freebsd/lib/msun/ld128/e_powl.c
index 15a57dd..2f3ee55 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/e_powl.c
+++ b/libm/upstream-freebsd/lib/msun/ld128/e_powl.c
@@ -32,7 +32,7 @@
* 1. Compute and return log2(x) in two pieces:
* log2(x) = w1 + w2,
* where w1 has 113-53 = 60 bit trailing zeros.
- * 2. Perform y*log2(x) = n+y' by simulating muti-precision
+ * 2. Perform y*log2(x) = n+y' by simulating multi-precision
* arithmetic, where |y'|<=0.5.
* 3. Return x**y = 2**n*exp(y'*log2)
*
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/ld128/e_powl.c 336362 2018-07-17 07:42:14Z bde $");
+__FBSDID("$FreeBSD: head/lib/msun/ld128/e_powl.c 342651 2018-12-31 15:43:06Z pfg $");
#include <float.h>
#include <math.h>
diff --git a/libm/upstream-freebsd/lib/msun/ld128/e_rem_pio2l.h b/libm/upstream-freebsd/lib/msun/ld128/e_rem_pio2l.h
index 5d78c4d..1ed79ae 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/e_rem_pio2l.h
+++ b/libm/upstream-freebsd/lib/msun/ld128/e_rem_pio2l.h
@@ -14,7 +14,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/ld128/e_rem_pio2l.h 336545 2018-07-20 12:42:24Z bde $");
/* ld128 version of __ieee754_rem_pio2l(x,y)
*
@@ -74,14 +74,9 @@
if (ex < BIAS + 45 || ex == BIAS + 45 &&
u.bits.manh < 0x921fb54442d1LL) {
/* |x| ~< 2^45*(pi/2), medium size */
- /* Use a specialized rint() to get fn. Assume round-to-nearest. */
- fn = x*invpio2+0x1.8p112;
- fn = fn-0x1.8p112;
-#ifdef HAVE_EFFICIENT_I64RINT
+ /* TODO: use only double precision for fn, as in expl(). */
+ fn = rnintl(x * invpio2);
n = i64rint(fn);
-#else
- n = fn;
-#endif
r = x-fn*pio2_1;
w = fn*pio2_1t; /* 1st round good to 180 bit */
{
diff --git a/libm/upstream-freebsd/lib/msun/ld128/k_expl.h b/libm/upstream-freebsd/lib/msun/ld128/k_expl.h
index 4c041e8..b80d00e 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/k_expl.h
+++ b/libm/upstream-freebsd/lib/msun/ld128/k_expl.h
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/ld128/k_expl.h 326219 2017-11-26 02:00:33Z pfg $");
+__FBSDID("$FreeBSD: head/lib/msun/ld128/k_expl.h 336545 2018-07-20 12:42:24Z bde $");
/*
* ld128 version of k_expl.h. See ../ld80/s_expl.c for most comments.
@@ -244,16 +244,8 @@
int n, n2;
/* Reduce x to (k*ln2 + endpoint[n2] + r1 + r2). */
- /* Use a specialized rint() to get fn. Assume round-to-nearest. */
- /* XXX assume no extra precision for the additions, as for trig fns. */
- /* XXX this set of comments is now quadruplicated. */
- /* XXX but see ../src/e_exp.c for a fix using double_t. */
- fn = (double)x * INV_L + 0x1.8p52 - 0x1.8p52;
-#if defined(HAVE_EFFICIENT_IRINT)
+ fn = rnint((double)x * INV_L);
n = irint(fn);
-#else
- n = (int)fn;
-#endif
n2 = (unsigned)n % INTERVALS;
/* Depend on the sign bit being propagated: */
*kp = n >> LOG2_INTERVALS;
diff --git a/libm/upstream-freebsd/lib/msun/ld128/s_expl.c b/libm/upstream-freebsd/lib/msun/ld128/s_expl.c
index 53bc04a..f4c18be 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/s_expl.c
+++ b/libm/upstream-freebsd/lib/msun/ld128/s_expl.c
@@ -29,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/ld128/s_expl.c 326219 2017-11-26 02:00:33Z pfg $");
+__FBSDID("$FreeBSD: head/lib/msun/ld128/s_expl.c 336545 2018-07-20 12:42:24Z bde $");
/*
* ld128 version of s_expl.c. See ../ld80/s_expl.c for most comments.
@@ -268,13 +268,8 @@
}
/* Reduce x to (k*ln2 + endpoint[n2] + r1 + r2). */
- /* Use a specialized rint() to get fn. Assume round-to-nearest. */
- fn = (double)x * INV_L + 0x1.8p52 - 0x1.8p52;
-#if defined(HAVE_EFFICIENT_IRINT)
+ fn = rnint((double)x * INV_L);
n = irint(fn);
-#else
- n = (int)fn;
-#endif
n2 = (unsigned)n % INTERVALS;
k = n >> LOG2_INTERVALS;
r1 = x - fn * L1;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_j0.c b/libm/upstream-freebsd/lib/msun/src/e_j0.c
index cfa71c2..6bca542 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_j0.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_j0.c
@@ -11,7 +11,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/src/e_j0.c 336089 2018-07-08 16:26:13Z markj $");
+__FBSDID("$FreeBSD: head/lib/msun/src/e_j0.c 343023 2019-01-14 15:48:35Z pfg $");
/* __ieee754_j0(x), __ieee754_y0(x)
* Bessel function of the first and second kinds of order zero.
@@ -80,7 +80,7 @@
S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */
S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */
-static const double zero = 0.0;
+static const double zero = 0, qrtr = 0.25;
double
__ieee754_j0(double x)
@@ -97,7 +97,7 @@
c = cos(x);
ss = s-c;
cc = s+c;
- if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ if(ix<0x7fe00000) { /* Make sure x+x does not overflow. */
z = -cos(x+x);
if ((s*c)<zero) cc = z/ss;
else ss = z/cc;
@@ -123,9 +123,9 @@
r = z*(R02+z*(R03+z*(R04+z*R05)));
s = one+z*(S01+z*(S02+z*(S03+z*S04)));
if(ix < 0x3FF00000) { /* |x| < 1.00 */
- return one + z*(-0.25+(r/s));
+ return one + z*((r/s)-qrtr);
} else {
- u = 0.5*x;
+ u = x/2;
return((one+u)*(one-u)+z*(r/s));
}
}
@@ -374,6 +374,7 @@
static __inline double
qzero(double x)
{
+ static const double eighth = 0.125;
const double *p,*q;
double s,r,z;
int32_t ix;
@@ -386,5 +387,5 @@
z = one/(x*x);
r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
- return (-.125 + r/s)/x;
+ return (r/s-eighth)/x;
}
diff --git a/libm/upstream-freebsd/lib/msun/src/e_j0f.c b/libm/upstream-freebsd/lib/msun/src/e_j0f.c
index e53b218..714caac 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_j0f.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_j0f.c
@@ -14,7 +14,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/src/e_j0f.c 283032 2015-05-17 16:27:06Z kargl $");
+__FBSDID("$FreeBSD: head/lib/msun/src/e_j0f.c 343023 2019-01-14 15:48:35Z pfg $");
/*
* See e_j0.c for complete comments.
@@ -42,7 +42,7 @@
S03 = 5.1354652442e-07, /* 0x3509daa6 */
S04 = 1.1661400734e-09; /* 0x30a045e8 */
-static const float zero = 0.0;
+static const float zero = 0, qrtr = 0.25;
float
__ieee754_j0f(float x)
@@ -59,7 +59,7 @@
c = cosf(x);
ss = s-c;
cc = s+c;
- if(ix<0x7f000000) { /* make sure x+x not overflow */
+ if(ix<0x7f000000) { /* Make sure x+x does not overflow. */
z = -cosf(x+x);
if ((s*c)<zero) cc = z/ss;
else ss = z/cc;
@@ -85,9 +85,9 @@
r = z*(R02+z*(R03+z*(R04+z*R05)));
s = one+z*(S01+z*(S02+z*(S03+z*S04)));
if(ix < 0x3F800000) { /* |x| < 1.00 */
- return one + z*((float)-0.25+(r/s));
+ return one + z*((r/s)-qrtr);
} else {
- u = (float)0.5*x;
+ u = x/2;
return((one+u)*(one-u)+z*(r/s));
}
}
@@ -328,6 +328,7 @@
static __inline float
qzerof(float x)
{
+ static const float eighth = 0.125;
const float *p,*q;
float s,r,z;
int32_t ix;
@@ -340,5 +341,5 @@
z = one/(x*x);
r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
- return (-(float).125 + r/s)/x;
+ return (r/s-eighth)/x;
}
diff --git a/libm/upstream-freebsd/lib/msun/src/e_pow.c b/libm/upstream-freebsd/lib/msun/src/e_pow.c
index 411dd52..b4f6a5a 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_pow.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_pow.c
@@ -10,7 +10,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/src/e_pow.c 336362 2018-07-17 07:42:14Z bde $");
+__FBSDID("$FreeBSD: head/lib/msun/src/e_pow.c 342851 2019-01-07 17:35:09Z pfg $");
/* __ieee754_pow(x,y) return x**y
*
@@ -133,7 +133,7 @@
k = (iy>>20)-0x3ff; /* exponent */
if(k>20) {
j = ly>>(52-k);
- if((j<<(52-k))==ly) yisint = 2-(j&1);
+ if(((u_int32_t)j<<(52-k))==ly) yisint = 2-(j&1);
} else if(ly==0) {
j = iy>>(20-k);
if((j<<(20-k))==iy) yisint = 2-(j&1);
diff --git a/libm/upstream-freebsd/lib/msun/src/e_rem_pio2.c b/libm/upstream-freebsd/lib/msun/src/e_rem_pio2.c
index be2630b..3e62c2b 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_rem_pio2.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_rem_pio2.c
@@ -14,7 +14,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/e_rem_pio2.c 336545 2018-07-20 12:42:24Z bde $");
/* __ieee754_rem_pio2(x,y)
*
@@ -127,14 +127,8 @@
}
if(ix<0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */
medium:
- /* Use a specialized rint() to get fn. Assume round-to-nearest. */
- STRICT_ASSIGN(double,fn,x*invpio2+0x1.8p52);
- fn = fn-0x1.8p52;
-#ifdef HAVE_EFFICIENT_IRINT
+ fn = rnint((double_t)x*invpio2);
n = irint(fn);
-#else
- n = (int32_t)fn;
-#endif
r = x-fn*pio2_1;
w = fn*pio2_1t; /* 1st round good to 85 bit */
{
diff --git a/libm/upstream-freebsd/lib/msun/src/e_rem_pio2f.c b/libm/upstream-freebsd/lib/msun/src/e_rem_pio2f.c
index f1ee7a0..2a89d27 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_rem_pio2f.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_rem_pio2f.c
@@ -15,7 +15,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/e_rem_pio2f.c 336545 2018-07-20 12:42:24Z bde $");
/* __ieee754_rem_pio2f(x,y)
*
@@ -55,14 +55,8 @@
ix = hx&0x7fffffff;
/* 33+53 bit pi is good enough for medium size */
if(ix<0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */
- /* Use a specialized rint() to get fn. Assume round-to-nearest. */
- STRICT_ASSIGN(double,fn,x*invpio2+0x1.8p52);
- fn = fn-0x1.8p52;
-#ifdef HAVE_EFFICIENT_IRINT
+ fn = rnint((float_t)x*invpio2);
n = irint(fn);
-#else
- n = (int32_t)fn;
-#endif
r = x-fn*pio2_1;
w = fn*pio2_1t;
*y = r-w;
diff --git a/libm/upstream-freebsd/lib/msun/src/k_rem_pio2.c b/libm/upstream-freebsd/lib/msun/src/k_rem_pio2.c
index 81363d4..0869e03 100644
--- a/libm/upstream-freebsd/lib/msun/src/k_rem_pio2.c
+++ b/libm/upstream-freebsd/lib/msun/src/k_rem_pio2.c
@@ -12,7 +12,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/src/k_rem_pio2.c 298896 2016-05-01 19:37:33Z pfg $");
+__FBSDID("$FreeBSD: head/lib/msun/src/k_rem_pio2.c 342651 2018-12-31 15:43:06Z pfg $");
/*
* __kernel_rem_pio2(x,y,e0,nx,prec)
@@ -52,7 +52,7 @@
* 64-bit precision 2
* 113-bit precision 3
* The actual value is the sum of them. Thus for 113-bit
- * precison, one may have to do something like:
+ * precision, one may have to do something like:
*
* long double t,w,r_head, r_tail;
* t = (long double)y[2] + (long double)y[1];
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cbrt.c b/libm/upstream-freebsd/lib/msun/src/s_cbrt.c
index d75ad0b..268425e 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cbrt.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cbrt.c
@@ -13,8 +13,9 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/src/s_cbrt.c 298896 2016-05-01 19:37:33Z pfg $");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_cbrt.c 342563 2018-12-28 01:34:08Z jhibbits $");
+#include <float.h>
#include "math.h"
#include "math_private.h"
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cpow.c b/libm/upstream-freebsd/lib/msun/src/s_cpow.c
index 9be5c51..1cb99aa 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cpow.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cpow.c
@@ -44,11 +44,12 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/src/s_cpow.c 336299 2018-07-15 00:23:10Z mmacy $");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_cpow.c 336563 2018-07-20 18:27:30Z dim $");
#include <complex.h>
#include <float.h>
#include <math.h>
+#include "math_private.h"
double complex
cpow(double complex a, double complex z)
@@ -60,7 +61,7 @@
y = cimag (z);
absa = cabs (a);
if (absa == 0.0) {
- return (0.0 + 0.0 * I);
+ return (CMPLX(0.0, 0.0));
}
arga = carg (a);
r = pow (absa, x);
@@ -69,6 +70,6 @@
r = r * exp (-y * arga);
theta = theta + y * log (absa);
}
- w = r * cos (theta) + (r * sin (theta)) * I;
+ w = CMPLX(r * cos (theta), r * sin (theta));
return (w);
}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cpowf.c b/libm/upstream-freebsd/lib/msun/src/s_cpowf.c
index 6e27f57..a2ef525 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cpowf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cpowf.c
@@ -44,10 +44,11 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/src/s_cpowf.c 336299 2018-07-15 00:23:10Z mmacy $");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_cpowf.c 336563 2018-07-20 18:27:30Z dim $");
#include <complex.h>
#include <math.h>
+#include "math_private.h"
float complex
cpowf(float complex a, float complex z)
@@ -59,7 +60,7 @@
y = cimagf(z);
absa = cabsf (a);
if (absa == 0.0f) {
- return (0.0f + 0.0f * I);
+ return (CMPLXF(0.0f, 0.0f));
}
arga = cargf (a);
r = powf (absa, x);
@@ -68,6 +69,6 @@
r = r * expf (-y * arga);
theta = theta + y * logf (absa);
}
- w = r * cosf (theta) + (r * sinf (theta)) * I;
+ w = CMPLXF(r * cosf (theta), r * sinf (theta));
return (w);
}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cpowl.c b/libm/upstream-freebsd/lib/msun/src/s_cpowl.c
index fcb5c7f..f9c6373 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cpowl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cpowl.c
@@ -44,10 +44,11 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/src/s_cpowl.c 336299 2018-07-15 00:23:10Z mmacy $");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_cpowl.c 336563 2018-07-20 18:27:30Z dim $");
#include <complex.h>
#include <math.h>
+#include "math_private.h"
long double complex
cpowl(long double complex a, long double complex z)
@@ -59,7 +60,7 @@
y = cimagl(z);
absa = cabsl(a);
if (absa == 0.0L) {
- return (0.0L + 0.0L * I);
+ return (CMPLXL(0.0L, 0.0L));
}
arga = cargl(a);
r = powl(absa, x);
@@ -68,6 +69,6 @@
r = r * expl(-y * arga);
theta = theta + y * logl(absa);
}
- w = r * cosl(theta) + (r * sinl(theta)) * I;
+ w = CMPLXL(r * cosl(theta), r * sinl(theta));
return (w);
}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cproj.c b/libm/upstream-freebsd/lib/msun/src/s_cproj.c
index 3083f2b..7677b5f 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cproj.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cproj.c
@@ -27,9 +27,10 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/msun/src/s_cproj.c 326219 2017-11-26 02:00:33Z pfg $");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_cproj.c 342563 2018-12-28 01:34:08Z jhibbits $");
#include <complex.h>
+#include <float.h>
#include <math.h>
#include "math_private.h"
diff --git a/libm/upstream-freebsd/lib/msun/src/s_erf.c b/libm/upstream-freebsd/lib/msun/src/s_erf.c
index e1d63bc..3e39d80 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_erf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_erf.c
@@ -11,7 +11,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_erf.c 342563 2018-12-28 01:34:08Z jhibbits $");
/* double erf(double x)
* double erfc(double x)
@@ -107,7 +107,7 @@
* erfc/erf(NaN) is NaN
*/
-
+#include <float.h>
#include "math.h"
#include "math_private.h"
diff --git a/linker/Android.bp b/linker/Android.bp
index 5ae09ba..fed921d 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -103,6 +103,7 @@
name: "linker_sources_arm64",
srcs: [
"arch/arm64/begin.S",
+ "arch/arm64/tlsdesc_resolver.S",
],
}
@@ -282,6 +283,8 @@
name: "linker",
symlinks: ["linker_asan"],
+ // The linker in the system partition is now only for bootstrapping
+ relative_install_path: "bootstrap",
recovery_available: true,
multilib: {
lib32: {
@@ -300,6 +303,7 @@
},
compile_multilib: "both",
xom: false,
+ required: ["linker.mountpoint"],
}
cc_library {
diff --git a/linker/arch/arm64/tlsdesc_resolver.S b/linker/arch/arm64/tlsdesc_resolver.S
new file mode 100644
index 0000000..ef46839
--- /dev/null
+++ b/linker/arch/arm64/tlsdesc_resolver.S
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <private/bionic_asm.h>
+#include <private/bionic_asm_tls.h>
+
+.globl __tls_get_addr
+
+// These resolver functions must preserve every register except x0. They set x0
+// to the offset of the TLS symbol relative to the thread pointer.
+
+ENTRY_PRIVATE(tlsdesc_resolver_static)
+ ldr x0, [x0, #8]
+ ret
+END(tlsdesc_resolver_static)
+
+ENTRY_PRIVATE(tlsdesc_resolver_dynamic)
+ stp x19, x20, [sp, #-32]!
+ .cfi_def_cfa_offset 32
+ .cfi_rel_offset x19, 0
+ .cfi_rel_offset x20, 8
+ stp x21, x22, [sp, #16]
+ .cfi_rel_offset x21, 16
+ .cfi_rel_offset x22, 24
+
+ mrs x19, tpidr_el0 // __get_tls()
+ ldr x20, [x19, #(TLS_SLOT_DTV * 8)]
+ ldr x21, [x20] // TlsDtv::generation
+
+ ldr x0, [x0, #8] // TlsDynamicResolverArg*
+ ldr x22, [x0] // TlsDynamicResolverArg::generation
+
+ cmp x21, x22
+ b.lo .fallback
+
+ ldr x21, [x0, #8] // TlsIndex::module
+ ldr x22, [x0, #16] // TlsIndex::offset
+ ldr x21, [x20, x21, lsl #3] // TlsDtv::modules[module]
+ cbz x21, .fallback
+ add x0, x21, x22
+ sub x0, x0, x19
+
+ ldp x21, x22, [sp, #16]
+ .cfi_remember_state
+ .cfi_restore x21
+ .cfi_restore x22
+ ldp x19, x20, [sp], #32
+ .cfi_adjust_cfa_offset -32
+ .cfi_restore x19
+ .cfi_restore x20
+ ret
+
+.fallback:
+ .cfi_restore_state
+ ldp x21, x22, [sp, #16]
+ .cfi_restore x21
+ .cfi_restore x22
+ ldp x19, x20, [sp], #32
+ .cfi_adjust_cfa_offset -32
+ .cfi_restore x19
+ .cfi_restore x20
+ b tlsdesc_resolver_dynamic_slow_path
+END(tlsdesc_resolver_dynamic)
+
+#define SAVE_REG(x, slot) \
+ str x, [sp, #((slot) * 8)]; \
+ .cfi_rel_offset x, (slot) * 8; \
+
+#define SAVE_GPR_PAIR(x, y, slot) \
+ stp x, y, [sp, #((slot) * 8)]; \
+ .cfi_rel_offset x, (slot) * 8; \
+ .cfi_rel_offset y, ((slot) + 1) * 8; \
+
+#define SAVE_VEC_PAIR(x, y, slot) \
+ stp x, y, [sp, #((slot) * 8)]; \
+ .cfi_rel_offset x, (slot) * 8; \
+ .cfi_rel_offset y, ((slot) + 2) * 8; \
+
+#define RESTORE_REG(x, slot) \
+ ldr x, [sp, #((slot) * 8)]; \
+ .cfi_restore x; \
+
+#define RESTORE_REG_PAIR(x, y, slot) \
+ ldp x, y, [sp, #((slot) * 8)]; \
+ .cfi_restore x; \
+ .cfi_restore y; \
+
+// On entry, x0 is the address of a TlsDynamicResolverArg object rather than
+// the TlsDescriptor address passed to the original resolver function.
+ENTRY_PRIVATE(tlsdesc_resolver_dynamic_slow_path)
+ sub sp, sp, #(8 * 84)
+ .cfi_def_cfa_offset (8 * 84)
+ SAVE_GPR_PAIR(x29, x30, 0)
+ mov x29, sp
+
+ // Avoid leaking the contents of the shadow call stack register (x18) into
+ // memory. x19 through x29 are callee-save registers, so we do not need to
+ // save them.
+ SAVE_GPR_PAIR(x1, x2, 2)
+ SAVE_GPR_PAIR(x3, x4, 4)
+ SAVE_GPR_PAIR(x5, x6, 6)
+ SAVE_GPR_PAIR(x7, x8, 8)
+ SAVE_GPR_PAIR(x9, x10, 10)
+ SAVE_GPR_PAIR(x11, x12, 12)
+ SAVE_GPR_PAIR(x13, x14, 14)
+ SAVE_GPR_PAIR(x15, x16, 16)
+ SAVE_REG(x17, 18)
+
+ SAVE_VEC_PAIR(q0, q1, 20)
+ SAVE_VEC_PAIR(q2, q3, 24)
+ SAVE_VEC_PAIR(q4, q5, 28)
+ SAVE_VEC_PAIR(q6, q7, 32)
+ SAVE_VEC_PAIR(q8, q9, 36)
+ SAVE_VEC_PAIR(q10, q11, 40)
+ SAVE_VEC_PAIR(q12, q13, 44)
+ SAVE_VEC_PAIR(q14, q15, 48)
+ SAVE_VEC_PAIR(q16, q17, 52)
+ SAVE_VEC_PAIR(q18, q19, 56)
+ SAVE_VEC_PAIR(q20, q21, 60)
+ SAVE_VEC_PAIR(q22, q23, 64)
+ SAVE_VEC_PAIR(q24, q25, 68)
+ SAVE_VEC_PAIR(q26, q27, 72)
+ SAVE_VEC_PAIR(q28, q29, 76)
+ SAVE_VEC_PAIR(q30, q31, 80)
+
+ add x0, x0, #8
+ bl __tls_get_addr
+ mrs x1, tpidr_el0 // __get_tls()
+ sub x0, x0, x1
+
+ RESTORE_REG_PAIR(q30, q31, 80)
+ RESTORE_REG_PAIR(q28, q29, 76)
+ RESTORE_REG_PAIR(q26, q27, 72)
+ RESTORE_REG_PAIR(q24, q25, 68)
+ RESTORE_REG_PAIR(q22, q23, 64)
+ RESTORE_REG_PAIR(q20, q21, 60)
+ RESTORE_REG_PAIR(q18, q19, 56)
+ RESTORE_REG_PAIR(q16, q17, 52)
+ RESTORE_REG_PAIR(q14, q15, 48)
+ RESTORE_REG_PAIR(q12, q13, 44)
+ RESTORE_REG_PAIR(q10, q11, 40)
+ RESTORE_REG_PAIR(q8, q9, 36)
+ RESTORE_REG_PAIR(q6, q7, 32)
+ RESTORE_REG_PAIR(q4, q5, 28)
+ RESTORE_REG_PAIR(q2, q3, 24)
+ RESTORE_REG_PAIR(q0, q1, 20)
+
+ RESTORE_REG(x17, 18)
+ RESTORE_REG_PAIR(x15, x16, 16)
+ RESTORE_REG_PAIR(x13, x14, 14)
+ RESTORE_REG_PAIR(x11, x12, 12)
+ RESTORE_REG_PAIR(x9, x10, 10)
+ RESTORE_REG_PAIR(x7, x8, 8)
+ RESTORE_REG_PAIR(x5, x6, 6)
+ RESTORE_REG_PAIR(x3, x4, 4)
+ RESTORE_REG_PAIR(x1, x2, 2)
+
+ RESTORE_REG_PAIR(x29, x30, 0)
+ add sp, sp, #(8 * 84)
+ .cfi_def_cfa_offset 0
+ ret
+END(tlsdesc_resolver_dynamic_slow_path)
+
+// The address of an unresolved weak TLS symbol evaluates to NULL with TLSDESC.
+// The value returned by this function is added to the thread pointer, so return
+// a negated thread pointer to cancel it out.
+ENTRY_PRIVATE(tlsdesc_resolver_unresolved_weak)
+ str x19, [sp, #-16]!
+ .cfi_def_cfa_offset 16
+ .cfi_rel_offset x19, 0
+ ldr x19, [x0, #8]
+ mrs x0, tpidr_el0 // __get_tls()
+ sub x0, x19, x0
+ ldr x19, [sp], #16
+ .cfi_def_cfa_offset 0
+ .cfi_restore x19
+ ret
+END(tlsdesc_resolver_unresolved_weak)
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 4dcdf7e..428dd25 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -536,6 +536,10 @@
allocator_.free(ptr);
}
+ static void purge() {
+ allocator_.purge();
+ }
+
private:
static LinkerBlockAllocator allocator_;
};
@@ -553,6 +557,10 @@
static void free(T* ptr) {
SizeBasedAllocator<sizeof(T)>::free(ptr);
}
+
+ static void purge() {
+ SizeBasedAllocator<sizeof(T)>::purge();
+ }
};
class LoadTask {
@@ -2074,6 +2082,8 @@
ns == nullptr ? "(null)" : ns->get_name(),
ns);
+ auto purge_guard = android::base::make_scope_guard([&]() { purge_unused_memory(); });
+
auto failure_guard = android::base::make_scope_guard(
[&]() { LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer()); });
@@ -2698,6 +2708,7 @@
bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
const size_t tls_tp_base = __libc_shared_globals()->static_tls_layout.offset_thread_pointer();
+ std::vector<std::pair<TlsDescriptor*, size_t>> deferred_tlsdesc_relocs;
for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
const auto rel = rel_iterator.next();
@@ -2977,6 +2988,49 @@
#endif // !defined(__aarch64__)
#if defined(__aarch64__)
+ // Bionic currently only implements TLSDESC for arm64. This implementation should work with
+ // other architectures, as long as the resolver functions are implemented.
+ case R_GENERIC_TLSDESC:
+ count_relocation(kRelocRelative);
+ MARK(rel->r_offset);
+ {
+ TlsDescriptor* desc = reinterpret_cast<TlsDescriptor*>(reloc);
+ if (lsi == nullptr) {
+ // Unresolved weak relocation.
+ desc->func = tlsdesc_resolver_unresolved_weak;
+ desc->arg = addend;
+ TRACE_TYPE(RELO, "RELO TLSDESC %16p <- unresolved weak 0x%zx %s\n",
+ reinterpret_cast<void*>(reloc), static_cast<size_t>(addend), sym_name);
+ } else {
+ CHECK(lsi->get_tls() != nullptr); // We rejected a missing TLS segment above.
+ size_t module_id = lsi->get_tls()->module_id;
+ const TlsModule& mod = get_tls_module(module_id);
+ if (mod.static_offset != SIZE_MAX) {
+ desc->func = tlsdesc_resolver_static;
+ desc->arg = mod.static_offset - tls_tp_base + sym_addr + addend;
+ TRACE_TYPE(RELO, "RELO TLSDESC %16p <- static (0x%zx - 0x%zx + 0x%zx + 0x%zx) %s\n",
+ reinterpret_cast<void*>(reloc), mod.static_offset, tls_tp_base,
+ static_cast<size_t>(sym_addr), static_cast<size_t>(addend), sym_name);
+ } else {
+ tlsdesc_args_.push_back({
+ .generation = mod.first_generation,
+ .index.module_id = module_id,
+ .index.offset = sym_addr + addend,
+ });
+ // Defer the TLSDESC relocation until the address of the TlsDynamicResolverArg object
+ // is finalized.
+ deferred_tlsdesc_relocs.push_back({ desc, tlsdesc_args_.size() - 1 });
+ const TlsDynamicResolverArg& desc_arg = tlsdesc_args_.back();
+ TRACE_TYPE(RELO, "RELO TLSDESC %16p <- dynamic (gen %zu, mod %zu, off %zu) %s",
+ reinterpret_cast<void*>(reloc), desc_arg.generation,
+ desc_arg.index.module_id, desc_arg.index.offset, sym_name);
+ }
+ }
+ }
+ break;
+#endif // defined(R_GENERIC_TLSDESC)
+
+#if defined(__aarch64__)
case R_AARCH64_ABS64:
count_relocation(kRelocAbsolute);
MARK(rel->r_offset);
@@ -3145,6 +3199,13 @@
return false;
}
}
+
+ for (const std::pair<TlsDescriptor*, size_t>& pair : deferred_tlsdesc_relocs) {
+ TlsDescriptor* desc = pair.first;
+ desc->func = tlsdesc_resolver_dynamic;
+ desc->arg = reinterpret_cast<size_t>(&tlsdesc_args_[pair.second]);
+ }
+
return true;
}
#endif // !defined(__mips__)
@@ -4018,3 +4079,17 @@
}
return it->second;
}
+
+void purge_unused_memory() {
+ // For now, we only purge the memory used by LoadTask because we know those
+ // are temporary objects.
+ //
+ // Purging other LinkerBlockAllocator hardly yields much because they hold
+ // information about namespaces and opened libraries, which are not freed
+ // when the control leaves the linker.
+ //
+ // Purging BionicAllocator may give us a few dirty pages back, but those pages
+ // would be already zeroed out, so they compress easily in ZRAM. Therefore,
+ // it is not worth munmap()'ing those pages.
+ TypeBasedAllocator<LoadTask>::purge();
+}
diff --git a/linker/linker.h b/linker/linker.h
index 91d3ddf..964c266 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -186,3 +186,5 @@
void increment_dso_handle_reference_counter(void* dso_handle);
void decrement_dso_handle_reference_counter(void* dso_handle);
+
+void purge_unused_memory();
diff --git a/linker/linker_block_allocator.cpp b/linker/linker_block_allocator.cpp
index 27f1e38..fdb4c85 100644
--- a/linker/linker_block_allocator.cpp
+++ b/linker/linker_block_allocator.cpp
@@ -109,9 +109,6 @@
free_block_list_ = block_info;
--allocated_;
- if (allocated_ == 0) {
- free_all_pages();
- }
}
void LinkerBlockAllocator::protect_all(int prot) {
@@ -163,9 +160,9 @@
abort();
}
-void LinkerBlockAllocator::free_all_pages() {
+void LinkerBlockAllocator::purge() {
if (allocated_) {
- abort();
+ return;
}
LinkerBlockAllocatorPage* page = page_list_;
diff --git a/linker/linker_block_allocator.h b/linker/linker_block_allocator.h
index 458d092..8ae4094 100644
--- a/linker/linker_block_allocator.h
+++ b/linker/linker_block_allocator.h
@@ -50,10 +50,12 @@
void free(void* block);
void protect_all(int prot);
+ // Purge all pages if all previously allocated blocks have been freed.
+ void purge();
+
private:
void create_new_page();
LinkerBlockAllocatorPage* find_page(void* block);
- void free_all_pages();
size_t block_size_;
LinkerBlockAllocatorPage* page_list_;
@@ -75,8 +77,7 @@
* 513 this allocator will use 516 (520 for lp64) bytes of data where
* generalized implementation is going to use 1024 sized blocks.
*
- * 2. Unless all allocated memory is freed, this allocator does not munmap
- * allocated memory, where BionicAllocator does.
+ * 2. This allocator does not munmap allocated memory, where BionicAllocator does.
*
* 3. This allocator provides mprotect services to the user, where BionicAllocator
* always treats its memory as READ|WRITE.
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index b0c27dc..7486cd7 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -503,6 +503,10 @@
fflush(stdout);
#endif
+ // We are about to hand control over to the executable loaded. We don't want
+ // to leave dirty pages behind unnecessarily.
+ purge_unused_memory();
+
ElfW(Addr) entry = exe_info.entry_point;
TRACE("[ Ready to execute \"%s\" @ %p ]", si->get_realpath(), reinterpret_cast<void*>(entry));
return entry;
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 3499cf7..dd9c6aa 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -32,6 +32,7 @@
#include <memory>
#include <string>
+#include <vector>
#include "private/bionic_elf_tls.h"
#include "linker_namespaces.h"
@@ -379,6 +380,7 @@
// version >= 5
std::unique_ptr<soinfo_tls> tls_;
+ std::vector<TlsDynamicResolverArg> tlsdesc_args_;
};
// This function is used by dlvsym() to calculate hash of sym_ver
diff --git a/linker/linker_tls.h b/linker/linker_tls.h
index fbb1dcf..87e1f0d 100644
--- a/linker/linker_tls.h
+++ b/linker/linker_tls.h
@@ -30,6 +30,8 @@
#include <stdlib.h>
+#include "private/bionic_elf_tls.h"
+
struct TlsModule;
struct soinfo;
@@ -40,3 +42,24 @@
void unregister_soinfo_tls(soinfo* si);
const TlsModule& get_tls_module(size_t module_id);
+
+typedef size_t TlsDescResolverFunc(size_t);
+
+struct TlsDescriptor {
+#if defined(__arm__)
+ size_t arg;
+ TlsDescResolverFunc* func;
+#else
+ TlsDescResolverFunc* func;
+ size_t arg;
+#endif
+};
+
+struct TlsDynamicResolverArg {
+ size_t generation;
+ TlsIndex index;
+};
+
+__LIBC_HIDDEN__ extern "C" size_t tlsdesc_resolver_static(size_t);
+__LIBC_HIDDEN__ extern "C" size_t tlsdesc_resolver_dynamic(size_t);
+__LIBC_HIDDEN__ extern "C" size_t tlsdesc_resolver_unresolved_weak(size_t);
diff --git a/tests/Android.bp b/tests/Android.bp
index 8b921d8..b039f00 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -40,7 +40,7 @@
],
stl: "libc++",
sanitize: {
- never: true,
+ address: false,
},
bootstrap: true,
}
@@ -95,6 +95,7 @@
"grp_pwd_file_test.cpp",
"iconv_test.cpp",
"ifaddrs_test.cpp",
+ "ifunc_test.cpp",
"inttypes_test.cpp",
"iso646_test.c",
"langinfo_test.cpp",
@@ -520,6 +521,7 @@
"libtest_dt_runpath_b",
"libtest_dt_runpath_c",
"libtest_dt_runpath_x",
+ "libtest_dt_runpath_y",
"libatest_simple_zip",
"libcfi-test",
"libcfi-test-bad",
@@ -533,7 +535,6 @@
"libdl_preempt_test_1",
"libdl_preempt_test_2",
"libdl_test_df_1_global",
- "libelf-tls-library",
"libgnu-hash-table-library",
"libsysv-hash-table-library",
"libtestshared",
@@ -571,6 +572,10 @@
"libtest_dlsym_from_this",
"libtest_dlsym_weak_func",
"libtest_dt_runpath_d",
+ "libtest_elftls_dynamic",
+ "libtest_elftls_dynamic_filler_1",
+ "libtest_elftls_dynamic_filler_2",
+ "libtest_elftls_dynamic_filler_3",
"libtest_elftls_shared_var",
"libtest_elftls_shared_var_ie",
"libtest_elftls_tprel",
diff --git a/tests/Android.build.mk b/tests/Android.build.mk
index 266c7d7..04fc92d 100644
--- a/tests/Android.build.mk
+++ b/tests/Android.build.mk
@@ -35,8 +35,20 @@
native_tests_var := TARGET_OUT_DATA_NATIVE_TESTS
endif
- LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)$(native_tests_var))/$($(module)_install_to_native_tests_dir)
- LOCAL_MODULE_PATH_64 := $($(native_tests_var))/$($(module)_install_to_native_tests_dir)
+ ifneq ($($(module)_install_to_native_tests_dir_32),)
+ tests_dir_32 := $($(module)_install_to_native_tests_dir_32)
+ else
+ tests_dir_32 := $($(module)_install_to_native_tests_dir)
+ endif
+
+ ifneq ($($(module)_install_to_native_tests_dir_64),)
+ tests_dir_64 := $($(module)_install_to_native_tests_dir_64)
+ else
+ tests_dir_64 := $($(module)_install_to_native_tests_dir)
+ endif
+
+ LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)$(native_tests_var))/$(tests_dir_32)
+ LOCAL_MODULE_PATH_64 := $($(native_tests_var))/$(tests_dir_64)
endif
endif
diff --git a/tests/buffer_tests.cpp b/tests/buffer_tests.cpp
index 7563448..fb0b6d8 100644
--- a/tests/buffer_tests.cpp
+++ b/tests/buffer_tests.cpp
@@ -20,6 +20,7 @@
#include <gtest/gtest.h>
#include "buffer_tests.h"
+#include "utils.h"
// For the comparison buffer tests, the maximum length to test for the
// miscompare checks.
@@ -227,16 +228,11 @@
}
}
-// 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.
+// Malloc can return a tagged pointer, which is not accepted in mm system calls like mprotect
+// in the preliminary version of the syscall tagging support in the current Pixel 2 kernel.
+// Note: the final version of the kernel patchset may relax this requirement.
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);
+ return mprotect(untag_address(addr), len, prot);
}
void RunSingleBufferAlignTest(
diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp
index aea92b4..468ce3d 100644
--- a/tests/dl_test.cpp
+++ b/tests/dl_test.cpp
@@ -138,7 +138,7 @@
TEST(dl, preinit_system_calls) {
#if defined(__BIONIC__)
- SKIP_WITH_HWASAN; // hwasan not initialized in preinit_array
+ SKIP_WITH_HWASAN; // hwasan not initialized in preinit_array, b/124007027
std::string helper = GetTestlibRoot() +
"/preinit_syscall_test_helper/preinit_syscall_test_helper";
chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
@@ -150,6 +150,7 @@
TEST(dl, preinit_getauxval) {
#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN; // hwasan not initialized in preinit_array, b/124007027
std::string helper = GetTestlibRoot() +
"/preinit_getauxval_test_helper/preinit_getauxval_test_helper";
chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index e3ba227..8a3b6f3 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1082,19 +1082,6 @@
ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
}
-TEST(dlfcn, dlopen_library_with_ELF_TLS) {
-// TODO: Remove this test. Once ELF TLS is implemented, this test will be
-// replaced with a larger set of tests. Removing the test requires matching CLs
-// in CTS and in internal test suites.
-#if 0
- dlerror(); // Clear any pending errors.
- void* handle = dlopen("libelf-tls-library.so", RTLD_NOW);
- ASSERT_TRUE(handle == nullptr);
- ASSERT_SUBSTR("unknown reloc type ", dlerror());
-#endif
- GTEST_LOG_(INFO) << "This test is disabled pending replacement with dynamic ELF TLS tests.\n";
-}
-
TEST(dlfcn, dlopen_bad_flags) {
dlerror(); // Clear any pending errors.
void* handle;
diff --git a/tests/elftls_dl_test.cpp b/tests/elftls_dl_test.cpp
index 0a97c28..e908fb9 100644
--- a/tests/elftls_dl_test.cpp
+++ b/tests/elftls_dl_test.cpp
@@ -34,6 +34,10 @@
#include "gtest_globals.h"
#include "utils.h"
+#if defined(__BIONIC__)
+#include "bionic/pthread_internal.h"
+#endif
+
// Access libtest_elftls_shared_var.so's TLS variable using an IE access.
__attribute__((tls_model("initial-exec"))) extern "C" __thread int elftls_shared_var;
@@ -78,3 +82,175 @@
eth.SetArgs({ helper.c_str(), nullptr });
eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, error.c_str());
}
+
+// Use a GD access (__tls_get_addr or TLSDESC) to modify a variable in static
+// TLS memory.
+TEST(elftls_dl, access_static_tls) {
+ void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, lib);
+
+ auto bump_shared_var = reinterpret_cast<int(*)()>(dlsym(lib, "bump_shared_var"));
+ ASSERT_NE(nullptr, bump_shared_var);
+
+ ASSERT_EQ(21, ++elftls_shared_var);
+ ASSERT_EQ(22, bump_shared_var());
+
+ std::thread([bump_shared_var] {
+ ASSERT_EQ(21, ++elftls_shared_var);
+ ASSERT_EQ(22, bump_shared_var());
+ }).join();
+}
+
+TEST(elftls_dl, bump_local_vars) {
+ void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, lib);
+
+ auto bump_local_vars = reinterpret_cast<int(*)()>(dlsym(lib, "bump_local_vars"));
+ ASSERT_NE(nullptr, bump_local_vars);
+
+ ASSERT_EQ(42, bump_local_vars());
+ std::thread([bump_local_vars] {
+ ASSERT_EQ(42, bump_local_vars());
+ }).join();
+}
+
+// The behavior of accessing an unresolved weak TLS symbol using a dynamic TLS
+// relocation depends on which kind of implementation the target uses. With
+// TLSDESC, the result is NULL. With __tls_get_addr, the result is the
+// generation count (or maybe undefined behavior)? This test only tests TLSDESC.
+TEST(elftls_dl, missing_weak) {
+#if defined(__aarch64__)
+ void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, lib);
+
+ auto missing_weak_dyn_tls_addr = reinterpret_cast<int*(*)()>(dlsym(lib, "missing_weak_dyn_tls_addr"));
+ ASSERT_NE(nullptr, missing_weak_dyn_tls_addr);
+
+ ASSERT_EQ(nullptr, missing_weak_dyn_tls_addr());
+ std::thread([missing_weak_dyn_tls_addr] {
+ ASSERT_EQ(nullptr, missing_weak_dyn_tls_addr());
+ }).join();
+#else
+ GTEST_LOG_(INFO) << "This test is only run on TLSDESC-based targets.\n";
+#endif
+}
+
+TEST(elftls_dl, dtv_resize) {
+#if defined(__BIONIC__)
+#define LOAD_LIB(soname) ({ \
+ auto lib = dlopen(soname, RTLD_LOCAL | RTLD_NOW); \
+ ASSERT_NE(nullptr, lib); \
+ reinterpret_cast<int(*)()>(dlsym(lib, "bump")); \
+ })
+
+ auto dtv = []() -> TlsDtv* { return __get_tcb_dtv(__get_bionic_tcb()); };
+
+ static_assert(sizeof(TlsDtv) == 3 * sizeof(void*),
+ "This test assumes that the Dtv has a 3-word header");
+
+ // Initially there are 3 modules:
+ // - the main test executable
+ // - libtest_elftls_shared_var
+ // - libtest_elftls_tprel
+
+ // The initial DTV is an empty DTV with no generation and a size of 0.
+ TlsDtv* zero_dtv = dtv();
+ ASSERT_EQ(0u, zero_dtv->count);
+ ASSERT_EQ(nullptr, zero_dtv->next);
+ ASSERT_EQ(kTlsGenerationNone, zero_dtv->generation);
+
+ // Load the fourth module.
+ auto func1 = LOAD_LIB("libtest_elftls_dynamic_filler_1.so");
+ ASSERT_EQ(101, func1());
+
+ // After loading one module, the DTV should be initialized to the next
+ // power-of-2 size (including the header).
+ TlsDtv* initial_dtv = dtv();
+ ASSERT_EQ(5u, initial_dtv->count);
+ ASSERT_EQ(zero_dtv, initial_dtv->next);
+ ASSERT_LT(0u, initial_dtv->generation);
+
+ // Load module 5.
+ auto func2 = LOAD_LIB("libtest_elftls_dynamic_filler_2.so");
+ ASSERT_EQ(102, func1());
+ ASSERT_EQ(201, func2());
+ ASSERT_EQ(initial_dtv, dtv());
+ ASSERT_EQ(5u, initial_dtv->count);
+
+ // Load module 6.
+ auto func3 = LOAD_LIB("libtest_elftls_dynamic_filler_3.so");
+ ASSERT_EQ(103, func1());
+ ASSERT_EQ(202, func2());
+
+#if defined(__aarch64__)
+ // The arm64 TLSDESC resolver doesn't update the DTV if it is new enough for
+ // the given access.
+ ASSERT_EQ(5u, dtv()->count);
+#else
+ // __tls_get_addr updates the DTV anytime the generation counter changes.
+ ASSERT_EQ(13u, dtv()->count);
+#endif
+
+ ASSERT_EQ(301, func3());
+
+ TlsDtv* new_dtv = dtv();
+ ASSERT_EQ(13u, new_dtv->count);
+ ASSERT_NE(initial_dtv, new_dtv);
+ ASSERT_EQ(initial_dtv, new_dtv->next);
+
+#undef LOAD_LIB
+#else
+ GTEST_LOG_(INFO) << "This test is skipped for glibc because it tests Bionic internals.";
+#endif
+}
+
+// Verify that variables are reset to their initial values after the library
+// containing them is closed.
+TEST(elftls_dl, dlclose_resets_values) {
+ for (int round = 0; round < 2; ++round) {
+ void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, lib);
+
+ auto bump_local_vars = reinterpret_cast<int(*)()>(dlsym(lib, "bump_local_vars"));
+ ASSERT_NE(nullptr, bump_local_vars);
+
+ ASSERT_EQ(42, bump_local_vars());
+ ASSERT_EQ(44, bump_local_vars());
+
+ ASSERT_EQ(0, dlclose(lib));
+ }
+}
+
+// Calling dlclose should remove the entry for the solib from the global list of
+// ELF TLS modules. Test that repeatedly loading and unloading a library doesn't
+// increase the DTV size.
+TEST(elftls_dl, dlclose_removes_entry) {
+#if defined(__BIONIC__)
+ auto dtv = []() -> TlsDtv* { return __get_tcb_dtv(__get_bionic_tcb()); };
+
+ bool first = true;
+ size_t count = 0;
+
+ // Use a large number of rounds in case the DTV is initially larger than
+ // expected.
+ for (int round = 0; round < 32; ++round) {
+ void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, lib);
+
+ auto bump_local_vars = reinterpret_cast<int(*)()>(dlsym(lib, "bump_local_vars"));
+ ASSERT_NE(nullptr, bump_local_vars);
+
+ ASSERT_EQ(42, bump_local_vars());
+ if (first) {
+ first = false;
+ count = dtv()->count;
+ } else {
+ ASSERT_EQ(count, dtv()->count);
+ }
+
+ dlclose(lib);
+ }
+#else
+ GTEST_LOG_(INFO) << "This test is skipped for glibc because it tests Bionic internals.";
+#endif
+}
diff --git a/tests/elftls_test.cpp b/tests/elftls_test.cpp
index 11d41ce..2d83d70 100644
--- a/tests/elftls_test.cpp
+++ b/tests/elftls_test.cpp
@@ -83,3 +83,17 @@
ASSERT_EQ(8, bump_static_tls_var_2());
}).join();
}
+
+// Because this C++ source file is built with -fpic, the compiler will access
+// this variable using a GD model. Typically, the static linker will relax the
+// GD to LE, but the arm32 linker doesn't do TLS relaxations, so we can test
+// calling __tls_get_addr in a static executable. The static linker knows that
+// the main executable's TlsIndex::module_id is 1 and writes that into the GOT.
+__thread int tlsvar_general = 30;
+
+TEST(elftls, general) {
+ ASSERT_EQ(31, ++tlsvar_general);
+ std::thread([] {
+ ASSERT_EQ(31, ++tlsvar_general);
+ }).join();
+}
diff --git a/tests/getauxval_test.cpp b/tests/getauxval_test.cpp
index 63bc963..aa21817 100644
--- a/tests/getauxval_test.cpp
+++ b/tests/getauxval_test.cpp
@@ -14,29 +14,14 @@
* limitations under the License.
*/
+#include <sys/auxv.h>
+
#include <errno.h>
#include <sys/cdefs.h>
#include <sys/utsname.h>
#include <gtest/gtest.h>
-// getauxval() was only added as of glibc version 2.16.
-// See: http://lwn.net/Articles/519085/
-// Don't try to compile this code on older glibc versions.
-
-#if defined(__BIONIC__)
- #define GETAUXVAL_CAN_COMPILE 1
-#elif defined(__GLIBC_PREREQ)
- #if __GLIBC_PREREQ(2, 16)
- #define GETAUXVAL_CAN_COMPILE 1
- #endif
-#endif
-
-#if defined(GETAUXVAL_CAN_COMPILE)
-#include <sys/auxv.h>
-#endif
-
TEST(getauxval, expected_values) {
-#if defined(GETAUXVAL_CAN_COMPILE)
ASSERT_EQ(0UL, getauxval(AT_SECURE));
ASSERT_EQ(getuid(), getauxval(AT_UID));
ASSERT_EQ(geteuid(), getauxval(AT_EUID));
@@ -48,19 +33,12 @@
ASSERT_NE(0UL, getauxval(AT_PHNUM));
ASSERT_NE(0UL, getauxval(AT_ENTRY));
ASSERT_NE(0UL, getauxval(AT_PAGESZ));
-#else
- GTEST_LOG_(INFO) << "This test requires a C library with getauxval.\n";
-#endif
}
TEST(getauxval, unexpected_values) {
-#if defined(GETAUXVAL_CAN_COMPILE)
errno = 0;
ASSERT_EQ(0UL, getauxval(0xdeadbeef));
ASSERT_EQ(ENOENT, errno);
-#else
- GTEST_LOG_(INFO) << "This test requires a C library with getauxval.\n";
-#endif
}
TEST(getauxval, arm_has_AT_HWCAP2) {
diff --git a/tests/headers/posix/signal_h.c b/tests/headers/posix/signal_h.c
index 661b55e..c2e544e 100644
--- a/tests/headers/posix/signal_h.c
+++ b/tests/headers/posix/signal_h.c
@@ -53,7 +53,7 @@
STRUCT_MEMBER(struct sigevent, int, sigev_signo);
STRUCT_MEMBER(struct sigevent, union sigval, sigev_value);
STRUCT_MEMBER_FUNCTION_POINTER(struct sigevent, void (*f)(union sigval), sigev_notify_function);
-#if defined(__BIONIC__) || defined(__GLIBC__)
+#if defined(__BIONIC__)
STRUCT_MEMBER(struct sigevent, void*, sigev_notify_attributes);
#else
STRUCT_MEMBER(struct sigevent, pthread_attr_t*, sigev_notify_attributes);
diff --git a/tests/libs/elf_tls_test_library.cpp b/tests/ifunc_test.cpp
similarity index 67%
rename from tests/libs/elf_tls_test_library.cpp
rename to tests/ifunc_test.cpp
index 56d0171..7ab5899 100644
--- a/tests/libs/elf_tls_test_library.cpp
+++ b/tests/ifunc_test.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,18 @@
* limitations under the License.
*/
-thread_local int elf_tls_variable;
+#include <gtest/gtest.h>
-extern "C" int* get() { return &elf_tls_variable; }
+int ret42() {
+ return 42;
+}
+
+extern "C" void* resolver() {
+ return (void*)ret42;
+}
+
+int ifunc() __attribute__((ifunc("resolver")));
+
+TEST(ifunc, function) {
+ ASSERT_EQ(42, ifunc());
+}
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 05d1ed2..d58b6b8 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -43,14 +43,6 @@
// Libraries and helper binaries for ELF TLS
// -----------------------------------------------------------------------------
cc_test_library {
- name: "libelf-tls-library",
- defaults: ["bionic_testlib_defaults"],
- srcs: ["elf_tls_test_library.cpp"],
- cflags: ["-fno-emulated-tls"],
- allow_undefined_symbols: true, // __tls_get_addr is undefined.
-}
-
-cc_test_library {
name: "libtest_elftls_shared_var",
defaults: ["bionic_testlib_defaults"],
srcs: ["elftls_shared_var.cpp"],
@@ -79,6 +71,35 @@
ldflags: ["-Wl,--rpath,${ORIGIN}/.."],
}
+cc_test_library {
+ name: "libtest_elftls_dynamic",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["elftls_dynamic.cpp"],
+ cflags: ["-fno-emulated-tls"],
+ shared_libs: ["libtest_elftls_shared_var"],
+}
+
+cc_test_library {
+ name: "libtest_elftls_dynamic_filler_1",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["elftls_dynamic_filler.cpp"],
+ cflags: ["-fno-emulated-tls", "-DTLS_FILLER=100"],
+}
+
+cc_test_library {
+ name: "libtest_elftls_dynamic_filler_2",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["elftls_dynamic_filler.cpp"],
+ cflags: ["-fno-emulated-tls", "-DTLS_FILLER=200"],
+}
+
+cc_test_library {
+ name: "libtest_elftls_dynamic_filler_3",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["elftls_dynamic_filler.cpp"],
+ cflags: ["-fno-emulated-tls", "-DTLS_FILLER=300"],
+}
+
// -----------------------------------------------------------------------------
// Library to test gnu-styled hash
// -----------------------------------------------------------------------------
diff --git a/tests/libs/Android.build.dlext_testzip.mk b/tests/libs/Android.build.dlext_testzip.mk
index 19fd64b..8775c29 100644
--- a/tests/libs/Android.build.dlext_testzip.mk
+++ b/tests/libs/Android.build.dlext_testzip.mk
@@ -59,21 +59,38 @@
lib_b := $(call intermediates-dir-for,SHARED_LIBRARIES,libtest_dt_runpath_b,,,$(bionic_2nd_arch_prefix))/libtest_dt_runpath_b.so
lib_c := $(call intermediates-dir-for,SHARED_LIBRARIES,libtest_dt_runpath_c,,,$(bionic_2nd_arch_prefix))/libtest_dt_runpath_c.so
lib_x := $(call intermediates-dir-for,SHARED_LIBRARIES,libtest_dt_runpath_x,,,$(bionic_2nd_arch_prefix))/libtest_dt_runpath_x.so
+lib_y := $(call intermediates-dir-for,SHARED_LIBRARIES,libtest_dt_runpath_y,,,$(bionic_2nd_arch_prefix))/libtest_dt_runpath_y.so
$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_D := $(lib_d)
$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_A := $(lib_a)
$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_B := $(lib_b)
$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_C := $(lib_c)
$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_X := $(lib_x)
-$(LOCAL_BUILT_MODULE) : $(lib_d) $(lib_a) $(lib_b) $(lib_c) $(lib_x) $(BIONIC_TESTS_ZIPALIGN)
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_Y := $(lib_y)
+ifeq ($(TARGET_IS_64_BIT),true)
+ ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
+ $(LOCAL_BUILT_MODULE) : PRIVATE_LIB_OR_LIB64 := $(if $(LOCAL_2ND_ARCH_VAR_PREFIX),lib/$(TARGET_2ND_ARCH),lib64)
+ else
+ $(LOCAL_BUILT_MODULE) : PRIVATE_LIB_OR_LIB64 := $(if $(LOCAL_2ND_ARCH_VAR_PREFIX),lib,lib64)
+ endif
+else
+ ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
+ $(LOCAL_BUILT_MODULE) : PRIVATE_LIB_OR_LIB64 := $(if $(LOCAL_2ND_ARCH_VAR_PREFIX),lib/$(TARGET_2ND_ARCH),lib)
+ else
+ $(LOCAL_BUILT_MODULE) : PRIVATE_LIB_OR_LIB64 := lib
+ endif
+endif
+$(LOCAL_BUILT_MODULE) : $(lib_d) $(lib_a) $(lib_b) $(lib_c) $(lib_x) $(lib_y) $(BIONIC_TESTS_ZIPALIGN)
@echo "Aligning zip: $@"
$(hide) rm -rf $@.unaligned $@ $(dir $@)/zipdir && mkdir -p $(dir $@)/zipdir/libdir && \
- mkdir -p $(dir $@)/zipdir/libdir/dt_runpath_a && mkdir -p $(dir $@)/zipdir/libdir/dt_runpath_b_c_x
+ mkdir -p $(dir $@)/zipdir/libdir/dt_runpath_a && mkdir -p $(dir $@)/zipdir/libdir/dt_runpath_b_c_x && \
+ mkdir -p $(dir $@)/zipdir/libdir/dt_runpath_y/$(PRIVATE_LIB_OR_LIB64)
$(hide) cp $(PRIVATE_LIB_D) $(dir $@)/zipdir/libdir
$(hide) cp $(PRIVATE_LIB_A) $(dir $@)/zipdir/libdir/dt_runpath_a
$(hide) cp $(PRIVATE_LIB_B) $(dir $@)/zipdir/libdir/dt_runpath_b_c_x
$(hide) cp $(PRIVATE_LIB_C) $(dir $@)/zipdir/libdir/dt_runpath_b_c_x
$(hide) cp $(PRIVATE_LIB_X) $(dir $@)/zipdir/libdir/dt_runpath_b_c_x
+ $(hide) cp $(PRIVATE_LIB_Y) $(dir $@)/zipdir/libdir/dt_runpath_y/$(PRIVATE_LIB_OR_LIB64)
$(hide) touch $(dir $@)/zipdir/empty_file.txt
$(hide) (cd $(dir $@)/zipdir && zip -qrD0 ../$(notdir $@).unaligned .)
$(hide) $(BIONIC_TESTS_ZIPALIGN) 4096 $@.unaligned $@
diff --git a/tests/libs/Android.build.dt_runpath.mk b/tests/libs/Android.build.dt_runpath.mk
index a3fcac5..b0d8e4b 100644
--- a/tests/libs/Android.build.dt_runpath.mk
+++ b/tests/libs/Android.build.dt_runpath.mk
@@ -21,11 +21,12 @@
#
# Dependencies
#
-# libtest_dt_runpath_d.so runpath: ${ORIGIN}/dt_runpath_b_c_x
+# libtest_dt_runpath_d.so runpath: ${ORIGIN}/dt_runpath_b_c_x, ${ORIGIN}/dt_runpath_y/${LIB}
# |-> dt_runpath_b_c_x/libtest_dt_runpath_b.so runpath: ${ORIGIN}/../dt_runpath_a
# | |-> dt_runpath_a/libtest_dt_runpath_a.so
# |-> dt_runpath_b_c_x/libtest_dt_runpath_c.so runpath: ${ORIGIN}/invalid_dt_runpath
# | |-> libtest_dt_runpath_a.so (soname)
+# |-> dt_runpath_y/lib[64]/libtest_dt_runpath_y.so
#
# This one is used to test dlopen
# dt_runpath_b_c_x/libtest_dt_runpath_x.so
@@ -61,12 +62,18 @@
module := libtest_dt_runpath_c
include $(LOCAL_PATH)/Android.build.testlib.mk
-# D depends on B and C with DT_RUNPATH.
+# D depends on B, C, and Y with DT_RUNPATH.
libtest_dt_runpath_d_src_files := \
dlopen_b.cpp
-libtest_dt_runpath_d_shared_libraries := libtest_dt_runpath_b libtest_dt_runpath_c
-libtest_dt_runpath_d_ldflags := -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x -Wl,--enable-new-dtags
+libtest_dt_runpath_d_shared_libraries := \
+ libtest_dt_runpath_b \
+ libtest_dt_runpath_c \
+ libtest_dt_runpath_y
+libtest_dt_runpath_d_ldflags := \
+ -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x \
+ -Wl,--rpath,\$${ORIGIN}/dt_runpath_y/\$${LIB} \
+ -Wl,--enable-new-dtags
libtest_dt_runpath_d_ldlibs := -ldl
module := libtest_dt_runpath_d
include $(LOCAL_PATH)/Android.build.testlib.mk
@@ -77,8 +84,14 @@
libtest_dt_runpath_d_zip_src_files := \
dlopen_b.cpp
-libtest_dt_runpath_d_zip_shared_libraries := libtest_dt_runpath_b libtest_dt_runpath_c
-libtest_dt_runpath_d_zip_ldflags := -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x -Wl,--enable-new-dtags
+libtest_dt_runpath_d_zip_shared_libraries := \
+ libtest_dt_runpath_b \
+ libtest_dt_runpath_c \
+ libtest_dt_runpath_y
+libtest_dt_runpath_d_zip_ldflags := \
+ -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x \
+ -Wl,--rpath,\$${ORIGIN}/dt_runpath_y/\$${LIB} \
+ -Wl,--enable-new-dtags
libtest_dt_runpath_d_zip_ldlibs := -ldl
libtest_dt_runpath_d_zip_install_to_native_tests_dir := $(module)
@@ -96,3 +109,20 @@
module := libtest_dt_runpath_x
include $(LOCAL_PATH)/Android.build.testlib.mk
+# A leaf library in lib or lib64 directory
+libtest_dt_runpath_y_src_files := \
+ empty.cpp
+
+ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
+libtest_dt_runpath_y_install_to_native_tests_dir_32 := bionic-loader-test-libs/dt_runpath_y/lib/$(TARGET_2ND_ARCH)
+else
+libtest_dt_runpath_y_install_to_native_tests_dir_32 := bionic-loader-test-libs/dt_runpath_y/lib
+endif
+ifeq ($(TARGET_IS_64_BIT),true)
+libtest_dt_runpath_y_install_to_native_tests_dir_64 := bionic-loader-test-libs/dt_runpath_y/lib64
+else
+libtest_dt_runpath_y_install_to_native_tests_dir_64 := bionic-loader-test-libs/dt_runpath_y/lib
+endif
+
+module := libtest_dt_runpath_y
+include $(LOCAL_PATH)/Android.build.testlib.mk
diff --git a/tests/libs/elftls_dynamic.cpp b/tests/libs/elftls_dynamic.cpp
new file mode 100644
index 0000000..7fa239c
--- /dev/null
+++ b/tests/libs/elftls_dynamic.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// This shared object test library is dlopen'ed by the main test executable.
+// This variable comes from libtest_elftls_shared_var.so, which is part of
+// static TLS. Verify that a GD-model access can access the variable.
+//
+// Accessing the static TLS variable from an solib prevents the static linker
+// from relaxing the GD access to IE and lets us test that __tls_get_addr and
+// the tlsdesc resolver handle a static TLS variable.
+extern "C" __thread int elftls_shared_var;
+
+extern "C" int bump_shared_var() {
+ return ++elftls_shared_var;
+}
+
+// The static linker denotes the current module by omitting the symbol from
+// the DTPMOD/TLSDESC relocations.
+static __thread int local_var_1 = 15;
+static __thread int local_var_2 = 25;
+
+extern "C" int bump_local_vars() {
+ return ++local_var_1 + ++local_var_2;
+}
+
+__attribute__((weak)) extern "C" __thread int missing_weak_dyn_tls;
+
+extern "C" int* missing_weak_dyn_tls_addr() {
+ return &missing_weak_dyn_tls;
+}
diff --git a/tests/libs/elftls_dynamic_filler.cpp b/tests/libs/elftls_dynamic_filler.cpp
new file mode 100644
index 0000000..9c00ab0
--- /dev/null
+++ b/tests/libs/elftls_dynamic_filler.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+__thread int var = TLS_FILLER;
+
+extern "C" int bump() {
+ return ++var;
+}
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 2506691..a3fe5af 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -515,6 +515,7 @@
TEST(malloc, mallopt_decay) {
#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN; // hwasan does not implement mallopt
errno = 0;
ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1));
ASSERT_EQ(1, mallopt(M_DECAY_TIME, 0));
@@ -527,6 +528,7 @@
TEST(malloc, mallopt_purge) {
#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN; // hwasan does not implement mallopt
errno = 0;
ASSERT_EQ(1, mallopt(M_PURGE, 0));
#else
@@ -564,6 +566,7 @@
TEST(malloc, mallinfo) {
#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN; // hwasan does not implement mallinfo
static size_t sizes[] = {
8, 32, 128, 4096, 32768, 131072, 1024000, 10240000, 20480000, 300000000
};
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 1c57264..973ca53 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <sys/mman.h>
#include <sys/prctl.h>
+#include <sys/resource.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
@@ -336,11 +337,14 @@
static void* thread_fn(void* arg) {
TestBug37410* data = reinterpret_cast<TestBug37410*>(arg);
+ // Unlocking data->mutex will cause the main thread to exit, invalidating *data. Save the handle.
+ pthread_t main_thread = data->main_thread;
+
// Let the main thread know we're running.
pthread_mutex_unlock(&data->mutex);
// And wait for the main thread to exit.
- pthread_join(data->main_thread, nullptr);
+ pthread_join(main_thread, nullptr);
return nullptr;
}
@@ -494,7 +498,8 @@
pthread_t dead_thread;
MakeDeadThread(dead_thread);
- EXPECT_DEATH(pthread_setname_np(dead_thread, "short 3"), "invalid pthread_t");
+ EXPECT_DEATH(pthread_setname_np(dead_thread, "short 3"),
+ "invalid pthread_t (.*) passed to pthread_setname_np");
}
TEST_F(pthread_DeathTest, pthread_setname_np__null_thread) {
@@ -507,7 +512,8 @@
MakeDeadThread(dead_thread);
char name[64];
- EXPECT_DEATH(pthread_getname_np(dead_thread, name, sizeof(name)), "invalid pthread_t");
+ EXPECT_DEATH(pthread_getname_np(dead_thread, name, sizeof(name)),
+ "invalid pthread_t (.*) passed to pthread_getname_np");
}
TEST_F(pthread_DeathTest, pthread_getname_np__null_thread) {
@@ -563,7 +569,8 @@
pthread_t dead_thread;
MakeDeadThread(dead_thread);
- EXPECT_DEATH(pthread_detach(dead_thread), "invalid pthread_t");
+ EXPECT_DEATH(pthread_detach(dead_thread),
+ "invalid pthread_t (.*) passed to pthread_detach");
}
TEST_F(pthread_DeathTest, pthread_detach__null_thread) {
@@ -590,7 +597,8 @@
MakeDeadThread(dead_thread);
clockid_t c;
- EXPECT_DEATH(pthread_getcpuclockid(dead_thread, &c), "invalid pthread_t");
+ EXPECT_DEATH(pthread_getcpuclockid(dead_thread, &c),
+ "invalid pthread_t (.*) passed to pthread_getcpuclockid");
}
TEST_F(pthread_DeathTest, pthread_getcpuclockid__null_thread) {
@@ -605,7 +613,8 @@
int policy;
sched_param param;
- EXPECT_DEATH(pthread_getschedparam(dead_thread, &policy, ¶m), "invalid pthread_t");
+ EXPECT_DEATH(pthread_getschedparam(dead_thread, &policy, ¶m),
+ "invalid pthread_t (.*) passed to pthread_getschedparam");
}
TEST_F(pthread_DeathTest, pthread_getschedparam__null_thread) {
@@ -621,7 +630,8 @@
int policy = 0;
sched_param param;
- EXPECT_DEATH(pthread_setschedparam(dead_thread, policy, ¶m), "invalid pthread_t");
+ EXPECT_DEATH(pthread_setschedparam(dead_thread, policy, ¶m),
+ "invalid pthread_t (.*) passed to pthread_setschedparam");
}
TEST_F(pthread_DeathTest, pthread_setschedparam__null_thread) {
@@ -635,7 +645,8 @@
pthread_t dead_thread;
MakeDeadThread(dead_thread);
- EXPECT_DEATH(pthread_setschedprio(dead_thread, 123), "invalid pthread_t");
+ EXPECT_DEATH(pthread_setschedprio(dead_thread, 123),
+ "invalid pthread_t (.*) passed to pthread_setschedprio");
}
TEST_F(pthread_DeathTest, pthread_setschedprio__null_thread) {
@@ -647,7 +658,8 @@
pthread_t dead_thread;
MakeDeadThread(dead_thread);
- EXPECT_DEATH(pthread_join(dead_thread, nullptr), "invalid pthread_t");
+ EXPECT_DEATH(pthread_join(dead_thread, nullptr),
+ "invalid pthread_t (.*) passed to pthread_join");
}
TEST_F(pthread_DeathTest, pthread_join__null_thread) {
@@ -659,7 +671,8 @@
pthread_t dead_thread;
MakeDeadThread(dead_thread);
- EXPECT_DEATH(pthread_kill(dead_thread, 0), "invalid pthread_t");
+ EXPECT_DEATH(pthread_kill(dead_thread, 0),
+ "invalid pthread_t (.*) passed to pthread_kill");
}
TEST_F(pthread_DeathTest, pthread_kill__null_thread) {
@@ -1540,7 +1553,7 @@
void* maps_stack_hi = nullptr;
std::vector<map_record> maps;
ASSERT_TRUE(Maps::parse_maps(&maps));
- uintptr_t stack_address = reinterpret_cast<uintptr_t>(&maps_stack_hi);
+ uintptr_t stack_address = reinterpret_cast<uintptr_t>(untag_address(&maps_stack_hi));
for (const auto& map : maps) {
if (map.addr_start <= stack_address && map.addr_end > stack_address){
maps_stack_hi = reinterpret_cast<void*>(map.addr_end);
@@ -1619,9 +1632,9 @@
// Verify if the stack used by the signal handler is the alternate stack just registered.
ASSERT_LE(getstack_signal_handler_arg.signal_stack_base, &attr);
- ASSERT_LT(static_cast<void*>(&attr),
+ ASSERT_LT(static_cast<void*>(untag_address(&attr)),
static_cast<char*>(getstack_signal_handler_arg.signal_stack_base) +
- getstack_signal_handler_arg.signal_stack_size);
+ getstack_signal_handler_arg.signal_stack_size);
// Verify if the main thread's stack got in the signal handler is correct.
ASSERT_EQ(getstack_signal_handler_arg.main_stack_base, stack_base);
@@ -1680,7 +1693,7 @@
// Test whether &local_variable is in [stack_base, stack_base + stack_size).
ASSERT_LE(reinterpret_cast<char*>(stack_base), &local_variable);
- ASSERT_LT(&local_variable, reinterpret_cast<char*>(stack_base) + stack_size);
+ ASSERT_LT(untag_address(&local_variable), reinterpret_cast<char*>(stack_base) + stack_size);
}
// Check whether something on stack is in the range of
diff --git a/tests/stack_protector_test.cpp b/tests/stack_protector_test.cpp
index 34e3c11..7a85cc3 100644
--- a/tests/stack_protector_test.cpp
+++ b/tests/stack_protector_test.cpp
@@ -104,6 +104,11 @@
TEST_F(stack_protector_DeathTest, modify_stack_protector) {
// In another file to prevent inlining, which removes stack protection.
extern void modify_stack_protector_test();
+#if __has_feature(hwaddress_sanitizer)
+ ASSERT_EXIT(modify_stack_protector_test(),
+ testing::KilledBySignal(SIGABRT), "tag-mismatch");
+#else
ASSERT_EXIT(modify_stack_protector_test(),
testing::KilledBySignal(SIGABRT), "stack corruption detected");
+#endif
}
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 479fd9d..ad6ed45 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -1820,6 +1820,14 @@
ASSERT_EQ(0, fclose(fp));
}
+TEST(STDIO_TEST, fmemopen_zero_length_buffer_overrun) {
+ char buf[2] = "x";
+ ASSERT_EQ('x', buf[0]);
+ FILE* fp = fmemopen(buf, 0, "w");
+ ASSERT_EQ('x', buf[0]);
+ ASSERT_EQ(0, fclose(fp));
+}
+
TEST(STDIO_TEST, fmemopen_write_only_allocated) {
// POSIX says fmemopen "may fail if the mode argument does not include a '+'".
// BSD fails, glibc doesn't. We side with the more lenient.
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index a249b75..408a9c7 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -36,14 +36,6 @@
#include "math_data_test.h"
#include "utils.h"
-#if defined(__BIONIC__)
- #define ALIGNED_ALLOC_AVAILABLE 1
-#elif defined(__GLIBC_PREREQ)
- #if __GLIBC_PREREQ(2, 16)
- #define ALIGNED_ALLOC_AVAILABLE 1
- #endif
-#endif
-
template <typename T = int (*)(char*)>
class GenericTemporaryFile {
public:
@@ -274,7 +266,6 @@
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.
size_t last_align = 1;
@@ -292,31 +283,20 @@
free(ptr);
last_align = align;
}
-#else
- GTEST_LOG_(INFO) << "This test requires a C library that has aligned_alloc.\n";
-#endif
}
TEST(stdlib, aligned_alloc_overflow) {
SKIP_WITH_HWASAN;
-#if defined(ALIGNED_ALLOC_AVAILABLE)
ASSERT_TRUE(aligned_alloc(16, SIZE_MAX) == nullptr);
-#else
- GTEST_LOG_(INFO) << "This test requires a C library that has aligned_alloc.\n";
-#endif
}
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);
ASSERT_TRUE(ptr != nullptr) << "Failed at size " << std::to_string(size);
free(ptr);
}
-#else
- GTEST_LOG_(INFO) << "This test requires a C library that has aligned_alloc.\n";
-#endif
}
TEST(stdlib, realpath__NULL_filename) {
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index fd2a787..b27ca87 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -1554,3 +1554,40 @@
ASSERT_EQ(haystack + 1, strstr(haystack, "i"));
ASSERT_EQ(haystack + 4, strstr(haystack, "da"));
}
+
+TEST(STRING_TEST, strcasestr_smoke) {
+ const char* haystack = "bIg dAdDy/gIaNt hAyStAcKs";
+ ASSERT_EQ(haystack, strcasestr(haystack, ""));
+ ASSERT_EQ(haystack + 0, strcasestr(haystack, "B"));
+ ASSERT_EQ(haystack + 1, strcasestr(haystack, "i"));
+ ASSERT_EQ(haystack + 4, strcasestr(haystack, "Da"));
+}
+
+TEST(STRING_TEST, strcoll_smoke) {
+ ASSERT_TRUE(strcoll("aab", "aac") < 0);
+ ASSERT_TRUE(strcoll("aab", "aab") == 0);
+ ASSERT_TRUE(strcoll("aac", "aab") > 0);
+}
+
+TEST(STRING_TEST, strxfrm_smoke) {
+ const char* src1 = "aab";
+ char dst1[16] = {};
+ ASSERT_GT(strxfrm(dst1, src1, sizeof(dst1)), 0U);
+ const char* src2 = "aac";
+ char dst2[16] = {};
+ ASSERT_GT(strxfrm(dst2, src2, sizeof(dst2)), 0U);
+ ASSERT_TRUE(strcmp(dst1, dst2) < 0);
+}
+
+TEST(STRING_TEST, memccpy_smoke) {
+ char dst[32];
+
+ memset(dst, 0, sizeof(dst));
+ char* p = static_cast<char*>(memccpy(dst, "hello world", ' ', 32));
+ ASSERT_STREQ("hello ", dst);
+ ASSERT_EQ(ptrdiff_t(6), p - dst);
+
+ memset(dst, 0, sizeof(dst));
+ ASSERT_EQ(nullptr, memccpy(dst, "hello world", ' ', 4));
+ ASSERT_STREQ("hell", dst);
+}
diff --git a/tests/sys_ptrace_test.cpp b/tests/sys_ptrace_test.cpp
index 83fd93b..04dcd4e 100644
--- a/tests/sys_ptrace_test.cpp
+++ b/tests/sys_ptrace_test.cpp
@@ -35,6 +35,8 @@
#include <android-base/macros.h>
#include <android-base/unique_fd.h>
+#include "utils.h"
+
using namespace std::chrono_literals;
using android::base::unique_fd;
@@ -193,7 +195,7 @@
return;
}
- set_watchpoint(child, uintptr_t(&data) + offset, size);
+ set_watchpoint(child, uintptr_t(untag_address(&data)) + offset, size);
ASSERT_EQ(0, ptrace(PTRACE_CONT, child, nullptr, nullptr)) << strerror(errno);
ASSERT_EQ(child, TEMP_FAILURE_RETRY(waitpid(child, &status, __WALL))) << strerror(errno);
diff --git a/tests/uchar_test.cpp b/tests/uchar_test.cpp
index 522d5ac..48c500d 100644
--- a/tests/uchar_test.cpp
+++ b/tests/uchar_test.cpp
@@ -15,12 +15,7 @@
*/
-#include <sys/cdefs.h>
-#if defined(__BIONIC__)
-#define HAVE_UCHAR 1
-#elif defined(__GLIBC__)
-#define HAVE_UCHAR __GLIBC_PREREQ(2, 16)
-#endif
+#include <uchar.h>
#include <gtest/gtest.h>
@@ -29,21 +24,12 @@
#include <locale.h>
#include <stdint.h>
-#if HAVE_UCHAR
-#include <uchar.h>
-#endif
-
TEST(uchar, sizeof_uchar_t) {
-#if HAVE_UCHAR
EXPECT_EQ(2U, sizeof(char16_t));
EXPECT_EQ(4U, sizeof(char32_t));
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, start_state) {
-#if HAVE_UCHAR
char out[MB_LEN_MAX];
mbstate_t ps;
@@ -64,31 +50,19 @@
EXPECT_EQ(static_cast<size_t>(-2), mbrtoc32(nullptr, "\xf0\xa4", 1, &ps));
EXPECT_EQ(1U, c32rtomb(out, L'\0', &ps));
EXPECT_TRUE(mbsinit(&ps));
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, c16rtomb_null_out) {
-#if HAVE_UCHAR
EXPECT_EQ(1U, c16rtomb(nullptr, L'\0', nullptr));
EXPECT_EQ(1U, c16rtomb(nullptr, L'h', nullptr));
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, c16rtomb_null_char) {
-#if HAVE_UCHAR
char bytes[MB_LEN_MAX];
EXPECT_EQ(1U, c16rtomb(bytes, L'\0', nullptr));
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, c16rtomb) {
-#if HAVE_UCHAR
char bytes[MB_LEN_MAX];
memset(bytes, 0, sizeof(bytes));
@@ -113,13 +87,9 @@
EXPECT_EQ('\xe2', bytes[0]);
EXPECT_EQ('\x82', bytes[1]);
EXPECT_EQ('\xac', bytes[2]);
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, c16rtomb_surrogate) {
-#if HAVE_UCHAR
char bytes[MB_LEN_MAX];
memset(bytes, 0, sizeof(bytes));
@@ -129,13 +99,9 @@
EXPECT_EQ('\x8a', bytes[1]);
EXPECT_EQ('\xaf', bytes[2]);
EXPECT_EQ('\x8d', bytes[3]);
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, c16rtomb_invalid) {
-#if HAVE_UCHAR
char bytes[MB_LEN_MAX];
memset(bytes, 0, sizeof(bytes));
@@ -143,21 +109,13 @@
EXPECT_EQ(0U, c16rtomb(bytes, 0xdbea, nullptr));
EXPECT_EQ(static_cast<size_t>(-1), c16rtomb(bytes, 0xdbea, nullptr));
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, mbrtoc16_null) {
-#if HAVE_UCHAR
ASSERT_EQ(0U, mbrtoc16(nullptr, nullptr, 0, nullptr));
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, mbrtoc16_zero_len) {
-#if HAVE_UCHAR
char16_t out;
out = L'x';
@@ -168,13 +126,9 @@
ASSERT_EQ(0U, mbrtoc16(&out, "", 0, nullptr));
ASSERT_EQ(1U, mbrtoc16(&out, "hello", 1, nullptr));
ASSERT_EQ(L'h', out);
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, mbrtoc16) {
-#if HAVE_UCHAR
char16_t out;
ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
@@ -189,13 +143,9 @@
// 3-byte UTF-8.
ASSERT_EQ(3U, mbrtoc16(&out, "\xe2\x82\xac" "def", 6, nullptr));
ASSERT_EQ(static_cast<char16_t>(0x20ac), out);
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, mbrtoc16_surrogate) {
-#if HAVE_UCHAR
char16_t out;
ASSERT_EQ(static_cast<size_t>(-3),
@@ -203,32 +153,20 @@
ASSERT_EQ(static_cast<char16_t>(0xdbea), out);
ASSERT_EQ(4U, mbrtoc16(&out, "\xf4\x8a\xaf\x8d" "ef", 6, nullptr));
ASSERT_EQ(static_cast<char16_t>(0xdfcd), out);
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, mbrtoc16_reserved_range) {
-#if HAVE_UCHAR
char16_t out;
ASSERT_EQ(static_cast<size_t>(-1),
mbrtoc16(&out, "\xf0\x80\xbf\xbf", 6, nullptr));
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, mbrtoc16_beyond_range) {
-#if HAVE_UCHAR
char16_t out;
ASSERT_EQ(static_cast<size_t>(-1),
mbrtoc16(&out, "\xf5\x80\x80\x80", 6, nullptr));
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
-#if HAVE_UCHAR
void test_mbrtoc16_incomplete(mbstate_t* ps) {
ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
uselocale(LC_GLOBAL_LOCALE);
@@ -259,22 +197,16 @@
ASSERT_EQ(static_cast<size_t>(-1), mbrtoc16(&out, "\x20" "cdef", 5, ps));
ASSERT_EQ(EILSEQ, errno);
}
-#endif
TEST(uchar, mbrtoc16_incomplete) {
-#if HAVE_UCHAR
mbstate_t ps;
memset(&ps, 0, sizeof(ps));
test_mbrtoc16_incomplete(&ps);
test_mbrtoc16_incomplete(nullptr);
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, c32rtomb) {
-#if HAVE_UCHAR
EXPECT_EQ(1U, c32rtomb(nullptr, L'\0', nullptr));
EXPECT_EQ(1U, c32rtomb(nullptr, L'h', nullptr));
@@ -317,13 +249,9 @@
// Invalid code point.
EXPECT_EQ(static_cast<size_t>(-1), c32rtomb(bytes, 0xffffffff, nullptr));
EXPECT_EQ(EILSEQ, errno);
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, mbrtoc32_valid_non_characters) {
-#if HAVE_UCHAR
ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
uselocale(LC_GLOBAL_LOCALE);
@@ -332,13 +260,9 @@
ASSERT_EQ(0xfffeU, out[0]);
ASSERT_EQ(3U, mbrtoc32(out, "\xef\xbf\xbf", 3, nullptr));
ASSERT_EQ(0xffffU, out[0]);
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, mbrtoc32_out_of_range) {
-#if HAVE_UCHAR
ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
uselocale(LC_GLOBAL_LOCALE);
@@ -346,13 +270,9 @@
errno = 0;
ASSERT_EQ(static_cast<size_t>(-1), mbrtoc32(out, "\xf5\x80\x80\x80", 4, nullptr));
ASSERT_EQ(EILSEQ, errno);
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
TEST(uchar, mbrtoc32) {
-#if HAVE_UCHAR
char32_t out[8];
out[0] = L'x';
@@ -393,12 +313,8 @@
// Illegal over-long sequence.
ASSERT_EQ(static_cast<size_t>(-1), mbrtoc32(out, "\xf0\x82\x82\xac" "ef", 6, nullptr));
ASSERT_EQ(EILSEQ, errno);
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
-#if HAVE_UCHAR
void test_mbrtoc32_incomplete(mbstate_t* ps) {
ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
uselocale(LC_GLOBAL_LOCALE);
@@ -427,16 +343,11 @@
ASSERT_EQ(static_cast<size_t>(-1), mbrtoc32(&out, "\x20" "cdef", 5, ps));
ASSERT_EQ(EILSEQ, errno);
}
-#endif
TEST(uchar, mbrtoc32_incomplete) {
-#if HAVE_UCHAR
mbstate_t ps;
memset(&ps, 0, sizeof(ps));
test_mbrtoc32_incomplete(&ps);
test_mbrtoc32_incomplete(nullptr);
-#else
- GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
-#endif
}
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index f4a7f1f..cb94e45 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -538,7 +538,7 @@
static int CloneStartRoutine(int (*start_routine)(void*)) {
void* child_stack[1024];
- return clone(start_routine, &child_stack[1024], SIGCHLD, nullptr);
+ return clone(start_routine, untag_address(&child_stack[1024]), SIGCHLD, nullptr);
}
static int GetPidCachingCloneStartRoutine(void*) {
diff --git a/tests/utils.h b/tests/utils.h
index 5fc1d93..cc1aa8c 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -66,6 +66,16 @@
#define SKIP_WITH_HWASAN if (running_with_hwasan()) { return; }
+static inline void* untag_address(void* addr) {
+#if defined(__LP64__)
+ if (running_with_hwasan()) {
+ constexpr uintptr_t mask = (static_cast<uintptr_t>(1) << 56) - 1;
+ addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & mask);
+ }
+#endif
+ return addr;
+}
+
#if defined(__linux__)
#include <sys/sysmacros.h>