Merge "Fix overflow check in malloc_limit"
diff --git a/libc/bionic/open.cpp b/libc/bionic/open.cpp
index 222e5d3..df5ab21 100644
--- a/libc/bionic/open.cpp
+++ b/libc/bionic/open.cpp
@@ -70,6 +70,7 @@
   if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
   return __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), 0);
 }
+__strong_alias(__open64_2, __open_2);
 
 int openat(int fd, const char *pathname, int flags, ...) {
   mode_t mode = 0;
@@ -89,3 +90,4 @@
   if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
   return __openat(fd, pathname, force_O_LARGEFILE(flags), 0);
 }
+__strong_alias(__openat64_2, __openat_2);
diff --git a/libc/include/bits/fortify/fcntl.h b/libc/include/bits/fortify/fcntl.h
index e7f2c82..4bb441e 100644
--- a/libc/include/bits/fortify/fcntl.h
+++ b/libc/include/bits/fortify/fcntl.h
@@ -92,6 +92,52 @@
 }
 #endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
 
+#if __ANDROID_API__ >= __ANDROID_API_R__
+int __open64_2(const char*, int) __INTRODUCED_IN(30);
+int __openat64_2(int, const char*, int) __INTRODUCED_IN(30);
+int __open64_real(const char* __path, int __flags, ...) __RENAME(open64);
+int __openat64_real(int, const char*, int, ...) __RENAME(openat64);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int open64(const char* pathname, int flags, mode_t modes, ...) __overloadable
+        __errorattr(__open_too_many_args_error);
+
+__BIONIC_FORTIFY_INLINE
+int open64(const char* const __pass_object_size pathname, int flags)
+        __overloadable
+        __clang_error_if(__open_modes_useful(flags), "'open64' " __open_too_few_args_error) {
+    return __open64_2(pathname, flags);
+}
+
+__BIONIC_FORTIFY_INLINE
+int open64(const char* const __pass_object_size pathname, int flags, mode_t modes)
+        __overloadable
+        __clang_warning_if(!__open_modes_useful(flags) && modes,
+                           "'open64' " __open_useless_modes_warning) {
+    return __open64_real(pathname, flags, modes);
+}
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int openat64(int dirfd, const char* pathname, int flags, mode_t modes, ...)
+        __overloadable
+        __errorattr(__open_too_many_args_error);
+
+__BIONIC_FORTIFY_INLINE
+int openat64(int dirfd, const char* const __pass_object_size pathname, int flags)
+        __overloadable
+        __clang_error_if(__open_modes_useful(flags), "'openat64' " __open_too_few_args_error) {
+    return __openat64_2(dirfd, pathname, flags);
+}
+
+__BIONIC_FORTIFY_INLINE
+int openat64(int dirfd, const char* const __pass_object_size pathname, int flags, mode_t modes)
+        __overloadable
+        __clang_warning_if(!__open_modes_useful(flags) && modes,
+                           "'openat64' " __open_useless_modes_warning) {
+    return __openat64_real(dirfd, pathname, flags, modes);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_R__ */
+
 #undef __open_too_many_args_error
 #undef __open_too_few_args_error
 #undef __open_useless_modes_warning
diff --git a/libc/include/bits/fortify/string.h b/libc/include/bits/fortify/string.h
index 1e12986..0e205d3 100644
--- a/libc/include/bits/fortify/string.h
+++ b/libc/include/bits/fortify/string.h
@@ -94,12 +94,18 @@
 }
 
 __BIONIC_FORTIFY_INLINE
