Merge "Add the recoverable GWP-ASan feature."
diff --git a/android-changes-for-ndk-developers.md b/android-changes-for-ndk-developers.md
index 13c8911..c5a6ac3 100644
--- a/android-changes-for-ndk-developers.md
+++ b/android-changes-for-ndk-developers.md
@@ -475,3 +475,7 @@
There are no plans to remove support for ELF files using the older
OS private use constants for RELR, nor for ELF files using packed
relocations.
+
+You can read more about relative relocations
+and their long and complicated history at
+https://maskray.me/blog/2021-10-31-relative-relocations-and-relr.
diff --git a/libc/Android.bp b/libc/Android.bp
index 5740105..67da126 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -252,7 +252,10 @@
srcs: [
"tzcode/**/*.c",
"tzcode/bionic.cpp",
- "upstream-openbsd/lib/libc/time/wcsftime.c", // tzcode doesn't include wcsftime, so we use the OpenBSD one.
+ // tzcode doesn't include strptime or wcsftime, so we use the OpenBSD
+ // code (with some local changes in the strptime case).
+ "upstream-openbsd/lib/libc/locale/_def_time.c",
+ "upstream-openbsd/lib/libc/time/wcsftime.c",
],
cflags: [
@@ -1198,6 +1201,7 @@
"bionic/termios.cpp",
"bionic/thread_private.cpp",
"bionic/threads.cpp",
+ "bionic/time_l.cpp",
"bionic/timespec_get.cpp",
"bionic/tmpfile.cpp",
"bionic/umount.cpp",
@@ -2292,6 +2296,7 @@
],
srcs: [
"bionic/fortify.cpp",
+ "bionic/strtol.cpp",
],
arch: {
arm64: {
diff --git a/libc/NOTICE b/libc/NOTICE
index 332885d..a6ca8b7 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -2579,6 +2579,36 @@
-------------------------------------------------------------------
+Copyright (c) 1994 Winning Strategies, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by Winning Strategies, Inc.
+4. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
Copyright (c) 1996 by Internet Software Consortium.
Permission to use, copy, modify, and distribute this software for any
@@ -2779,41 +2809,6 @@
-------------------------------------------------------------------
-Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
-All rights reserved.
-
-This code was contributed to The NetBSD Foundation by Klaus Klein.
-
-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. All advertising materials mentioning features or use of this software
- must display the following acknowledgement:
- This product includes software developed by the NetBSD
- Foundation, Inc. and its contributors.
-4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
-
--------------------------------------------------------------------
-
Copyright (c) 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc.
All rights reserved.
@@ -2879,6 +2874,34 @@
-------------------------------------------------------------------
+Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code was contributed to The NetBSD Foundation by Klaus Klein.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+
+-------------------------------------------------------------------
+
Copyright (c) 1997, 2005 Todd C. Miller <Todd.Miller@courtesan.com>
Permission to use, copy, modify, and distribute this software for any
diff --git a/libc/arch-arm64/dynamic_function_dispatch.cpp b/libc/arch-arm64/dynamic_function_dispatch.cpp
index bbd4218..cd55311 100644
--- a/libc/arch-arm64/dynamic_function_dispatch.cpp
+++ b/libc/arch-arm64/dynamic_function_dispatch.cpp
@@ -41,6 +41,12 @@
}
}
+typedef void* memcmp_func(void*, const void*, size_t);
+DEFINE_IFUNC_FOR(memcmp) {
+ // TODO: enable the SVE version.
+ RETURN_FUNC(memcmp_func, __memcmp_aarch64);
+}
+
typedef void* memcpy_func(void*, const void*, size_t);
DEFINE_IFUNC_FOR(memcpy) {
if (arg->_hwcap & HWCAP_ASIMD) {
@@ -61,11 +67,8 @@
typedef int stpcpy_func(char*, const char*);
DEFINE_IFUNC_FOR(stpcpy) {
- if (arg->_hwcap2 & HWCAP2_MTE) {
- RETURN_FUNC(stpcpy_func, __stpcpy_aarch64_mte);
- } else {
- RETURN_FUNC(stpcpy_func, __stpcpy_aarch64);
- }
+ // TODO: enable the SVE version.
+ RETURN_FUNC(stpcpy_func, __stpcpy_aarch64);
}
typedef char* strchr_func(const char*, int);
@@ -88,20 +91,14 @@
typedef int strcmp_func(const char*, const char*);
DEFINE_IFUNC_FOR(strcmp) {
- if (arg->_hwcap2 & HWCAP2_MTE) {
- RETURN_FUNC(strcmp_func, __strcmp_aarch64_mte);
- } else {
- RETURN_FUNC(strcmp_func, __strcmp_aarch64);
- }
+ // TODO: enable the SVE version.
+ RETURN_FUNC(strcmp_func, __strcmp_aarch64);
}
typedef int strcpy_func(char*, const char*);
DEFINE_IFUNC_FOR(strcpy) {
- if (arg->_hwcap2 & HWCAP2_MTE) {
- RETURN_FUNC(strcpy_func, __strcpy_aarch64_mte);
- } else {
- RETURN_FUNC(strcpy_func, __strcpy_aarch64);
- }
+ // TODO: enable the SVE version.
+ RETURN_FUNC(strcpy_func, __strcpy_aarch64);
}
typedef size_t strlen_func(const char*);
@@ -115,11 +112,14 @@
typedef int strncmp_func(const char*, const char*, int);
DEFINE_IFUNC_FOR(strncmp) {
- if (arg->_hwcap2 & HWCAP2_MTE) {
- RETURN_FUNC(strncmp_func, __strncmp_aarch64_mte);
- } else {
- RETURN_FUNC(strncmp_func, __strncmp_aarch64);
- }
+ // TODO: enable the SVE version.
+ RETURN_FUNC(strncmp_func, __strncmp_aarch64);
+}
+
+typedef size_t strnlen_func(const char*);
+DEFINE_IFUNC_FOR(strnlen) {
+ // TODO: enable the SVE version.
+ RETURN_FUNC(strnlen_func, __strnlen_aarch64);
}
typedef char* strrchr_func(const char*, int);
diff --git a/libc/arch-arm64/static_function_dispatch.S b/libc/arch-arm64/static_function_dispatch.S
index d00f071..c7557f8 100644
--- a/libc/arch-arm64/static_function_dispatch.S
+++ b/libc/arch-arm64/static_function_dispatch.S
@@ -34,15 +34,17 @@
END(name)
FUNCTION_DELEGATE(memchr, __memchr_aarch64_mte)
+FUNCTION_DELEGATE(memcmp, __memcmp_aarch64)
FUNCTION_DELEGATE(memcpy, __memcpy_aarch64)
FUNCTION_DELEGATE(memmove, __memmove_aarch64)
-FUNCTION_DELEGATE(stpcpy, __stpcpy_aarch64_mte)
+FUNCTION_DELEGATE(stpcpy, __stpcpy_aarch64)
FUNCTION_DELEGATE(strchr, __strchr_aarch64_mte)
FUNCTION_DELEGATE(strchrnul, __strchrnul_aarch64_mte)
-FUNCTION_DELEGATE(strcmp, __strcmp_aarch64_mte)
-FUNCTION_DELEGATE(strcpy, __strcpy_aarch64_mte)
+FUNCTION_DELEGATE(strcmp, __strcmp_aarch64)
+FUNCTION_DELEGATE(strcpy, __strcpy_aarch64)
FUNCTION_DELEGATE(strlen, __strlen_aarch64_mte)
FUNCTION_DELEGATE(strrchr, __strrchr_aarch64_mte)
-FUNCTION_DELEGATE(strncmp, __strncmp_aarch64_mte)
+FUNCTION_DELEGATE(strncmp, __strncmp_aarch64)
+FUNCTION_DELEGATE(strnlen, __strnlen_aarch64)
NOTE_GNU_PROPERTY()
diff --git a/libc/bionic/gwp_asan_wrappers.cpp b/libc/bionic/gwp_asan_wrappers.cpp
index ff6ca12..251633d 100644
--- a/libc/bionic/gwp_asan_wrappers.cpp
+++ b/libc/bionic/gwp_asan_wrappers.cpp
@@ -262,6 +262,10 @@
*process_sample_rate = 1;
if (mallopt_options.desire == Action::TURN_ON_WITH_SAMPLING) {
*process_sample_rate = kDefaultProcessSampling;
+ } else if (mallopt_options.desire == Action::TURN_ON_FOR_APP_SAMPLED_NON_CRASHING) {
+ *process_sample_rate = kDefaultProcessSampling;
+ options->Recoverable = true;
+ GwpAsanRecoverable = true;
}
}
diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp
index dd6b129..1c06c9e 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -88,7 +88,7 @@
case _SC_PAGESIZE:
case _SC_PAGE_SIZE:
// _SC_PAGESIZE and _SC_PAGE_SIZE are distinct, but return the same value.
- return static_cast<long>(getauxval(AT_PAGESZ));
+ return getpagesize();
case _SC_PHYS_PAGES: return get_phys_pages();
diff --git a/libm/riscv64/sqrt.S b/libc/bionic/time_l.cpp
similarity index 89%
rename from libm/riscv64/sqrt.S
rename to libc/bionic/time_l.cpp
index 0db1335..e5fa9a5 100644
--- a/libm/riscv64/sqrt.S
+++ b/libc/bionic/time_l.cpp
@@ -26,14 +26,9 @@
* SUCH DAMAGE.
*/
-#include <private/bionic_asm.h>
+#include <time.h>
+//#include <xlocale.h>
-ENTRY(sqrt)
- fsqrt.d fa0, fa0
- ret
-END(sqrt)
-
-ENTRY(sqrtf)
- fsqrt.s fa0, fa0
- ret
-END(sqrtf)
+char* strptime_l(const char* buf, const char* fmt, struct tm* tm, locale_t) {
+ return strptime(buf, fmt, tm);
+}
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 1ea94e6..1ec932b 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -111,9 +111,9 @@
* Returns a new file descriptor on success and returns -1 and sets `errno` on
* failure.
*/
-int creat(const char* __path, mode_t __mode);
+int creat(const char* _Nonnull __path, mode_t __mode);
/** See creat(). */
-int creat64(const char* __path, mode_t __mode) __INTRODUCED_IN(21);
+int creat64(const char* _Nonnull __path, mode_t __mode) __INTRODUCED_IN(21);
/**
* [openat(2)](http://man7.org/linux/man-pages/man2/openat.2.html)
@@ -122,9 +122,9 @@
* Returns a new file descriptor on success and returns -1 and sets `errno` on
* failure.
*/
-int openat(int __dir_fd, const char* __path, int __flags, ...);
+int openat(int __dir_fd, const char* _Nonnull __path, int __flags, ...);
/** See openat(). */
-int openat64(int __dir_fd, const char* __path, int __flags, ...) __INTRODUCED_IN(21);
+int openat64(int __dir_fd, const char* _Nonnull __path, int __flags, ...) __INTRODUCED_IN(21);
/**
* [open(2)](http://man7.org/linux/man-pages/man2/open.2.html)
@@ -133,9 +133,9 @@
* Returns a new file descriptor on success and returns -1 and sets `errno` on
* failure.
*/
-int open(const char* __path, int __flags, ...);
+int open(const char* _Nonnull __path, int __flags, ...);
/** See open(). */
-int open64(const char* __path, int __flags, ...) __INTRODUCED_IN(21);
+int open64(const char* _Nonnull __path, int __flags, ...) __INTRODUCED_IN(21);
/**
* [splice(2)](http://man7.org/linux/man-pages/man2/splice.2.html)
@@ -149,7 +149,7 @@
*
* Available since API level 21.
*/
-ssize_t splice(int __in_fd, off64_t* __in_offset, int __out_fd, off64_t* __out_offset, size_t __length, unsigned int __flags) __INTRODUCED_IN(21);
+ssize_t splice(int __in_fd, off64_t* __BIONIC_COMPLICATED_NULLNESS __in_offset, int __out_fd, off64_t* __BIONIC_COMPLICATED_NULLNESS __out_offset, size_t __length, unsigned int __flags) __INTRODUCED_IN(21);
/**
* [tee(2)](http://man7.org/linux/man-pages/man2/tee.2.html)
@@ -177,7 +177,7 @@
*
* Available since API level 21.
*/
-ssize_t vmsplice(int __fd, const struct iovec* __iov, size_t __count, unsigned int __flags) __INTRODUCED_IN(21);
+ssize_t vmsplice(int __fd, const struct iovec* _Nonnull __iov, size_t __count, unsigned int __flags) __INTRODUCED_IN(21);
/**
* [fallocate(2)](http://man7.org/linux/man-pages/man2/fallocate.2.html)
diff --git a/libc/include/nl_types.h b/libc/include/nl_types.h
index 1c80e4e..f4d7f43 100644
--- a/libc/include/nl_types.h
+++ b/libc/include/nl_types.h
@@ -62,7 +62,7 @@
*
* Available since API level 28.
*/
-nl_catd catopen(const char* __name, int __flag) __INTRODUCED_IN(26);
+nl_catd _Nonnull catopen(const char* _Nonnull __name, int __flag) __INTRODUCED_IN(26);
/**
* [catgets(3)](http://man7.org/linux/man-pages/man3/catgets.3.html) translates the given message
@@ -72,13 +72,13 @@
*
* Available since API level 28.
*/
-char* catgets(nl_catd __catalog, int __set_number, int __msg_number, const char* __msg) __INTRODUCED_IN(26);
+char* _Nonnull catgets(nl_catd _Nonnull __catalog, int __set_number, int __msg_number, const char* _Nonnull __msg) __INTRODUCED_IN(26);
/**
* [catclose(3)](http://man7.org/linux/man-pages/man3/catclose.3.html) closes a message catalog.
*
* On Android, this always returns -1 with `errno` set to `EBADF`.
*/
-int catclose(nl_catd __catalog) __INTRODUCED_IN(26);
+int catclose(nl_catd _Nonnull __catalog) __INTRODUCED_IN(26);
__END_DECLS
diff --git a/libc/include/regex.h b/libc/include/regex.h
index be1418e..be33819 100644
--- a/libc/include/regex.h
+++ b/libc/include/regex.h
@@ -49,8 +49,8 @@
typedef struct {
int re_magic;
size_t re_nsub; /* number of parenthesized subexpressions */
- const char * _Null_unspecified re_endp; /* end pointer for REG_PEND */
- struct re_guts * _Null_unspecified re_g; /* none of your business :-) */
+ const char * __BIONIC_COMPLICATED_NULLNESS re_endp; /* end pointer for REG_PEND */
+ struct re_guts * __BIONIC_COMPLICATED_NULLNESS re_g; /* none of your business :-) */
} regex_t;
typedef struct {
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 5b9d99b..484757e 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -63,6 +63,14 @@
#define __BIONIC_ALIGN(__value, __alignment) (((__value) + (__alignment)-1) & ~((__alignment)-1))
/*
+ * The nullness constraints of this parameter or return value are
+ * quite complex. This is used to highlight spots where developers
+ * are encouraged to read relevant manuals or code to understand
+ * the full picture of nullness for this pointer.
+ */
+#define __BIONIC_COMPLICATED_NULLNESS _Null_unspecified
+
+/*
* The __CONCAT macro is used to concatenate parts of symbol names, e.g.
* with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
* The __CONCAT macro is a bit tricky -- make sure you don't put spaces
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 3efc9a2..566caaa 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -73,7 +73,7 @@
#define _PC_PRIO_IO 18
#define _PC_SYNC_IO 19
-extern char** environ;
+extern char* _Nullable * _Nullable environ;
__noreturn void _exit(int __status);
@@ -89,15 +89,15 @@
pid_t getsid(pid_t __pid) __INTRODUCED_IN(17);
pid_t setsid(void);
-int execv(const char* __path, char* const* __argv);
-int execvp(const char* __file, char* const* __argv);
-int execvpe(const char* __file, char* const* __argv, char* const* __envp) __INTRODUCED_IN(21);
-int execve(const char* __file, char* const* __argv, char* const* __envp);
-int execl(const char* __path, const char* __arg0, ...) __attribute__((__sentinel__));
-int execlp(const char* __file, const char* __arg0, ...) __attribute__((__sentinel__));
-int execle(const char* __path, const char* __arg0, ... /*, char* const* __envp */)
+int execv(const char* _Nonnull __path, char* _Nullable const* _Nullable __argv);
+int execvp(const char* _Nonnull __file, char* _Nullable const* _Nullable __argv);
+int execvpe(const char* _Nonnull __file, char* _Nullable const* _Nullable __argv, char* _Nullable const* _Nullable __envp) __INTRODUCED_IN(21);
+int execve(const char* _Nonnull __file, char* _Nullable const* _Nullable __argv, char* _Nullable const* _Nullable __envp);
+int execl(const char* _Nonnull __path, const char* _Nullable __arg0, ...) __attribute__((__sentinel__));
+int execlp(const char* _Nonnull __file, const char* _Nullable __arg0, ...) __attribute__((__sentinel__));
+int execle(const char* _Nonnull __path, const char* _Nullable __arg0, ... /*, char* const* __envp */)
__attribute__((__sentinel__(1)));
-int fexecve(int __fd, char* const* __argv, char* const* __envp) __INTRODUCED_IN(28);
+int fexecve(int __fd, char* _Nullable const* _Nullable __argv, char* _Nullable const* _Nullable __envp) __INTRODUCED_IN(28);
int nice(int __incr);
@@ -193,40 +193,40 @@
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
-int getgroups(int __size, gid_t* __list);
-int setgroups(size_t __size, const gid_t* __list);
-int getresuid(uid_t* __ruid, uid_t* __euid, uid_t* __suid);
-int getresgid(gid_t* __rgid, gid_t* __egid, gid_t* __sgid);
-char* getlogin(void);
-int getlogin_r(char* __buffer, size_t __buffer_size) __INTRODUCED_IN(28);
+int getgroups(int __size, gid_t* _Nullable __list);
+int setgroups(size_t __size, const gid_t* _Nullable __list);
+int getresuid(uid_t* _Nonnull __ruid, uid_t* _Nonnull __euid, uid_t* _Nonnull __suid);
+int getresgid(gid_t* _Nonnull __rgid, gid_t* _Nonnull __egid, gid_t* _Nonnull __sgid);
+char* _Nullable getlogin(void);
+int getlogin_r(char* _Nonnull __buffer, size_t __buffer_size) __INTRODUCED_IN(28);
long fpathconf(int __fd, int __name);
-long pathconf(const char* __path, int __name);
+long pathconf(const char* _Nonnull __path, int __name);
-int access(const char* __path, int __mode);
-int faccessat(int __dirfd, const char* __path, int __mode, int __flags);
-int link(const char* __old_path, const char* __new_path);
-int linkat(int __old_dir_fd, const char* __old_path, int __new_dir_fd, const char* __new_path, int __flags) __INTRODUCED_IN(21);
-int unlink(const char* __path);
-int unlinkat(int __dirfd, const char* __path, int __flags);
-int chdir(const char* __path);
+int access(const char* _Nonnull __path, int __mode);
+int faccessat(int __dirfd, const char* _Nonnull __path, int __mode, int __flags);
+int link(const char* _Nonnull __old_path, const char* _Nonnull __new_path);
+int linkat(int __old_dir_fd, const char* _Nonnull __old_path, int __new_dir_fd, const char* _Nonnull __new_path, int __flags) __INTRODUCED_IN(21);
+int unlink(const char* _Nonnull __path);
+int unlinkat(int __dirfd, const char* _Nonnull __path, int __flags);
+int chdir(const char* _Nonnull __path);
int fchdir(int __fd);
-int rmdir(const char* __path);
-int pipe(int __fds[2]);
+int rmdir(const char* _Nonnull __path);
+int pipe(int __fds[_Nonnull 2]);
#if defined(__USE_GNU)
-int pipe2(int __fds[2], int __flags);
+int pipe2(int __fds[_Nonnull 2], int __flags);
#endif
-int chroot(const char* __path);
-int symlink(const char* __old_path, const char* __new_path);
-int symlinkat(const char* __old_path, int __new_dir_fd, const char* __new_path) __INTRODUCED_IN(21);
-ssize_t readlink(const char* __path, char* __buf, size_t __buf_size);
-ssize_t readlinkat(int __dir_fd, const char* __path, char* __buf, size_t __buf_size)
+int chroot(const char* _Nonnull __path);
+int symlink(const char* _Nonnull __old_path, const char* _Nonnull __new_path);
+int symlinkat(const char* _Nonnull __old_path, int __new_dir_fd, const char* _Nonnull __new_path) __INTRODUCED_IN(21);
+ssize_t readlink(const char* _Nonnull __path, char* _Nonnull __buf, size_t __buf_size);
+ssize_t readlinkat(int __dir_fd, const char* _Nonnull __path, char* _Nonnull __buf, size_t __buf_size)
__INTRODUCED_IN(21);
-int chown(const char* __path, uid_t __owner, gid_t __group);
+int chown(const char* _Nonnull __path, uid_t __owner, gid_t __group);
int fchown(int __fd, uid_t __owner, gid_t __group);
-int fchownat(int __dir_fd, const char* __path, uid_t __owner, gid_t __group, int __flags);
-int lchown(const char* __path, uid_t __owner, gid_t __group);
-char* getcwd(char* __buf, size_t __size);
+int fchownat(int __dir_fd, const char* _Nonnull __path, uid_t __owner, gid_t __group, int __flags);
+int lchown(const char* _Nonnull __path, uid_t __owner, gid_t __group);
+char* _Nullable getcwd(char* _Nullable __buf, size_t __size);
void sync(void);
#if defined(__USE_GNU)
@@ -235,8 +235,29 @@
int close(int __fd);
-ssize_t read(int __fd, void* __buf, size_t __count);
-ssize_t write(int __fd, const void* __buf, size_t __count);
+/**
+ * [read(2)](https://man7.org/linux/man-pages/man2/read.2.html) reads
+ * up to `__count` bytes from file descriptor `__fd` into `__buf`.
+ *
+ * Note: `__buf` is not normally nullable, but may be null in the
+ * special case of a zero-length read(), which while not generally
+ * useful may be meaningful to some device drivers.
+ *
+ * Returns the number of bytes read on success, and returns -1 and sets `errno` on failure.
+ */
+ssize_t read(int __fd, void* __BIONIC_COMPLICATED_NULLNESS __buf, size_t __count);
+
+/**
+ * [write(2)](https://man7.org/linux/man-pages/man2/write.2.html) writes
+ * up to `__count` bytes to file descriptor `__fd` from `__buf`.
+ *
+ * Note: `__buf` is not normally nullable, but may be null in the
+ * special case of a zero-length write(), which while not generally
+ * useful may be meaningful to some device drivers.
+ *
+ * Returns the number of bytes written on success, and returns -1 and sets `errno` on failure.
+ */
+ssize_t write(int __fd, const void* __BIONIC_COMPLICATED_NULLNESS __buf, size_t __count);
int dup(int __old_fd);
int dup2(int __old_fd, int __new_fd);
@@ -246,23 +267,23 @@
/* See https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
#if defined(__USE_FILE_OFFSET64)
-int truncate(const char* __path, off_t __length) __RENAME(truncate64) __INTRODUCED_IN(21);
+int truncate(const char* _Nonnull __path, off_t __length) __RENAME(truncate64) __INTRODUCED_IN(21);
off_t lseek(int __fd, off_t __offset, int __whence) __RENAME(lseek64);
-ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset) __RENAME(pread64);
-ssize_t pwrite(int __fd, const void* __buf, size_t __count, off_t __offset) __RENAME(pwrite64);
+ssize_t pread(int __fd, void* _Nonnull __buf, size_t __count, off_t __offset) __RENAME(pread64);
+ssize_t pwrite(int __fd, const void* _Nonnull __buf, size_t __count, off_t __offset) __RENAME(pwrite64);
int ftruncate(int __fd, off_t __length) __RENAME(ftruncate64);
#else
-int truncate(const char* __path, off_t __length);
+int truncate(const char* _Nonnull __path, off_t __length);
off_t lseek(int __fd, off_t __offset, int __whence);
-ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset);
-ssize_t pwrite(int __fd, const void* __buf, size_t __count, off_t __offset);
+ssize_t pread(int __fd, void* _Nonnull __buf, size_t __count, off_t __offset);
+ssize_t pwrite(int __fd, const void* _Nonnull __buf, size_t __count, off_t __offset);
int ftruncate(int __fd, off_t __length);
#endif
-int truncate64(const char* __path, off64_t __length) __INTRODUCED_IN(21);
+int truncate64(const char* _Nonnull __path, off64_t __length) __INTRODUCED_IN(21);
off64_t lseek64(int __fd, off64_t __offset, int __whence);
-ssize_t pread64(int __fd, void* __buf, size_t __count, off64_t __offset);
-ssize_t pwrite64(int __fd, const void* __buf, size_t __count, off64_t __offset);
+ssize_t pread64(int __fd, void* _Nonnull __buf, size_t __count, off64_t __offset);
+ssize_t pwrite64(int __fd, const void* _Nonnull __buf, size_t __count, off64_t __offset);
int ftruncate64(int __fd, off64_t __length);
int pause(void);
@@ -270,17 +291,17 @@
unsigned int sleep(unsigned int __seconds);
int usleep(useconds_t __microseconds);
-int gethostname(char* __buf, size_t __buf_size);
-int sethostname(const char* __name, size_t __n) __INTRODUCED_IN(23);
+int gethostname(char* _Nonnull _buf, size_t __buf_size);
+int sethostname(const char* _Nonnull __name, size_t __n) __INTRODUCED_IN(23);
-int brk(void* __addr);
-void* sbrk(ptrdiff_t __increment);
+int brk(void* _Nonnull __addr);
+void* _Nullable sbrk(ptrdiff_t __increment);
int isatty(int __fd);
-char* ttyname(int __fd);
-int ttyname_r(int __fd, char* __buf, size_t __buf_size);
+char* _Nullable ttyname(int __fd);
+int ttyname_r(int __fd, char* _Nonnull __buf, size_t __buf_size);
-int acct(const char* __path);
+int acct(const char* _Nullable __path);
#if __ANDROID_API__ >= 21
int getpagesize(void) __INTRODUCED_IN(21);
@@ -310,8 +331,8 @@
} while (_rc == -1 && errno == EINTR); \
_rc; })
-int getdomainname(char* __buf, size_t __buf_size) __INTRODUCED_IN(26);
-int setdomainname(const char* __name, size_t __n) __INTRODUCED_IN(26);
+int getdomainname(char* _Nonnull __buf, size_t __buf_size) __INTRODUCED_IN(26);
+int setdomainname(const char* _Nonnull __name, size_t __n) __INTRODUCED_IN(26);
/**
* [copy_file_range(2)](https://man7.org/linux/man-pages/man2/copy_file_range.2.html) copies
@@ -322,10 +343,10 @@
* Returns the number of bytes copied on success, and returns -1 and sets
* `errno` on failure.
*/
-ssize_t copy_file_range(int __fd_in, off64_t* __off_in, int __fd_out, off64_t* __off_out, size_t __length, unsigned int __flags) __INTRODUCED_IN(34);
+ssize_t copy_file_range(int __fd_in, off64_t* _Nullable __off_in, int __fd_out, off64_t* _Nullable __off_out, size_t __length, unsigned int __flags) __INTRODUCED_IN(34);
#if __ANDROID_API__ >= 28
-void swab(const void* __src, void* __dst, ssize_t __byte_count) __INTRODUCED_IN(28);
+void swab(const void* _Nonnull __src, void* _Nonnull __dst, ssize_t __byte_count) __INTRODUCED_IN(28);
#endif
/**
diff --git a/libc/include/utmp.h b/libc/include/utmp.h
index cb72ce2..7aa5718 100644
--- a/libc/include/utmp.h
+++ b/libc/include/utmp.h
@@ -99,7 +99,7 @@
/**
* Does nothing.
*/
-int utmpname(const char* __path);
+int utmpname(const char* _Nonnull __path);
/**
* Does nothing.
*/
@@ -107,11 +107,11 @@
/**
* Does nothing.
*/
-struct utmp* getutent(void);
+struct utmp* _Nullable getutent(void);
/**
* Does nothing.
*/
-struct utmp* pututline(const struct utmp* __entry);
+struct utmp* _Nullable pututline(const struct utmp* _Nonnull __entry);
/**
* Does nothing.
*/
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index 6a81277..be577bc 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -87,35 +87,65 @@
{BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceSize},
},
{
+ "bt_sz",
+ {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceSize},
+ },
+ {
"backtrace_min_size",
{BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMinSize},
},
{
+ "bt_min_sz",
+ {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMinSize},
+ },
+ {
"backtrace_max_size",
{BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMaxSize},
},
-
+ {
+ "bt_max_sz",
+ {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMaxSize},
+ },
{
"backtrace",
{BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
},
{
+ "bt",
+ {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
+ },
+ {
"backtrace_enable_on_signal",
{BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
},
-
+ {
+ "bt_en_on_sig",
+ {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
+ },
{
"backtrace_dump_on_exit",
{0, &Config::SetBacktraceDumpOnExit},
},
{
+ "bt_dmp_on_ex",
+ {0, &Config::SetBacktraceDumpOnExit},
+ },
+ {
"backtrace_dump_prefix",
{0, &Config::SetBacktraceDumpPrefix},
},
{
+ "bt_dmp_pre",
+ {0, &Config::SetBacktraceDumpPrefix},
+ },
+ {
"backtrace_full",
{BACKTRACE_FULL, &Config::VerifyValueEmpty},
},
+ {
+ "bt_full",
+ {BACKTRACE_FULL, &Config::VerifyValueEmpty},
+ },
{
"fill",
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index 3667624..fddc4a3 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -200,6 +200,20 @@
that is extra thorough and can unwind through Java frames. This will run
slower than the normal backtracing function.
+### bt, bt\_dmp\_on\_ex, bt\_dmp\_pre, bt\_en\_on\_sig, bt\_full, bt\_max\_sz, bt\_min\_sz, bt\_sz
+As of U, add shorter aliases for backtrace related options to avoid property length restrictions.
+
+| Alias | Option |
+|:----------------|:------------------------------|
+| bt | backtrace |
+| bt\_dmp\_on\_ex | backtrace\_dump\_on\_exit |
+| bt\_dmp\_pre | backtrace\_dump\_prefix |
+| bt\_en\_on\_sig | backtrace\_enable\_on\_signal |
+| bt\_full | backtrace\_full |
+| bt\_max\_sz | backtrace\_max\_size |
+| bt\_min\_sz | backtrace\_min\_size |
+| bt\_sz | backtrace\_size |
+
### check\_unreachable\_on\_signal
As of Android U, this option will trigger a check for unreachable memory
in a process. Specifically, if the signal SIGRTMAX - 16 (which is 48 on
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 4bc5649..7b0f599 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -494,6 +494,9 @@
void debug_free_malloc_leak_info(uint8_t* info) {
g_dispatch->free(info);
+ // Purge the memory that was freed since a significant amount of
+ // memory could have been allocated and freed.
+ g_dispatch->mallopt(M_PURGE, 0);
}
size_t debug_malloc_usable_size(void* pointer) {
@@ -1117,6 +1120,10 @@
dprintf(fd, "%s", content.c_str());
}
dprintf(fd, "END\n");
+
+ // Purge the memory that was allocated and freed during this operation
+ // since it can be large enough to expand the RSS significantly.
+ g_dispatch->mallopt(M_PURGE, 0);
}
bool debug_write_malloc_leak_info(FILE* fp) {
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index 0a0eaef..bc7af6d 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -215,6 +215,13 @@
ASSERT_FALSE(config->backtrace_enable_on_signal());
ASSERT_FALSE(config->backtrace_dump_on_exit());
+ ASSERT_TRUE(InitConfig("bt=23")) << getFakeLogPrint();
+ ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
+ ASSERT_EQ(23U, config->backtrace_frames());
+ ASSERT_TRUE(config->backtrace_enabled());
+ ASSERT_FALSE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
+
ASSERT_TRUE(InitConfig("backtrace")) << getFakeLogPrint();
ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
ASSERT_EQ(16U, config->backtrace_frames());
@@ -222,6 +229,13 @@
ASSERT_FALSE(config->backtrace_enable_on_signal());
ASSERT_FALSE(config->backtrace_dump_on_exit());
+ ASSERT_TRUE(InitConfig("bt")) << getFakeLogPrint();
+ ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
+ ASSERT_EQ(16U, config->backtrace_frames());
+ ASSERT_TRUE(config->backtrace_enabled());
+ ASSERT_FALSE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
+
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
@@ -234,6 +248,13 @@
ASSERT_TRUE(config->backtrace_enable_on_signal());
ASSERT_FALSE(config->backtrace_dump_on_exit());
+ ASSERT_TRUE(InitConfig("bt_en_on_sig=64")) << getFakeLogPrint();
+ ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
+ ASSERT_EQ(64U, config->backtrace_frames());
+ ASSERT_FALSE(config->backtrace_enabled());
+ ASSERT_TRUE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
+
ASSERT_TRUE(InitConfig("backtrace_enable_on_signal")) << getFakeLogPrint();
ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
ASSERT_EQ(16U, config->backtrace_frames());
@@ -241,6 +262,13 @@
ASSERT_TRUE(config->backtrace_enable_on_signal());
ASSERT_FALSE(config->backtrace_dump_on_exit());
+ ASSERT_TRUE(InitConfig("bt_en_on_sig")) << getFakeLogPrint();
+ ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
+ ASSERT_EQ(16U, config->backtrace_frames());
+ ASSERT_FALSE(config->backtrace_enabled());
+ ASSERT_TRUE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
+
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
@@ -288,6 +316,10 @@
ASSERT_EQ(0U, config->options());
ASSERT_TRUE(config->backtrace_dump_on_exit());
+ ASSERT_TRUE(InitConfig("bt_dmp_on_ex")) << getFakeLogPrint();
+ ASSERT_EQ(0U, config->options());
+ ASSERT_TRUE(config->backtrace_dump_on_exit());
+
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
@@ -307,10 +339,18 @@
ASSERT_EQ(0U, config->options());
ASSERT_EQ("/data/local/tmp/backtrace_heap", config->backtrace_dump_prefix());
+ ASSERT_TRUE(InitConfig("bt_dmp_pre")) << getFakeLogPrint();
+ ASSERT_EQ(0U, config->options());
+ ASSERT_EQ("/data/local/tmp/backtrace_heap", config->backtrace_dump_prefix());
+
ASSERT_TRUE(InitConfig("backtrace_dump_prefix=/fake/location")) << getFakeLogPrint();
ASSERT_EQ(0U, config->options());
ASSERT_EQ("/fake/location", config->backtrace_dump_prefix());
+ ASSERT_TRUE(InitConfig("bt_dmp_pre=/fake/location")) << getFakeLogPrint();
+ ASSERT_EQ(0U, config->options());
+ ASSERT_EQ("/fake/location", config->backtrace_dump_prefix());
+
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
@@ -319,6 +359,9 @@
ASSERT_TRUE(InitConfig("backtrace_full")) << getFakeLogPrint();
ASSERT_EQ(BACKTRACE_FULL, config->options());
+ ASSERT_TRUE(InitConfig("bt_full")) << getFakeLogPrint();
+ ASSERT_EQ(BACKTRACE_FULL, config->options());
+
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
@@ -786,6 +829,11 @@
ASSERT_EQ(37U, config->backtrace_min_size_bytes());
ASSERT_EQ(37U, config->backtrace_max_size_bytes());
+ ASSERT_TRUE(InitConfig("bt_sz=39")) << getFakeLogPrint();
+ ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
+ ASSERT_EQ(39U, config->backtrace_min_size_bytes());
+ ASSERT_EQ(39U, config->backtrace_max_size_bytes());
+
ASSERT_FALSE(InitConfig("backtrace_size")) << getFakeLogPrint();
ASSERT_FALSE(InitConfig("backtrace_size=0")) << getFakeLogPrint();
ASSERT_FALSE(InitConfig("backtrace_size=-1")) << getFakeLogPrint();
@@ -808,6 +856,11 @@
ASSERT_EQ(9U, config->backtrace_min_size_bytes());
ASSERT_EQ(SIZE_MAX, config->backtrace_max_size_bytes());
+ ASSERT_TRUE(InitConfig("bt_min_sz=11")) << getFakeLogPrint();
+ ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
+ ASSERT_EQ(11U, config->backtrace_min_size_bytes());
+ ASSERT_EQ(SIZE_MAX, config->backtrace_max_size_bytes());
+
ASSERT_FALSE(InitConfig("backtrace_min_size")) << getFakeLogPrint();
ASSERT_FALSE(InitConfig("backtrace_min_size=0")) << getFakeLogPrint();
ASSERT_FALSE(InitConfig("backtrace_min_size=-1")) << getFakeLogPrint();
@@ -830,6 +883,11 @@
ASSERT_EQ(0U, config->backtrace_min_size_bytes());
ASSERT_EQ(13U, config->backtrace_max_size_bytes());
+ ASSERT_TRUE(InitConfig("bt_max_sz=15")) << getFakeLogPrint();
+ ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
+ ASSERT_EQ(0U, config->backtrace_min_size_bytes());
+ ASSERT_EQ(15U, config->backtrace_max_size_bytes());
+
ASSERT_FALSE(InitConfig("backtrace_max_size")) << getFakeLogPrint();
ASSERT_FALSE(InitConfig("backtrace_max_size=0")) << getFakeLogPrint();
ASSERT_FALSE(InitConfig("backtrace_max_size=-1")) << getFakeLogPrint();
diff --git a/libc/platform/bionic/malloc.h b/libc/platform/bionic/malloc.h
index ecc8743..3c290fc 100644
--- a/libc/platform/bionic/malloc.h
+++ b/libc/platform/bionic/malloc.h
@@ -121,15 +121,28 @@
// apply to system apps. They use the "libc.debug.gwp_asan.*.system_default"
// sysprops.
enum Action {
- // The app has opted-in to GWP-ASan, and should always have it enabled. This
- // should only be used by apps.
+ // Enable GWP-ASan. This is used by apps that have `gwpAsanMode=always` in
+ // the manifest.
TURN_ON_FOR_APP,
- // System processes apps have GWP-ASan enabled by default, but use the
- // process sampling method.
+ // Enable GWP-ASan, but only a small percentage of the time. This is used by
+ // system processes and system apps, and we use a lottery to determine which
+ // processes have GWP-ASan enabled. This allows us to mitigate system-wide
+ // memory overhead concerns, as each GWP-ASan enabled process uses ~70KiB of
+ // extra memory.
TURN_ON_WITH_SAMPLING,
- // Non-system apps don't have GWP-ASan by default.
+ // Don't enable GWP-ASan, unless overwritten by a system property or
+ // environment variable. This is used by apps that have `gwpAsanMode=never`
+ // in the manifest. Prior to Android 14, this also was used by non-system
+ // apps that didn't specify a `gwpAsanMode` in their manifest.
DONT_TURN_ON_UNLESS_OVERRIDDEN,
- // Note: GWP-ASan cannot be disabled once it's been enabled.
+ // Enable GWP-ASan, but only a small percentage of the time, and enable it
+ // in the non-crashing ("recoverable") mode. In Android 14, this is used by
+ // apps that don't specify `gwpAsanMode` (or use `gwpAsanMode=default`) in
+ // their manifest. GWP-ASan will detect heap memory safety bugs in this
+ // mode, and bug reports will be created by debuggerd, however the process
+ // will recover and continue to function as if the memory safety bug wasn't
+ // detected.
+ TURN_ON_FOR_APP_SAMPLED_NON_CRASHING,
};
Action desire = DONT_TURN_ON_UNLESS_OVERRIDDEN;
diff --git a/libc/tzcode/localedef.h b/libc/tzcode/localedef.h
new file mode 100644
index 0000000..19d4df9
--- /dev/null
+++ b/libc/tzcode/localedef.h
@@ -0,0 +1,106 @@
+/* $OpenBSD: localedef.h,v 1.1 2016/05/23 00:05:15 guenther Exp $ */
+/* $NetBSD: localedef.h,v 1.4 1996/04/09 20:55:31 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994 Winning Strategies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef _LOCALEDEF_H_
+#define _LOCALEDEF_H_
+
+#include <sys/types.h>
+
+typedef struct
+{
+ char *yesexpr;
+ char *noexpr;
+ char *yesstr;
+ char *nostr;
+} _MessagesLocale;
+
+
+typedef struct
+{
+ char *int_curr_symbol;
+ char *currency_symbol;
+ char *mon_decimal_point;
+ char *mon_thousands_sep;
+ char *mon_grouping;
+ char *positive_sign;
+ char *negative_sign;
+ char int_frac_digits;
+ char frac_digits;
+ char p_cs_precedes;
+ char p_sep_by_space;
+ char n_cs_precedes;
+ char n_sep_by_space;
+ char p_sign_posn;
+ char n_sign_posn;
+ char int_p_cs_precedes;
+ char int_p_sep_by_space;
+ char int_n_cs_precedes;
+ char int_n_sep_by_space;
+ char int_p_sign_posn;
+ char int_n_sign_posn;
+} _MonetaryLocale;
+
+
+typedef struct
+{
+ const char *decimal_point;
+ const char *thousands_sep;
+ const char *grouping;
+} _NumericLocale;
+
+
+typedef struct {
+ const char *abday[7];
+ const char *day[7];
+ const char *abmon[12];
+ const char *mon[12];
+ const char *am_pm[2];
+ const char *d_t_fmt;
+ const char *d_fmt;
+ const char *t_fmt;
+ const char *t_fmt_ampm;
+} _TimeLocale;
+
+
+//__BEGIN_HIDDEN_DECLS
+extern const _MessagesLocale *_CurrentMessagesLocale;
+extern const _MessagesLocale _DefaultMessagesLocale;
+extern const _MonetaryLocale *_CurrentMonetaryLocale;
+extern const _MonetaryLocale _DefaultMonetaryLocale;
+extern const _NumericLocale *_CurrentNumericLocale;
+extern const _NumericLocale _DefaultNumericLocale;
+extern const _TimeLocale *_CurrentTimeLocale;
+extern const _TimeLocale _DefaultTimeLocale;
+//__END_HIDDEN_DECLS
+
+#endif /* !_LOCALEDEF_H_ */
diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c
index 7e8e234..fe9e10f 100644
--- a/libc/tzcode/strptime.c
+++ b/libc/tzcode/strptime.c
@@ -1,8 +1,7 @@
-/* $OpenBSD: strptime.c,v 1.11 2005/08/08 08:05:38 espie Exp $ */
-/* $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */
-
+/* $OpenBSD: strptime.c,v 1.30 2019/05/12 12:49:52 schwarze Exp $ */
+/* $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */
/*-
- * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code was contributed to The NetBSD Foundation by Klaus Klein.
@@ -15,13 +14,6 @@
* 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
@@ -36,65 +28,40 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-//#include <sys/localedef.h>
#include <ctype.h>
-#include <errno.h>
#include <locale.h>
-#include <stdlib.h>
+#include <stdint.h>
#include <string.h>
#include <time.h>
+
+#include "localedef.h"
+#include "private.h"
#include "tzfile.h"
-static const struct {
- const char *abday[7];
- const char *day[7];
- const char *abmon[12];
- const char *mon[12];
- const char *am_pm[2];
- const char *d_t_fmt;
- const char *d_fmt;
- const char *t_fmt;
- const char *t_fmt_ampm;
-} _DefaultTimeLocale = {
- {
- "Sun","Mon","Tue","Wed","Thu","Fri","Sat",
- },
- {
- "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
- "Friday", "Saturday"
- },
- {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- },
- {
- "January", "February", "March", "April", "May", "June", "July",
- "August", "September", "October", "November", "December"
- },
- {
- "AM", "PM"
- },
- "%a %b %d %H:%M:%S %Y",
- "%m/%d/%y",
- "%H:%M:%S",
- "%I:%M:%S %p"
-};
+// Android: ignore OpenBSD's DEF_WEAK() stuff.
+#define DEF_WEAK(sym) /* */
+// Android: this code is not pointer-sign clean.
+#pragma clang diagnostic ignored "-Wpointer-sign"
+#pragma clang diagnostic ignored "-Wunused-function"
-#define _ctloc(x) (_DefaultTimeLocale.x)
+#define _ctloc(x) (_CurrentTimeLocale->x)
/*
* We do not implement alternate representations. However, we always
* check whether a given modifier is allowed for a certain conversion.
*/
-#define _ALT_E 0x01
-#define _ALT_O 0x02
-#define _LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
+#define _ALT_E 0x01
+#define _ALT_O 0x02
+#define _LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
-
-struct century_relyear {
- int century;
- int relyear;
-};
+/*
+ * We keep track of some of the fields we set in order to compute missing ones.
+ */
+#define FIELD_TM_MON (1 << 0)
+#define FIELD_TM_MDAY (1 << 1)
+#define FIELD_TM_WDAY (1 << 2)
+#define FIELD_TM_YDAY (1 << 3)
+#define FIELD_TM_YEAR (1 << 4)
static char gmt[] = { "GMT" };
static char utc[] = { "UTC" };
@@ -106,9 +73,15 @@
"EDT", "CDT", "MDT", "PDT", "\0\0\0"
};
-static int _conv_num(const unsigned char **, int *, int, int);
-static unsigned char *_strptime(const unsigned char *, const char *, struct tm *,
- struct century_relyear *);
+static const int mon_lengths[2][MONSPERYEAR] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static int _conv_num64(const unsigned char **, int64_t *, int64_t, int64_t);
+static int _conv_num(const unsigned char **, int *, int, int);
+static int leaps_thru_end_of(const int y);
+static char *_strptime(const char *, const char *, struct tm *, int);
static const u_char *_find_string(const u_char *, int *, const char * const *,
const char * const *, int);
@@ -116,335 +89,353 @@
char *
strptime(const char *buf, const char *fmt, struct tm *tm)
{
- struct century_relyear cr;
- cr.century = TM_YEAR_BASE;
- cr.relyear = -1;
- return (char*)(_strptime((const unsigned char*)buf, fmt, tm, &cr));
+ return(_strptime(buf, fmt, tm, 1));
}
+DEF_WEAK(strptime);
-static unsigned char *
-_strptime(const unsigned char *buf, const char *fmt, struct tm *tm, struct century_relyear *cr)
+static char *
+_strptime(const char *buf, const char *fmt, struct tm *tm, int initialize)
{
- unsigned char c;
- const unsigned char *bp, *ep;
- size_t len = 0;
- int alt_format, i, offs;
- int neg = 0;
+ unsigned char c;
+ const unsigned char *bp, *ep;
+ size_t len;
+ int alt_format, i, offs;
+ int neg = 0;
+ static int century, relyear, fields;
- bp = (unsigned char *)buf;
- while ((c = *fmt) != '\0') {
- /* Clear `alternate' modifier prior to new conversion. */
- alt_format = 0;
+ if (initialize) {
+ century = TM_YEAR_BASE;
+ relyear = -1;
+ fields = 0;
+ }
- /* Eat up white-space. */
- if (isspace(c)) {
- while (isspace(*bp))
- bp++;
+ bp = (const unsigned char *)buf;
+ while ((c = *fmt) != '\0') {
+ /* Clear `alternate' modifier prior to new conversion. */
+ alt_format = 0;
- fmt++;
- continue;
- }
+ /* Eat up white-space. */
+ if (isspace(c)) {
+ while (isspace(*bp))
+ bp++;
- if ((c = *fmt++) != '%')
- goto literal;
+ fmt++;
+ continue;
+ }
+
+ if ((c = *fmt++) != '%')
+ goto literal;
-again: switch (c = *fmt++) {
- case '%': /* "%%" is converted to "%". */
+again: switch (c = *fmt++) {
+ case '%': /* "%%" is converted to "%". */
literal:
- if (c != *bp++)
- return (NULL);
+ if (c != *bp++)
+ return (NULL);
- break;
+ break;
- /*
- * "Alternative" modifiers. Just set the appropriate flag
- * and start over again.
- */
- case 'E': /* "%E?" alternative conversion modifier. */
- _LEGAL_ALT(0);
- alt_format |= _ALT_E;
- goto again;
+ /*
+ * "Alternative" modifiers. Just set the appropriate flag
+ * and start over again.
+ */
+ case 'E': /* "%E?" alternative conversion modifier. */
+ _LEGAL_ALT(0);
+ alt_format |= _ALT_E;
+ goto again;
- case 'O': /* "%O?" alternative conversion modifier. */
- _LEGAL_ALT(0);
- alt_format |= _ALT_O;
- goto again;
+ case 'O': /* "%O?" alternative conversion modifier. */
+ _LEGAL_ALT(0);
+ alt_format |= _ALT_O;
+ goto again;
- /*
- * "Complex" conversion rules, implemented through recursion.
- */
- case 'c': /* Date and time, using the locale's format. */
- _LEGAL_ALT(_ALT_E);
- if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, cr)))
- return (NULL);
- break;
+ /*
+ * "Complex" conversion rules, implemented through recursion.
+ */
+ case 'c': /* Date and time, using the locale's format. */
+ _LEGAL_ALT(_ALT_E);
+ if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, 0)))
+ return (NULL);
+ break;
- case 'D': /* The date as "%m/%d/%y". */
- _LEGAL_ALT(0);
- if (!(bp = _strptime(bp, "%m/%d/%y", tm, cr)))
- return (NULL);
- break;
+ case 'D': /* The date as "%m/%d/%y". */
+ _LEGAL_ALT(0);
+ if (!(bp = _strptime(bp, "%m/%d/%y", tm, 0)))
+ return (NULL);
+ break;
- case 'F': /* The date as "%Y-%m-%d". */
- _LEGAL_ALT(0);
- if (!(bp = _strptime(bp, "%Y-%m-%d", tm, cr)))
- return (NULL);
- continue;
+ case 'F': /* The date as "%Y-%m-%d". */
+ _LEGAL_ALT(0);
+ if (!(bp = _strptime(bp, "%Y-%m-%d", tm, 0)))
+ return (NULL);
+ continue;
- case 'R': /* The time as "%H:%M". */
- _LEGAL_ALT(0);
- if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
- return (NULL);
- break;
+ case 'R': /* The time as "%H:%M". */
+ _LEGAL_ALT(0);
+ if (!(bp = _strptime(bp, "%H:%M", tm, 0)))
+ return (NULL);
+ break;
- case 'r': /* The time as "%I:%M:%S %p". */
- _LEGAL_ALT(0);
- if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, cr)))
- return (NULL);
- break;
+ case 'r': /* The time as "%I:%M:%S %p". */
+ _LEGAL_ALT(0);
+ if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, 0)))
+ return (NULL);
+ break;
- case 'T': /* The time as "%H:%M:%S". */
- _LEGAL_ALT(0);
- if (!(bp = _strptime(bp, "%H:%M:%S", tm, cr)))
- return (NULL);
- break;
+ case 'T': /* The time as "%H:%M:%S". */
+ _LEGAL_ALT(0);
+ if (!(bp = _strptime(bp, "%H:%M:%S", tm, 0)))
+ return (NULL);
+ break;
- case 'v': /* The date as "%e-%b-%Y". */
- _LEGAL_ALT(0);
- if (!(bp = _strptime(bp, "%e-%b-%Y", tm, cr)))
- return (NULL);
- break;
+ case 'v': /* Android: the date as "%e-%b-%Y" for strftime() compat; glibc does this too. */
+ _LEGAL_ALT(0);
+ if (!(bp = _strptime(bp, "%e-%b-%Y", tm, 0)))
+ return (NULL);
+ break;
- case 'X': /* The time, using the locale's format. */
- _LEGAL_ALT(_ALT_E);
- if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, cr)))
- return (NULL);
- break;
+ case 'X': /* The time, using the locale's format. */
+ _LEGAL_ALT(_ALT_E);
+ if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, 0)))
+ return (NULL);
+ break;
- case 'x': /* The date, using the locale's format. */
- _LEGAL_ALT(_ALT_E);
- if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, cr)))
- return (NULL);
- break;
+ case 'x': /* The date, using the locale's format. */
+ _LEGAL_ALT(_ALT_E);
+ if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, 0)))
+ return (NULL);
+ break;
- /*
- * "Elementary" conversion rules.
- */
- case 'A': /* The day of week, using the locale's form. */
- case 'a':
- _LEGAL_ALT(0);
- for (i = 0; i < 7; i++) {
- /* Full name. */
- len = strlen(_ctloc(day[i]));
- if (strncasecmp(_ctloc(day[i]), (const char*)bp, len) == 0)
- break;
+ /*
+ * "Elementary" conversion rules.
+ */
+ case 'A': /* The day of week, using the locale's form. */
+ case 'a':
+ _LEGAL_ALT(0);
+ for (i = 0; i < 7; i++) {
+ /* Full name. */
+ len = strlen(_ctloc(day[i]));
+ if (strncasecmp(_ctloc(day[i]), bp, len) == 0)
+ break;
- /* Abbreviated name. */
- len = strlen(_ctloc(abday[i]));
- if (strncasecmp(_ctloc(abday[i]), (const char*)bp, len) == 0)
- break;
- }
+ /* Abbreviated name. */
+ len = strlen(_ctloc(abday[i]));
+ if (strncasecmp(_ctloc(abday[i]), bp, len) == 0)
+ break;
+ }
- /* Nothing matched. */
- if (i == 7)
- return (NULL);
+ /* Nothing matched. */
+ if (i == 7)
+ return (NULL);
- tm->tm_wday = i;
- bp += len;
- break;
+ tm->tm_wday = i;
+ bp += len;
+ fields |= FIELD_TM_WDAY;
+ break;
- case 'B': /* The month, using the locale's form. */
- case 'b':
- case 'h':
- _LEGAL_ALT(0);
- for (i = 0; i < 12; i++) {
- /* Full name. */
- len = strlen(_ctloc(mon[i]));
- if (strncasecmp(_ctloc(mon[i]), (const char*)bp, len) == 0)
- break;
+ case 'B': /* The month, using the locale's form. */
+ case 'b':
+ case 'h':
+ _LEGAL_ALT(0);
+ for (i = 0; i < 12; i++) {
+ /* Full name. */
+ len = strlen(_ctloc(mon[i]));
+ if (strncasecmp(_ctloc(mon[i]), bp, len) == 0)
+ break;
- /* Abbreviated name. */
- len = strlen(_ctloc(abmon[i]));
- if (strncasecmp(_ctloc(abmon[i]), (const char*)bp, len) == 0)
- break;
- }
+ /* Abbreviated name. */
+ len = strlen(_ctloc(abmon[i]));
+ if (strncasecmp(_ctloc(abmon[i]), bp, len) == 0)
+ break;
+ }
- /* Nothing matched. */
- if (i == 12)
- return (NULL);
+ /* Nothing matched. */
+ if (i == 12)
+ return (NULL);
- tm->tm_mon = i;
- bp += len;
- break;
+ tm->tm_mon = i;
+ bp += len;
+ fields |= FIELD_TM_MON;
+ break;
- case 'C': /* The century number. */
- _LEGAL_ALT(_ALT_E);
- if (!(_conv_num(&bp, &i, 0, 99)))
- return (NULL);
+ case 'C': /* The century number. */
+ _LEGAL_ALT(_ALT_E);
+ if (!(_conv_num(&bp, &i, 0, 99)))
+ return (NULL);
- cr->century = i * 100;
- break;
+ century = i * 100;
+ break;
- case 'd': /* The day of month. */
- case 'e':
- _LEGAL_ALT(_ALT_O);
- if (!(_conv_num(&bp, &tm->tm_mday, 1, 31)))
- return (NULL);
- break;
+ case 'e': /* The day of month. */
+ if (isspace(*bp))
+ bp++;
+ /* FALLTHROUGH */
+ case 'd':
+ _LEGAL_ALT(_ALT_O);
+ if (!(_conv_num(&bp, &tm->tm_mday, 1, 31)))
+ return (NULL);
+ fields |= FIELD_TM_MDAY;
+ break;
- case 'k': /* The hour (24-hour clock representation). */
- _LEGAL_ALT(0);
- /* FALLTHROUGH */
- case 'H':
- _LEGAL_ALT(_ALT_O);
- if (!(_conv_num(&bp, &tm->tm_hour, 0, 23)))
- return (NULL);
- break;
+ case 'k': /* The hour (24-hour clock representation). */
+ _LEGAL_ALT(0);
+ /* FALLTHROUGH */
+ case 'H':
+ _LEGAL_ALT(_ALT_O);
+ if (!(_conv_num(&bp, &tm->tm_hour, 0, 23)))
+ return (NULL);
+ break;
- case 'l': /* The hour (12-hour clock representation). */
- _LEGAL_ALT(0);
- /* FALLTHROUGH */
- case 'I':
- _LEGAL_ALT(_ALT_O);
- if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
- return (NULL);
- break;
+ case 'l': /* The hour (12-hour clock representation). */
+ _LEGAL_ALT(0);
+ /* FALLTHROUGH */
+ case 'I':
+ _LEGAL_ALT(_ALT_O);
+ if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
+ return (NULL);
+ break;
- case 'j': /* The day of year. */
- _LEGAL_ALT(0);
- if (!(_conv_num(&bp, &tm->tm_yday, 1, 366)))
- return (NULL);
- tm->tm_yday--;
- break;
+ case 'j': /* The day of year. */
+ _LEGAL_ALT(0);
+ if (!(_conv_num(&bp, &tm->tm_yday, 1, 366)))
+ return (NULL);
+ tm->tm_yday--;
+ fields |= FIELD_TM_YDAY;
+ break;
- case 'M': /* The minute. */
- _LEGAL_ALT(_ALT_O);
- if (!(_conv_num(&bp, &tm->tm_min, 0, 59)))
- return (NULL);
- break;
+ case 'M': /* The minute. */
+ _LEGAL_ALT(_ALT_O);
+ if (!(_conv_num(&bp, &tm->tm_min, 0, 59)))
+ return (NULL);
+ break;
- case 'm': /* The month. */
- _LEGAL_ALT(_ALT_O);
- if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
- return (NULL);
- tm->tm_mon--;
- break;
+ case 'm': /* The month. */
+ _LEGAL_ALT(_ALT_O);
+ if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
+ return (NULL);
+ tm->tm_mon--;
+ fields |= FIELD_TM_MON;
+ break;
- case 'P':
- case 'p': /* The locale's equivalent of AM/PM. */
- _LEGAL_ALT(0);
- /* AM? */
- len = strlen(_ctloc(am_pm[0]));
- if (strncasecmp(_ctloc(am_pm[0]), (const char*)bp, len) == 0) {
- if (tm->tm_hour > 12) /* i.e., 13:00 AM ?! */
- return (NULL);
- else if (tm->tm_hour == 12)
- tm->tm_hour = 0;
+ case 'P': /* Android addition for strftime() compat; glibc does this too. */
+ case 'p': /* The locale's equivalent of AM/PM. */
+ _LEGAL_ALT(0);
+ /* AM? */
+ len = strlen(_ctloc(am_pm[0]));
+ if (strncasecmp(_ctloc(am_pm[0]), bp, len) == 0) {
+ if (tm->tm_hour > 12) /* i.e., 13:00 AM ?! */
+ return (NULL);
+ else if (tm->tm_hour == 12)
+ tm->tm_hour = 0;
- bp += len;
- break;
- }
- /* PM? */
- len = strlen(_ctloc(am_pm[1]));
- if (strncasecmp(_ctloc(am_pm[1]), (const char*)bp, len) == 0) {
- if (tm->tm_hour > 12) /* i.e., 13:00 PM ?! */
- return (NULL);
- else if (tm->tm_hour < 12)
- tm->tm_hour += 12;
+ bp += len;
+ break;
+ }
+ /* PM? */
+ len = strlen(_ctloc(am_pm[1]));
+ if (strncasecmp(_ctloc(am_pm[1]), bp, len) == 0) {
+ if (tm->tm_hour > 12) /* i.e., 13:00 PM ?! */
+ return (NULL);
+ else if (tm->tm_hour < 12)
+ tm->tm_hour += 12;
- bp += len;
- break;
- }
+ bp += len;
+ break;
+ }
- /* Nothing matched. */
- return (NULL);
+ /* Nothing matched. */
+ return (NULL);
- case 'S': /* The seconds. */
- _LEGAL_ALT(_ALT_O);
- if (!(_conv_num(&bp, &tm->tm_sec, 0, 61)))
- return (NULL);
- break;
+ case 'S': /* The seconds. */
+ _LEGAL_ALT(_ALT_O);
+ if (!(_conv_num(&bp, &tm->tm_sec, 0, 60)))
+ return (NULL);
+ break;
+ case 's': /* Seconds since epoch */
+ {
+ // Android change based on FreeBSD's implementation.
+ int saved_errno = errno;
+ errno = 0;
+ const unsigned char* old_bp = bp;
+ long n = strtol((const char*) bp, (char**) &bp, 10);
+ errno = saved_errno;
+ time_t t = n;
+ if (bp == old_bp || errno == ERANGE ||
+ ((long) t) != n) return NULL;
- case 's':
- {
- // Android addition, based on FreeBSD's implementation.
- int saved_errno = errno;
- errno = 0;
- const unsigned char* old_bp = bp;
- long n = strtol((const char*) bp, (char**) &bp, 10);
- time_t t = n;
- if (bp == old_bp || errno == ERANGE || ((long) t) != n) {
- errno = saved_errno;
- return NULL;
- }
- errno = saved_errno;
+ if (localtime_r(&t, tm) == NULL) return NULL;
- if (localtime_r(&t, tm) == NULL) return NULL;
- }
- break;
+ //int64_t i64;
+ //if (!(_conv_num64(&bp, &i64, 0, INT64_MAX)))
+ // return (NULL);
+ //if (!gmtime_r(&i64, tm))
+ // return (NULL);
+ fields = 0xffff; /* everything */
+ }
+ break;
+ case 'U': /* The week of year, beginning on sunday. */
+ case 'W': /* The week of year, beginning on monday. */
+ _LEGAL_ALT(_ALT_O);
+ /*
+ * XXX This is bogus, as we can not assume any valid
+ * information present in the tm structure at this
+ * point to calculate a real value, so just check the
+ * range for now.
+ */
+ if (!(_conv_num(&bp, &i, 0, 53)))
+ return (NULL);
+ break;
+ case 'w': /* The day of week, beginning on sunday. */
+ _LEGAL_ALT(_ALT_O);
+ if (!(_conv_num(&bp, &tm->tm_wday, 0, 6)))
+ return (NULL);
+ fields |= FIELD_TM_WDAY;
+ break;
- case 'U': /* The week of year, beginning on sunday. */
- case 'W': /* The week of year, beginning on monday. */
- _LEGAL_ALT(_ALT_O);
- /*
- * XXX This is bogus, as we can not assume any valid
- * information present in the tm structure at this
- * point to calculate a real value, so just check the
- * range for now.
- */
- if (!(_conv_num(&bp, &i, 0, 53)))
- return (NULL);
- break;
+ case 'u': /* The day of week, monday = 1. */
+ _LEGAL_ALT(_ALT_O);
+ if (!(_conv_num(&bp, &i, 1, 7)))
+ return (NULL);
+ tm->tm_wday = i % 7;
+ fields |= FIELD_TM_WDAY;
+ continue;
- case 'w': /* The day of week, beginning on sunday. */
- _LEGAL_ALT(_ALT_O);
- if (!(_conv_num(&bp, &tm->tm_wday, 0, 6)))
- return (NULL);
- break;
+ case 'g': /* The year corresponding to the ISO week
+ * number but without the century.
+ */
+ if (!(_conv_num(&bp, &i, 0, 99)))
+ return (NULL);
+ continue;
- case 'u': /* The day of week, monday = 1. */
- _LEGAL_ALT(_ALT_O);
- if (!(_conv_num(&bp, &i, 1, 7)))
- return (NULL);
- tm->tm_wday = i % 7;
- continue;
+ case 'G': /* The year corresponding to the ISO week
+ * number with century.
+ */
+ do
+ bp++;
+ while (isdigit(*bp));
+ continue;
- case 'g': /* The year corresponding to the ISO week
- * number but without the century.
- */
- if (!(_conv_num(&bp, &i, 0, 99)))
- return (NULL);
- continue;
+ case 'V': /* The ISO 8601:1988 week number as decimal */
+ if (!(_conv_num(&bp, &i, 0, 53)))
+ return (NULL);
+ continue;
- case 'G': /* The year corresponding to the ISO week
- * number with century.
- */
- do
- bp++;
- while (isdigit(*bp));
- continue;
+ case 'Y': /* The year. */
+ _LEGAL_ALT(_ALT_E);
+ if (!(_conv_num(&bp, &i, 0, 9999)))
+ return (NULL);
- case 'V': /* The ISO 8601:1988 week number as decimal */
- if (!(_conv_num(&bp, &i, 0, 53)))
- return (NULL);
- continue;
+ relyear = -1;
+ tm->tm_year = i - TM_YEAR_BASE;
+ fields |= FIELD_TM_YEAR;
+ break;
- case 'Y': /* The year. */
- _LEGAL_ALT(_ALT_E);
- if (!(_conv_num(&bp, &i, 0, 9999)))
- return (NULL);
-
- cr->relyear = -1;
- tm->tm_year = i - TM_YEAR_BASE;
- break;
-
- case 'y': /* The year within the century (2 digits). */
- _LEGAL_ALT(_ALT_E | _ALT_O);
- if (!(_conv_num(&bp, &cr->relyear, 0, 99)))
- return (NULL);
- break;
+ case 'y': /* The year within the century (2 digits). */
+ _LEGAL_ALT(_ALT_E | _ALT_O);
+ if (!(_conv_num(&bp, &relyear, 0, 99)))
+ return (NULL);
+ break;
case 'Z':
tzset();
@@ -548,42 +539,78 @@
tm->tm_zone = NULL; /* XXX */
continue;
- /*
- * Miscellaneous conversions.
- */
- case 'n': /* Any kind of white-space. */
- case 't':
- _LEGAL_ALT(0);
- while (isspace(*bp))
- bp++;
- break;
+ /*
+ * Miscellaneous conversions.
+ */
+ case 'n': /* Any kind of white-space. */
+ case 't':
+ _LEGAL_ALT(0);
+ while (isspace(*bp))
+ bp++;
+ break;
- default: /* Unknown/unsupported conversion. */
- return (NULL);
- }
+ default: /* Unknown/unsupported conversion. */
+ return (NULL);
+ }
- }
+ }
- /*
- * We need to evaluate the two digit year spec (%y)
- * last as we can get a century spec (%C) at any time.
- */
- if (cr->relyear != -1) {
- if (cr->century == TM_YEAR_BASE) {
- if (cr->relyear <= 68)
- tm->tm_year = cr->relyear + 2000 - TM_YEAR_BASE;
- else
- tm->tm_year = cr->relyear + 1900 - TM_YEAR_BASE;
- } else {
- tm->tm_year = cr->relyear + cr->century - TM_YEAR_BASE;
- }
- }
+ /*
+ * We need to evaluate the two digit year spec (%y)
+ * last as we can get a century spec (%C) at any time.
+ */
+ if (relyear != -1) {
+ if (century == TM_YEAR_BASE) {
+ if (relyear <= 68)
+ tm->tm_year = relyear + 2000 - TM_YEAR_BASE;
+ else
+ tm->tm_year = relyear + 1900 - TM_YEAR_BASE;
+ } else {
+ tm->tm_year = relyear + century - TM_YEAR_BASE;
+ }
+ fields |= FIELD_TM_YEAR;
+ }
- return (unsigned char*)bp;
+ /* Compute some missing values when possible. */
+ if (fields & FIELD_TM_YEAR) {
+ const int year = tm->tm_year + TM_YEAR_BASE;
+ const int *mon_lens = mon_lengths[isleap(year)];
+ if (!(fields & FIELD_TM_YDAY) &&
+ (fields & FIELD_TM_MON) && (fields & FIELD_TM_MDAY)) {
+ tm->tm_yday = tm->tm_mday - 1;
+ for (i = 0; i < tm->tm_mon; i++)
+ tm->tm_yday += mon_lens[i];
+ fields |= FIELD_TM_YDAY;
+ }
+ if (fields & FIELD_TM_YDAY) {
+ int days = tm->tm_yday;
+ if (!(fields & FIELD_TM_WDAY)) {
+ tm->tm_wday = EPOCH_WDAY +
+ ((year - EPOCH_YEAR) % DAYSPERWEEK) *
+ (DAYSPERNYEAR % DAYSPERWEEK) +
+ leaps_thru_end_of(year - 1) -
+ leaps_thru_end_of(EPOCH_YEAR - 1) +
+ tm->tm_yday;
+ tm->tm_wday %= DAYSPERWEEK;
+ if (tm->tm_wday < 0)
+ tm->tm_wday += DAYSPERWEEK;
+ }
+ if (!(fields & FIELD_TM_MON)) {
+ tm->tm_mon = 0;
+ while (tm->tm_mon < MONSPERYEAR && days >= mon_lens[tm->tm_mon])
+ days -= mon_lens[tm->tm_mon++];
+ }
+ if (!(fields & FIELD_TM_MDAY))
+ tm->tm_mday = days + 1;
+ }
+ }
+
+ return ((char *)bp);
}
+
static int
_conv_num(const unsigned char **buf, int *dest, int llim, int ulim)
{
@@ -607,6 +634,29 @@
return (1);
}
+static int
+_conv_num64(const unsigned char **buf, int64_t *dest, int64_t llim, int64_t ulim)
+{
+ int result = 0;
+ int64_t rulim = ulim;
+
+ if (**buf < '0' || **buf > '9')
+ return (0);
+
+ /* we use rulim to break out of the loop when we run out of digits */
+ do {
+ result *= 10;
+ result += *(*buf)++ - '0';
+ rulim /= 10;
+ } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
+
+ if (result < llim || result > ulim)
+ return (0);
+
+ *dest = result;
+ return (1);
+}
+
static const u_char *
_find_string(const u_char *bp, int *tgt, const char * const *n1,
const char * const *n2, int c)
@@ -629,6 +679,9 @@
return NULL;
}
-char* strptime_l(const char* buf, const char* fmt, struct tm* tm, locale_t l) {
- return strptime(buf, fmt, tm);
+static int
+leaps_thru_end_of(const int y)
+{
+ return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
+ -(leaps_thru_end_of(-(y + 1)) + 1);
}
diff --git a/libc/upstream-openbsd/lib/libc/locale/_def_time.c b/libc/upstream-openbsd/lib/libc/locale/_def_time.c
new file mode 100644
index 0000000..ba83fb8
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/locale/_def_time.c
@@ -0,0 +1,36 @@
+/* $OpenBSD: _def_time.c,v 1.6 2016/05/23 00:05:15 guenther Exp $ */
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <locale.h>
+#include "localedef.h"
+
+const _TimeLocale _DefaultTimeLocale =
+{
+ {
+ "Sun","Mon","Tue","Wed","Thu","Fri","Sat",
+ },
+ {
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+ "Friday", "Saturday"
+ },
+ {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ },
+ {
+ "January", "February", "March", "April", "May", "June", "July",
+ "August", "September", "October", "November", "December"
+ },
+ {
+ "AM", "PM"
+ },
+ "%a %b %e %H:%M:%S %Y",
+ "%m/%d/%y",
+ "%H:%M:%S",
+ "%I:%M:%S %p"
+};
+
+const _TimeLocale *_CurrentTimeLocale = &_DefaultTimeLocale;
diff --git a/libm/Android.bp b/libm/Android.bp
index 3e271fa..b6c7b6a 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -305,8 +305,6 @@
arm64: {
srcs: [
"arm64/fenv.c",
- "arm64/lrint.S",
- "arm64/sqrt.S",
],
exclude_srcs: [
"upstream-freebsd/lib/msun/src/s_ceil.c",
@@ -342,8 +340,6 @@
riscv64: {
srcs: [
"riscv64/fenv.c",
- "riscv64/lrint.S",
- "riscv64/sqrt.S",
],
exclude_srcs: [
diff --git a/libm/arm64/lrint.S b/libm/arm64/lrint.S
deleted file mode 100644
index e835d08..0000000
--- a/libm/arm64/lrint.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <private/bionic_asm.h>
-
-ENTRY(lrint)
- frintX d0, d0
- fcvtzs x0, d0
- ret
-END(lrint)
-
-ENTRY(lrintf)
- frintX s0, s0
- fcvtzs x0, s0
- ret
-END(lrintf)
-
-// sizeof(long) and sizeof(long long) are the same for aarch64
-ALIAS_SYMBOL(llrint, lrint);
-
-ALIAS_SYMBOL(llrintf, lrintf);
-
-NOTE_GNU_PROPERTY()
diff --git a/libm/arm64/sqrt.S b/libm/arm64/sqrt.S
deleted file mode 100644
index 0659b13..0000000
--- a/libm/arm64/sqrt.S
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <private/bionic_asm.h>
-
-ENTRY(sqrt)
- fsqrt d0, d0
- ret
-END(sqrt)
-
-ENTRY(sqrtf)
- fsqrt s0, s0
- ret
-END(sqrtf)
-
-NOTE_GNU_PROPERTY()
diff --git a/libm/builtins.cpp b/libm/builtins.cpp
index 58cd81d..256436e 100644
--- a/libm/builtins.cpp
+++ b/libm/builtins.cpp
@@ -47,6 +47,11 @@
float fminf(float x, float y) { return __builtin_fminf(x, y); }
double fmin(double x, double y) { return __builtin_fmin(x, y); }
+long lrint(double x) { return __builtin_lrint(x); }
+long lrintf(float x) { return __builtin_lrintf(x); }
+long long llrint(double x) { return __builtin_llrint(x); }
+long long llrintf(float x) { return __builtin_llrintf(x); }
+
long lround(double x) { return __builtin_lround(x); }
long lroundf(float x) { return __builtin_lroundf(x); }
long long llround(double x) { return __builtin_llround(x); }
@@ -59,7 +64,14 @@
float roundf(float x) { return __builtin_roundf(x); }
double round(double x) { return __builtin_round(x); }
+#endif
+#if defined(__aarch64__) || defined(__riscv)
+float sqrtf(float x) { return __builtin_sqrtf(x); }
+double sqrt(double x) { return __builtin_sqrt(x); }
+#endif
+
+#if defined(__aarch64__)
float truncf(float x) { return __builtin_truncf(x); }
double trunc(double x) { return __builtin_trunc(x); }
#endif
diff --git a/libm/riscv64/lrint.S b/libm/riscv64/lrint.S
deleted file mode 100644
index eb13833..0000000
--- a/libm/riscv64/lrint.S
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2022 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>
-
-ENTRY(lrint)
- fcvt.l.d a0, fa0, dyn
- ret
-END(lrint)
-
-ENTRY(lrintf)
- fcvt.l.s a0, fa0, dyn
- ret
-END(lrintf)
-
-// sizeof(long) and sizeof(long long) are the same for riscv64
-ALIAS_SYMBOL(llrint, lrint);
-
-ALIAS_SYMBOL(llrintf, lrintf);
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index f0e7b1b..833157e 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -203,35 +203,29 @@
ElfW(Addr) entry_point;
};
-static ExecutableInfo get_executable_info() {
+static ExecutableInfo get_executable_info(const char* arg_path) {
ExecutableInfo result = {};
+ char const* exe_path = "/proc/self/exe";
- if (is_first_stage_init()) {
- // /proc fs is not mounted when first stage init starts. Therefore we can't
- // use /proc/self/exe for init.
- stat("/init", &result.file_stat);
-
- // /init may be a symlink, so try to read it as such.
- char path[PATH_MAX];
- ssize_t path_len = readlink("/init", path, sizeof(path));
- if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
- result.path = "/init";
- } else {
- result.path = std::string(path, path_len);
+ // Stat "/proc/self/exe" instead of executable_path because
+ // the executable could be unlinked by this point and it should
+ // not cause a crash (see http://b/31084669)
+ if (TEMP_FAILURE_RETRY(stat(exe_path, &result.file_stat) == -1)) {
+ // Fallback to argv[0] for the case where /proc isn't available
+ if (TEMP_FAILURE_RETRY(stat(arg_path, &result.file_stat) == -1)) {
+ async_safe_fatal("unable to stat either \"/proc/self/exe\" or \"%s\": %s",
+ arg_path, strerror(errno));
}
+ exe_path = arg_path;
+ }
+
+ // Path might be a symlink
+ char sym_path[PATH_MAX];
+ ssize_t sym_path_len = readlink(exe_path, sym_path, sizeof(sym_path));
+ if (sym_path_len > 0 && sym_path_len < static_cast<ssize_t>(sizeof(sym_path))) {
+ result.path = std::string(sym_path, sym_path_len);
} else {
- // Stat "/proc/self/exe" instead of executable_path because
- // the executable could be unlinked by this point and it should
- // not cause a crash (see http://b/31084669)
- if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &result.file_stat)) != 0) {
- async_safe_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
- }
- char path[PATH_MAX];
- ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
- if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
- async_safe_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
- }
- result.path = std::string(path, path_len);
+ result.path = std::string(exe_path, strlen(exe_path));
}
result.phdr = reinterpret_cast<const ElfW(Phdr)*>(getauxval(AT_PHDR));
@@ -359,7 +353,7 @@
}
const ExecutableInfo exe_info = exe_to_load ? load_executable(exe_to_load) :
- get_executable_info();
+ get_executable_info(args.argv[0]);
INFO("[ Linking executable \"%s\" ]", exe_info.path.c_str());
diff --git a/tests/headers/posix/Android.bp b/tests/headers/posix/Android.bp
index 4a20d45..0809cdb 100644
--- a/tests/headers/posix/Android.bp
+++ b/tests/headers/posix/Android.bp
@@ -33,8 +33,5 @@
darwin: {
enabled: false,
},
- musl: {
- enabled: false,
- },
},
}
diff --git a/tests/headers/posix/fcntl_h.c b/tests/headers/posix/fcntl_h.c
index a55fe89..418add0 100644
--- a/tests/headers/posix/fcntl_h.c
+++ b/tests/headers/posix/fcntl_h.c
@@ -84,7 +84,11 @@
// POSIX: "The <fcntl.h> header shall define the symbolic constants for
// file modes for use as values of mode_t as described in <sys/stat.h>."
+ // Musl only defines the file mode bits (S_IFUSR, etc.) and not the file
+ // type bits (S_IFMT, etc.).
+#if !defined(ANDROID_HOST_MUSL)
#include "sys_stat_h_mode_constants.h"
+#endif
MACRO(AT_FDCWD);
#if !defined(__BIONIC__) // See comment in "faccessat.cpp".
diff --git a/tests/headers/posix/limits_h.c b/tests/headers/posix/limits_h.c
index 143f717..7e92d81 100644
--- a/tests/headers/posix/limits_h.c
+++ b/tests/headers/posix/limits_h.c
@@ -32,15 +32,17 @@
static void limits_h() {
// These are only defined if they're constants.
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
MACRO(AIO_LISTIO_MAX);
MACRO(AIO_MAX);
#endif
-#if !defined(__BIONIC__)
+#if !defined(__BIONIC__) && !defined(ANDROID_HOST_MUSL)
MACRO(AIO_PRIO_DELTA_MAX);
#endif
#if !defined(__BIONIC__) && !defined(__GLIBC__)
MACRO(ARG_MAX);
+#endif
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
MACRO(ATEXIT_MAX);
MACRO(CHILD_MAX);
#endif
@@ -50,14 +52,16 @@
MACRO(HOST_NAME_MAX);
MACRO(IOV_MAX);
MACRO(LOGIN_NAME_MAX);
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
MACRO(MQ_OPEN_MAX);
#endif
#if !defined(__BIONIC__)
MACRO(MQ_PRIO_MAX);
#endif
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
MACRO(OPEN_MAX);
+#endif
+#if !defined(__BIONIC__) && !defined(__GLIBC__)
MACRO(PAGESIZE);
MACRO(PAGE_SIZE);
#endif
@@ -66,19 +70,25 @@
#if !defined(__BIONIC__)
MACRO(PTHREAD_STACK_MIN);
#endif
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
MACRO(PTHREAD_THREADS_MAX);
#endif
+#if !defined(ANDROID_HOST_MUSL)
MACRO(RTSIG_MAX);
+#endif
#if !defined(__BIONIC__) && !defined(__GLIBC__)
MACRO(SEM_NSEMS_MAX);
#endif
MACRO(SEM_VALUE_MAX);
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
MACRO(SIGQUEUE_MAX);
MACRO(SS_REPL_MAX);
MACRO(STREAM_MAX);
+#endif
+#if !defined(__BIONIC__) && !defined(__GLIBC__)
MACRO(SYMLOOP_MAX);
+#endif
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
MACRO(TIMER_MAX);
#endif
#if !defined(__BIONIC__)
@@ -90,10 +100,14 @@
#if !defined(__BIONIC__) && !defined(__GLIBC__)
MACRO(FILESIZEBITS);
+#endif
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
MACRO(LINK_MAX);
#endif
+#if !defined(ANDROID_HOST_MUSL)
MACRO(MAX_CANON);
MACRO(MAX_INPUT);
+#endif
MACRO(NAME_MAX);
MACRO(PATH_MAX);
MACRO(PIPE_BUF);
@@ -104,7 +118,7 @@
MACRO(POSIX_REC_MIN_XFER_SIZE);
MACRO(POSIX_REC_XFER_ALIGN);
#endif
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
MACRO(SYMLINK_MAX);
#endif
diff --git a/tests/headers/posix/unistd_h.c b/tests/headers/posix/unistd_h.c
index b713f53..0b2cee5 100644
--- a/tests/headers/posix/unistd_h.c
+++ b/tests/headers/posix/unistd_h.c
@@ -51,8 +51,10 @@
MACRO(_POSIX_MESSAGE_PASSING);
MACRO(_POSIX_MONOTONIC_CLOCK);
MACRO(_POSIX_NO_TRUNC);
+#if !defined(ANDROID_HOST_MUSL)
MACRO(_POSIX_PRIORITIZED_IO);
MACRO(_POSIX_PRIORITY_SCHEDULING);
+#endif
MACRO(_POSIX_RAW_SOCKETS);
MACRO(_POSIX_READER_WRITER_LOCKS);
MACRO(_POSIX_REALTIME_SIGNALS);
@@ -63,35 +65,51 @@
MACRO(_POSIX_SHELL);
MACRO(_POSIX_SPAWN);
MACRO(_POSIX_SPIN_LOCKS);
+#if !defined(ANDROID_HOST_MUSL)
MACRO(_POSIX_SPORADIC_SERVER);
MACRO(_POSIX_SYNCHRONIZED_IO);
+#endif
MACRO(_POSIX_THREAD_ATTR_STACKADDR);
MACRO(_POSIX_THREAD_ATTR_STACKSIZE);
MACRO(_POSIX_THREAD_CPUTIME);
+#if !defined(ANDROID_HOST_MUSL)
MACRO(_POSIX_THREAD_PRIO_INHERIT);
MACRO(_POSIX_THREAD_PRIO_PROTECT);
+#endif
MACRO(_POSIX_THREAD_PRIORITY_SCHEDULING);
MACRO(_POSIX_THREAD_PROCESS_SHARED);
+#if !defined(ANDROID_HOST_MUSL)
MACRO(_POSIX_THREAD_ROBUST_PRIO_INHERIT);
MACRO(_POSIX_THREAD_ROBUST_PRIO_PROTECT);
+#endif
MACRO(_POSIX_THREAD_SAFE_FUNCTIONS);
+#if !defined(ANDROID_HOST_MUSL)
MACRO(_POSIX_THREAD_SPORADIC_SERVER);
+#endif
MACRO(_POSIX_THREADS);
MACRO(_POSIX_TIMEOUTS);
MACRO(_POSIX_TIMERS);
+#if !defined(ANDROID_HOST_MUSL)
MACRO(_POSIX_TYPED_MEMORY_OBJECTS);
+#endif
MACRO(_POSIX2_C_BIND);
+#if !defined(ANDROID_HOST_MUSL)
MACRO(_POSIX2_CHAR_TERM);
MACRO(_POSIX2_LOCALEDEF);
MACRO(_POSIX2_SW_DEV);
+#endif
#if 0 // No libc I can find actually has this.
MACRO(_POSIX2_UPE);
#endif
+#if !defined(ANDROID_HOST_MUSL)
MACRO(_XOPEN_CRYPT);
+#endif
MACRO(_XOPEN_ENH_I18N);
+#if !defined(ANDROID_HOST_MUSL)
MACRO(_XOPEN_REALTIME);
MACRO(_XOPEN_REALTIME_THREADS);
MACRO(_XOPEN_SHM);
+#endif
MACRO(_XOPEN_UNIX);
#if defined(_XOPEN_UUCP)
#if _XOPEN_UUCP != -1 && _XOPEN_UUCP != 0 && _XOPEN_UUCP != 200809L
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 3cc5bbd..63ad99d 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -35,6 +35,7 @@
#include <algorithm>
#include <atomic>
+#include <functional>
#include <thread>
#include <vector>
@@ -661,13 +662,13 @@
}
TEST(malloc, mallopt_smoke) {
-#if !defined(ANDROID_HOST_MUSL)
+#if defined(__BIONIC__)
errno = 0;
ASSERT_EQ(0, mallopt(-1000, 1));
// mallopt doesn't set errno.
ASSERT_EQ(0, errno);
#else
- GTEST_SKIP() << "musl doesn't have mallopt";
+ GTEST_SKIP() << "bionic-only test";
#endif
}
@@ -1528,3 +1529,157 @@
}
}
}
+
+void VerifyAllocationsAreZero(std::function<void*(size_t)> alloc_func, std::string function_name,
+ std::vector<size_t>& test_sizes, size_t max_allocations) {
+ // Vector of zero'd data used for comparisons. Make it twice the largest size.
+ std::vector<char> zero(test_sizes.back() * 2, 0);
+
+ SCOPED_TRACE(testing::Message() << function_name << " failed to zero memory");
+
+ for (size_t test_size : test_sizes) {
+ std::vector<void*> ptrs(max_allocations);
+ for (size_t i = 0; i < ptrs.size(); i++) {
+ SCOPED_TRACE(testing::Message() << "size " << test_size << " at iteration " << i);
+ ptrs[i] = alloc_func(test_size);
+ ASSERT_TRUE(ptrs[i] != nullptr);
+ size_t alloc_size = malloc_usable_size(ptrs[i]);
+ ASSERT_LE(alloc_size, zero.size());
+ ASSERT_EQ(0, memcmp(ptrs[i], zero.data(), alloc_size));
+
+ // Set the memory to non-zero to make sure if the pointer
+ // is reused it's still zero.
+ memset(ptrs[i], 0xab, alloc_size);
+ }
+ // Free the pointers.
+ for (size_t i = 0; i < ptrs.size(); i++) {
+ free(ptrs[i]);
+ }
+ for (size_t i = 0; i < ptrs.size(); i++) {
+ SCOPED_TRACE(testing::Message() << "size " << test_size << " at iteration " << i);
+ ptrs[i] = malloc(test_size);
+ ASSERT_TRUE(ptrs[i] != nullptr);
+ size_t alloc_size = malloc_usable_size(ptrs[i]);
+ ASSERT_LE(alloc_size, zero.size());
+ ASSERT_EQ(0, memcmp(ptrs[i], zero.data(), alloc_size));
+ }
+ // Free all of the pointers later to maximize the chance of reusing from
+ // the first loop.
+ for (size_t i = 0; i < ptrs.size(); i++) {
+ free(ptrs[i]);
+ }
+ }
+}
+
+// Verify that small and medium allocations are always zero.
+TEST(malloc, zeroed_allocations_small_medium_sizes) {
+#if !defined(__BIONIC__)
+ GTEST_SKIP() << "Only valid on bionic";
+#endif
+
+ if (IsLowRamDevice()) {
+ GTEST_SKIP() << "Skipped on low memory devices.";
+ }
+
+ constexpr size_t kMaxAllocations = 1024;
+ std::vector<size_t> test_sizes = {16, 48, 128, 1024, 4096, 65536};
+ VerifyAllocationsAreZero([](size_t size) -> void* { return malloc(size); }, "malloc", test_sizes,
+ kMaxAllocations);
+
+ VerifyAllocationsAreZero([](size_t size) -> void* { return memalign(64, size); }, "memalign",
+ test_sizes, kMaxAllocations);
+
+ VerifyAllocationsAreZero(
+ [](size_t size) -> void* {
+ void* ptr;
+ if (posix_memalign(&ptr, 64, size) == 0) {
+ return ptr;
+ }
+ return nullptr;
+ },
+ "posix_memalign", test_sizes, kMaxAllocations);
+}
+
+// Verify that large allocations are always zero.
+TEST(malloc, zeroed_allocations_large_sizes) {
+#if !defined(__BIONIC__)
+ GTEST_SKIP() << "Only valid on bionic";
+#endif
+
+ if (IsLowRamDevice()) {
+ GTEST_SKIP() << "Skipped on low memory devices.";
+ }
+
+ constexpr size_t kMaxAllocations = 20;
+ std::vector<size_t> test_sizes = {1000000, 2000000, 3000000, 4000000};
+ VerifyAllocationsAreZero([](size_t size) -> void* { return malloc(size); }, "malloc", test_sizes,
+ kMaxAllocations);
+
+ VerifyAllocationsAreZero([](size_t size) -> void* { return memalign(64, size); }, "memalign",
+ test_sizes, kMaxAllocations);
+
+ VerifyAllocationsAreZero(
+ [](size_t size) -> void* {
+ void* ptr;
+ if (posix_memalign(&ptr, 64, size) == 0) {
+ return ptr;
+ }
+ return nullptr;
+ },
+ "posix_memalign", test_sizes, kMaxAllocations);
+}
+
+TEST(malloc, zeroed_allocations_realloc) {
+#if !defined(__BIONIC__)
+ GTEST_SKIP() << "Only valid on bionic";
+#endif
+
+ if (IsLowRamDevice()) {
+ GTEST_SKIP() << "Skipped on low memory devices.";
+ }
+
+ // Vector of zero'd data used for comparisons.
+ constexpr size_t kMaxMemorySize = 131072;
+ std::vector<char> zero(kMaxMemorySize, 0);
+
+ constexpr size_t kMaxAllocations = 1024;
+ std::vector<size_t> test_sizes = {16, 48, 128, 1024, 4096, 65536};
+ // Do a number of allocations and set them to non-zero.
+ for (size_t test_size : test_sizes) {
+ std::vector<void*> ptrs(kMaxAllocations);
+ for (size_t i = 0; i < kMaxAllocations; i++) {
+ ptrs[i] = malloc(test_size);
+ ASSERT_TRUE(ptrs[i] != nullptr);
+
+ // Set the memory to non-zero to make sure if the pointer
+ // is reused it's still zero.
+ memset(ptrs[i], 0xab, malloc_usable_size(ptrs[i]));
+ }
+ // Free the pointers.
+ for (size_t i = 0; i < kMaxAllocations; i++) {
+ free(ptrs[i]);
+ }
+ }
+
+ // Do the reallocs to a larger size and verify the rest of the allocation
+ // is zero.
+ constexpr size_t kInitialSize = 8;
+ for (size_t test_size : test_sizes) {
+ std::vector<void*> ptrs(kMaxAllocations);
+ for (size_t i = 0; i < kMaxAllocations; i++) {
+ ptrs[i] = malloc(kInitialSize);
+ ASSERT_TRUE(ptrs[i] != nullptr);
+ size_t orig_alloc_size = malloc_usable_size(ptrs[i]);
+
+ ptrs[i] = realloc(ptrs[i], test_size);
+ ASSERT_TRUE(ptrs[i] != nullptr);
+ size_t new_alloc_size = malloc_usable_size(ptrs[i]);
+ char* ptr = reinterpret_cast<char*>(ptrs[i]);
+ ASSERT_EQ(0, memcmp(&ptr[orig_alloc_size], zero.data(), new_alloc_size - orig_alloc_size))
+ << "realloc from " << kInitialSize << " to size " << test_size << " at iteration " << i;
+ }
+ for (size_t i = 0; i < kMaxAllocations; i++) {
+ free(ptrs[i]);
+ }
+ }
+}
diff --git a/tests/utils.cpp b/tests/utils.cpp
index 8258833..92ab145 100644
--- a/tests/utils.cpp
+++ b/tests/utils.cpp
@@ -28,6 +28,10 @@
#include "utils.h"
+#include <string>
+
+#include <android-base/properties.h>
+
void RunGwpAsanTest(const char* test_name) {
ExecTestHelper eh;
eh.SetEnv({"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1", "GWP_ASAN_MAX_ALLOCS=40000",
@@ -53,3 +57,9 @@
// |expected_output_regex|, ensure at least one test ran:
R"(\[ PASSED \] [1-9]+0? test)");
}
+
+bool IsLowRamDevice() {
+ return android::base::GetBoolProperty("ro.config.low_ram", false) ||
+ (android::base::GetBoolProperty("ro.debuggable", false) &&
+ android::base::GetBoolProperty("debug.force_low_ram", false));
+}
diff --git a/tests/utils.h b/tests/utils.h
index 81869e3..2e00cc1 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -313,3 +313,5 @@
return false;
#endif
}
+
+bool IsLowRamDevice();
diff --git a/tests/utmp_test.cpp b/tests/utmp_test.cpp
index 6d0d6f1..b024818 100644
--- a/tests/utmp_test.cpp
+++ b/tests/utmp_test.cpp
@@ -29,5 +29,6 @@
setutent();
ASSERT_EQ(NULL, getutent());
endutent();
- ASSERT_EQ(NULL, pututline(NULL));
+ utmp failure = {.ut_type = EMPTY};
+ ASSERT_EQ(NULL, pututline(&failure));
}