Revert "Retire GCC FORTIFY."

This reverts commit 067bdc9546557a1a107f2617d7d15b864ff493f1.

The angler/bullhead builds still use GCC, so I'll wait until they're turned down.

Bug: https://issuetracker.google.com/74404306
Change-Id: I777b08dd6ab5250d532b4b5cc56e9a790c13db20
diff --git a/libc/include/bits/fortify/fcntl.h b/libc/include/bits/fortify/fcntl.h
index e7f2c82..75cd4f2 100644
--- a/libc/include/bits/fortify/fcntl.h
+++ b/libc/include/bits/fortify/fcntl.h
@@ -44,6 +44,7 @@
 #define __open_useless_modes_warning "has superfluous mode bits; missing O_CREAT?"
 /* O_TMPFILE shares bits with O_DIRECTORY. */
 #define __open_modes_useful(flags) (((flags) & O_CREAT) || ((flags) & O_TMPFILE) == O_TMPFILE)
+#if defined(__clang__)
 
 #if __ANDROID_API__ >= __ANDROID_API_J_MR1__
 __BIONIC_ERROR_FUNCTION_VISIBILITY
@@ -92,6 +93,52 @@
 }
 #endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
 
+#else /* defined(__clang__) */
+__errordecl(__creat_missing_mode, __open_too_few_args_error);
+__errordecl(__creat_too_many_args, __open_too_many_args_error);
+
+#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
+__BIONIC_FORTIFY_VARIADIC
+int open(const char* pathname, int flags, ...) {
+    if (__builtin_constant_p(flags)) {
+        if (__open_modes_useful(flags) && __builtin_va_arg_pack_len() == 0) {
+            __creat_missing_mode();  /* Compile time error. */
+        }
+    }
+
+    if (__builtin_va_arg_pack_len() > 1) {
+        __creat_too_many_args();  /* Compile time error. */
+    }
+
+    if ((__builtin_va_arg_pack_len() == 0) && !__builtin_constant_p(flags)) {
+        return __open_2(pathname, flags);
+    }
+
+    return __open_real(pathname, flags, __builtin_va_arg_pack());
+}
+
+__BIONIC_FORTIFY_VARIADIC
+int openat(int dirfd, const char* pathname, int flags, ...) {
+    if (__builtin_constant_p(flags)) {
+        if (__open_modes_useful(flags) && __builtin_va_arg_pack_len() == 0) {
+            __creat_missing_mode();  /* Compile time error. */
+        }
+    }
+
+    if (__builtin_va_arg_pack_len() > 1) {
+        __creat_too_many_args();  /* Compile time error. */
+    }
+
+    if ((__builtin_va_arg_pack_len() == 0) && !__builtin_constant_p(flags)) {
+        return __openat_2(dirfd, pathname, flags);
+    }
+
+    return __openat_real(dirfd, pathname, flags, __builtin_va_arg_pack());
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
+
+#endif /* defined(__clang__) */
+
 #undef __open_too_many_args_error
 #undef __open_too_few_args_error
 #undef __open_useless_modes_warning
diff --git a/libc/include/bits/fortify/poll.h b/libc/include/bits/fortify/poll.h
index 718ee96..c3ae31d 100644
--- a/libc/include/bits/fortify/poll.h
+++ b/libc/include/bits/fortify/poll.h
@@ -36,7 +36,7 @@
 
 #if defined(__BIONIC_FORTIFY)
 #if __ANDROID_API__ >= __ANDROID_API_M__
-
+#if defined(__clang__)
 __BIONIC_FORTIFY_INLINE
 int poll(struct pollfd* const fds __pass_object_size, nfds_t fd_count, int timeout)
     __overloadable
@@ -81,5 +81,39 @@
 }
 #endif
 
+#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_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");
+
+__BIONIC_FORTIFY_INLINE
+int poll(struct pollfd* fds, nfds_t fd_count, int timeout) {
+  if (__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+    if (!__builtin_constant_p(fd_count)) {
+      return __poll_chk(fds, fd_count, timeout, __bos(fds));
+    } else if (__bos(fds) / sizeof(*fds) < fd_count) {
+      __poll_too_small_error();
+    }
+  }
+  return __poll_real(fds, fd_count, timeout);
+}
+
+__BIONIC_FORTIFY_INLINE
+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));
+    } else if (__bos(fds) / sizeof(*fds) < fd_count) {
+      __ppoll_too_small_error();
+    }
+  }
+  return __ppoll_real(fds, fd_count, timeout, mask);
+}
+
+#endif /* defined(__clang__) */
 #endif /* __ANDROID_API__ >= __ANDROID_API_M__ */
 #endif /* defined(__BIONIC_FORTIFY) */
