Merge "Fix wchar.wcstold_hex_floats on arm64"
diff --git a/libc/Android.bp b/libc/Android.bp
index 42d0914..be45f40 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1385,6 +1385,7 @@
     defaults: ["libc_defaults"],
     srcs: [
         "bionic/NetdClientDispatch.cpp",
+        "bionic/__bionic_get_shell_path.cpp",
         "bionic/__cmsg_nxthdr.cpp",
         "bionic/__errno.cpp",
         "bionic/__gnu_basename.cpp",
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
index 99ff0c7..d81ef34 100644
--- a/libc/async_safe/async_safe_log.cpp
+++ b/libc/async_safe/async_safe_log.cpp
@@ -60,43 +60,36 @@
 
 struct BufferOutputStream {
  public:
-  BufferOutputStream(char* buffer, size_t size) : total(0) {
-    buffer_ = buffer;
-    end_ = buffer + size - 1;
-    pos_ = buffer_;
-    pos_[0] = '\0';
+  BufferOutputStream(char* buffer, size_t size) : total(0), pos_(buffer), avail_(size) {
+    if (avail_ > 0) pos_[0] = '\0';
   }
-
-  ~BufferOutputStream() {}
+  ~BufferOutputStream() = default;
 
   void Send(const char* data, int len) {
     if (len < 0) {
       len = strlen(data);
     }
-
     total += len;
 
-    while (len > 0) {
-      int avail = end_ - pos_;
-      if (avail == 0) {
-        return;
-      }
-      if (avail > len) {
-        avail = len;
-      }
-      memcpy(pos_, data, avail);
-      pos_ += avail;
-      pos_[0] = '\0';
-      len -= avail;
+    if (avail_ <= 1) {
+      // No space to put anything else.
+      return;
     }
+
+    if (static_cast<size_t>(len) >= avail_) {
+      len = avail_ - 1;
+    }
+    memcpy(pos_, data, len);
+    pos_ += len;
+    pos_[0] = '\0';
+    avail_ -= len;
   }
 
   size_t total;
 
  private:
-  char* buffer_;
   char* pos_;
-  char* end_;
+  size_t avail_;
 };
 
 struct FdOutputStream {
@@ -107,16 +100,15 @@
     if (len < 0) {
       len = strlen(data);
     }
-
     total += len;
 
     while (len > 0) {
-      int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
-      if (rc == -1) {
+      ssize_t bytes = TEMP_FAILURE_RETRY(write(fd_, data, len));
+      if (bytes == -1) {
         return;
       }
-      data += rc;
-      len -= rc;
+      data += bytes;
+      len -= bytes;
     }
   }
 
@@ -409,15 +401,6 @@
   }
 }
 
-int async_safe_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
-  BufferOutputStream os(buffer, buffer_size);
-  va_list args;
-  va_start(args, format);
-  out_vformat(os, format, args);
-  va_end(args);
-  return os.total;
-}
-
 int async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format,
                                      va_list args) {
   BufferOutputStream os(buffer, buffer_size);
@@ -425,6 +408,14 @@
   return os.total;
 }
 
+int async_safe_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  int buffer_len = async_safe_format_buffer_va_list(buffer, buffer_size, format, args);
+  va_end(args);
+  return buffer_len;
+}
+
 int async_safe_format_fd(int fd, const char* format, ...) {
   FdOutputStream os(fd);
   va_list args;
diff --git a/libc/bionic/__bionic_get_shell_path.cpp b/libc/bionic/__bionic_get_shell_path.cpp
new file mode 100644
index 0000000..477fa4a
--- /dev/null
+++ b/libc/bionic/__bionic_get_shell_path.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <unistd.h>
+
+__LIBC_HIDDEN__ static const char* __libc_system_sh = "/system/bin/sh";
+__LIBC_HIDDEN__ static const char* __libc_vendor_sh = "/vendor/bin/sh";
+
+static const char* init_sh_path() {
+  /* look for /system or /vendor prefix */
+  char exe_path[7];
+  ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path));
+  if (len != -1 && !strncmp(exe_path, __libc_vendor_sh, sizeof(exe_path))) {
+    return __libc_vendor_sh;
+  }
+
+  return __libc_system_sh;
+}
+
+__LIBC_HIDDEN__ extern "C" const char* __bionic_get_shell_path() {
+  static const char* sh_path = init_sh_path();
+  return sh_path;
+}
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index a958699..6906ecd 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -1051,16 +1051,15 @@
     if (!initialize_properties_from_file("/system/etc/selinux/plat_property_contexts")) {
       return false;
     }