-char* strcat(char* const dst __pass_object_size, const char* src) __overloadable {
+char* strcat(char* const dst __pass_object_size, const char* src)
+        __overloadable
+        __clang_error_if(__bos_unevaluated_le(__bos(dst), __builtin_strlen(src)),
+                         "'strcat' called with string bigger than buffer") {
     return __builtin___strcat_chk(dst, src, __bos(dst));
 }
 
 __BIONIC_FORTIFY_INLINE
-char* strncat(char* const dst __pass_object_size, const char* src, size_t n) __overloadable {
+char* strncat(char* const dst __pass_object_size, const char* src, size_t n)
+        __overloadable
+        __clang_error_if(__bos_unevaluated_lt(__bos(dst), n),
+                         "'strncat' called with size bigger than buffer") {
     return __builtin___strncat_chk(dst, src, n, __bos(dst));
 }
 
@@ -145,7 +151,9 @@
 #if __ANDROID_API__ >= __ANDROID_API_L__
 __BIONIC_FORTIFY_INLINE
 char* stpncpy(char* const dst __pass_object_size, const char* const src __pass_object_size, size_t n)
-        __overloadable {
+        __overloadable
+        __clang_error_if(__bos_unevaluated_lt(__bos(dst), n),
+                         "'stpncpy' called with size bigger than buffer") {
     size_t bos_dst = __bos(dst);
     size_t bos_src = __bos(src);
 
@@ -159,7 +167,9 @@
 
 __BIONIC_FORTIFY_INLINE
 char* strncpy(char* const dst __pass_object_size, const char* const src __pass_object_size, size_t n)
-        __overloadable {
+        __overloadable
+        __clang_error_if(__bos_unevaluated_lt(__bos(dst), n),
+                         "'strncpy' called with size bigger than buffer") {
     size_t bos_dst = __bos(dst);
     size_t bos_src = __bos(src);
 
@@ -174,7 +184,10 @@
 
 #if __ANDROID_API__ >= __ANDROID_API_J_MR1__
 __BIONIC_FORTIFY_INLINE
-size_t strlcpy(char* const dst __pass_object_size, const char* src, size_t size) __overloadable {
+size_t strlcpy(char* const dst __pass_object_size, const char* src, size_t size)
+        __overloadable
+        __clang_error_if(__bos_unevaluated_lt(__bos(dst), size),
+                         "'strlcpy' called with size bigger than buffer") {
     size_t bos = __bos(dst);
 
     if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
@@ -185,7 +198,10 @@
 }
 
 __BIONIC_FORTIFY_INLINE
-size_t strlcat(char* const dst __pass_object_size, const char* src, size_t size) __overloadable {
+size_t strlcat(char* const dst __pass_object_size, const char* src, size_t size)
+        __overloadable
+        __clang_error_if(__bos_unevaluated_lt(__bos(dst), size),
+                         "'strlcat' called with size bigger than buffer") {
     size_t bos = __bos(dst);
 
     if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 424c8f3..b12df56 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1482,6 +1482,8 @@
 
 LIBC_R { # introduced=R
   global:
+    __open64_2;
+    __openat64_2;
     call_once;
     cnd_broadcast;
     cnd_destroy;
diff --git a/tests/Android.bp b/tests/Android.bp
index a55d08b..97712d3 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -286,6 +286,7 @@
         "-Wno-builtin-memcpy-chk-size",
         "-Wno-format-zero-length",
         "-Wno-memset-transposed-args",
+        "-Wno-strlcpy-strlcat-size",
         "-Wno-strncat-size",
     ],
 }
diff --git a/tests/clang_fortify_tests.cpp b/tests/clang_fortify_tests.cpp
index 0c09d36..4c4e510 100644
--- a/tests/clang_fortify_tests.cpp
+++ b/tests/clang_fortify_tests.cpp
@@ -177,22 +177,18 @@
     EXPECT_FORTIFY_DEATH(strcpy(small_buffer, large_string));
     // expected-error@+1{{string bigger than buffer}}
     EXPECT_FORTIFY_DEATH(stpcpy(small_buffer, large_string));
-#if 0
-    // expected-error@+1{{called with bigger length than the destination}}
-#endif
+    // expected-error@+1{{size bigger than buffer}}
     EXPECT_FORTIFY_DEATH(strncpy(small_buffer, large_string, sizeof(large_string)));
-#if 0
-    // expected-error@+1{{called with bigger length than the destination}}
-#endif
+    // expected-error@+1{{size bigger than buffer}}
     EXPECT_FORTIFY_DEATH(stpncpy(small_buffer, large_string, sizeof(large_string)));
-#if 0
-    // expected-error@+1{{destination buffer will always be overflown}}
-#endif
+    // expected-error@+1{{string bigger than buffer}}
     EXPECT_FORTIFY_DEATH(strcat(small_buffer, large_string));
-#if 0
-    // expected-error@+1{{destination buffer will always be overflown}}
-#endif
+    // expected-error@+1{{size bigger than buffer}}
     EXPECT_FORTIFY_DEATH(strncat(small_buffer, large_string, sizeof(large_string)));
+    // expected-error@+1{{size bigger than buffer}}
+    EXPECT_FORTIFY_DEATH(strlcpy(small_buffer, large_string, sizeof(large_string)));
+    // expected-error@+1{{size bigger than buffer}}
+    EXPECT_FORTIFY_DEATH(strlcat(small_buffer, large_string, sizeof(large_string)));
   }
 
   {
@@ -224,35 +220,81 @@
     EXPECT_FORTIFY_DEATH_STRUCT(stpcpy(split.tiny_buffer, small_string));
 
 #if _FORTIFY_SOURCE > 1
-#if 0
-    // expected-error@+2{{called with bigger length than the destination}}
-#endif
+    // expected-error@+2{{size bigger than buffer}}
 #endif
     EXPECT_FORTIFY_DEATH_STRUCT(strncpy(split.tiny_buffer, small_string, sizeof(small_string)));
 
 #if _FORTIFY_SOURCE > 1
-#if 0
-    // expected-error@+2{{called with bigger length than the destination}}
-#endif
+    // expected-error@+2{{size bigger than buffer}}
 #endif
     EXPECT_FORTIFY_DEATH_STRUCT(stpncpy(split.tiny_buffer, small_string, sizeof(small_string)));
 
 #if _FORTIFY_SOURCE > 1
-#if 0
-    // expected-error@+2{{destination buffer will always be overflown}}
-#endif
+    // expected-error@+2{{string bigger than buffer}}
 #endif
     EXPECT_FORTIFY_DEATH_STRUCT(strcat(split.tiny_buffer, small_string));
 
 #if _FORTIFY_SOURCE > 1
-#if 0
-    // expected-error@+2{{destination buffer will always be overflown}}
-#endif
+    // expected-error@+2{{size bigger than buffer}}
 #endif
     EXPECT_FORTIFY_DEATH_STRUCT(strncat(split.tiny_buffer, small_string, sizeof(small_string)));
+
+#if _FORTIFY_SOURCE > 1
+    // expected-error@+2{{size bigger than buffer}}
+#endif
+    EXPECT_FORTIFY_DEATH_STRUCT(strlcat(split.tiny_buffer, small_string, sizeof(small_string)));
+
+#if _FORTIFY_SOURCE > 1
+    // expected-error@+2{{size bigger than buffer}}
+#endif
+    EXPECT_FORTIFY_DEATH_STRUCT(strlcpy(split.tiny_buffer, small_string, sizeof(small_string)));
   }
 }
 
+FORTIFY_TEST(fcntl) {
+  const char target[] = "/dev/null";
+  int dirfd = 0;
+
+  // These all emit hard errors without diagnose_if, so running them is a bit
+  // more involved.
+#ifdef COMPILATION_TESTS
+  // expected-error@+1{{too many arguments}}
+  open("/", 0, 0, 0);
+  // expected-error@+1{{too many arguments}}
+  open64("/", 0, 0, 0);
+  // expected-error@+1{{too many arguments}}
+  openat(0, "/", 0, 0, 0);
+  // expected-error@+1{{too many arguments}}
+  openat64(0, "/", 0, 0, 0);
+#endif
+
+  // expected-error@+1{{missing mode}}
+  EXPECT_FORTIFY_DEATH(open(target, O_CREAT));
+  // expected-error@+1{{missing mode}}
+  EXPECT_FORTIFY_DEATH(open(target, O_TMPFILE));
+  // expected-error@+1{{missing mode}}
+  EXPECT_FORTIFY_DEATH(open64(target, O_CREAT));
+  // expected-error@+1{{missing mode}}
+  EXPECT_FORTIFY_DEATH(open64(target, O_TMPFILE));
+  // expected-error@+1{{missing mode}}
+  EXPECT_FORTIFY_DEATH(openat(dirfd, target, O_CREAT));
+  // expected-error@+1{{missing mode}}
+  EXPECT_FORTIFY_DEATH(openat(dirfd, target, O_TMPFILE));
+  // expected-error@+1{{missing mode}}
+  EXPECT_FORTIFY_DEATH(openat64(dirfd, target, O_CREAT));
+  // expected-error@+1{{missing mode}}
+  EXPECT_FORTIFY_DEATH(openat64(dirfd, target, O_TMPFILE));
+
+  // expected-warning@+1{{superfluous mode bits}}
+  EXPECT_NO_DEATH(open(target, O_RDONLY, 0777));
+  // expected-warning@+1{{superfluous mode bits}}
+  EXPECT_NO_DEATH(open64(target, O_RDONLY, 0777));
+  // expected-warning@+1{{superfluous mode bits}}
+  EXPECT_NO_DEATH(openat(dirfd, target, O_RDONLY, 0777));
+  // expected-warning@+1{{superfluous mode bits}}
+  EXPECT_NO_DEATH(openat64(dirfd, target, O_RDONLY, 0777));
+}
+
 // Since these emit hard errors, it's sort of hard to run them...
 #ifdef COMPILATION_TESTS
 namespace compilation_tests {
@@ -261,49 +303,6 @@
   __builtin_unreachable();
 }
 
-static void testFcntl() {
-  // expected-error@+1{{too many arguments}}
-  open("/", 0, 0, 0);
-#if 0
-  // expected-error@+1{{either with 2 or 3 arguments, not more}}
-#endif
-  open64("/", 0, 0, 0);
-  // expected-error@+1{{too many arguments}}
-  openat(0, "/", 0, 0, 0);
-#if 0
-  // expected-error@+1{{either with 3 or 4 arguments, not more}}
-#endif
-  openat64(0, "/", 0, 0, 0);
-
-  // expected-error@+1{{missing mode}}
-  open("/", O_CREAT);
-  // expected-error@+1{{missing mode}}
-  open("/", O_TMPFILE);
-#if 0
-  // expected-error@+1{{needs 3 arguments}}
-#endif
-  open64("/", O_CREAT);
-#if 0
-  // expected-error@+1{{needs 3 arguments}}
-#endif
-  open64("/", O_TMPFILE);
-  // expected-error@+1{{missing mode}}
-  openat(0, "/", O_CREAT);
-  // expected-error@+1{{missing mode}}
-  openat(0, "/", O_TMPFILE);
-#if 0
-  // expected-error@+1{{needs 4 arguments}}
-#endif
-  openat64(0, "/", O_CREAT);
-#if 0
-  // expected-error@+1{{needs 4 arguments}}
-#endif
-  openat64(0, "/", O_TMPFILE);
-
-  // Superfluous modes are sometimes bugs, but not often enough to complain
-  // about, apparently.
-}
-
 static void testFormatStrings() {
   const auto unsigned_value = declval<unsigned long long>();
   const auto* unknown_string = declval<const char*>();