diff --git a/libc/include/bits/fortify/socket.h b/libc/include/bits/fortify/socket.h
index 3d070c5..3e610d6 100644
--- a/libc/include/bits/fortify/socket.h
+++ b/libc/include/bits/fortify/socket.h
@@ -39,7 +39,7 @@
 
 #define __recvfrom_bad_size "'recvfrom' called with size bigger than buffer"
 #define __sendto_bad_size "'sendto' called with size bigger than buffer"
-
+#if defined(__clang__)
 #if __ANDROID_API__ >= __ANDROID_API_N__
 __BIONIC_FORTIFY_INLINE
 ssize_t recvfrom(int fd, void* const buf __pass_object_size0, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addr_len)
@@ -86,6 +86,69 @@
   return sendto(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_bad_size);
+
+extern ssize_t __sendto_real(int, const void*, size_t, int, const struct sockaddr*, socklen_t)
+        __RENAME(sendto);
+__errordecl(__sendto_error, __sendto_bad_size);
+
+#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);
+  }
+
+  if (__builtin_constant_p(len) && (len <= bos)) {
+    return __recvfrom_real(fd, buf, len, flags, src_addr, addr_len);
+  }
+
+  if (__builtin_constant_p(len) && (len > bos)) {
+    __recvfrom_error();
+  }
+
+  return __recvfrom_chk(fd, buf, len, bos, flags, src_addr, addr_len);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_N_MR1__
+__BIONIC_FORTIFY_INLINE
+ssize_t sendto(int fd, const void* buf, size_t len, int flags,
+               const struct sockaddr* dest_addr, socklen_t addr_len) {
+  size_t bos = __bos0(buf);
+
+  if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+    return __sendto_real(fd, buf, len, flags, dest_addr, addr_len);
+  }
+
+  if (__builtin_constant_p(len) && (len <= bos)) {
+    return __sendto_real(fd, buf, len, flags, dest_addr, addr_len);
+  }
+
+  if (__builtin_constant_p(len) && (len > bos)) {
+    __sendto_error();
+  }
+
+  return __sendto_chk(fd, buf, len, bos, flags, dest_addr, addr_len);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_N_MR1__ */
+
+__BIONIC_FORTIFY_INLINE
+ssize_t recv(int socket, void* buf, size_t len, int flags) {
+  return recvfrom(socket, buf, len, flags, NULL, 0);
+}
+
+__BIONIC_FORTIFY_INLINE
+ssize_t send(int socket, const void* buf, size_t len, int flags) {
+  return sendto(socket, buf, len, flags, NULL, 0);
+}
+#endif /* defined(__clang__) */
+
 #undef __recvfrom_bad_size
 #undef __sendto_bad_size
 #endif /* __BIONIC_FORTIFY */
diff --git a/libc/include/bits/fortify/stat.h b/libc/include/bits/fortify/stat.h
index b248aca..c168c38 100644
--- a/libc/include/bits/fortify/stat.h
+++ b/libc/include/bits/fortify/stat.h
@@ -35,6 +35,8 @@
 #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 this an overload of umask. */
 __BIONIC_FORTIFY_INLINE
@@ -46,6 +48,24 @@
 }
 #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 (__builtin_constant_p(mode)) {
+    if ((mode & 0777) != mode) {
+      __umask_invalid_mode();
+    }
+    return __umask_real(mode);
+  }
+  return __umask_chk(mode);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR2__ */
+
+#endif /* defined(__clang__) */
 #undef __umask_invalid_mode_str
 
 #endif /* defined(__BIONIC_FORTIFY) */
diff --git a/libc/include/bits/fortify/stdio.h b/libc/include/bits/fortify/stdio.h
index 0b5700a..6a6b433 100644
--- a/libc/include/bits/fortify/stdio.h
+++ b/libc/include/bits/fortify/stdio.h
@@ -49,6 +49,7 @@
 }
 #endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
 