-    if (!initialize_properties_from_file("/vendor/etc/selinux/nonplat_property_contexts")) {
-      return false;
-    }
+    // Don't check for failure here, so we always have a sane list of properties.
+    // E.g. In case of recovery, the vendor partition will not have mounted and we
+    // still need the system / platform properties to function.
+    initialize_properties_from_file("/vendor/etc/selinux/nonplat_property_contexts");
   } else {
     if (!initialize_properties_from_file("/plat_property_contexts")) {
       return false;
     }
-    if (!initialize_properties_from_file("/nonplat_property_contexts")) {
-      return false;
-    }
+    initialize_properties_from_file("/nonplat_property_contexts");
   }
 
   return true;
diff --git a/libc/include/arpa/nameser.h b/libc/include/arpa/nameser.h
index 9507f49..ffb5250 100644
--- a/libc/include/arpa/nameser.h
+++ b/libc/include/arpa/nameser.h
@@ -562,63 +562,61 @@
 #define	ns_makecanon		__ns_makecanon
 #define	ns_samename		__ns_samename
 
-int ns_msg_getflag(ns_msg, int);
-uint16_t ns_get16(const u_char*);
-uint32_t ns_get32(const u_char*);
-void ns_put16(uint16_t, u_char*);
-void ns_put32(uint32_t, u_char*);
-int ns_initparse(const u_char*, int, ns_msg*);
-int ns_skiprr(const u_char*, const u_char*, ns_sect, int);
-int ns_parserr(ns_msg*, ns_sect, int, ns_rr*);
-int ns_sprintrr(const ns_msg*, const ns_rr*, const char*, const char*, char*, size_t);
-int ns_sprintrrf(const u_char*, size_t, const char*, ns_class, ns_type, u_long, const u_char*,
-                 size_t, const char*, const char*, char*, size_t);
-int ns_format_ttl(u_long, char*, size_t);
-int ns_name_ntol(const u_char*, u_char*, size_t);
-int ns_name_ntop(const u_char*, char*, size_t);
-int ns_name_pton(const char*, u_char*, size_t);
-int ns_name_unpack(const u_char*, const u_char*, const u_char*, u_char*, size_t);
-int ns_name_pack(const u_char*, u_char*, int, const u_char**, const u_char**);
-int ns_name_uncompress(const u_char*, const u_char*, const u_char*, char*, size_t);
-int ns_name_compress(const char*, u_char*, size_t, const u_char**, const u_char**);
-int ns_name_skip(const u_char**, const u_char*);
-void ns_name_rollback(const u_char*, const u_char**, const u_char**);
+int ns_msg_getflag(ns_msg __handle, int __flag);
+uint16_t ns_get16(const u_char* __src);
+uint32_t ns_get32(const u_char* __src);
+void ns_put16(uint16_t __src, u_char* __dst);
+void ns_put32(uint32_t __src, u_char* __dst);
+int ns_initparse(const u_char* __msg, int __msg_size, ns_msg* __handle);
+int ns_skiprr(const u_char* __ptr, const u_char* __eom, ns_sect __section, int __count);
+int ns_parserr(ns_msg* __handle, ns_sect __section, int __rr_number, ns_rr* __rr);
+int ns_sprintrr(const ns_msg* __handle, const ns_rr* __rr, const char* __name_ctx, const char* __origin, char* __buf, size_t __buf_size);
+int ns_sprintrrf(const u_char* __msg, size_t __msg_size, const char* __name, ns_class __class, ns_type __type, u_long __ttl, const u_char* __rdata, size_t __rdata_size, const char* __name_ctx, const char* __origin, char* __buf, size_t __buf_size);
+int ns_format_ttl(u_long __ttl, char* __dst, size_t __dst_size);
+int ns_name_ntol(const u_char* __src, u_char* __dst, size_t __dst_size);
+int ns_name_ntop(const u_char* __src, char* __dst, size_t __dst_size);
+int ns_name_pton(const char* __src, u_char* __dst, size_t __dst_size);
+int ns_name_unpack(const u_char* __msg, const u_char* __eom, const u_char* __src, u_char* __dst, size_t __dst_size);
+int ns_name_pack(const u_char* __src, u_char* __dst, int __dst_size, const u_char** __dn_ptrs, const u_char** __last_dn_ptr);
+int ns_name_uncompress(const u_char* __msg, const u_char* __eom, const u_char* __src, char* __dst, size_t __dst_size);
+int ns_name_compress(const char* __src, u_char* __dst, size_t __dst_size, const u_char** __dn_ptrs, const u_char** __last_dn_ptr);
+int ns_name_skip(const u_char** __ptr_ptr, const u_char* __eom);
+void ns_name_rollback(const u_char* __src, const u_char** __dn_ptrs, const u_char** __last_dn_ptr);
 
