Merge "avx2 memset: add missing `vzeroupper`." into main
diff --git a/docs/status.md b/docs/status.md
index fc68b80..5514935 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -62,7 +62,8 @@
functions for avoiding $TZ if you need to use multiple timezones in
multi-threaded C).
* `mbsrtowcs_l` and `wcsrtombs_l` aliases for `mbsrtowcs` and `wcsrtombs`.
- * New system call wrapper: `__riscv_flush_icache` (`<sys/cachectl.h>`).
+ * New system call wrappers: `__riscv_flush_icache` (`<sys/cachectl.h>`),
+ `__riscv_hwprobe` (`<sys/hwprobe.h>`).
New libc functions in U (API level 34):
* `close_range` and `copy_file_range` (Linux-specific GNU extensions).
diff --git a/libc/SECCOMP_ALLOWLIST_COMMON.TXT b/libc/SECCOMP_ALLOWLIST_COMMON.TXT
index 4a8d501..67b662e 100644
--- a/libc/SECCOMP_ALLOWLIST_COMMON.TXT
+++ b/libc/SECCOMP_ALLOWLIST_COMMON.TXT
@@ -74,5 +74,3 @@
int rt_sigtimedwait_time64(const sigset64_t*, siginfo_t*, const timespec64*, size_t) lp32
int futex_time64(int*, int, int, const timespec64*, int*, int) lp32
int sched_rr_get_interval_time64(pid_t, timespec64*) lp32
-# Since Linux 6.4, not in glibc (https://www.openwall.com/lists/libc-coord/2023/07/13/1).
-int riscv_hwprobe(riscv_hwprobe*, size_t, size_t, unsigned long*, unsigned) riscv64
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index e8dde7c..079acf9 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -357,6 +357,7 @@
# riscv64-specific
int __riscv_flush_icache:riscv_flush_icache(void*, void*, unsigned long) riscv64
+int __riscv_hwprobe:riscv_hwprobe(riscv_hwprobe*, size_t, size_t, unsigned long*, unsigned) riscv64
# x86-specific
int __set_thread_area:set_thread_area(void*) x86
diff --git a/libc/include/sys/hwprobe.h b/libc/include/sys/hwprobe.h
new file mode 100644
index 0000000..f2fd98d
--- /dev/null
+++ b/libc/include/sys/hwprobe.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if __riscv
+
+/**
+ * @file sys/hwprobe.h
+ * @brief RISC-V hardware probing.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/* Pull in struct riscv_hwprobe and corresponding constants. */
+#include <asm/hwprobe.h>
+
+__BEGIN_DECLS
+
+/**
+ * [__riscv_hwprobe(2)](https://docs.kernel.org/riscv/hwprobe.html)
+ * queries hardware characteristics.
+ *
+ * A `__cpu_count` of 0 and null `__cpus` means "all online cpus".
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ */
+int __riscv_hwprobe(struct riscv_hwprobe* _Nonnull __pairs, size_t __pair_count, size_t __cpu_count, unsigned long* _Nullable __cpus, unsigned __flags);
+
+__END_DECLS
+
+#endif
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 86c8288..e90618d 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1590,6 +1590,7 @@
mbsrtowcs_l;
mktime_z;
__riscv_flush_icache; # riscv64
+ __riscv_hwprobe; # riscv64
timespec_getres;
tzalloc;
tzfree;
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index a3f5246..fee19f4 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -97,7 +97,7 @@
void* context) __LINKER_PUBLIC__;
}
-static pthread_mutex_t g_dl_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+pthread_mutex_t g_dl_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
static char* __bionic_set_dlerror(char* new_value) {
char* old_value = __get_thread()->current_dlerror;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 5c26944..1553ba9 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -27,6 +27,7 @@
*/
#include <android/api-level.h>
+#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
diff --git a/linker/linker_globals.h b/linker/linker_globals.h
index 0998629..0cb7ca9 100644
--- a/linker/linker_globals.h
+++ b/linker/linker_globals.h
@@ -104,3 +104,4 @@
};
__LIBC_HIDDEN__ extern bool g_is_ldd;
+__LIBC_HIDDEN__ extern pthread_mutex_t g_dl_mutex;
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index f7c8ea9..e92aada 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -43,10 +43,11 @@
#include "linker_tls.h"
#include "linker_utils.h"
+#include "private/KernelArgumentBlock.h"
+#include "private/ScopedPthreadMutexLocker.h"
#include "private/bionic_call_ifunc_resolver.h"
#include "private/bionic_globals.h"
#include "private/bionic_tls.h"
-#include "private/KernelArgumentBlock.h"
#include "android-base/unique_fd.h"
#include "android-base/strings.h"
@@ -498,6 +499,11 @@
if (!get_cfi_shadow()->InitialLinkDone(solist)) __linker_cannot_link(g_argv[0]);
+ // A constructor could spawn a thread that calls into the loader, so as soon
+ // as we've called a constructor, we need to hold the lock while accessing
+ // global loader state.
+ ScopedPthreadMutexLocker locker(&g_dl_mutex);
+
si->call_pre_init_constructors();
si->call_constructors();
diff --git a/linker/linker_memory.cpp b/linker/linker_memory.cpp
index 456d254..7ce53b8 100644
--- a/linker/linker_memory.cpp
+++ b/linker/linker_memory.cpp
@@ -76,6 +76,10 @@
return get_allocator().memalign(alignment, byte_count);
}
+void* aligned_alloc(size_t alignment, size_t byte_count) {
+ return get_allocator().memalign(alignment, byte_count);
+}
+
void* calloc(size_t item_count, size_t item_size) {
return get_allocator().alloc(item_count*item_size);
}
diff --git a/tests/Android.bp b/tests/Android.bp
index 8dc8eaf..a4298ab 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -472,6 +472,7 @@
"sys_auxv_test.cpp",
"sys_cachectl_test.cpp",
"sys_epoll_test.cpp",
+ "sys_hwprobe_test.cpp",
"sys_mman_test.cpp",
"sys_msg_test.cpp",
"sys_param_test.cpp",
diff --git a/tests/execinfo_test.cpp b/tests/execinfo_test.cpp
index b8e1325..1a0c51b 100644
--- a/tests/execinfo_test.cpp
+++ b/tests/execinfo_test.cpp
@@ -79,9 +79,13 @@
}
static size_t FindFunction(std::vector<void*>& frames, uintptr_t func_addr) {
+ Dl_info func_info;
+ if (!dladdr(reinterpret_cast<void*>(func_addr), &func_info)) {
+ return 0;
+ }
for (size_t i = 0; i < frames.size(); i++) {
- uintptr_t frame_addr = reinterpret_cast<uintptr_t>(frames[i]);
- if (frame_addr >= func_addr && frame_addr <= func_addr + 0x100) {
+ Dl_info frame_info;
+ if (dladdr(frames[i], &frame_info) && func_info.dli_saddr == frame_info.dli_saddr) {
return i + 1;
}
}
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index 862f498..c1c586c 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -360,6 +360,6 @@
#endif
}
-TEST(fcntl_DeathTest, fcntl_F_SETFD) {
+TEST_F(fcntl_DeathTest, fcntl_F_SETFD) {
EXPECT_DEATH(fcntl(0, F_SETFD, O_NONBLOCK), "non-FD_CLOEXEC");
}
diff --git a/tests/gwp_asan_test.cpp b/tests/gwp_asan_test.cpp
index c31f48c..709a939 100644
--- a/tests/gwp_asan_test.cpp
+++ b/tests/gwp_asan_test.cpp
@@ -34,12 +34,15 @@
#if defined(__BIONIC__)
#include "android-base/file.h"
+#include "android-base/silent_death_test.h"
#include "android-base/test_utils.h"
#include "gwp_asan/options.h"
#include "platform/bionic/malloc.h"
#include "sys/system_properties.h"
#include "utils.h"
+using gwp_asan_integration_DeathTest = SilentDeathTest;
+
// basename is a mess, use gnu basename explicitly to avoid the need for string
// mutation.
extern "C" const char* __gnu_basename(const char* path);
@@ -133,7 +136,7 @@
}
};
-TEST(gwp_asan_integration, DISABLED_assert_gwp_asan_enabled) {
+TEST_F(gwp_asan_integration_DeathTest, DISABLED_assert_gwp_asan_enabled) {
std::string maps;
EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
EXPECT_TRUE(maps.find("GWP-ASan") != std::string::npos) << maps;
@@ -173,7 +176,7 @@
__system_property_set((std::string("libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
"40000");
- RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+ RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
}
TEST(gwp_asan_integration, sysprops_persist_program_specific) {
@@ -191,7 +194,7 @@
__system_property_set((std::string("persist.libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
"40000");
- RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+ RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
}
TEST(gwp_asan_integration, sysprops_non_persist_overrides_persist) {
@@ -235,7 +238,7 @@
__system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
__system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
- RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+ RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
}
TEST(gwp_asan_integration, sysprops_can_disable) {
@@ -261,7 +264,7 @@
__system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
__system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
- RunGwpAsanTest("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+ RunGwpAsanTest("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
}
#endif // defined(__BIONIC__)
diff --git a/tests/heap_tagging_level_test.cpp b/tests/heap_tagging_level_test.cpp
index 5d85e97..b88d64a 100644
--- a/tests/heap_tagging_level_test.cpp
+++ b/tests/heap_tagging_level_test.cpp
@@ -19,6 +19,8 @@
#include <malloc.h>
#include <sys/prctl.h>
+#include <android-base/silent_death_test.h>
+
#if defined(__BIONIC__)
#include "gtest_globals.h"
#include "platform/bionic/mte.h"
@@ -44,7 +46,9 @@
}
#endif
-TEST(heap_tagging_level, tagged_pointer_dies) {
+using heap_tagging_level_DeathTest = SilentDeathTest;
+
+TEST_F(heap_tagging_level_DeathTest, tagged_pointer_dies) {
#if defined(__BIONIC__)
if (!KernelSupportsTaggedPointers()) {
GTEST_SKIP() << "Kernel doesn't support tagged pointers.";
diff --git a/tests/scs_test.cpp b/tests/scs_test.cpp
index 0776a43..3d5ebc1 100644
--- a/tests/scs_test.cpp
+++ b/tests/scs_test.cpp
@@ -16,8 +16,12 @@
#include <gtest/gtest.h>
+#include <android-base/silent_death_test.h>
+
#include "private/bionic_constants.h"
+using scs_DeathTest = SilentDeathTest;
+
int recurse2(int count);
__attribute__((weak, noinline)) int recurse1(int count) {
@@ -30,7 +34,7 @@
return 0;
}
-TEST(scs_test, stack_overflow) {
+TEST_F(scs_DeathTest, stack_overflow) {
#if defined(__aarch64__) || defined(__riscv)
ASSERT_EXIT(recurse1(SCS_SIZE), testing::KilledBySignal(SIGSEGV), "");
#else
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index b3a296d..b0f59bb 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -1049,11 +1049,13 @@
}
TEST(STDIO_TEST, popen_return_value_signal) {
- FILE* fp = popen("kill -7 $$", "r");
+ // Use a realtime signal to avoid creating a tombstone when running.
+ std::string cmd = android::base::StringPrintf("kill -%d $$", SIGRTMIN);
+ FILE* fp = popen(cmd.c_str(), "r");
ASSERT_TRUE(fp != nullptr);
int status = pclose(fp);
EXPECT_TRUE(WIFSIGNALED(status));
- EXPECT_EQ(7, WTERMSIG(status));
+ EXPECT_EQ(SIGRTMIN, WTERMSIG(status));
}
TEST(STDIO_TEST, getc) {
@@ -3310,7 +3312,7 @@
#endif
}
-TEST(STDIO_TEST, snprintf_invalid_w_width) {
+TEST_F(STDIO_DEATHTEST, snprintf_invalid_w_width) {
#if defined(__BIONIC__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
@@ -3323,7 +3325,7 @@
#endif
}
-TEST(STDIO_TEST, swprintf_invalid_w_width) {
+TEST_F(STDIO_DEATHTEST, swprintf_invalid_w_width) {
#if defined(__BIONIC__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
@@ -3459,7 +3461,7 @@
#endif
}
-TEST(STDIO_TEST, snprintf_invalid_wf_width) {
+TEST_F(STDIO_DEATHTEST, snprintf_invalid_wf_width) {
#if defined(__BIONIC__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat"
@@ -3473,7 +3475,7 @@
#endif
}
-TEST(STDIO_TEST, swprintf_invalid_wf_width) {
+TEST_F(STDIO_DEATHTEST, swprintf_invalid_wf_width) {
#if defined(__BIONIC__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat"
@@ -3572,7 +3574,7 @@
#endif
}
-TEST(STDIO_TEST, sscanf_invalid_w_or_wf_width) {
+TEST_F(STDIO_DEATHTEST, sscanf_invalid_w_or_wf_width) {
#if defined(__BIONIC__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat"
@@ -3672,7 +3674,7 @@
#endif
}
-TEST(STDIO_TEST, swscanf_invalid_w_or_wf_width) {
+TEST_F(STDIO_DEATHTEST, swscanf_invalid_w_or_wf_width) {
#if defined(__BIONIC__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat"
diff --git a/tests/sys_hwprobe_test.cpp b/tests/sys_hwprobe_test.cpp
new file mode 100644
index 0000000..15028ff
--- /dev/null
+++ b/tests/sys_hwprobe_test.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 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 <gtest/gtest.h>
+
+#if __has_include(<sys/hwprobe.h>)
+#include <sys/hwprobe.h>
+#endif
+
+TEST(sys_hwprobe, __riscv_hwprobe) {
+#if defined(__riscv) && __has_include(<sys/cachectl.h>)
+ riscv_hwprobe probes[] = {{.key = RISCV_HWPROBE_KEY_IMA_EXT_0},
+ {.key = RISCV_HWPROBE_KEY_CPUPERF_0}};
+ ASSERT_EQ(0, __riscv_hwprobe(probes, 2, 0, nullptr, 0));
+ EXPECT_EQ(RISCV_HWPROBE_KEY_IMA_EXT_0, probes[0].key);
+ EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_IMA_FD) != 0);
+ EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_IMA_C) != 0);
+ // TODO: remove #define when our uapi headers are new enough.
+#define RISCV_HWPROBE_IMA_V (1 << 2)
+ EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_IMA_V) != 0);
+ // TODO: remove #ifs when our kernel is new enough.
+#if defined(RISCV_HWPROBE_EXT_ZBA)
+ EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_EXT_ZBA) != 0);
+#endif
+#if defined(RISCV_HWPROBE_EXT_ZBB)
+ EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_EXT_ZBB) != 0);
+#endif
+#if defined(RISCV_HWPROBE_EXT_ZBS)
+ EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_EXT_ZBS) != 0);
+#endif
+
+ EXPECT_EQ(RISCV_HWPROBE_KEY_CPUPERF_0, probes[1].key);
+ EXPECT_TRUE((probes[1].value & RISCV_HWPROBE_MISALIGNED_MASK) == RISCV_HWPROBE_MISALIGNED_FAST);
+#else
+ GTEST_SKIP() << "__riscv_hwprobe requires riscv64";
+#endif
+}