+#if defined(__clang__)
 #if __ANDROID_API__ >= __ANDROID_API_J_MR1__
 /*
  * Simple case: `format` can't have format specifiers, so we can just compare
@@ -140,4 +141,114 @@
 }
 #endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
 
+#else /* defined(__clang__) */
+
+size_t __fread_real(void*, size_t, size_t, FILE*) __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*, size_t, size_t, FILE*) __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_VARIADIC __printflike(3, 4)
+int snprintf(char* dest, size_t size, const char* format, ...) {
+    return __builtin___snprintf_chk(dest, size, 0, __bos(dest), format, __builtin_va_arg_pack());
+}
+
+__BIONIC_FORTIFY_VARIADIC __printflike(2, 3)
+int sprintf(char* dest, const char* 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* buf, size_t size, size_t count, FILE* stream) {
+    size_t bos = __bos0(buf);
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __fread_real(buf, size, count, stream);
+    }
+
+    if (__builtin_constant_p(size) && __builtin_constant_p(count)) {
+        size_t total;
+        if (__size_mul_overflow(size, count, &total)) {
+            __fread_overflow();
+        }
+
+        if (total > bos) {
+            __fread_too_big_error();
+        }
+
+        return __fread_real(buf, size, count, stream);
+    }
+
+    return __fread_chk(buf, size, count, stream, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+size_t fwrite(const void* buf, size_t size, size_t count, FILE* stream) {
+    size_t bos = __bos0(buf);
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __fwrite_real(buf, size, count, stream);
+    }
+
+    if (__builtin_constant_p(size) && __builtin_constant_p(count)) {
+        size_t total;
+        if (__size_mul_overflow(size, count, &total)) {
+            __fwrite_overflow();
+        }
+
+        if (total > bos) {
+            __fwrite_too_big_error();
+        }
+
+        return __fwrite_real(buf, size, count, stream);
+    }
+
+    return __fwrite_chk(buf, size, count, stream, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
+__BIONIC_FORTIFY_INLINE
+char *fgets(char* dest, int size, FILE* stream) {
+    size_t bos = __bos(dest);
+
+    // Compiler can prove, at compile time, that the passed in size
+    // is always negative. Force a compiler error.
+    if (__builtin_constant_p(size) && (size < 0)) {
+        __fgets_too_small_error();
+    }
+
+    // Compiler doesn't know destination size. Don't call __fgets_chk
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __fgets_real(dest, size, stream);
+    }
+
+    // Compiler can prove, at compile time, that the passed in size
+    // is always <= the actual object size. Don't call __fgets_chk
+    if (__builtin_constant_p(size) && (size <= (int) bos)) {
+        return __fgets_real(dest, size, stream);
+    }
+
+    // Compiler can prove, at compile time, that the passed in size
+    // is always > the actual object size. Force a compiler error.
+    if (__builtin_constant_p(size) && (size > (int) bos)) {
+        __fgets_too_big_error();
+    }
+
+    return __fgets_chk(dest, size, stream, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
+
+#endif /* defined(__clang__) */
 #endif /* defined(__BIONIC_FORTIFY) */
diff --git a/libc/include/bits/fortify/stdlib.h b/libc/include/bits/fortify/stdlib.h
index d47c0b0..8f3b02c 100644
--- a/libc/include/bits/fortify/stdlib.h
+++ b/libc/include/bits/fortify/stdlib.h
@@ -37,12 +37,31 @@
 /* PATH_MAX is unavailable without polluting the namespace, but it's always 4096 on Linux */
 #define __PATH_MAX 4096
 
+#if defined(__clang__)
 char* realpath(const char* path, char* resolved)
         __clang_error_if(__bos(resolved) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
                          __bos(resolved) < __PATH_MAX, __realpath_buf_too_small_str)
         __clang_error_if(!path, "'realpath': NULL path is never correct; flipped arguments?");
 /* No need for a definition; the only issues we can catch are at compile-time. */
 
+#else /* defined(__clang__) */
+
+char* __realpath_real(const char*, char*) __RENAME(realpath);
+__errordecl(__realpath_size_error, __realpath_buf_too_small_str);
+
+__BIONIC_FORTIFY_INLINE
+char* realpath(const char* path, char* resolved) {
+    size_t bos = __bos(resolved);
+
+    if (bos != __BIONIC_FORTIFY_UNKNOWN_SIZE && bos < __PATH_MAX) {
+        __realpath_size_error();
+    }
+
+    return __realpath_real(path, resolved);
+}
+
+#endif /* defined(__clang__) */
+
 #undef __PATH_MAX
 #undef __realpath_buf_too_small_str
 #endif /* defined(__BIONIC_FORTIFY) */
diff --git a/libc/include/bits/fortify/string.h b/libc/include/bits/fortify/string.h
index 14bb133..f994e3e 100644
--- a/libc/include/bits/fortify/string.h
+++ b/libc/include/bits/fortify/string.h
@@ -40,6 +40,8 @@
 #if defined(__BIONIC_FORTIFY)
 extern void* __memrchr_real(const void*, int, size_t) __RENAME(memrchr);
 
+// 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* const dst __pass_object_size0, const void* src, size_t copy_amount)
@@ -100,6 +102,9 @@
 }
 #endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
 
+
+#if defined(__clang__)
+
 #if __ANDROID_API__ >= __ANDROID_API_M__
 __BIONIC_FORTIFY_INLINE
 void* memchr(const void* const s __pass_object_size, int c, size_t n) __overloadable {
@@ -226,6 +231,192 @@
 }
 #endif /* __ANDROID_API__ >= __ANDROID_API_J_MR2__ */
 
+#else // defined(__clang__)
+extern char* __strncpy_real(char*, const char*, size_t) __RENAME(strncpy);
+extern size_t __strlcpy_real(char*, const char*, size_t)
+    __RENAME(strlcpy);
+extern size_t __strlcat_real(char*, const char*, 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* 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);
+    }
+
+    if (__builtin_constant_p(n) && (n > bos)) {
+        __memchr_buf_size_error();
+    }
+
+    if (__builtin_constant_p(n) && (n <= bos)) {
+        return __builtin_memchr(s, c, n);
+    }
+
+    return __memchr_chk(s, c, n, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+void* __memrchr_fortify(const void* s, int c, size_t n) {
+    size_t bos = __bos(s);
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __memrchr_real(s, c, n);
+    }
+
+    if (__builtin_constant_p(n) && (n > bos)) {
+        __memrchr_buf_size_error();
+    }
+
+    if (__builtin_constant_p(n) && (n <= bos)) {
+        return __memrchr_real(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* dst, const char* src, size_t n) {
+    size_t bos_dst = __bos(dst);
+    size_t bos_src = __bos(src);
+
+    if (bos_src == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __builtin___stpncpy_chk(dst, src, n, bos_dst);
+    }
+
+    if (__builtin_constant_p(n) && (n <= bos_src)) {
+        return __builtin___stpncpy_chk(dst, src, n, bos_dst);
+    }
+
+    size_t slen = __builtin_strlen(src);
+    if (__builtin_constant_p(slen)) {
+        return __builtin___stpncpy_chk(dst, src, n, bos_dst);
+    }
+
+    return __stpncpy_chk2(dst, src, n, bos_dst, bos_src);
+}
+
+__BIONIC_FORTIFY_INLINE
+char* strncpy(char* dst, const char* src, size_t n) {
+    size_t bos_dst = __bos(dst);
+    size_t bos_src = __bos(src);
+
+    if (bos_src == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __strncpy_real(dst, src, n);
+    }
+
+    if (__builtin_constant_p(n) && (n <= bos_src)) {
+        return __builtin___strncpy_chk(dst, src, n, bos_dst);
+    }
+
+    size_t slen = __builtin_strlen(src);
+    if (__builtin_constant_p(slen)) {
+        return __builtin___strncpy_chk(dst, src, n, bos_dst);
+    }
+
+    return __strncpy_chk2(dst, src, n, bos_dst, bos_src);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_L__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
+__BIONIC_FORTIFY_INLINE
+size_t strlcpy(char* dst __pass_object_size, const char* src, size_t size) {
+    size_t bos = __bos(dst);
+
+    // Compiler doesn't know destination size. Don't call __strlcpy_chk
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __strlcpy_real(dst, src, size);
+    }
+
+    // Compiler can prove, at compile time, that the passed in size
+    // is always <= the actual object size. Don't call __strlcpy_chk
+    if (__builtin_constant_p(size) && (size <= bos)) {
+        return __strlcpy_real(dst, src, size);
+    }
+
+    return __strlcpy_chk(dst, src, size, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+size_t strlcat(char* dst, const char* src, size_t size) {
+    size_t bos = __bos(dst);
+
+    // Compiler doesn't know destination size. Don't call __strlcat_chk
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __strlcat_real(dst, src, size);
+    }
+
+    // Compiler can prove, at compile time, that the passed in size
+    // is always <= the actual object size. Don't call __strlcat_chk
+    if (__builtin_constant_p(size) && (size <= bos)) {
+        return __strlcat_real(dst, src, size);
+    }
+
+    return __strlcat_chk(dst, src, size, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+size_t strlen(const char* s) __overloadable {
+    size_t bos = __bos(s);
+
+    // Compiler doesn't know destination size. Don't call __strlen_chk
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __builtin_strlen(s);
+    }
+
+    size_t slen = __builtin_strlen(s);
+    if (__builtin_constant_p(slen)) {
+        return slen;
+    }
+
+    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* s, int c) {
+    size_t bos = __bos(s);
+
+    // Compiler doesn't know destination size. Don't call __strchr_chk
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __builtin_strchr(s, c);
+    }
+
+    size_t slen = __builtin_strlen(s);
+    if (__builtin_constant_p(slen) && (slen < bos)) {
+        return __builtin_strchr(s, c);
+    }
+
+    return __strchr_chk(s, c, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+char* strrchr(const char* s, int c) {
+    size_t bos = __bos(s);
+
+    // Compiler doesn't know destination size. Don't call __strrchr_chk
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __builtin_strrchr(s, c);
+    }
+
+    size_t slen = __builtin_strlen(s);
+    if (__builtin_constant_p(slen) && (slen < bos)) {
+        return __builtin_strrchr(s, c);
+    }
+
+    return __strrchr_chk(s, c, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR2__ */
+#endif /* defined(__clang__) */
+
 #if __ANDROID_API__ >= __ANDROID_API_M__
 #if defined(__cplusplus)
 extern "C++" {
diff --git a/libc/include/bits/fortify/unistd.h b/libc/include/bits/fortify/unistd.h
index a07907b..ea5c89d 100644
--- a/libc/include/bits/fortify/unistd.h
+++ b/libc/include/bits/fortify/unistd.h
@@ -59,6 +59,7 @@
 #define __PWRITE_PREFIX(x) __pwrite_ ## x
 #endif
 
+#if defined(__clang__)
 #define __error_if_overflows_ssizet(what, fn) \
     __clang_error_if((what) > SSIZE_MAX, "in call to '" #fn "', '" #what "' must be <= SSIZE_MAX")
 
@@ -206,6 +207,243 @@
 #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);
+    }
+
+    if (__builtin_constant_p(size) && (size > bos)) {
+        __getcwd_dest_size_error();
+    }
+
+    if (__builtin_constant_p(size) && (size <= bos)) {
+        return __getcwd_real(buf, size);
+    }
+
+    return __getcwd_chk(buf, size, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
+
+#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 (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
+        __PREAD_PREFIX(count_toobig_error)();
+    }
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __PREAD_PREFIX(real)(fd, buf, count, offset);
+    }
+
+    if (__builtin_constant_p(count) && (count > bos)) {
+        __PREAD_PREFIX(dest_size_error)();
+    }
+
+    if (__builtin_constant_p(count) && (count <= bos)) {
+        return __PREAD_PREFIX(real)(fd, buf, count, offset);
+    }
+
+    return __PREAD_PREFIX(chk)(fd, buf, count, offset, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+ssize_t pread64(int fd, void* buf, size_t count, off64_t offset) {
+    size_t bos = __bos0(buf);
+
+    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
+        __pread64_count_toobig_error();
+    }
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __pread64_real(fd, buf, count, offset);
+    }
+
+    if (__builtin_constant_p(count) && (count > bos)) {
+        __pread64_dest_size_error();
+    }
+
+    if (__builtin_constant_p(count) && (count <= bos)) {
+        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_FORTIFY_INLINE
+ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) {
+    size_t bos = __bos0(buf);
+
+    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
+        __PWRITE_PREFIX(count_toobig_error)();
+    }
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __PWRITE_PREFIX(real)(fd, buf, count, offset);
+    }
+
+    if (__builtin_constant_p(count) && (count > bos)) {
+        __PWRITE_PREFIX(dest_size_error)();
+    }
+
+    if (__builtin_constant_p(count) && (count <= bos)) {
+        return __PWRITE_PREFIX(real)(fd, buf, count, offset);
+    }
+
+    return __PWRITE_PREFIX(chk)(fd, buf, count, offset, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+ssize_t pwrite64(int fd, const void* buf, size_t count, off64_t offset) {
+    size_t bos = __bos0(buf);
+
+    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
+        __pwrite64_count_toobig_error();
+    }
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __pwrite64_real(fd, buf, count, offset);
+    }
+
+    if (__builtin_constant_p(count) && (count > bos)) {
+        __pwrite64_dest_size_error();
+    }
+
+    if (__builtin_constant_p(count) && (count <= bos)) {
+        return __pwrite64_real(fd, buf, count, offset);
+    }
+
+    return __pwrite64_chk(fd, buf, count, offset, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_L__
+__BIONIC_FORTIFY_INLINE
+ssize_t read(int fd, void* buf, size_t count) {
+    size_t bos = __bos0(buf);
+
+    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
+        __read_count_toobig_error();
+    }
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __read_real(fd, buf, count);
+    }
+
+    if (__builtin_constant_p(count) && (count > bos)) {
+        __read_dest_size_error();
+    }
+
+    if (__builtin_constant_p(count) && (count <= bos)) {
+        return __read_real(fd, buf, count);
+    }
+
+    return __read_chk(fd, buf, count, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_L__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_N__
+__BIONIC_FORTIFY_INLINE
+ssize_t write(int fd, const void* buf, size_t count) {
+    size_t bos = __bos0(buf);
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __write_real(fd, buf, count);
+    }
+
+    if (__builtin_constant_p(count) && (count > bos)) {
+        __write_dest_size_error();
+    }
+
+    if (__builtin_constant_p(count) && (count <= bos)) {
+        return __write_real(fd, buf, count);
+    }
+
+    return __write_chk(fd, buf, count, bos);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
+
+#if __ANDROID_API__ >= __ANDROID_API_M__
+__BIONIC_FORTIFY_INLINE
+ssize_t readlink(const char* path, char* buf, size_t size) {
+    size_t bos = __bos(buf);
+
+    if (__builtin_constant_p(size) && (size > SSIZE_MAX)) {
+        __readlink_size_toobig_error();
+    }
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __readlink_real(path, buf, size);
+    }
+
+    if (__builtin_constant_p(size) && (size > bos)) {
+        __readlink_dest_size_error();
+    }
+
+    if (__builtin_constant_p(size) && (size <= bos)) {
+        return __readlink_real(path, buf, size);
+    }
+
+    return __readlink_chk(path, buf, size, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+ssize_t readlinkat(int dirfd, const char* path, char* buf, size_t size) {
+    size_t bos = __bos(buf);
+
+    if (__builtin_constant_p(size) && (size > SSIZE_MAX)) {
+        __readlinkat_size_toobig_error();
+    }
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __readlinkat_real(dirfd, path, buf, size);
+    }
+
+    if (__builtin_constant_p(size) && (size > bos)) {
+        __readlinkat_dest_size_error();
+    }
+
+    if (__builtin_constant_p(size) && (size <= bos)) {
+        return __readlinkat_real(dirfd, path, buf, size);
+    }
+
+    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) */
diff --git a/libc/include/bits/ioctl.h b/libc/include/bits/ioctl.h
index 745bbf0..3357c1b 100644
--- a/libc/include/bits/ioctl.h
+++ b/libc/include/bits/ioctl.h
@@ -51,7 +51,8 @@
  * FIXME: __has_extension is more or less a clang version check. Remove it when
  * we don't need to support old clang code.
  */
-#if __has_extension(overloadable_unmarked) && !defined(BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD)
+#if defined(__clang__) && __has_extension(overloadable_unmarked) && \
+  !defined(BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD)
 /* enable_if(1) just exists to break overloading ties. */
 int ioctl(int __fd, unsigned __request, ...) __overloadable __enable_if(1, "") __RENAME(ioctl);
 #endif