-int ns_makecanon(const char*, char*, size_t);
-int ns_samename(const char*, const char*);
+int ns_makecanon(const char* __src, char* __dst, size_t __dst_size);
+int ns_samename(const char* __lhs, const char* __rhs);
 
 #else
 /* The names of these symbols were accidentally prefixed with __ in L. */
 /* The duplication here is intentional to avoid declaring different symbols with the same
  * declaration. */
-int ns_msg_getflag(ns_msg, int) __INTRODUCED_IN_64(23);
-uint16_t ns_get16(const u_char*) __INTRODUCED_IN_64(23);
-uint32_t ns_get32(const u_char*) __INTRODUCED_IN_64(23);
-void ns_put16(uint16_t, u_char*) __INTRODUCED_IN_64(23);
-void ns_put32(uint32_t, u_char*) __INTRODUCED_IN_64(23);
-int ns_initparse(const u_char*, int, ns_msg*) __INTRODUCED_IN_64(23);
-int ns_skiprr(const u_char*, const u_char*, ns_sect, int) __INTRODUCED_IN_64(23);
-int ns_parserr(ns_msg*, ns_sect, int, ns_rr*) __INTRODUCED_IN_64(23);
-int ns_sprintrr(const ns_msg*, const ns_rr*, const char*, const char*, char*, size_t)
+int ns_msg_getflag(ns_msg __handle, int __flag) __INTRODUCED_IN_64(23);
+uint16_t ns_get16(const u_char* __src) __INTRODUCED_IN_64(23);
+uint32_t ns_get32(const u_char* __src) __INTRODUCED_IN_64(23);
+void ns_put16(uint16_t __src, u_char* __dst) __INTRODUCED_IN_64(23);
+void ns_put32(uint32_t __src, u_char* __dst) __INTRODUCED_IN_64(23);
+int ns_initparse(const u_char* __msg, int __msg_size, ns_msg* __handle) __INTRODUCED_IN_64(23);
+int ns_skiprr(const u_char* __ptr, const u_char* __eom, ns_sect __section, int __count) __INTRODUCED_IN_64(23);
+int ns_parserr(ns_msg* __handle, ns_sect __section, int __rr_number, ns_rr* __rr) __INTRODUCED_IN_64(23);
+int ns_sprintrr(const ns_msg* __handle, const ns_rr* __rr, const char* __name_ctx, const char* __origin, char* __buf, size_t __buf_size)
   __INTRODUCED_IN_64(23);
