Merge "Sync with upstream FreeBSD." into main
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 5f49c8c..e8dde7c 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -161,7 +161,7 @@
int linkat(int, const char*, int, const char*, int) all
int mkdirat(int, const char*, mode_t) all
int mknodat(int, const char*, mode_t, dev_t) all
-int readlinkat(int, const char*, char*, size_t) all
+ssize_t readlinkat(int, const char*, char*, size_t) all
int renameat2(int, const char*, int, const char*, unsigned) all
int symlinkat(const char*, int, const char*) all
int unlinkat(int, const char*, int) all
diff --git a/libc/include/bits/getentropy.h b/libc/include/bits/getentropy.h
new file mode 100644
index 0000000..a5a14f7
--- /dev/null
+++ b/libc/include/bits/getentropy.h
@@ -0,0 +1,53 @@
+/*
+ * 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
+
+/**
+ * @file bits/getentropy.h
+ * @brief The getentropy() function.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+/**
+ * [getentropy(3)](http://man7.org/linux/man-pages/man3/getentropy.3.html) fills the given buffer
+ * with random bytes.
+ *
+ * Returns 0 on success, and returns -1 and sets `errno` on failure.
+ *
+ * Available since API level 28.
+ *
+ * See also arc4random_buf() which is available in all API levels.
+ */
+int getentropy(void* _Nonnull __buffer, size_t __buffer_size) __wur __INTRODUCED_IN(28);
+
+__END_DECLS
diff --git a/libc/include/sys/cachectl.h b/libc/include/sys/cachectl.h
index fd775ee..b5fabe3 100644
--- a/libc/include/sys/cachectl.h
+++ b/libc/include/sys/cachectl.h
@@ -37,6 +37,8 @@
__BEGIN_DECLS
+#if defined(__riscv)
+
/**
* Flag for __riscv_flush_icache() to indicate that only the current
* thread's instruction cache needs to be flushed (rather than the
@@ -46,9 +48,12 @@
/**
* __riscv_flush_icache(2) flushes the instruction cache for the given range of addresses.
+ * The address range is currently (Linux 6.4) ignored, so both pointers may be null.
*
* Returns 0 on success, and returns -1 and sets `errno` on failure.
*/
-int __riscv_flush_icache(void* __start, void* __end, unsigned long __flags);
+int __riscv_flush_icache(void* _Nullable __start, void* _Nullable __end, unsigned long __flags);
+
+#endif
__END_DECLS
diff --git a/libc/include/sys/random.h b/libc/include/sys/random.h
index 0251176..2ff5349 100644
--- a/libc/include/sys/random.h
+++ b/libc/include/sys/random.h
@@ -38,19 +38,9 @@
#include <linux/random.h>
-__BEGIN_DECLS
+#include <bits/getentropy.h>
-/**
- * [getentropy(3)](http://man7.org/linux/man-pages/man3/getentropy.3.html) fills the given buffer
- * with random bytes.
- *
- * Returns 0 on success, and returns -1 and sets `errno` on failure.
- *
- * Available since API level 28.
- *
- * See also arc4random_buf() which is available in all API levels.
- */
-int getentropy(void* _Nonnull __buffer, size_t __buffer_size) __wur __INTRODUCED_IN(28);
+__BEGIN_DECLS
/**
* [getrandom(2)](http://man7.org/linux/man-pages/man2/getrandom.2.html) fills the given buffer
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 9385264..dcad630 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -34,6 +34,7 @@
#include <sys/select.h>
#include <bits/fcntl.h>
+#include <bits/getentropy.h>
#include <bits/getopt.h>
#include <bits/ioctl.h>
#include <bits/lockf.h>
diff --git a/libc/private/thread_private.h b/libc/private/thread_private.h
index 1f9eeb6..1a13690 100644
--- a/libc/private/thread_private.h
+++ b/libc/private/thread_private.h
@@ -29,7 +29,6 @@
#define _ARC4_LOCK() _thread_arc4_lock()
#define _ARC4_UNLOCK() _thread_arc4_unlock()
-#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f))
extern volatile sig_atomic_t _rs_forked;
diff --git a/libc/upstream-netbsd/android/include/rand48.h b/libc/upstream-netbsd/lib/libc/stdlib/rand48.h
similarity index 80%
rename from libc/upstream-netbsd/android/include/rand48.h
rename to libc/upstream-netbsd/lib/libc/stdlib/rand48.h
index 1279906..1ad8b0d 100644
--- a/libc/upstream-netbsd/android/include/rand48.h
+++ b/libc/upstream-netbsd/lib/libc/stdlib/rand48.h
@@ -18,10 +18,10 @@
#include <stdlib.h>
-__LIBC_HIDDEN__ void __dorand48(unsigned short[3]);
-__LIBC_HIDDEN__ unsigned short __rand48_seed[3];
-__LIBC_HIDDEN__ unsigned short __rand48_mult[3];
-__LIBC_HIDDEN__ unsigned short __rand48_add;
+extern void __dorand48(unsigned short[3]);
+extern unsigned short __rand48_seed[3];
+extern unsigned short __rand48_mult[3];
+extern unsigned short __rand48_add;
#define RAND48_SEED_0 (0x330e)
#define RAND48_SEED_1 (0xabcd)
diff --git a/tests/uchar_test.cpp b/tests/uchar_test.cpp
index 4dc6314..793a5b3 100644
--- a/tests/uchar_test.cpp
+++ b/tests/uchar_test.cpp
@@ -24,6 +24,47 @@
#include <locale.h>
#include <stdint.h>
+// Modern versions of UTF-8 (https://datatracker.ietf.org/doc/html/rfc3629 and
+// newer) explicitly disallow code points beyond U+10FFFF, which exclude all 5-
+// and 6-byte sequences. Earlier versions of UTF-8 allowed the wider range:
+// https://datatracker.ietf.org/doc/html/rfc2279.
+//
+// Bionic's unicode implementation was written after the high values were
+// excluded, so it has never supported them. Other implementations (at least
+// as of glibc 2.36), do support those sequences.
+#if defined(__ANDROID__) || defined(ANDROID_HOST_MUSL)
+constexpr bool kLibcSupportsLongUtf8Sequences = 0;
+#elif defined(__GLIBC__)
+constexpr bool kLibcSupportsLongUtf8Sequences = 1;
+#else
+#error kLibcSupportsLongUtf8Sequences must be configured for this platform
+#endif
+
+// C23 7.30.1 (for each `mbrtoc*` function) says:
+//
+// Returns:
+//
+// 0 if the next n or fewer bytes complete the multibyte character that
+// corresponds to the null wide character (which is the value stored).
+//
+// (size_t)(-2) if the next n bytes contribute to an incomplete (but
+// potentially valid) multibyte character, and all n bytes have been
+// processed (no value is stored).
+//
+// Bionic historically interpreted the behavior when n is 0 to be the next 0
+// bytes decoding to the null. That's a pretty bad interpretation, and both
+// glibc and musl return -2 for that case.
+//
+// The tests currently checks the incorrect behavior for bionic because gtest
+// doesn't support explicit xfail annotations. The behavior difference here
+// should be fixed, but danalbert wants to add more tests before tackling the
+// bugs.
+#ifdef __ANDROID__
+constexpr size_t kExpectedResultForZeroLength = 0U;
+#else
+constexpr size_t kExpectedResultForZeroLength = static_cast<size_t>(-2);
+#endif
+
TEST(uchar, sizeof_uchar_t) {
EXPECT_EQ(2U, sizeof(char16_t));
EXPECT_EQ(4U, sizeof(char32_t));
@@ -116,13 +157,13 @@
char16_t out;
out = L'x';
- ASSERT_EQ(0U, mbrtoc16(&out, "hello", 0, nullptr));
- ASSERT_EQ(L'x', out);
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtoc16(&out, "hello", 0, nullptr));
+ EXPECT_EQ(L'x', out);
- ASSERT_EQ(0U, mbrtoc16(&out, "hello", 0, nullptr));
- ASSERT_EQ(0U, mbrtoc16(&out, "", 0, nullptr));
- ASSERT_EQ(1U, mbrtoc16(&out, "hello", 1, nullptr));
- ASSERT_EQ(L'h', out);
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtoc16(&out, "hello", 0, nullptr));
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtoc16(&out, "", 0, nullptr));
+ EXPECT_EQ(1U, mbrtoc16(&out, "hello", 1, nullptr));
+ EXPECT_EQ(L'h', out);
}
TEST(uchar, mbrtoc16) {
@@ -146,10 +187,24 @@
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);
- // Illegal 5-byte UTF-8.
+}
+
+TEST(uchar, mbrtoc16_long_sequences) {
+ ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+ uselocale(LC_GLOBAL_LOCALE);
+
+ char16_t out = u'\0';
errno = 0;
- ASSERT_EQ(static_cast<size_t>(-1), mbrtoc16(&out, "\xf8\xa1\xa2\xa3\xa4", 5, nullptr));
- ASSERT_EQ(EILSEQ, errno);
+ auto result = mbrtoc16(&out, "\xf8\xa1\xa2\xa3\xa4", 5, nullptr);
+ if (kLibcSupportsLongUtf8Sequences) {
+ EXPECT_EQ(5U, result);
+ EXPECT_EQ(0, errno);
+ EXPECT_EQ(u'\uf94a', out);
+ } else {
+ EXPECT_EQ(static_cast<size_t>(-1), result);
+ EXPECT_EQ(EILSEQ, errno);
+ EXPECT_EQ(u'\0', out);
+ }
}
TEST(uchar, mbrtoc16_reserved_range) {
@@ -265,55 +320,78 @@
ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
uselocale(LC_GLOBAL_LOCALE);
- char32_t out[8] = {};
+ char32_t out = U'\0';
errno = 0;
- ASSERT_EQ(static_cast<size_t>(-1), mbrtoc32(out, "\xf5\x80\x80\x80", 4, nullptr));
- ASSERT_EQ(EILSEQ, errno);
+ auto result = mbrtoc32(&out, "\xf5\x80\x80\x80", 4, nullptr);
+ if (kLibcSupportsLongUtf8Sequences) {
+ EXPECT_EQ(4U, result);
+ EXPECT_EQ(0, errno);
+ EXPECT_EQ(U'\x140000', out);
+ } else {
+ EXPECT_EQ(static_cast<size_t>(-1), result);
+ EXPECT_EQ(EILSEQ, errno);
+ EXPECT_EQ(U'\0', out);
+ }
}
TEST(uchar, mbrtoc32) {
char32_t out[8];
out[0] = L'x';
- ASSERT_EQ(0U, mbrtoc32(out, "hello", 0, nullptr));
- ASSERT_EQ(static_cast<char32_t>(L'x'), out[0]);
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtoc32(out, "hello", 0, nullptr));
+ EXPECT_EQ(static_cast<char32_t>(L'x'), out[0]);
- ASSERT_EQ(0U, mbrtoc32(out, "hello", 0, nullptr));
- ASSERT_EQ(0U, mbrtoc32(out, "", 0, nullptr));
- ASSERT_EQ(1U, mbrtoc32(out, "hello", 1, nullptr));
- ASSERT_EQ(static_cast<char32_t>(L'h'), out[0]);
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtoc32(out, "hello", 0, nullptr));
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtoc32(out, "", 0, nullptr));
+ EXPECT_EQ(1U, mbrtoc32(out, "hello", 1, nullptr));
+ EXPECT_EQ(static_cast<char32_t>(L'h'), out[0]);
- ASSERT_EQ(0U, mbrtoc32(nullptr, "hello", 0, nullptr));
- ASSERT_EQ(0U, mbrtoc32(nullptr, "", 0, nullptr));
- ASSERT_EQ(1U, mbrtoc32(nullptr, "hello", 1, nullptr));
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtoc32(nullptr, "hello", 0, nullptr));
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtoc32(nullptr, "", 0, nullptr));
+ EXPECT_EQ(1U, mbrtoc32(nullptr, "hello", 1, nullptr));
- ASSERT_EQ(0U, mbrtoc32(nullptr, nullptr, 0, nullptr));
+ EXPECT_EQ(0U, mbrtoc32(nullptr, nullptr, 0, nullptr));
ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
uselocale(LC_GLOBAL_LOCALE);
// 1-byte UTF-8.
- ASSERT_EQ(1U, mbrtoc32(out, "abcdef", 6, nullptr));
- ASSERT_EQ(static_cast<char32_t>(L'a'), out[0]);
+ EXPECT_EQ(1U, mbrtoc32(out, "abcdef", 6, nullptr));
+ EXPECT_EQ(static_cast<char32_t>(L'a'), out[0]);
// 2-byte UTF-8.
- ASSERT_EQ(2U, mbrtoc32(out, "\xc2\xa2" "cdef", 6, nullptr));
- ASSERT_EQ(static_cast<char32_t>(0x00a2), out[0]);
+ EXPECT_EQ(2U, mbrtoc32(out,
+ "\xc2\xa2"
+ "cdef",
+ 6, nullptr));
+ EXPECT_EQ(static_cast<char32_t>(0x00a2), out[0]);
// 3-byte UTF-8.
- ASSERT_EQ(3U, mbrtoc32(out, "\xe2\x82\xac" "def", 6, nullptr));
- ASSERT_EQ(static_cast<char32_t>(0x20ac), out[0]);
+ EXPECT_EQ(3U, mbrtoc32(out,
+ "\xe2\x82\xac"
+ "def",
+ 6, nullptr));
+ EXPECT_EQ(static_cast<char32_t>(0x20ac), out[0]);
// 4-byte UTF-8.
- ASSERT_EQ(4U, mbrtoc32(out, "\xf0\xa4\xad\xa2" "ef", 6, nullptr));
- ASSERT_EQ(static_cast<char32_t>(0x24b62), out[0]);
+ EXPECT_EQ(4U, mbrtoc32(out,
+ "\xf0\xa4\xad\xa2"
+ "ef",
+ 6, nullptr));
+ EXPECT_EQ(static_cast<char32_t>(0x24b62), out[0]);
#if defined(__BIONIC__) // glibc allows this.
// Illegal 5-byte UTF-8.
errno = 0;
- ASSERT_EQ(static_cast<size_t>(-1), mbrtoc32(out, "\xf8\xa1\xa2\xa3\xa4" "f", 6, nullptr));
- ASSERT_EQ(EILSEQ, errno);
+ EXPECT_EQ(static_cast<size_t>(-1), mbrtoc32(out,
+ "\xf8\xa1\xa2\xa3\xa4"
+ "f",
+ 6, nullptr));
+ EXPECT_EQ(EILSEQ, errno);
#endif
// Illegal over-long sequence.
errno = 0;
- ASSERT_EQ(static_cast<size_t>(-1), mbrtoc32(out, "\xf0\x82\x82\xac" "ef", 6, nullptr));
- ASSERT_EQ(EILSEQ, errno);
+ EXPECT_EQ(static_cast<size_t>(-1), mbrtoc32(out,
+ "\xf0\x82\x82\xac"
+ "ef",
+ 6, nullptr));
+ EXPECT_EQ(EILSEQ, errno);
}
void test_mbrtoc32_incomplete(mbstate_t* ps) {