libc: add clang FORTIFY support
This patch adds clang-style FORTIFY to Bionic. For more information on
FORTIFY, please see https://goo.gl/8HS2dW . This implementation works
for versions of clang that don't support diagnose_if, so please see the
"without diagnose_if" sections. We plan to swap to a diagnose_if-based
FORTIFY later this year (since it doesn't really add any features; it
just simplifies the implementation a lot, and it gives us much prettier
diagnostics)
Bug: 32073964
Test: Builds on angler, bullhead, marlin, sailfish. Bionic CTS tests
pass on Angler and Bullhead.
Change-Id: I607aecbeee81529709b1eee7bef5b0836151eb2b
diff --git a/libc/arch-arm/generic/bionic/strlen.c b/libc/arch-arm/generic/bionic/strlen.c
index b9f3a2a..f6b9209 100644
--- a/libc/arch-arm/generic/bionic/strlen.c
+++ b/libc/arch-arm/generic/bionic/strlen.c
@@ -29,7 +29,7 @@
#include <string.h>
#include <stdint.h>
-size_t strlen(const char *s)
+size_t strlen(const char *s) __overloadable
{
__builtin_prefetch(s);
__builtin_prefetch(s+32);
diff --git a/libc/arch-mips/string/mips_strlen.c b/libc/arch-mips/string/mips_strlen.c
index 45fc4b4..f1465f2 100644
--- a/libc/arch-mips/string/mips_strlen.c
+++ b/libc/arch-mips/string/mips_strlen.c
@@ -49,7 +49,7 @@
#endif
size_t
-strlen (const char *_a)
+strlen (const char *_a) __overloadable
{
int cnt = 0;
unsigned x;
diff --git a/libc/arch-mips/string/strlen.c b/libc/arch-mips/string/strlen.c
index 7e0e27b..488e3c8 100644
--- a/libc/arch-mips/string/strlen.c
+++ b/libc/arch-mips/string/strlen.c
@@ -32,7 +32,7 @@
#include <string.h>
size_t
-strlen(const char *str)
+strlen(const char *str) __overloadable
{
const char *s;
diff --git a/libc/bionic/fortify.cpp b/libc/bionic/fortify.cpp
index cf50664..117de48 100644
--- a/libc/bionic/fortify.cpp
+++ b/libc/bionic/fortify.cpp
@@ -71,6 +71,8 @@
#include "private/bionic_fortify.h"
+struct __bionic_zero_size_is_okay_t __bionic_zero_size_is_okay;
+
//
// For more details see:
// http://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html
diff --git a/libc/bionic/getcwd.cpp b/libc/bionic/getcwd.cpp
index bcd6a57..c2a7e23 100644
--- a/libc/bionic/getcwd.cpp
+++ b/libc/bionic/getcwd.cpp
@@ -34,7 +34,7 @@
extern "C" int __getcwd(char* buf, size_t size);
-char* getcwd(char* buf, size_t size) {
+char* getcwd(char* buf, size_t size) __overloadable {
// You can't specify size 0 unless you're asking us to allocate for you.
if (buf != NULL && size == 0) {
errno = EINVAL;
diff --git a/libc/bionic/poll.cpp b/libc/bionic/poll.cpp
index 23ef90a..eded56a 100644
--- a/libc/bionic/poll.cpp
+++ b/libc/bionic/poll.cpp
@@ -37,7 +37,7 @@
extern "C" int __ppoll(pollfd*, unsigned int, timespec*, const kernel_sigset_t*, size_t);
extern "C" int __pselect6(int, fd_set*, fd_set*, fd_set*, timespec*, void*);
-int poll(pollfd* fds, nfds_t fd_count, int ms) {
+int poll(pollfd* fds, nfds_t fd_count, int ms) __overloadable {
timespec ts;
timespec* ts_ptr = NULL;
if (ms >= 0) {
@@ -47,7 +47,7 @@
return __ppoll(fds, fd_count, ts_ptr, NULL, 0);
}
-int ppoll(pollfd* fds, nfds_t fd_count, const timespec* ts, const sigset_t* ss) {
+int ppoll(pollfd* fds, nfds_t fd_count, const timespec* ts, const sigset_t* ss) __overloadable {
timespec mutable_ts;
timespec* mutable_ts_ptr = NULL;
if (ts != NULL) {
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 94ea153..88bcc78 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -67,9 +67,10 @@
int creat(const char*, mode_t);
int creat64(const char*, mode_t) __INTRODUCED_IN(21);
-int openat(int, const char*, int, ...);
+int openat(int, const char*, int, ...) __overloadable
+ __RENAME_CLANG(openat);
int openat64(int, const char*, int, ...) __INTRODUCED_IN(21);
-int open(const char*, int, ...);
+int open(const char*, int, ...) __overloadable __RENAME_CLANG(open);
int open64(const char*, int, ...) __INTRODUCED_IN(21);
ssize_t splice(int, off64_t*, int, off64_t*, size_t, unsigned int) __INTRODUCED_IN(21);
ssize_t tee(int, int, size_t, unsigned int) __INTRODUCED_IN(21);
@@ -94,15 +95,71 @@
#endif
int __open_2(const char*, int) __INTRODUCED_IN(17);
-int __open_real(const char*, int, ...) __RENAME(open);
int __openat_2(int, const char*, int) __INTRODUCED_IN(17);
+/*
+ * These are the easiest way to call the real open even in clang FORTIFY.
+ */
+int __open_real(const char*, int, ...) __RENAME(open);
int __openat_real(int, const char*, int, ...) __RENAME(openat);
-__errordecl(__creat_missing_mode, "called with O_CREAT, but missing mode");
-__errordecl(__creat_too_many_args, "too many arguments");
+
#if defined(__BIONIC_FORTIFY)
+#define __open_too_many_args_error "too many arguments"
+#define __open_too_few_args_error "called with O_CREAT, but missing mode"
+#if defined(__clang__)
-#if !defined(__clang__)
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int open(const char* pathname, int flags, mode_t modes, ...) __overloadable
+ __errorattr(__open_too_many_args_error);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int open(const char* pathname, int flags) __overloadable
+ __enable_if(flags & O_CREAT, __open_too_few_args_error)
+ __errorattr(__open_too_few_args_error);
+
+/*
+ * pass_object_size serves two purposes here, neither of which involve __bos: it
+ * disqualifies this function from having its address taken (so &open works),
+ * and it makes overload resolution prefer open(const char *, int) over
+ * open(const char *, int, ...).
+ */
+__BIONIC_FORTIFY_INLINE
+int open(const char* const __pass_object_size pathname,
+ int flags) __overloadable {
+ return __open_2(pathname, flags);
+}
+
+__BIONIC_FORTIFY_INLINE
+int open(const char* const __pass_object_size pathname, int flags, mode_t modes)
+ __overloadable {
+ return __open_real(pathname, flags, modes);
+}
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int openat(int dirfd, const char* pathname, int flags) __overloadable
+ __enable_if(flags & O_CREAT, __open_too_few_args_error)
+ __errorattr(__open_too_few_args_error);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int openat(int dirfd, const char* pathname, int flags, mode_t modes, ...)
+ __overloadable
+ __errorattr(__open_too_many_args_error);
+
+__BIONIC_FORTIFY_INLINE
+int openat(int dirfd, const char* const __pass_object_size pathname,
+ int flags) __overloadable {
+ return __openat_2(dirfd, pathname, flags);
+}
+
+__BIONIC_FORTIFY_INLINE
+int openat(int dirfd, const char* const __pass_object_size pathname, int flags,
+ mode_t modes) __overloadable {
+ return __openat_real(dirfd, pathname, flags, modes);
+}
+
+#else /* defined(__clang__) */
+__errordecl(__creat_missing_mode, __open_too_few_args_error);
+__errordecl(__creat_too_many_args, __open_too_many_args_error);
__BIONIC_FORTIFY_INLINE
int open(const char* pathname, int flags, ...) {
@@ -142,8 +199,10 @@
return __openat_real(dirfd, pathname, flags, __builtin_va_arg_pack());
}
-#endif /* !defined(__clang__) */
+#endif /* defined(__clang__) */
+#undef __open_too_many_args_error
+#undef __open_too_few_args_error
#endif /* defined(__BIONIC_FORTIFY) */
__END_DECLS
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 7452e53..752ee72 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -24,7 +24,12 @@
__BEGIN_DECLS
#if defined(__clang__)
-#define __BIONIC_ALLOC_SIZE(...) /* clang doesn't support attribute alloc_size. */
+/* clang should support alloc_size in the nearish future. */
+#if __has_attribute(alloc_size)
+#error "We should enable alloc_size for clang."
+#else
+#define __BIONIC_ALLOC_SIZE(...)
+#endif
#else
#define __BIONIC_ALLOC_SIZE(...) __attribute__((__alloc_size__(__VA_ARGS__)))
#endif
diff --git a/libc/include/poll.h b/libc/include/poll.h
index c4e62f9..3287a0c 100644
--- a/libc/include/poll.h
+++ b/libc/include/poll.h
@@ -38,27 +38,65 @@
typedef unsigned int nfds_t;
-int poll(struct pollfd*, nfds_t, int);
-int ppoll(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*) __INTRODUCED_IN(21);
+int poll(struct pollfd*, nfds_t, int) __overloadable __RENAME_CLANG(poll);
+int ppoll(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*)
+ __overloadable __RENAME_CLANG(ppoll) __INTRODUCED_IN(21);
int __poll_chk(struct pollfd*, nfds_t, int, size_t) __INTRODUCED_IN(23);
+int __ppoll_chk(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*, size_t)
+ __INTRODUCED_IN(23);
+
+#if defined(__BIONIC_FORTIFY)
+#if __ANDROID_API__ >= __ANDROID_API_M__
+#if defined(__clang__)
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int poll(struct pollfd* fds, nfds_t fd_count, int timeout) __overloadable
+ __enable_if(__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(fds) < sizeof(*fds) * fd_count,
+ "selected when there aren't fd_count fds")
+ __errorattr("too many fds specified");
+
+__BIONIC_FORTIFY_INLINE
+int poll(struct pollfd* const fds __pass_object_size, nfds_t fd_count,
+ int timeout) __overloadable {
+ size_t bos_fds = __bos(fds);
+
+ if (bos_fds == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(poll)(fds, fd_count, timeout);
+ }
+
+ return __poll_chk(fds, fd_count, timeout, bos_fds);
+}
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int ppoll(struct pollfd* fds, nfds_t fd_count, const struct timespec* timeout,
+ const sigset_t* mask) __overloadable
+ __enable_if(__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(fds) < sizeof(*fds) * fd_count,
+ "selected when there aren't fd_count fds")
+ __errorattr("too many fds specified");
+
+__BIONIC_FORTIFY_INLINE
+int ppoll(struct pollfd* const fds __pass_object_size, nfds_t fd_count,
+ const struct timespec* timeout, const sigset_t* mask) __overloadable {
+ size_t bos_fds = __bos(fds);
+
+ if (bos_fds == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(ppoll)(fds, fd_count, timeout, mask);
+ }
+
+ return __ppoll_chk(fds, fd_count, timeout, mask, bos_fds);
+}
+#else /* defined(__clang__) */
int __poll_real(struct pollfd*, nfds_t, int) __RENAME(poll);
__errordecl(__poll_too_small_error, "poll: pollfd array smaller than fd count");
-int __ppoll_chk(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*, size_t)
- __INTRODUCED_IN(23);
int __ppoll_real(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*) __RENAME(ppoll)
__INTRODUCED_IN(21);
__errordecl(__ppoll_too_small_error, "ppoll: pollfd array smaller than fd count");
-#if defined(__BIONIC_FORTIFY)
-
-#if __ANDROID_API__ >= __ANDROID_API_M__
__BIONIC_FORTIFY_INLINE
int poll(struct pollfd* fds, nfds_t fd_count, int timeout) {
-#if defined(__clang__)
- return __poll_chk(fds, fd_count, timeout, __bos(fds));
-#else
if (__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE) {
if (!__builtin_constant_p(fd_count)) {
return __poll_chk(fds, fd_count, timeout, __bos(fds));
@@ -67,14 +105,11 @@
}
}
return __poll_real(fds, fd_count, timeout);
-#endif
}
__BIONIC_FORTIFY_INLINE
-int ppoll(struct pollfd* fds, nfds_t fd_count, const struct timespec* timeout, const sigset_t* mask) {
-#if defined(__clang__)
- return __ppoll_chk(fds, fd_count, timeout, mask, __bos(fds));
-#else
+int ppoll(struct pollfd* fds, nfds_t fd_count, const struct timespec* timeout,
+ const sigset_t* mask) {
if (__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE) {
if (!__builtin_constant_p(fd_count)) {
return __ppoll_chk(fds, fd_count, timeout, mask, __bos(fds));
@@ -83,11 +118,11 @@
}
}
return __ppoll_real(fds, fd_count, timeout, mask);
-#endif
}
-#endif /* __ANDROID_API__ >= __ANDROID_API_M__ */
-#endif
+#endif /* defined(__clang__) */
+#endif /* __ANDROID_API__ >= __ANDROID_API_M__ */
+#endif /* defined(__BIONIC_FORTIFY) */
__END_DECLS
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 9125e4c..6a76da6 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -121,13 +121,16 @@
int ferror(FILE *);
int fflush(FILE *);
int fgetc(FILE *);
-char *fgets(char * __restrict, int, FILE * __restrict);
+char *fgets(char * __restrict, int, FILE * __restrict) __overloadable
+ __RENAME_CLANG(fgets);
int fprintf(FILE * __restrict , const char * __restrict _Nonnull, ...) __printflike(2, 3);
int fputc(int, FILE *);
int fputs(const char * __restrict, FILE * __restrict);
-size_t fread(void * __restrict, size_t, size_t, FILE * __restrict);
+size_t fread(void * __restrict, size_t, size_t, FILE * __restrict)
+ __overloadable __RENAME_CLANG(fread);
int fscanf(FILE * __restrict, const char * __restrict _Nonnull, ...) __scanflike(2, 3);
-size_t fwrite(const void * __restrict, size_t, size_t, FILE * __restrict);
+size_t fwrite(const void * __restrict, size_t, size_t, FILE * __restrict)
+ __overloadable __RENAME_CLANG(fwrite);
int getc(FILE *);
int getchar(void);
ssize_t getdelim(char** __restrict, size_t* __restrict, int, FILE* __restrict) __INTRODUCED_IN(18);
@@ -155,12 +158,17 @@
(defined(__cplusplus) && __cplusplus <= 201103L)
char* gets(char*) __attribute__((deprecated("gets is unsafe, use fgets instead")));
#endif
-int sprintf(char* __restrict, const char* __restrict _Nonnull, ...) __printflike(2, 3);
-int vsprintf(char* __restrict, const char* __restrict _Nonnull, __va_list) __printflike(2, 0);
-char* tmpnam(char*) __attribute__((deprecated("tmpnam is unsafe, use mkstemp or tmpfile instead")));
+int sprintf(char* __restrict, const char* __restrict _Nonnull, ...)
+ __printflike(2, 3) __warnattr_strict("sprintf is often misused; please use snprintf")
+ __overloadable __RENAME_CLANG(sprintf);
+int vsprintf(char* __restrict, const char* __restrict _Nonnull, __va_list)
+ __overloadable __printflike(2, 0) __RENAME_CLANG(vsprintf)
+ __warnattr_strict("vsprintf is often misused; please use vsnprintf");
+char* tmpnam(char*)
+ __warnattr("tempnam is unsafe, use mkstemp or tmpfile instead");
#define P_tmpdir "/tmp/" /* deprecated */
char* tempnam(const char*, const char*)
- __attribute__((deprecated("tempnam is unsafe, use mkstemp or tmpfile instead")));
+ __warnattr("tempnam is unsafe, use mkstemp or tmpfile instead");
int rename(const char*, const char*);
int renameat(int, const char*, int, const char*);
@@ -210,10 +218,12 @@
FILE* tmpfile(void);
FILE* tmpfile64(void) __INTRODUCED_IN(24);
-int snprintf(char* __restrict, size_t, const char* __restrict _Nonnull, ...) __printflike(3, 4);
+int snprintf(char* __restrict, size_t, const char* __restrict _Nonnull, ...)
+ __printflike(3, 4) __overloadable __RENAME_CLANG(snprintf);
int vfscanf(FILE* __restrict, const char* __restrict _Nonnull, __va_list) __scanflike(2, 0);
int vscanf(const char* _Nonnull , __va_list) __scanflike(1, 0);
-int vsnprintf(char* __restrict, size_t, const char* __restrict _Nonnull, __va_list) __printflike(3, 0);
+int vsnprintf(char* __restrict, size_t, const char* __restrict _Nonnull, __va_list)
+ __printflike(3, 0) __overloadable __RENAME_CLANG(vsnprintf);
int vsscanf(const char* __restrict _Nonnull, const char* __restrict _Nonnull, __va_list) __scanflike(2, 0);
#define L_ctermid 1024 /* size for ctermid() */
@@ -250,66 +260,182 @@
#endif /* __USE_BSD */
char* __fgets_chk(char*, int, FILE*, size_t) __INTRODUCED_IN(17);
-char* __fgets_real(char*, int, FILE*) __RENAME(fgets);
-__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer");
-__errordecl(__fgets_too_small_error, "fgets called with size less than zero");
-
size_t __fread_chk(void* __restrict, size_t, size_t, FILE* __restrict, size_t)
- __INTRODUCED_IN(24);
-size_t __fread_real(void * __restrict, size_t, size_t, FILE * __restrict) __RENAME(fread);
-__errordecl(__fread_too_big_error, "fread called with size * count bigger than buffer");
-__errordecl(__fread_overflow, "fread called with overflowing size * count");
-
+ __INTRODUCED_IN(24);
size_t __fwrite_chk(const void* __restrict, size_t, size_t, FILE* __restrict, size_t)
- __INTRODUCED_IN(24);
-size_t __fwrite_real(const void * __restrict, size_t, size_t, FILE * __restrict) __RENAME(fwrite);
-__errordecl(__fwrite_too_big_error, "fwrite called with size * count bigger than buffer");
-__errordecl(__fwrite_overflow, "fwrite called with overflowing size * count");
+ __INTRODUCED_IN(24);
#if defined(__BIONIC_FORTIFY) && !defined(__BIONIC_NO_STDIO_FORTIFY)
#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
-__BIONIC_FORTIFY_INLINE
-__printflike(3, 0) int vsnprintf(char* dest, size_t size, const char* _Nonnull format, __va_list ap) {
+__BIONIC_FORTIFY_INLINE __printflike(3, 0)
+int vsnprintf(char *const __pass_object_size dest, size_t size,
+ const char *_Nonnull format, __va_list ap) __overloadable {
return __builtin___vsnprintf_chk(dest, size, 0, __bos(dest), format, ap);
}
-__BIONIC_FORTIFY_INLINE
-__printflike(2, 0) int vsprintf(char* dest, const char* _Nonnull format, __va_list ap) {
+__BIONIC_FORTIFY_INLINE __printflike(2, 0)
+int vsprintf(char *const __pass_object_size dest, const char *_Nonnull format,
+ __va_list ap) __overloadable {
return __builtin___vsprintf_chk(dest, 0, __bos(dest), format, ap);
}
+#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
#if defined(__clang__)
- #if !defined(snprintf)
- #define __wrap_snprintf(dest, size, ...) __builtin___snprintf_chk(dest, size, 0, __bos(dest), __VA_ARGS__)
- #define snprintf(...) __wrap_snprintf(__VA_ARGS__)
- #endif
-#else
-__BIONIC_FORTIFY_INLINE
-__printflike(3, 4) int snprintf(char* dest, size_t size, const char* _Nonnull format, ...) {
- return __builtin___snprintf_chk(dest, size, 0, __bos(dest), format, __builtin_va_arg_pack());
-}
-#endif
+#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
+/*
+ * Simple case: `format` can't have format specifiers, so we can just compare
+ * its length to the length of `dest`
+ */
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int snprintf(char *__restrict dest, size_t size, const char *__restrict format)
+ __overloadable
+ __enable_if(__bos(dest) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(dest) < __builtin_strlen(format),
+ "format string will always overflow destination buffer")
+ __errorattr("format string will always overflow destination buffer");
-#if defined(__clang__)
- #if !defined(sprintf)
- #define __wrap_sprintf(dest, ...) __builtin___sprintf_chk(dest, 0, __bos(dest), __VA_ARGS__)
- #define sprintf(...) __wrap_sprintf(__VA_ARGS__)
- #endif
-#else
__BIONIC_FORTIFY_INLINE
-__printflike(2, 3) int sprintf(char* dest, const char* _Nonnull format, ...) {
- return __builtin___sprintf_chk(dest, 0, __bos(dest), format, __builtin_va_arg_pack());
+__printflike(3, 4)
+int snprintf(char *__restrict const __pass_object_size dest,
+ size_t size, const char *__restrict format, ...) __overloadable {
+ va_list va;
+ va_start(va, format);
+ int result = __builtin___vsnprintf_chk(dest, size, 0, __bos(dest), format, va);
+ va_end(va);
+ return result;
}
-#endif
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int sprintf(char *__restrict dest, const char *__restrict format) __overloadable
+ __enable_if(__bos(dest) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(dest) < __builtin_strlen(format),
+ "format string will always overflow destination buffer")
+ __errorattr("format string will always overflow destination buffer");
+
+__BIONIC_FORTIFY_INLINE
+__printflike(2, 3)
+int sprintf(char *__restrict const __pass_object_size dest,
+ const char *__restrict format, ...) __overloadable {
+ va_list va;
+ va_start(va, format);
+ int result = __builtin___vsprintf_chk(dest, 0, __bos(dest), format, va);
+ va_end(va);
+ return result;
+}
#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
#if __ANDROID_API__ >= __ANDROID_API_N__
__BIONIC_FORTIFY_INLINE
-size_t fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict stream) {
+size_t fread(void *__restrict buf, size_t size, size_t count,
+ FILE *__restrict stream) __overloadable
+ __enable_if(__unsafe_check_mul_overflow(size, count), "size * count overflows")
+ __errorattr("size * count overflows");
+
+__BIONIC_FORTIFY_INLINE
+size_t fread(void *__restrict buf, size_t size, size_t count,
+ FILE *__restrict stream) __overloadable
+ __enable_if(!__unsafe_check_mul_overflow(size, count), "no overflow")
+ __enable_if(__bos(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ size * count > __bos(buf), "size * count is too large")
+ __errorattr("size * count is too large");
+
+__BIONIC_FORTIFY_INLINE
+size_t fread(void *__restrict const __pass_object_size buf, size_t size,
+ size_t count, FILE *__restrict stream) __overloadable {
size_t bos = __bos0(buf);
-#if !defined(__clang__)
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(fread)(buf, size, count, stream);
+ }
+
+ return __fread_chk(buf, size, count, stream, bos);
+}
+
+size_t fwrite(const void * __restrict buf, size_t size,
+ size_t count, FILE * __restrict stream) __overloadable
+ __enable_if(__unsafe_check_mul_overflow(size, count),
+ "size * count overflows")
+ __errorattr("size * count overflows");
+
+size_t fwrite(const void * __restrict buf, size_t size,
+ size_t count, FILE * __restrict stream) __overloadable
+ __enable_if(!__unsafe_check_mul_overflow(size, count), "no overflow")
+ __enable_if(__bos(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ size * count > __bos(buf), "size * count is too large")
+ __errorattr("size * count is too large");
+
+__BIONIC_FORTIFY_INLINE
+size_t fwrite(const void * __restrict const __pass_object_size buf, size_t size,
+ size_t count, FILE * __restrict stream) __overloadable {
+ size_t bos = __bos0(buf);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(fwrite)(buf, size, count, stream);
+ }
+
+ return __fwrite_chk(buf, size, count, stream, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+char *fgets(char* __restrict dest, int size, FILE* stream) __overloadable
+ __enable_if(size < 0, "size is negative")
+ __errorattr("size is negative");
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+char *fgets(char* dest, int size, FILE* stream) __overloadable
+ __enable_if(size >= 0 && size > __bos(dest),
+ "size is larger than the destination buffer")
+ __errorattr("size is larger than the destination buffer");
+
+__BIONIC_FORTIFY_INLINE
+char *fgets(char* __restrict const __pass_object_size dest,
+ int size, FILE* stream) __overloadable {
+ size_t bos = __bos(dest);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(fgets)(dest, size, stream);
+ }
+
+ return __fgets_chk(dest, size, stream, bos);
+}
+
+#else /* defined(__clang__) */
+
+size_t __fread_real(void * __restrict, size_t, size_t, FILE * __restrict) __RENAME(fread);
+__errordecl(__fread_too_big_error, "fread called with size * count bigger than buffer");
+__errordecl(__fread_overflow, "fread called with overflowing size * count");
+
+char* __fgets_real(char*, int, FILE*) __RENAME(fgets);
+__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer");
+__errordecl(__fgets_too_small_error, "fgets called with size less than zero");
+
+size_t __fwrite_real(const void * __restrict, size_t, size_t, FILE * __restrict) __RENAME(fwrite);
+__errordecl(__fwrite_too_big_error, "fwrite called with size * count bigger than buffer");
+__errordecl(__fwrite_overflow, "fwrite called with overflowing size * count");
+
+
+#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
+__BIONIC_FORTIFY_INLINE __printflike(3, 4)
+int snprintf(char *__restrict dest, size_t size, const char* _Nonnull format, ...)
+{
+ return __builtin___snprintf_chk(dest, size, 0, __bos(dest), format,
+ __builtin_va_arg_pack());
+}
+
+__BIONIC_FORTIFY_INLINE __printflike(2, 3)
+int sprintf(char *__restrict dest, const char* _Nonnull format, ...) {
+ return __builtin___sprintf_chk(dest, 0, __bos(dest), format,
+ __builtin_va_arg_pack());
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_N__
+__BIONIC_FORTIFY_INLINE
+size_t fread(void *__restrict buf, size_t size, size_t count, FILE * __restrict stream) {
+ size_t bos = __bos0(buf);
+
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __fread_real(buf, size, count, stream);
}
@@ -326,7 +452,6 @@
return __fread_real(buf, size, count, stream);
}
-#endif
return __fread_chk(buf, size, count, stream, bos);
}
@@ -335,7 +460,6 @@
size_t fwrite(const void * __restrict buf, size_t size, size_t count, FILE * __restrict stream) {
size_t bos = __bos0(buf);
-#if !defined(__clang__)
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __fwrite_real(buf, size, count, stream);
}
@@ -352,14 +476,11 @@
return __fwrite_real(buf, size, count, stream);
}
-#endif
return __fwrite_chk(buf, size, count, stream, bos);
}
#endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
-#if !defined(__clang__)
-
__BIONIC_FORTIFY_INLINE
char *fgets(char* dest, int size, FILE* stream) {
size_t bos = __bos(dest);
@@ -390,8 +511,7 @@
return __fgets_chk(dest, size, stream, bos);
}
-#endif /* !defined(__clang__) */
-
+#endif /* defined(__clang__) */
#endif /* defined(__BIONIC_FORTIFY) */
#if defined(__clang__)
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index d0c08e1..eefee13 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -83,8 +83,9 @@
long atol(const char*) __attribute_pure__;
long long atoll(const char*) __attribute_pure__;
-char* realpath(const char* path, char* resolved);
-int system(const char* string);
+char * realpath(const char *path, char *resolved) __overloadable
+ __RENAME_CLANG(realpath);
+int system(const char *string);
void* bsearch(const void* key, const void* base0, size_t nmemb, size_t size,
int (*compar)(const void*, const void*));
@@ -164,24 +165,44 @@
#endif
#if defined(__BIONIC_FORTIFY)
+#define __realpath_buf_too_small_str \
+ "realpath output parameter must be NULL or a >= PATH_MAX bytes buffer"
+
+/* PATH_MAX is unavailable without polluting the namespace, but it's always 4096 on Linux */
+#define __PATH_MAX 4096
+
+#if defined(__clang__)
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+char* realpath(const char* path, char* resolved) __overloadable
+ __enable_if(__bos(resolved) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(resolved) < __PATH_MAX, __realpath_buf_too_small_str)
+ __errorattr(__realpath_buf_too_small_str);
+
+/* No need for a FORTIFY version; the only things we can catch are at
+ * compile-time.
+ */
+
+#else /* defined(__clang__) */
char* __realpath_real(const char*, char*) __RENAME(realpath);
-__errordecl(__realpath_size_error, "realpath output parameter must be NULL or a >= PATH_MAX bytes buffer");
+__errordecl(__realpath_size_error, __realpath_buf_too_small_str);
-#if !defined(__clang__)
__BIONIC_FORTIFY_INLINE
char* realpath(const char* path, char* resolved) {
size_t bos = __bos(resolved);
- /* PATH_MAX is unavailable without polluting the namespace, but it's always 4096 on Linux */
- if (bos != __BIONIC_FORTIFY_UNKNOWN_SIZE && bos < 4096) {
+ if (bos != __BIONIC_FORTIFY_UNKNOWN_SIZE && bos < __PATH_MAX) {
__realpath_size_error();
}
return __realpath_real(path, resolved);
}
-#endif
+#endif /* defined(__clang__) */
+
+#undef __PATH_MAX
+#undef __realpath_buf_too_small_str
#endif /* defined(__BIONIC_FORTIFY) */
#if __ANDROID_API__ >= __ANDROID_API_L__
diff --git a/libc/include/string.h b/libc/include/string.h
index 3e52f48..38595b2 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -47,18 +47,23 @@
#endif
void* memccpy(void* _Nonnull __restrict, const void* _Nonnull __restrict, int, size_t);
-void* memchr(const void* _Nonnull, int, size_t) __attribute_pure__;
-void* memrchr(const void* _Nonnull, int, size_t) __attribute_pure__;
+void* memchr(const void* _Nonnull, int, size_t) __attribute_pure__ __overloadable
+ __RENAME_CLANG(memchr);
+void* memrchr(const void* _Nonnull, int, size_t) __attribute_pure__ __overloadable
+ __RENAME_CLANG(memrchr);
int memcmp(const void* _Nonnull, const void* _Nonnull, size_t) __attribute_pure__;
-void* memcpy(void* _Nonnull __restrict, const void* _Nonnull __restrict, size_t);
+void* memcpy(void* _Nonnull __restrict, const void* _Nonnull __restrict, size_t)
+ __overloadable __RENAME_CLANG(memcpy);
#if defined(__USE_GNU)
void* mempcpy(void* _Nonnull __restrict, const void* _Nonnull __restrict, size_t) __INTRODUCED_IN(23);
#endif
-void* memmove(void* _Nonnull, const void* _Nonnull, size_t);
-void* memset(void* _Nonnull, int, size_t);
+void* memmove(void* _Nonnull, const void* _Nonnull, size_t) __overloadable
+ __RENAME_CLANG(memmove);
+void* memset(void* _Nonnull, int, size_t) __overloadable __RENAME_CLANG(memset);
void* memmem(const void* _Nonnull, size_t, const void* _Nonnull, size_t) __attribute_pure__;
-char* strchr(const char* _Nonnull, int) __attribute_pure__;
+char* strchr(const char* _Nonnull, int) __attribute_pure__ __overloadable
+ __RENAME_CLANG(strchr);
char* __strchr_chk(const char* _Nonnull, int, size_t) __INTRODUCED_IN(18);
#if defined(__USE_GNU)
#if defined(__cplusplus)
@@ -69,16 +74,21 @@
#endif
#endif
-char* strrchr(const char* _Nonnull, int) __attribute_pure__;
+char* strrchr(const char* _Nonnull, int) __attribute_pure__ __overloadable
+ __RENAME_CLANG(strrchr);
char* __strrchr_chk(const char* _Nonnull, int, size_t) __INTRODUCED_IN(18);
-size_t strlen(const char* _Nonnull) __attribute_pure__;
+size_t strlen(const char* _Nonnull) __attribute_pure__ __overloadable
+ __RENAME_CLANG(strlen);
size_t __strlen_chk(const char* _Nonnull, size_t) __INTRODUCED_IN(17);
-int strcmp(const char* _Nonnull, const char* _Nonnull) __attribute_pure__;
-char* stpcpy(char* _Nonnull __restrict, const char* _Nonnull__restrict) __INTRODUCED_IN(21);
-char* strcpy(char* _Nonnull __restrict, const char* _Nonnull __restrict);
-char* strcat(char* _Nonnull __restrict, const char* _Nonnull __restrict);
+int strcmp(const char* _Nonnull, const char* _Nonnull) __attribute_pure__;
+char* stpcpy(char* _Nonnull __restrict, const char* _Nonnull __restrict)
+ __overloadable __RENAME_CLANG(stpcpy) __INTRODUCED_IN(21);
+char* strcpy(char* _Nonnull __restrict, const char* _Nonnull __restrict)
+ __overloadable __RENAME_CLANG(strcpy);
+char* strcat(char* _Nonnull __restrict, const char* _Nonnull __restrict)
+ __overloadable __RENAME_CLANG(strcat);
char* strdup(const char* _Nonnull);
char* strstr(const char* _Nonnull, const char* _Nonnull) __attribute_pure__;
@@ -95,14 +105,19 @@
#endif
size_t strnlen(const char* _Nonnull, size_t) __attribute_pure__;
-char* strncat(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t);
+char* strncat(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t)
+ __overloadable __RENAME_CLANG(strncat);
char* strndup(const char* _Nonnull, size_t);
int strncmp(const char* _Nonnull, const char* _Nonnull, size_t) __attribute_pure__;
-char* stpncpy(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t) __INTRODUCED_IN(21);
-char* strncpy(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t);
+char* stpncpy(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t)
+ __overloadable __RENAME_CLANG(stpncpy) __INTRODUCED_IN(21);
+char* strncpy(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t)
+ __overloadable __RENAME_CLANG(strncpy);
-size_t strlcat(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t);
-size_t strlcpy(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t);
+size_t strlcat(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t)
+ __overloadable __RENAME_CLANG(strlcat);
+size_t strlcpy(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t)
+ __overloadable __RENAME_CLANG(strlcpy);
size_t strcspn(const char* _Nonnull, const char* _Nonnull) __attribute_pure__;
char* strpbrk(const char* _Nonnull, const char* _Nonnull) __attribute_pure__;
@@ -135,29 +150,287 @@
#endif
void* __memchr_chk(const void* _Nonnull, int, size_t, size_t) __INTRODUCED_IN(23);
-__errordecl(__memchr_buf_size_error, "memchr called with size bigger than buffer");
-
void* __memrchr_chk(const void* _Nonnull, int, size_t, size_t) __INTRODUCED_IN(23);
-__errordecl(__memrchr_buf_size_error, "memrchr called with size bigger than buffer");
-void* __memrchr_real(const void* _Nonnull, int, size_t) __RENAME(memrchr);
-
char* __stpncpy_chk2(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t, size_t, size_t)
__INTRODUCED_IN(21);
char* __strncpy_chk2(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t, size_t, size_t)
__INTRODUCED_IN(21);
-size_t __strlcpy_real(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t) __RENAME(strlcpy);
size_t __strlcpy_chk(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t, size_t) __INTRODUCED_IN(17);
-size_t __strlcat_real(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t) __RENAME(strlcat);
size_t __strlcat_chk(char* _Nonnull __restrict, const char* _Nonnull __restrict, size_t, size_t) __INTRODUCED_IN(17);
+/* Only used with FORTIFY, but some headers that need it undef FORTIFY, so we
+ * have the definition out here.
+ */
+struct __bionic_zero_size_is_okay_t {};
+
#if defined(__BIONIC_FORTIFY)
+// These can share their implementation between gcc and clang with minimal
+// trickery...
+#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
+__BIONIC_FORTIFY_INLINE
+void* memcpy(void* _Nonnull __restrict const dst __pass_object_size,
+ const void* _Nonnull __restrict src, size_t copy_amount) __overloadable {
+ return __builtin___memcpy_chk(dst, src, copy_amount, __bos0(dst));
+}
+
+__BIONIC_FORTIFY_INLINE
+void* memmove(void* const _Nonnull dst __pass_object_size,
+ const void* _Nonnull src, size_t len) __overloadable {
+ return __builtin___memmove_chk(dst, src, len, __bos0(dst));
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_L__
+__BIONIC_FORTIFY_INLINE
+char* stpcpy(char* _Nonnull __restrict const dst __pass_object_size,
+ const char* _Nonnull __restrict src) __overloadable {
+ return __builtin___stpcpy_chk(dst, src, __bos(dst));
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_L__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
+__BIONIC_FORTIFY_INLINE
+char* strcpy(char* _Nonnull __restrict const dst __pass_object_size,
+ const char* _Nonnull __restrict src) __overloadable {
+ return __builtin___strcpy_chk(dst, src, __bos(dst));
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
+
+__BIONIC_FORTIFY_INLINE
+char* strcat(char* _Nonnull __restrict const dst __pass_object_size,
+ const char* _Nonnull __restrict src) __overloadable {
+ return __builtin___strcat_chk(dst, src, __bos(dst));
+}
+
+__BIONIC_FORTIFY_INLINE
+char* strncat(char* const _Nonnull __restrict dst __pass_object_size,
+ const char* _Nonnull __restrict src, size_t n) __overloadable {
+ return __builtin___strncat_chk(dst, src, n, __bos(dst));
+}
+
+__BIONIC_FORTIFY_INLINE
+void* memset(void* const _Nonnull s __pass_object_size, int c, size_t n)
+ __overloadable {
+ return __builtin___memset_chk(s, c, n, __bos0(s));
+}
+
+
+#if defined(__clang__)
+
+#define __error_if_overflows_dst(name, dst, n, what) \
+ __enable_if(__bos0(dst) != __BIONIC_FORTIFY_UNKNOWN_SIZE && \
+ __bos0(dst) < (n), "selected when the buffer is too small") \
+ __errorattr(#name " called with " what " bigger than buffer")
+
+/*
+ * N.B. _Nonnull isn't necessary on params, since these functions just emit
+ * errors.
+ */
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+void* memcpy(void* dst, const void* src, size_t copy_amount) __overloadable
+ __error_if_overflows_dst(memcpy, dst, copy_amount, "size");
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+void* memmove(void *dst, const void* src, size_t len) __overloadable
+ __error_if_overflows_dst(memmove, dst, len, "size");
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+void* memset(void* s, int c, size_t n) __overloadable
+ __error_if_overflows_dst(memset, s, n, "size");
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+char* stpcpy(char* dst, const char* src) __overloadable
+ __error_if_overflows_dst(stpcpy, dst, __builtin_strlen(src), "string");
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+char* strcpy(char* dst, const char* src) __overloadable
+ __error_if_overflows_dst(strcpy, dst, __builtin_strlen(src), "string");
#if __ANDROID_API__ >= __ANDROID_API_M__
__BIONIC_FORTIFY_INLINE
-void* memchr(const void* s, int c, size_t n) {
+void* memchr(const void* const _Nonnull s __pass_object_size, int c, size_t n)
+ __overloadable {
size_t bos = __bos(s);
-#if !defined(__clang__)
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __builtin_memchr(s, c, n);
+ }
+
+ return __memchr_chk(s, c, n, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+void* memrchr(const void* const _Nonnull s __pass_object_size, int c, size_t n)
+ __overloadable {
+ size_t bos = __bos(s);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(memrchr)(s, c, n);
+ }
+
+ return __memrchr_chk(s, c, n, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_M__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_L__
+__BIONIC_FORTIFY_INLINE
+char* stpncpy(char* __restrict const _Nonnull dst __pass_object_size,
+ const char* __restrict const _Nonnull src __pass_object_size,
+ size_t n) __overloadable {
+ size_t bos_dst = __bos(dst);
+ size_t bos_src = __bos(src);
+
+ /* Ignore dst size checks; they're handled in strncpy_chk */
+ if (bos_src == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __builtin___stpncpy_chk(dst, src, n, bos_dst);
+ }
+
+ return __stpncpy_chk2(dst, src, n, bos_dst, bos_src);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_L__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
+__BIONIC_FORTIFY_INLINE
+char* strncpy(char* __restrict const _Nonnull dst __pass_object_size,
+ const char* __restrict const _Nonnull src __pass_object_size,
+ size_t n) __overloadable {
+ size_t bos_dst = __bos(dst);
+ size_t bos_src = __bos(src);
+
+ /* Ignore dst size checks; they're handled in strncpy_chk */
+ if (bos_src == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __builtin___strncpy_chk(dst, src, n, bos_dst);
+ }
+
+ return __strncpy_chk2(dst, src, n, bos_dst, bos_src);
+}
+
+__BIONIC_FORTIFY_INLINE
+size_t strlcpy(char* const _Nonnull __restrict dst __pass_object_size,
+ const char *_Nonnull __restrict src, size_t size) __overloadable {
+ size_t bos = __bos(dst);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(strlcpy)(dst, src, size);
+ }
+
+ return __strlcpy_chk(dst, src, size, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+size_t strlcat(char* const _Nonnull __restrict dst __pass_object_size,
+ const char* _Nonnull __restrict src, size_t size) __overloadable {
+ size_t bos = __bos(dst);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(strlcat)(dst, src, size);
+ }
+
+ return __strlcat_chk(dst, src, size, bos);
+}
+
+/*
+ * If we can evaluate the size of s at compile-time, just call __builtin_strlen
+ * on it directly. This makes it way easier for compilers to fold things like
+ * strlen("Foo") into a constant, as users would expect. -1ULL is chosen simply
+ * because it's large.
+ */
+__BIONIC_FORTIFY_INLINE
+size_t strlen(const char* const _Nonnull s __pass_object_size)
+ __overloadable __enable_if(__builtin_strlen(s) != -1ULL,
+ "enabled if s is a known good string.") {
+ return __builtin_strlen(s);
+}
+
+__BIONIC_FORTIFY_INLINE
+size_t strlen(const char* const _Nonnull s __pass_object_size_n(0))
+ __overloadable {
+ size_t bos = __bos0(s);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __builtin_strlen(s);
+ }
+
+ // return __builtin_strlen(s);
+ return __strlen_chk(s, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_J_MR2__
+__BIONIC_FORTIFY_INLINE
+char* strchr(const char* const _Nonnull s __pass_object_size_n(0), int c)
+ __overloadable {
+ size_t bos = __bos0(s);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __builtin_strchr(s, c);
+ }
+
+ // return __builtin_strchr(s, c);
+ return __strchr_chk(s, c, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+char* strrchr(const char* const _Nonnull s __pass_object_size, int c)
+ __overloadable {
+ size_t bos = __bos(s);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __builtin_strrchr(s, c);
+ }
+
+ return __strrchr_chk(s, c, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR2__ */
+
+/* In *many* cases, memset(foo, sizeof(foo), 0) is a mistake where the user has
+ * flipped the size + value arguments. However, there may be cases (e.g. with
+ * macros) where it's okay for the size to fold to zero. We should warn on this,
+ * but we should also provide a FORTIFY'ed escape hatch.
+ */
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+void* memset(void* _Nonnull s, int c, size_t n,
+ struct __bionic_zero_size_is_okay_t ok)
+ __overloadable
+ __error_if_overflows_dst(memset, s, n, "size");
+
+__BIONIC_FORTIFY_INLINE
+void* memset(void* const _Nonnull s __pass_object_size, int c, size_t n,
+ struct __bionic_zero_size_is_okay_t ok __attribute__((unused)))
+ __overloadable {
+ return __builtin___memset_chk(s, c, n, __bos0(s));
+}
+
+extern struct __bionic_zero_size_is_okay_t __bionic_zero_size_is_okay;
+/* We verify that `c` is non-zero, because as pointless as memset(foo, 0, 0) is,
+ * flipping size + count will do nothing.
+ */
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+void* memset(void* _Nonnull s, int c, size_t n) __overloadable
+ __enable_if(c && !n, "selected when we'll set zero bytes")
+ __RENAME_CLANG(memset)
+ __warnattr_real("will set 0 bytes; maybe the arguments got flipped? "
+ "(Add __bionic_zero_size_is_okay as a fourth argument "
+ "to silence this.)");
+
+#undef __error_zero_size
+#undef __error_if_overflows_dst
+#else // defined(__clang__)
+extern char* __strncpy_real(char* __restrict, const char*, size_t) __RENAME(strcpy);
+extern void* __memrchr_real(const void*, int, size_t) __RENAME(memrchr);
+extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t)
+ __RENAME(strlcpy);
+extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t)
+ __RENAME(strlcat);
+
+__errordecl(__memchr_buf_size_error, "memchr called with size bigger than buffer");
+__errordecl(__memrchr_buf_size_error, "memrchr called with size bigger than buffer");
+
+#if __ANDROID_API__ >= __ANDROID_API_M__
+__BIONIC_FORTIFY_INLINE
+void* memchr(const void *_Nonnull s __pass_object_size, int c, size_t n) {
+ size_t bos = __bos(s);
+
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __builtin_memchr(s, c, n);
}
@@ -169,7 +442,6 @@
if (__builtin_constant_p(n) && (n <= bos)) {
return __builtin_memchr(s, c, n);
}
-#endif
return __memchr_chk(s, c, n, bos);
}
@@ -178,7 +450,6 @@
void* memrchr(const void* s, int c, size_t n) {
size_t bos = __bos(s);
-#if !defined(__clang__)
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __memrchr_real(s, c, n);
}
@@ -190,38 +461,11 @@
if (__builtin_constant_p(n) && (n <= bos)) {
return __memrchr_real(s, c, n);
}
-#endif
return __memrchr_chk(s, c, n, bos);
}
#endif /* __ANDROID_API__ >= __ANDROID_API_M__ */
-#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
-__BIONIC_FORTIFY_INLINE
-void* memcpy(void* _Nonnull __restrict dst, const void* _Nonnull __restrict src, size_t copy_amount) {
- return __builtin___memcpy_chk(dst, src, copy_amount, __bos0(dst));
-}
-
-__BIONIC_FORTIFY_INLINE
-void* memmove(void* _Nonnull dst, const void* _Nonnull src, size_t len) {
- return __builtin___memmove_chk(dst, src, len, __bos0(dst));
-}
-#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
-
-#if __ANDROID_API__ >= __ANDROID_API_L__
-__BIONIC_FORTIFY_INLINE
-char* stpcpy(char* _Nonnull __restrict dst, const char* _Nonnull __restrict src) {
- return __builtin___stpcpy_chk(dst, src, __bos(dst));
-}
-#endif /* __ANDROID_API__ >= __ANDROID_API_L__ */
-
-#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
-__BIONIC_FORTIFY_INLINE
-char* strcpy(char* _Nonnull __restrict dst, const char* _Nonnull __restrict src) {
- return __builtin___strcpy_chk(dst, src, __bos(dst));
-}
-#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
-
#if __ANDROID_API__ >= __ANDROID_API_L__
__BIONIC_FORTIFY_INLINE
char* stpncpy(char* _Nonnull __restrict dst, const char* _Nonnull __restrict src, size_t n) {
@@ -250,7 +494,7 @@
size_t bos_src = __bos(src);
if (bos_src == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
- return __builtin___strncpy_chk(dst, src, n, bos_dst);
+ return __strncpy_real(dst, src, n);
}
if (__builtin_constant_p(n) && (n <= bos_src)) {
@@ -268,25 +512,10 @@
#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
__BIONIC_FORTIFY_INLINE
-char* strcat(char* _Nonnull __restrict dst, const char* _Nonnull __restrict src) {
- return __builtin___strcat_chk(dst, src, __bos(dst));
-}
-
-__BIONIC_FORTIFY_INLINE
-char *strncat(char* _Nonnull __restrict dst, const char* _Nonnull __restrict src, size_t n) {
- return __builtin___strncat_chk(dst, src, n, __bos(dst));
-}
-
-__BIONIC_FORTIFY_INLINE
-void* memset(void* _Nonnull s, int c, size_t n) {
- return __builtin___memset_chk(s, c, n, __bos0(s));
-}
-
-__BIONIC_FORTIFY_INLINE
-size_t strlcpy(char* _Nonnull __restrict dst, const char* _Nonnull __restrict src, size_t size) {
+size_t strlcpy(char* _Nonnull __restrict dst __pass_object_size,
+ const char* _Nonnull __restrict src, size_t size) {
size_t bos = __bos(dst);
-#if !defined(__clang__)
// Compiler doesn't know destination size. Don't call __strlcpy_chk
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __strlcpy_real(dst, src, size);
@@ -297,17 +526,14 @@
if (__builtin_constant_p(size) && (size <= bos)) {
return __strlcpy_real(dst, src, size);
}
-#endif /* !defined(__clang__) */
return __strlcpy_chk(dst, src, size, bos);
}
-
__BIONIC_FORTIFY_INLINE
size_t strlcat(char* _Nonnull __restrict dst, const char* _Nonnull __restrict src, size_t size) {
size_t bos = __bos(dst);
-#if !defined(__clang__)
// Compiler doesn't know destination size. Don't call __strlcat_chk
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __strlcat_real(dst, src, size);
@@ -318,16 +544,14 @@
if (__builtin_constant_p(size) && (size <= bos)) {
return __strlcat_real(dst, src, size);
}
-#endif /* !defined(__clang__) */
return __strlcat_chk(dst, src, size, bos);
}
__BIONIC_FORTIFY_INLINE
-size_t strlen(const char* _Nonnull s) {
+size_t strlen(const char* _Nonnull s) __overloadable {
size_t bos = __bos(s);
-#if !defined(__clang__)
// Compiler doesn't know destination size. Don't call __strlen_chk
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __builtin_strlen(s);
@@ -337,7 +561,6 @@
if (__builtin_constant_p(slen)) {
return slen;
}
-#endif /* !defined(__clang__) */
return __strlen_chk(s, bos);
}
@@ -348,7 +571,6 @@
char* strchr(const char* _Nonnull s, int c) {
size_t bos = __bos(s);
-#if !defined(__clang__)
// Compiler doesn't know destination size. Don't call __strchr_chk
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __builtin_strchr(s, c);
@@ -358,7 +580,6 @@
if (__builtin_constant_p(slen) && (slen < bos)) {
return __builtin_strchr(s, c);
}
-#endif /* !defined(__clang__) */
return __strchr_chk(s, c, bos);
}
@@ -367,7 +588,6 @@
char* strrchr(const char* _Nonnull s, int c) {
size_t bos = __bos(s);
-#if !defined(__clang__)
// Compiler doesn't know destination size. Don't call __strrchr_chk
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __builtin_strrchr(s, c);
@@ -377,12 +597,11 @@
if (__builtin_constant_p(slen) && (slen < bos)) {
return __builtin_strrchr(s, c);
}
-#endif /* !defined(__clang__) */
return __strrchr_chk(s, c, bos);
}
#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR2__ */
-
+#endif /* defined(__clang__) */
#endif /* defined(__BIONIC_FORTIFY) */
#if defined(__clang__)
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 63e782e..9492d92 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -181,12 +181,29 @@
#define __wur __attribute__((__warn_unused_result__))
#ifdef __clang__
-#define __errorattr(msg) __attribute__((unavailable(msg)))
+# define __errorattr(msg) __attribute__((unavailable(msg)))
+# define __warnattr(msg) __attribute__((deprecated(msg)))
+# define __warnattr_real(msg) __attribute__((deprecated(msg)))
+# define __enable_if(cond, msg) __attribute__((enable_if(cond, msg)))
#else
-#define __errorattr(msg) __attribute__((__error__(msg)))
+# define __errorattr(msg) __attribute__((__error__(msg)))
+# define __warnattr(msg) __attribute__((__warning__(msg)))
+# define __warnattr_real __warnattr
+/* enable_if doesn't exist on other compilers; give an error if it's used. */
+
+/* errordecls really don't work as well in clang as they do in GCC. */
+# define __errordecl(name, msg) extern void name(void) __errorattr(msg)
#endif
-#define __errordecl(name, msg) extern void name(void) __errorattr(msg)
+#if defined(ANDROID_STRICT)
+/*
+ * For things that are sketchy, but not necessarily an error. FIXME: Enable
+ * this.
+ */
+# define __warnattr_strict(msg) /* __warnattr(msg) */
+#else
+# define __warnattr_strict(msg)
+#endif
/*
* Some BSD source needs these macros.
@@ -242,21 +259,59 @@
* See
* http://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html for details.
*/
+
+#define __BIONIC_FORTIFY_UNKNOWN_SIZE ((size_t) -1)
+
#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0
# define __BIONIC_FORTIFY 1
# if _FORTIFY_SOURCE == 2
-# define __bos(s) __builtin_object_size((s), 1)
+# define __bos_level 1
# else
-# define __bos(s) __builtin_object_size((s), 0)
+# define __bos_level 0
# endif
-# define __bos0(s) __builtin_object_size((s), 0)
+# define __bosn(s, n) __builtin_object_size((s), (n))
+# define __bos(s) __bosn((s), __bos_level)
+# define __bos0(s) __bosn((s), 0)
# if defined(__clang__)
-# define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline))
+# define __pass_object_size_n(n) __attribute__((pass_object_size(n)))
+/*
+ * FORTIFY'ed functions all have either enable_if or pass_object_size, which
+ * makes taking their address impossible. Saying (&read)(foo, bar, baz); will
+ * therefore call the unFORTIFYed version of read.
+ */
+# define __call_bypassing_fortify(fn) (&fn)
+/*
+ * Because clang-FORTIFY uses overloads, we can't mark functions as `extern
+ * inline` without making them available externally.
+ */
+# define __BIONIC_FORTIFY_INLINE static __inline__ __always_inline
+/* Error functions don't have bodies, so they can just be static. */
+# define __BIONIC_ERROR_FUNCTION_VISIBILITY static
# else
+/*
+ * Where they can, GCC and clang-style FORTIFY share implementations.
+ * So, make these nops in GCC.
+ */
+# define __pass_object_size_n(n)
+# define __call_bypassing_fortify(fn) (fn)
+/* __BIONIC_FORTIFY_NONSTATIC_INLINE is pointless in GCC's FORTIFY */
# define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline)) __attribute__((__artificial__))
# endif
+# define __pass_object_size __pass_object_size_n(__bos_level)
#endif
-#define __BIONIC_FORTIFY_UNKNOWN_SIZE __BIONIC_CAST(static_cast, size_t, -1)
+
+/* Used to support clangisms with FORTIFY. This isn't in the FORTIFY section
+ * because these change how symbols are emitted. The linker must be kept happy.
+ */
+#ifdef __clang__
+# define __overloadable __attribute__((overloadable))
+// Don't use __RENAME directly because on gcc, this could result in a number of
+// unnecessary renames.
+# define __RENAME_CLANG(x) __RENAME(x)
+#else
+# define __overloadable
+# define __RENAME_CLANG(x)
+#endif
/* Used to tag non-static symbols that are private and never exposed by the shared library. */
#define __LIBC_HIDDEN__ __attribute__((visibility("hidden")))
@@ -303,5 +358,15 @@
* build working.
*/
#define __NDK_FPABI__
+#if defined(__clang__)
+/*
+ * Used when we need to check for overflow when multiplying x and y. This
+ * should only be used where __size_mul_overflow can not work, because it makes
+ * assumptions that __size_mul_overflow doesn't (x and y are positive, ...),
+ * *and* doesn't make use of compiler intrinsics, so it's probably slower than
+ * __size_mul_overflow.
+ */
+#define __unsafe_check_mul_overflow(x, y) ((__SIZE_TYPE__)-1 / (x) < (y))
+#endif
#endif /* !_SYS_CDEFS_H_ */
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index f9f6764..997191e 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -317,25 +317,59 @@
__socketcall int socket(int, int, int);
__socketcall int socketpair(int, int, int, int*);
-ssize_t recv(int, void*, size_t, int);
+ssize_t recv(int, void*, size_t, int) __overloadable __RENAME_CLANG(recv);
ssize_t send(int, const void*, size_t, int);
__socketcall ssize_t sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t);
-__socketcall ssize_t recvfrom(int, void*, size_t, int, struct sockaddr*, socklen_t*);
+__socketcall ssize_t recvfrom(int, void*, size_t, int, struct sockaddr*,
+ socklen_t*) __overloadable __RENAME_CLANG(recvfrom);
-__errordecl(__recvfrom_error, "recvfrom called with size bigger than buffer");
-ssize_t __recvfrom_chk(int, void*, size_t, size_t, int, struct sockaddr*, socklen_t*)
- __INTRODUCED_IN(21);
-ssize_t __recvfrom_real(int, void*, size_t, int, struct sockaddr*, socklen_t*) __RENAME(recvfrom);
+ssize_t __recvfrom_chk(int, void*, size_t, size_t, int, struct sockaddr*,
+ socklen_t*) __INTRODUCED_IN(21);
#if defined(__BIONIC_FORTIFY)
+#if defined(__clang__)
#if __ANDROID_API__ >= __ANDROID_API_N__
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t recvfrom(int fd, void* const buf __pass_object_size, size_t len,
+ int flags, struct sockaddr* src_addr, socklen_t* addr_len)
+ __overloadable
+ __enable_if(__bos(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(buf) < len, "selected when the buffer is too small")
+ __errorattr("size is larger than the destination buffer");
+
__BIONIC_FORTIFY_INLINE
-ssize_t recvfrom(int fd, void* buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addr_len) {
+ssize_t recvfrom(int fd, void* const buf __pass_object_size, size_t len,
+ int flags, struct sockaddr* src_addr, socklen_t* addr_len)
+ __overloadable {
size_t bos = __bos0(buf);
-#if !defined(__clang__)
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(recvfrom)(fd, buf, len, flags, src_addr,
+ addr_len);
+ }
+
+ return __recvfrom_chk(fd, buf, len, bos, flags, src_addr, addr_len);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
+
+__BIONIC_FORTIFY_INLINE
+ssize_t recv(int socket, void* const buf __pass_object_size, size_t len,
+ int flags) __overloadable {
+ return recvfrom(socket, buf, len, flags, NULL, 0);
+}
+
+#else /* defined(__clang__) */
+ssize_t __recvfrom_real(int, void*, size_t, int, struct sockaddr*, socklen_t*) __RENAME(recvfrom);
+__errordecl(__recvfrom_error, "recvfrom called with size bigger than buffer");
+
+#if __ANDROID_API__ >= __ANDROID_API_N__
+__BIONIC_FORTIFY_INLINE
+ssize_t recvfrom(int fd, void* buf, size_t len, int flags,
+ struct sockaddr* src_addr, socklen_t* addr_len) {
+ size_t bos = __bos0(buf);
+
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __recvfrom_real(fd, buf, len, flags, src_addr, addr_len);
}
@@ -347,7 +381,6 @@
if (__builtin_constant_p(len) && (len > bos)) {
__recvfrom_error();
}
-#endif
return __recvfrom_chk(fd, buf, len, bos, flags, src_addr, addr_len);
}
@@ -358,6 +391,8 @@
return recvfrom(socket, buf, len, flags, NULL, 0);
}
+#endif /* defined(__clang__) */
+
#endif /* __BIONIC_FORTIFY */
#undef __socketcall
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index f961cf8..f8d854d 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -161,29 +161,52 @@
int stat64(const char*, struct stat64*) __INTRODUCED_IN(21);
int mknod(const char*, mode_t, dev_t);
-mode_t umask(mode_t);
+mode_t umask(mode_t) __overloadable __RENAME_CLANG(umask);
mode_t __umask_chk(mode_t) __INTRODUCED_IN(18);
-mode_t __umask_real(mode_t) __RENAME(umask);
-__errordecl(__umask_invalid_mode, "umask called with invalid mode");
#if defined(__BIONIC_FORTIFY)
+#define __umask_invalid_mode_str "umask called with invalid mode"
+
+#if defined(__clang__)
+
+#if __ANDROID_API__ >= __ANDROID_API_J_MR2__
+/*
+ * Abuse enable_if to make these be seen as overloads of umask, rather than
+ * definitions.
+ */
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+mode_t umask(mode_t mode) __overloadable
+ __enable_if(1, "")
+ __enable_if(mode & ~0777, __umask_invalid_mode_str)
+ __errorattr(__umask_invalid_mode_str);
+
+__BIONIC_FORTIFY_INLINE
+mode_t umask(mode_t mode) __enable_if(1, "") __overloadable {
+ return __umask_chk(mode);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR2__ */
+
+#else /* defined(__clang__) */
+__errordecl(__umask_invalid_mode, __umask_invalid_mode_str);
+extern mode_t __umask_real(mode_t) __RENAME(umask);
#if __ANDROID_API__ >= __ANDROID_API_J_MR2__
__BIONIC_FORTIFY_INLINE
mode_t umask(mode_t mode) {
-#if !defined(__clang__)
if (__builtin_constant_p(mode)) {
if ((mode & 0777) != mode) {
__umask_invalid_mode();
}
return __umask_real(mode);
}
-#endif
return __umask_chk(mode);
}
#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR2__ */
+#endif /* defined(__clang__) */
+#undef __umask_invalid_mode_str
+
#endif /* defined(__BIONIC_FORTIFY) */
#if __ANDROID_API__ >= __ANDROID_API_L__
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index cbdb438..b3f8c11 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -139,21 +139,25 @@
int chroot(const char* __path);
int symlink(const char* __oldpath, const char* __newpath);
int symlinkat(const char* __oldpath, int __newdirfd, const char* __newpath) __INTRODUCED_IN(21);
-ssize_t readlink(const char* __path, char* __buf, size_t __bufsiz);
+ssize_t readlink(const char* __path, char* __buf, size_t __bufsiz)
+ __overloadable __RENAME_CLANG(readlink);
ssize_t readlinkat(int __dirfd, const char* __path, char* __buf,
- size_t __bufsiz) __INTRODUCED_IN(21);
+ size_t __bufsiz)
+ __INTRODUCED_IN(21) __overloadable __RENAME_CLANG(readlinkat);
int chown(const char* __path, uid_t __owner, gid_t __group);
int fchown(int __fd, uid_t __owner, gid_t __group);
int fchownat(int __dirfd, 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);
+char* getcwd(char* __buf, size_t __size) __overloadable __RENAME_CLANG(getcwd);
void sync(void);
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);
+ssize_t read(int __fd, void* __buf, size_t __count) __overloadable
+ __RENAME_CLANG(read);
+ssize_t write(int __fd, const void* __buf, size_t __count) __overloadable
+ __RENAME_CLANG(write);
int dup(int __oldfd);
int dup2(int __oldfd, int __newfd);
@@ -171,22 +175,25 @@
#if defined(__USE_FILE_OFFSET64) && __ANDROID_API__ >= __ANDROID_API_L__
int truncate(const char* __path, off_t __length) __RENAME(truncate64) __INTRODUCED_IN(21);
-ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset) __RENAME(pread64)
- __INTRODUCED_IN(12);
+ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset)
+ __overloadable __RENAME(pread64) __INTRODUCED_IN(12);
ssize_t pwrite(int __fd, const void* __buf, size_t __count, off_t __offset)
- __RENAME(pwrite64) __INTRODUCED_IN(12);
+ __overloadable __RENAME(pwrite64) __INTRODUCED_IN(12);
int ftruncate(int __fd, off_t __length) __RENAME(ftruncate64) __INTRODUCED_IN(12);
#else
int truncate(const char* __path, off_t __length);
-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* __buf, size_t __count, off_t __offset)
+ __overloadable __RENAME_CLANG(pread);
+ssize_t pwrite(int __fd, const void* __buf, size_t __count, off_t __offset)
+ __overloadable __RENAME_CLANG(pwrite);
int ftruncate(int __fd, off_t __length);
#endif
int truncate64(const char* __path, off64_t __length) __INTRODUCED_IN(21);
-ssize_t pread64(int __fd, void* __buf, size_t __count, off64_t __offset) __INTRODUCED_IN(12);
+ssize_t pread64(int __fd, void* __buf, size_t __count, off64_t __offset)
+ __INTRODUCED_IN(12) __overloadable __RENAME_CLANG(pread64);
ssize_t pwrite64(int __fd, const void* __buf, size_t __count, off64_t __offset)
- __INTRODUCED_IN(12);
+ __INTRODUCED_IN(12) __overloadable __RENAME_CLANG(pwrite64);
int ftruncate64(int __fd, off64_t __length) __INTRODUCED_IN(12);
int pause(void);
@@ -236,70 +243,288 @@
/* TODO(unified-headers): Factor out all the FORTIFY features. */
char* __getcwd_chk(char*, size_t, size_t) __INTRODUCED_IN(24);
-__errordecl(__getcwd_dest_size_error, "getcwd called with size bigger than destination");
-char* __getcwd_real(char*, size_t) __RENAME(getcwd);
ssize_t __pread_chk(int, void*, size_t, off_t, size_t) __INTRODUCED_IN(23);
-__errordecl(__pread_dest_size_error, "pread called with size bigger than destination");
-__errordecl(__pread_count_toobig_error, "pread called with count > SSIZE_MAX");
ssize_t __pread_real(int, void*, size_t, off_t) __RENAME(pread);
ssize_t __pread64_chk(int, void*, size_t, off64_t, size_t) __INTRODUCED_IN(23);
-__errordecl(__pread64_dest_size_error, "pread64 called with size bigger than destination");
-__errordecl(__pread64_count_toobig_error, "pread64 called with count > SSIZE_MAX");
ssize_t __pread64_real(int, void*, size_t, off64_t) __RENAME(pread64) __INTRODUCED_IN(12);
ssize_t __pwrite_chk(int, const void*, size_t, off_t, size_t) __INTRODUCED_IN(24);
-__errordecl(__pwrite_dest_size_error, "pwrite called with size bigger than destination");
-__errordecl(__pwrite_count_toobig_error, "pwrite called with count > SSIZE_MAX");
ssize_t __pwrite_real(int, const void*, size_t, off_t) __RENAME(pwrite);
ssize_t __pwrite64_chk(int, const void*, size_t, off64_t, size_t) __INTRODUCED_IN(24);
-__errordecl(__pwrite64_dest_size_error, "pwrite64 called with size bigger than destination");
-__errordecl(__pwrite64_count_toobig_error, "pwrite64 called with count > SSIZE_MAX");
-ssize_t __pwrite64_real(int, const void*, size_t, off64_t) __RENAME(pwrite64) __INTRODUCED_IN(12);
+ssize_t __pwrite64_real(int, const void*, size_t, off64_t) __RENAME(pwrite64)
+ __INTRODUCED_IN(12);
ssize_t __read_chk(int, void*, size_t, size_t) __INTRODUCED_IN(21);
-__errordecl(__read_dest_size_error, "read called with size bigger than destination");
-__errordecl(__read_count_toobig_error, "read called with count > SSIZE_MAX");
-ssize_t __read_real(int, void*, size_t) __RENAME(read);
-
ssize_t __write_chk(int, const void*, size_t, size_t) __INTRODUCED_IN(24);
-__errordecl(__write_dest_size_error, "write called with size bigger than destination");
-__errordecl(__write_count_toobig_error, "write called with count > SSIZE_MAX");
-ssize_t __write_real(int, const void*, size_t) __RENAME(write);
-
ssize_t __readlink_chk(const char*, char*, size_t, size_t) __INTRODUCED_IN(23);
-__errordecl(__readlink_dest_size_error, "readlink called with size bigger than destination");
-__errordecl(__readlink_size_toobig_error, "readlink called with size > SSIZE_MAX");
-ssize_t __readlink_real(const char*, char*, size_t) __RENAME(readlink);
-
ssize_t __readlinkat_chk(int dirfd, const char*, char*, size_t, size_t) __INTRODUCED_IN(23);
-__errordecl(__readlinkat_dest_size_error, "readlinkat called with size bigger than destination");
-__errordecl(__readlinkat_size_toobig_error, "readlinkat called with size > SSIZE_MAX");
-ssize_t __readlinkat_real(int dirfd, const char*, char*, size_t) __RENAME(readlinkat) __INTRODUCED_IN(21);
int getdomainname(char*, size_t) __INTRODUCED_IN_FUTURE;
int setdomainname(const char*, size_t) __INTRODUCED_IN_FUTURE;
#if defined(__BIONIC_FORTIFY)
-#if __ANDROID_API__ >= __ANDROID_API_N__
-__BIONIC_FORTIFY_INLINE
-char* getcwd(char* buf, size_t size) {
- size_t bos = __bos(buf);
+#if defined(__USE_FILE_OFFSET64)
+#define __PREAD_PREFIX(x) __pread64_ ## x
+#define __PWRITE_PREFIX(x) __pwrite64_ ## x
+#else
+#define __PREAD_PREFIX(x) __pread_ ## x
+#define __PWRITE_PREFIX(x) __pwrite_ ## x
+#endif
#if defined(__clang__)
+#define __error_if_overflows_ssizet(what) \
+ __enable_if(what > SSIZE_MAX, #what " must be <= SSIZE_MAX") \
+ __errorattr(#what " must be <= SSIZE_MAX")
+
+#define __enable_if_no_overflow_ssizet(what) \
+ __enable_if((what) <= SSIZE_MAX, "enabled if " #what " <= SSIZE_MAX")
+
+#define __error_if_overflows_objectsize(what, objsize) \
+ __enable_if((objsize) != __BIONIC_FORTIFY_UNKNOWN_SIZE && \
+ (what) > (objsize), \
+ "'" #what "' bytes overflows the given object") \
+ __errorattr("'" #what "' bytes overflows the given object")
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+char* getcwd(char* buf, size_t size) __overloadable
+ __error_if_overflows_objectsize(size, __bos(buf));
+
+#if __ANDROID_API__ >= __ANDROID_API_N__
+__BIONIC_FORTIFY_INLINE
+char* getcwd(char* const __pass_object_size buf, size_t size) __overloadable {
+ size_t bos = __bos(buf);
+
/*
- * Work around LLVM's incorrect __builtin_object_size implementation here
- * to avoid needing the workaround in the __getcwd_chk ABI forever.
- *
- * https://llvm.org/bugs/show_bug.cgi?id=23277
+ * Clang responds bos==0 if buf==NULL
+ * (https://llvm.org/bugs/show_bug.cgi?id=23277). Given that NULL is a valid
+ * value, we need to handle that.
*/
- if (buf == NULL) {
- bos = __BIONIC_FORTIFY_UNKNOWN_SIZE;
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE || buf == NULL) {
+ return __call_bypassing_fortify(getcwd)(buf, size);
}
-#else
+
+ return __getcwd_chk(buf, size, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_M__
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t pread(int fd, void* buf, size_t count, off_t offset) __overloadable
+ __error_if_overflows_ssizet(count);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t pread(int fd, void* buf, size_t count, off_t offset) __overloadable
+ __enable_if_no_overflow_ssizet(count)
+ __error_if_overflows_objectsize(count, __bos0(buf));
+
+__BIONIC_FORTIFY_INLINE
+ssize_t pread(int fd, void* const __pass_object_size buf, size_t count,
+ off_t offset) __overloadable {
+ size_t bos = __bos0(buf);
+
+ if (count == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __PREAD_PREFIX(real)(fd, buf, count, offset);
+ }
+
+ return __PREAD_PREFIX(chk)(fd, buf, count, offset, bos);
+}
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t pread64(int fd, void* buf, size_t count, off64_t offset) __overloadable
+ __error_if_overflows_ssizet(count);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t pread64(int fd, void* buf, size_t count, off64_t offset) __overloadable
+ __enable_if_no_overflow_ssizet(count)
+ __error_if_overflows_objectsize(count, __bos0(buf));
+
+__BIONIC_FORTIFY_INLINE
+ssize_t pread64(int fd, void* const __pass_object_size buf, size_t count,
+ off64_t offset) __overloadable {
+ size_t bos = __bos0(buf);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __pread64_real(fd, buf, count, offset);
+ }
+
+ return __pread64_chk(fd, buf, count, offset, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_M__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_N__
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset)
+ __overloadable
+ __error_if_overflows_ssizet(count);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset)
+ __overloadable
+ __enable_if_no_overflow_ssizet(count)
+ __error_if_overflows_objectsize(count, __bos0(buf));
+
+__BIONIC_FORTIFY_INLINE
+ssize_t pwrite(int fd, const void* const __pass_object_size buf, size_t count,
+ off_t offset) __overloadable {
+ size_t bos = __bos0(buf);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __PWRITE_PREFIX(real)(fd, buf, count, offset);
+ }
+
+ return __PWRITE_PREFIX(chk)(fd, buf, count, offset, bos);
+}
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t pwrite64(int fd, const void* buf, size_t count, off64_t offset)
+ __overloadable
+ __error_if_overflows_ssizet(count);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t pwrite64(int fd, const void* buf, size_t count, off64_t offset)
+ __overloadable
+ __enable_if_no_overflow_ssizet(count)
+ __error_if_overflows_objectsize(count, __bos0(buf));
+
+__BIONIC_FORTIFY_INLINE
+ssize_t pwrite64(int fd, const void* const __pass_object_size buf, size_t count,
+ off64_t offset) __overloadable {
+ size_t bos = __bos0(buf);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __pwrite64_real(fd, buf, count, offset);
+ }
+
+ return __pwrite64_chk(fd, buf, count, offset, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t read(int fd, void* buf, size_t count) __overloadable
+ __error_if_overflows_ssizet(count);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t read(int fd, void* buf, size_t count) __overloadable
+ __enable_if_no_overflow_ssizet(count)
+ __error_if_overflows_objectsize(count, __bos0(buf));
+
+__BIONIC_FORTIFY_INLINE
+ssize_t read(int fd, void* const __pass_object_size buf, size_t count)
+ __overloadable {
+ size_t bos = __bos0(buf);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(read)(fd, buf, count);
+ }
+
+ return __read_chk(fd, buf, count, bos);
+}
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t write(int fd, const void* buf, size_t count) __overloadable
+ __error_if_overflows_ssizet(count);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t write(int fd, const void* buf, size_t count) __overloadable
+ __enable_if_no_overflow_ssizet(count)
+ __error_if_overflows_objectsize(count, __bos0(buf));
+
+__BIONIC_FORTIFY_INLINE
+ssize_t write(int fd, const void* const __pass_object_size buf, size_t count)
+ __overloadable {
+ size_t bos = __bos0(buf);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(write)(fd, buf, count);
+ }
+
+ return __write_chk(fd, buf, count, bos);
+}
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t readlink(const char* path, char* buf, size_t size) __overloadable
+ __error_if_overflows_ssizet(size);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t readlink(const char* path, char* buf, size_t size) __overloadable
+ __enable_if_no_overflow_ssizet(size)
+ __error_if_overflows_objectsize(size, __bos(buf));
+
+__BIONIC_FORTIFY_INLINE
+ssize_t readlink(const char* path, char* const __pass_object_size buf,
+ size_t size) __overloadable {
+ size_t bos = __bos(buf);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(readlink)(path, buf, size);
+ }
+
+ return __readlink_chk(path, buf, size, bos);
+}
+
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t readlinkat(int dirfd, const char* path, char* buf, size_t size)
+ __overloadable
+ __error_if_overflows_ssizet(size);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+ssize_t readlinkat(int dirfd, const char* path, char* buf, size_t size)
+ __overloadable
+ __enable_if_no_overflow_ssizet(size)
+ __error_if_overflows_objectsize(size, __bos(buf));
+
+__BIONIC_FORTIFY_INLINE
+ssize_t readlinkat(int dirfd, const char* path,
+ char* const __pass_object_size buf, size_t size)
+ __overloadable {
+ size_t bos = __bos(buf);
+
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(readlinkat)(dirfd, path, buf, size);
+ }
+
+ return __readlinkat_chk(dirfd, path, buf, size, bos);
+}
+
+#undef __enable_if_no_overflow_ssizet
+#undef __error_if_overflows_objectsize
+#undef __error_if_overflows_ssizet
+#else /* defined(__clang__) */
+
+char* __getcwd_real(char*, size_t) __RENAME(getcwd);
+ssize_t __read_real(int, void*, size_t) __RENAME(read);
+ssize_t __write_real(int, const void*, size_t) __RENAME(write);
+ssize_t __readlink_real(const char*, char*, size_t) __RENAME(readlink);
+ssize_t __readlinkat_real(int dirfd, const char*, char*, size_t) __RENAME(readlinkat);
+
+__errordecl(__getcwd_dest_size_error, "getcwd called with size bigger than destination");
+__errordecl(__pread_dest_size_error, "pread called with size bigger than destination");
+__errordecl(__pread_count_toobig_error, "pread called with count > SSIZE_MAX");
+__errordecl(__pread64_dest_size_error, "pread64 called with size bigger than destination");
+__errordecl(__pread64_count_toobig_error, "pread64 called with count > SSIZE_MAX");
+__errordecl(__pwrite_dest_size_error, "pwrite called with size bigger than destination");
+__errordecl(__pwrite_count_toobig_error, "pwrite called with count > SSIZE_MAX");
+__errordecl(__pwrite64_dest_size_error, "pwrite64 called with size bigger than destination");
+__errordecl(__pwrite64_count_toobig_error, "pwrite64 called with count > SSIZE_MAX");
+__errordecl(__read_dest_size_error, "read called with size bigger than destination");
+__errordecl(__read_count_toobig_error, "read called with count > SSIZE_MAX");
+__errordecl(__write_dest_size_error, "write called with size bigger than destination");
+__errordecl(__write_count_toobig_error, "write called with count > SSIZE_MAX");
+__errordecl(__readlink_dest_size_error, "readlink called with size bigger than destination");
+__errordecl(__readlink_size_toobig_error, "readlink called with size > SSIZE_MAX");
+__errordecl(__readlinkat_dest_size_error, "readlinkat called with size bigger than destination");
+__errordecl(__readlinkat_size_toobig_error, "readlinkat called with size > SSIZE_MAX");
+
+#if __ANDROID_API__ >= __ANDROID_API_N__
+__BIONIC_FORTIFY_INLINE
+char* getcwd(char* buf, size_t size) __overloadable {
+ size_t bos = __bos(buf);
+
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __getcwd_real(buf, size);
}
@@ -311,24 +536,16 @@
if (__builtin_constant_p(size) && (size <= bos)) {
return __getcwd_real(buf, size);
}
-#endif
return __getcwd_chk(buf, size, bos);
}
#endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
-#if defined(__USE_FILE_OFFSET64)
-#define __PREAD_PREFIX(x) __pread64_ ## x
-#else
-#define __PREAD_PREFIX(x) __pread_ ## x
-#endif
-
#if __ANDROID_API__ >= __ANDROID_API_M__
__BIONIC_FORTIFY_INLINE
ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
size_t bos = __bos0(buf);
-#if !defined(__clang__)
if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
__PREAD_PREFIX(count_toobig_error)();
}
@@ -344,7 +561,6 @@
if (__builtin_constant_p(count) && (count <= bos)) {
return __PREAD_PREFIX(real)(fd, buf, count, offset);
}
-#endif
return __PREAD_PREFIX(chk)(fd, buf, count, offset, bos);
}
@@ -353,7 +569,6 @@
ssize_t pread64(int fd, void* buf, size_t count, off64_t offset) {
size_t bos = __bos0(buf);
-#if !defined(__clang__)
if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
__pread64_count_toobig_error();
}
@@ -369,24 +584,16 @@
if (__builtin_constant_p(count) && (count <= bos)) {
return __pread64_real(fd, buf, count, offset);
}
-#endif
return __pread64_chk(fd, buf, count, offset, bos);
}
#endif /* __ANDROID_API__ >= __ANDROID_API_M__ */
-#if defined(__USE_FILE_OFFSET64)
-#define __PWRITE_PREFIX(x) __pwrite64_ ## x
-#else
-#define __PWRITE_PREFIX(x) __pwrite_ ## x
-#endif
-
#if __ANDROID_API__ >= __ANDROID_API_N__
__BIONIC_FORTIFY_INLINE
ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) {
size_t bos = __bos0(buf);
-#if !defined(__clang__)
if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
__PWRITE_PREFIX(count_toobig_error)();
}
@@ -402,7 +609,6 @@
if (__builtin_constant_p(count) && (count <= bos)) {
return __PWRITE_PREFIX(real)(fd, buf, count, offset);
}
-#endif
return __PWRITE_PREFIX(chk)(fd, buf, count, offset, bos);
}
@@ -411,7 +617,6 @@
ssize_t pwrite64(int fd, const void* buf, size_t count, off64_t offset) {
size_t bos = __bos0(buf);
-#if !defined(__clang__)
if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
__pwrite64_count_toobig_error();
}
@@ -427,7 +632,6 @@
if (__builtin_constant_p(count) && (count <= bos)) {
return __pwrite64_real(fd, buf, count, offset);
}
-#endif
return __pwrite64_chk(fd, buf, count, offset, bos);
}
@@ -438,7 +642,6 @@
ssize_t read(int fd, void* buf, size_t count) {
size_t bos = __bos0(buf);
-#if !defined(__clang__)
if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
__read_count_toobig_error();
}
@@ -454,7 +657,6 @@
if (__builtin_constant_p(count) && (count <= bos)) {
return __read_real(fd, buf, count);
}
-#endif
return __read_chk(fd, buf, count, bos);
}
@@ -465,13 +667,6 @@
ssize_t write(int fd, const void* buf, size_t count) {
size_t bos = __bos0(buf);
-#if !defined(__clang__)
-#if 0 /* work around a false positive due to a missed optimization */
- if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
- __write_count_toobig_error();
- }
-#endif
-
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __write_real(fd, buf, count);
}
@@ -483,7 +678,6 @@
if (__builtin_constant_p(count) && (count <= bos)) {
return __write_real(fd, buf, count);
}
-#endif
return __write_chk(fd, buf, count, bos);
}
@@ -494,7 +688,6 @@
ssize_t readlink(const char* path, char* buf, size_t size) {
size_t bos = __bos(buf);
-#if !defined(__clang__)
if (__builtin_constant_p(size) && (size > SSIZE_MAX)) {
__readlink_size_toobig_error();
}
@@ -510,7 +703,6 @@
if (__builtin_constant_p(size) && (size <= bos)) {
return __readlink_real(path, buf, size);
}
-#endif
return __readlink_chk(path, buf, size, bos);
}
@@ -519,7 +711,6 @@
ssize_t readlinkat(int dirfd, const char* path, char* buf, size_t size) {
size_t bos = __bos(buf);
-#if !defined(__clang__)
if (__builtin_constant_p(size) && (size > SSIZE_MAX)) {
__readlinkat_size_toobig_error();
}
@@ -535,12 +726,13 @@
if (__builtin_constant_p(size) && (size <= bos)) {
return __readlinkat_real(dirfd, path, buf, size);
}
-#endif
return __readlinkat_chk(dirfd, path, buf, size, bos);
}
#endif /* __ANDROID_API__ >= __ANDROID_API_M__ */
-
+#endif /* defined(__clang__) */
+#undef __PREAD_PREFIX
+#undef __PWRITE_PREFIX
#endif /* defined(__BIONIC_FORTIFY) */
__END_DECLS
diff --git a/libc/stdio/fread.c b/libc/stdio/fread.c
index f3f0127..7b858ae 100644
--- a/libc/stdio/fread.c
+++ b/libc/stdio/fread.c
@@ -41,7 +41,7 @@
#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
size_t
-fread(void *buf, size_t size, size_t count, FILE *fp)
+fread(void *buf, size_t size, size_t count, FILE *fp) __overloadable
{
/*
* Extension: Catch integer overflow.
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/realpath.c b/libc/upstream-freebsd/lib/libc/stdlib/realpath.c
index c4bd953..914ecc9 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/realpath.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/realpath.c
@@ -48,7 +48,7 @@
* in which case the path which caused trouble is left in (resolved).
*/
char *
-realpath(const char * __restrict path, char * __restrict resolved)
+realpath(const char * __restrict path, char * __restrict resolved) __overloadable
{
struct stat sb;
char *p, *q, *s;
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fgets.c b/libc/upstream-openbsd/lib/libc/stdio/fgets.c
index 0ba8770..345884a 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fgets.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/fgets.c
@@ -43,7 +43,7 @@
* Do not return NULL if n == 1.
*/
char *
-fgets(char *buf, int n, FILE *fp)
+fgets(char *buf, int n, FILE *fp) __overloadable
{
size_t len;
char *s;
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fwrite.c b/libc/upstream-openbsd/lib/libc/stdio/fwrite.c
index f0a17bf..c72d968 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fwrite.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/fwrite.c
@@ -45,7 +45,7 @@
* Return the number of whole objects written.
*/
size_t
-fwrite(const void *buf, size_t size, size_t count, FILE *fp)
+fwrite(const void *buf, size_t size, size_t count, FILE *fp) __overloadable
{
size_t n;
struct __suio uio;
diff --git a/libc/upstream-openbsd/lib/libc/string/memchr.c b/libc/upstream-openbsd/lib/libc/string/memchr.c
index 4573e3c..05a1197 100644
--- a/libc/upstream-openbsd/lib/libc/string/memchr.c
+++ b/libc/upstream-openbsd/lib/libc/string/memchr.c
@@ -34,8 +34,7 @@
#include <string.h>
void *
-memchr(const void *s, int c, size_t n)
-{
+memchr(const void *s, int c, size_t n) __overloadable {
if (n != 0) {
const unsigned char *p = s;
diff --git a/libc/upstream-openbsd/lib/libc/string/memmove.c b/libc/upstream-openbsd/lib/libc/string/memmove.c
index 1baad53..910f48c 100644
--- a/libc/upstream-openbsd/lib/libc/string/memmove.c
+++ b/libc/upstream-openbsd/lib/libc/string/memmove.c
@@ -46,7 +46,7 @@
* Copy a block of memory, handling overlap.
*/
void *
-memmove(void *dst0, const void *src0, size_t length)
+memmove(void *dst0, const void *src0, size_t length) __overloadable
{
char *dst = dst0;
const char *src = src0;
diff --git a/libc/upstream-openbsd/lib/libc/string/memrchr.c b/libc/upstream-openbsd/lib/libc/string/memrchr.c
index bd27ebc..1cce809 100644
--- a/libc/upstream-openbsd/lib/libc/string/memrchr.c
+++ b/libc/upstream-openbsd/lib/libc/string/memrchr.c
@@ -23,7 +23,7 @@
* Find the last occurrence of 'c' in the buffer 's' of size 'n'.
*/
void *
-memrchr(const void *s, int c, size_t n)
+memrchr(const void *s, int c, size_t n) __overloadable
{
const unsigned char *cp;
diff --git a/libc/upstream-openbsd/lib/libc/string/stpcpy.c b/libc/upstream-openbsd/lib/libc/string/stpcpy.c
index d88afac..3ed5782 100644
--- a/libc/upstream-openbsd/lib/libc/string/stpcpy.c
+++ b/libc/upstream-openbsd/lib/libc/string/stpcpy.c
@@ -37,7 +37,7 @@
#endif
char *
-stpcpy(char *to, const char *from)
+stpcpy(char *to, const char *from) __overloadable
{
for (; (*to = *from) != '\0'; ++from, ++to);
return(to);
diff --git a/libc/upstream-openbsd/lib/libc/string/stpncpy.c b/libc/upstream-openbsd/lib/libc/string/stpncpy.c
index c7c2a57..661a4fd 100644
--- a/libc/upstream-openbsd/lib/libc/string/stpncpy.c
+++ b/libc/upstream-openbsd/lib/libc/string/stpncpy.c
@@ -35,7 +35,7 @@
#include <string.h>
char *
-stpncpy(char *dst, const char *src, size_t n)
+stpncpy(char *dst, const char *src, size_t n) __overloadable
{
if (n != 0) {
char *d = dst;
diff --git a/libc/upstream-openbsd/lib/libc/string/strcat.c b/libc/upstream-openbsd/lib/libc/string/strcat.c
index 646c9c2..7872a2d 100644
--- a/libc/upstream-openbsd/lib/libc/string/strcat.c
+++ b/libc/upstream-openbsd/lib/libc/string/strcat.c
@@ -37,7 +37,7 @@
#endif
char *
-strcat(char *s, const char *append)
+strcat(char *s, const char *append) __overloadable
{
char *save = s;
diff --git a/libc/upstream-openbsd/lib/libc/string/strcpy.c b/libc/upstream-openbsd/lib/libc/string/strcpy.c
index 5a9001e..1b1169c 100644
--- a/libc/upstream-openbsd/lib/libc/string/strcpy.c
+++ b/libc/upstream-openbsd/lib/libc/string/strcpy.c
@@ -37,7 +37,7 @@
#endif
char *
-strcpy(char *to, const char *from)
+strcpy(char *to, const char *from) __overloadable
{
char *save = to;
diff --git a/libc/upstream-openbsd/lib/libc/string/strlcat.c b/libc/upstream-openbsd/lib/libc/string/strlcat.c
index 073b0d4..7bf98aa 100644
--- a/libc/upstream-openbsd/lib/libc/string/strlcat.c
+++ b/libc/upstream-openbsd/lib/libc/string/strlcat.c
@@ -27,7 +27,7 @@
* If retval >= dsize, truncation occurred.
*/
size_t
-strlcat(char *dst, const char *src, size_t dsize)
+strlcat(char *dst, const char *src, size_t dsize) __overloadable
{
const char *odst = dst;
const char *osrc = src;
diff --git a/libc/upstream-openbsd/lib/libc/string/strlcpy.c b/libc/upstream-openbsd/lib/libc/string/strlcpy.c
index 5fcf084..a5343b8 100644
--- a/libc/upstream-openbsd/lib/libc/string/strlcpy.c
+++ b/libc/upstream-openbsd/lib/libc/string/strlcpy.c
@@ -25,7 +25,7 @@
* Returns strlen(src); if retval >= dsize, truncation occurred.
*/
size_t
-strlcpy(char *dst, const char *src, size_t dsize)
+strlcpy(char *dst, const char *src, size_t dsize) __overloadable
{
const char *osrc = src;
size_t nleft = dsize;
diff --git a/libc/upstream-openbsd/lib/libc/string/strncat.c b/libc/upstream-openbsd/lib/libc/string/strncat.c
index c4df4f2..32334b3 100644
--- a/libc/upstream-openbsd/lib/libc/string/strncat.c
+++ b/libc/upstream-openbsd/lib/libc/string/strncat.c
@@ -38,7 +38,7 @@
* are written at dst (at most n+1 bytes being appended). Return dst.
*/
char *
-strncat(char *dst, const char *src, size_t n)
+strncat(char *dst, const char *src, size_t n) __overloadable
{
if (n != 0) {
char *d = dst;
diff --git a/libc/upstream-openbsd/lib/libc/string/strncpy.c b/libc/upstream-openbsd/lib/libc/string/strncpy.c
index 5003a19..e83c7e5 100644
--- a/libc/upstream-openbsd/lib/libc/string/strncpy.c
+++ b/libc/upstream-openbsd/lib/libc/string/strncpy.c
@@ -39,7 +39,7 @@
* Return dst.
*/
char *
-strncpy(char *dst, const char *src, size_t n)
+strncpy(char *dst, const char *src, size_t n) __overloadable
{
if (n != 0) {
char *d = dst;