-int ns_sprintrrf(const u_char*, size_t, const char*, ns_class, ns_type, u_long, const u_char*,
-                 size_t, const char*, const char*, char*, size_t) __INTRODUCED_IN_64(23);
-int ns_format_ttl(u_long, char*, size_t) __INTRODUCED_IN_64(23);
-int ns_name_ntol(const u_char*, u_char*, size_t) __INTRODUCED_IN_64(23);
-int ns_name_ntop(const u_char*, char*, size_t) __INTRODUCED_IN_64(23);
-int ns_name_pton(const char*, u_char*, size_t) __INTRODUCED_IN_64(23);
-int ns_name_unpack(const u_char*, const u_char*, const u_char*, u_char*, size_t)
+int ns_sprintrrf(const u_char* __msg, size_t __msg_size, const char* __name, ns_class __class, ns_type __type, u_long __ttl, const u_char* __rdata, size_t __rdata_size, const char* __name_ctx, const char* __origin, char* __buf, size_t __buf_size) __INTRODUCED_IN_64(23);
+int ns_format_ttl(u_long __ttl, char* __dst, size_t __dst_size) __INTRODUCED_IN_64(23);
+int ns_name_ntol(const u_char* __src, u_char* __dst, size_t __dst_size) __INTRODUCED_IN_64(23);
+int ns_name_ntop(const u_char* __src, char* __dst, size_t __dst_size) __INTRODUCED_IN_64(23);
+int ns_name_pton(const char* __src, u_char* __dst, size_t __dst_size) __INTRODUCED_IN_64(23);
+int ns_name_unpack(const u_char* __msg, const u_char* __eom, const u_char* __src, u_char* __dst, size_t __dst_size)
   __INTRODUCED_IN_64(23);
-int ns_name_pack(const u_char*, u_char*, int, const u_char**, const u_char**) __INTRODUCED_IN_64(23);
-int ns_name_uncompress(const u_char*, const u_char*, const u_char*, char*, size_t)
+int ns_name_pack(const u_char* __src, u_char* __dst, int __dst_size, const u_char** __dn_ptrs, const u_char** __last_dn_ptr) __INTRODUCED_IN_64(23);
+int ns_name_uncompress(const u_char* __msg, const u_char* __eom, const u_char* __src, char* __dst, size_t __dst_size)
   __INTRODUCED_IN_64(23);
-int ns_name_compress(const char*, u_char*, size_t, const u_char**, const u_char**)
+int ns_name_compress(const char* __src, u_char* __dst, size_t __dst_size, const u_char** __dn_ptrs, const u_char** __last_dn_ptr)
   __INTRODUCED_IN_64(23);
-int ns_name_skip(const u_char**, const u_char*) __INTRODUCED_IN_64(23);
-void ns_name_rollback(const u_char*, const u_char**, const u_char**) __INTRODUCED_IN_64(23);
+int ns_name_skip(const u_char** __ptr_ptr, const u_char* __eom) __INTRODUCED_IN_64(23);
+void ns_name_rollback(const u_char* __src, const u_char** __dn_ptrs, const u_char** __last_dn_ptr) __INTRODUCED_IN_64(23);
 
-int ns_makecanon(const char*, char*, size_t) __INTRODUCED_IN_64(23);
-int ns_samename(const char*, const char*) __INTRODUCED_IN_64(23);
+int ns_makecanon(const char* __src, char* __dst, size_t __dst_size) __INTRODUCED_IN_64(23);
+int ns_samename(const char* __lhs, const char* __rhs) __INTRODUCED_IN_64(23);
 #endif /* !defined(__LP64__) */
 
 __END_DECLS
diff --git a/libc/include/paths.h b/libc/include/paths.h
index b76d045..d2c5956 100644
--- a/libc/include/paths.h
+++ b/libc/include/paths.h
@@ -34,7 +34,9 @@
 
 #include <sys/cdefs.h>
 
+#ifndef _PATH_BSHELL
 #define	_PATH_BSHELL	"/system/bin/sh"
+#endif
 #define	_PATH_CONSOLE	"/dev/console"
 #define	_PATH_DEFPATH	"/sbin:/system/sbin:/system/bin:/system/xbin:/vendor/bin:/vendor/xbin"
 #define	_PATH_DEV	"/dev/"
diff --git a/libc/include/resolv.h b/libc/include/resolv.h
index 2c12819..d6db4cf 100644
--- a/libc/include/resolv.h
+++ b/libc/include/resolv.h
@@ -40,25 +40,25 @@
 __BEGIN_DECLS
 
 #define b64_ntop __b64_ntop
-int b64_ntop(u_char const*, size_t, char*, size_t);
+int b64_ntop(u_char const* __src, size_t __src_size, char* __dst, size_t __dst_size);
 #define b64_pton __b64_pton
-int b64_pton(char const*, u_char*, size_t);
+int b64_pton(char const* __src, u_char* __dst, size_t __dst_size);
 
 #define dn_comp __dn_comp
-int dn_comp(const char*, u_char*, int, u_char**, u_char**);
+int dn_comp(const char* __src, u_char* __dst, int __dst_size, u_char** __dn_ptrs , u_char** __last_dn_ptr);
 
-int dn_expand(const u_char*, const u_char*, const u_char*, char*, int);
+int dn_expand(const u_char* __msg, const u_char* __eom, const u_char* __src, char* __dst, int __dst_size);
 
 #define p_class __p_class
-const char* p_class(int);
+const char* p_class(int __class);
 #define p_type __p_type
-const char* p_type(int);
+const char* p_type(int __type);
 
 int res_init(void);
-int res_mkquery(int, const char*, int, int, const u_char*, int, const u_char*, u_char*, int);
-int res_query(const char*, int, int, u_char*, int);
-int res_search(const char*, int, int, u_char*, int);
+int res_mkquery(int __opcode, const char* __domain_name, int __class, int __type, const u_char* __data, int __data_size, const u_char* __new_rr_in, u_char* __buf, int __buf_size);
+int res_query(const char* __name, int __class, int __type, u_char* __answer, int __answer_size);
+int res_search(const char* __name, int __class, int __type, u_char* __answer, int __answer_size);
 
 __END_DECLS
 
-#endif /* _RESOLV_H_ */
+#endif
diff --git a/libc/tools/check-symbols-glibc.py b/libc/tools/check-symbols-glibc.py
index 631fd93..e40f3e3 100755
--- a/libc/tools/check-symbols-glibc.py
+++ b/libc/tools/check-symbols-glibc.py
@@ -186,14 +186,17 @@
 # being implemented (fattach).
 in_posix_and_glibc_but_actually_dead = set([
   'a64l',
+  'confstr',
   'fattach',
   'fdetach',
+  'gethostid',
   'getmsg',
   'getpmsg',
   'isastream',
   'l64a',
   'putmsg',
   'putpmsg',
+  'ulimit',
 ])
 
 posix = posix - in_posix_and_glibc_but_actually_dead
diff --git a/libc/upstream-netbsd/android/include/netbsd-compat.h b/libc/upstream-netbsd/android/include/netbsd-compat.h
index 45b974a..af5ae29 100644
--- a/libc/upstream-netbsd/android/include/netbsd-compat.h
+++ b/libc/upstream-netbsd/android/include/netbsd-compat.h
@@ -44,4 +44,8 @@
 #include <stddef.h>
 int reallocarr(void*, size_t, size_t);
 
+/* Use appropriate shell depending on process's executable. */
+__LIBC_HIDDEN__ extern const char* __bionic_get_shell_path();
+#define _PATH_BSHELL __bionic_get_shell_path()
+
 #endif
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index baf5057..d831435 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -71,6 +71,10 @@
  */
 #define _PATH_TMP "/data/local/tmp/"
 
+/* Use appropriate shell depending on process's executable. */
+__LIBC_HIDDEN__ extern const char* __bionic_get_shell_path();
+#define _PATH_BSHELL __bionic_get_shell_path()
+
 /* We have OpenBSD's getentropy_linux.c, but we don't mention getentropy in any header. */
 __LIBC_HIDDEN__ extern int getentropy(void*, size_t);
 
diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp
index 0a9aeab..2bdde1e 100644
--- a/linker/linker_config.cpp
+++ b/linker/linker_config.cpp
@@ -371,6 +371,15 @@
                                       bool is_asan,
                                       const Config** config,
                                       std::string* error_msg) {
+  // TODO(b/38114603) Currently, multiple namespaces does not support ASAN mode
+  // where some symbols should be intercepted via LD_PRELOAD; LD_PRELOADed libs
+  // are not being preloaded into the linked namespaces other than the default
+  // namespace. Until we fix the problem, we temporarily disable ld.config.txt
+  // in ASAN mode.
+  if (is_asan) {
+    return false;
+  }
+
   g_config.clear();
 
   std::unordered_map<std::string, PropertyValue> property_map;
diff --git a/linker/tests/linker_config_test.cpp b/linker/tests/linker_config_test.cpp
index c6fade9..87609d0 100644
--- a/linker/tests/linker_config_test.cpp
+++ b/linker/tests/linker_config_test.cpp
@@ -168,6 +168,7 @@
   run_linker_config_smoke_test(false);
 }
 
-TEST(linker_config, asan_smoke) {
-  run_linker_config_smoke_test(true);
-}
+// TODO(b/38114603) revive this test when ld.config.txt is enabled for ASAN mode
+//TEST(linker_config, asan_smoke) {
+//  run_linker_config_smoke_test(true);
+//}
diff --git a/tests/async_safe_test.cpp b/tests/async_safe_test.cpp
index 3d6fcaa..e71ba7a 100644
--- a/tests/async_safe_test.cpp
+++ b/tests/async_safe_test.cpp
@@ -181,8 +181,20 @@
   char buf[BUFSIZ];
   ASSERT_EQ(11, async_safe_format_buffer(buf, sizeof(buf), "hello %s", "world"));
   EXPECT_STREQ("hello world", buf);
+
   ASSERT_EQ(11, async_safe_format_buffer(buf, 8, "hello %s", "world"));
   EXPECT_STREQ("hello w", buf);
+
+  ASSERT_EQ(11, async_safe_format_buffer(buf, 6, "hello %s", "world"));
+  EXPECT_STREQ("hello", buf);
+
+  ASSERT_EQ(4, async_safe_format_buffer(nullptr, 0, "xxxx"));
+
+  ASSERT_EQ(4, async_safe_format_buffer(buf, 1, "xxxx"));
+  EXPECT_STREQ("", buf);
+
+  ASSERT_EQ(4, async_safe_format_buffer(buf, 2, "xxxx"));
+  EXPECT_STREQ("x", buf);
 #else // __BIONIC__
   GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif // __BIONIC__
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index 4532a4b..7e78830 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -20,6 +20,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <sys/utsname.h>
+#include <sys/vfs.h>
 
 #include "TemporaryFile.h"
 
@@ -28,6 +29,7 @@
 // Glibc v2.19 doesn't include these in fcntl.h so host builds will fail without.
 #if !defined(FALLOC_FL_PUNCH_HOLE) || !defined(FALLOC_FL_KEEP_SIZE)
 #include <linux/falloc.h>
+#include <linux/magic.h>
 #endif
 
 TEST(fcntl, fcntl_smoke) {
@@ -290,8 +292,12 @@
 
   if (major < 4 || (major == 4 && minor < 1)) {
     TemporaryFile tf;
-    ASSERT_EQ(-1, fallocate(tf.fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1));
-    ASSERT_EQ(errno, EOPNOTSUPP);
+    struct statfs sfs;
+    ASSERT_EQ(0, fstatfs(tf.fd, &sfs));
+    if (sfs.f_type == EXT4_SUPER_MAGIC) {
+      ASSERT_EQ(-1, fallocate(tf.fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1));
+      ASSERT_EQ(errno, EOPNOTSUPP);
+    }
   }
 }