Merge "Document the historical dlopen issues."
diff --git a/docs/status.md b/docs/status.md
index a0e6824..e81ac7e 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -173,3 +173,31 @@
 bug we found that existing code relied on the old behavior. To preserve
 compatibility, `sem_wait` can only return EINTR on Android if the app
 targets N or later.
+
+
+## FORTIFY
+
+The `_FORTIFY_SOURCE` macro can be used to enable extra
+automatic bounds checking for common libc functions. If a buffer
+overrun is detected, the program is safely aborted as in this
+(example)[https://source.android.com/devices/tech/debug/native-crash#fortify].
+
+Note that in recent releases Android's FORTIFY has been extended to
+cover other issues. It can now detect, for example, passing `O_CREAT`
+to open(2) without specifying a mode. It also performs some checking
+regardless of whether the caller was built with FORTIFY enabled. In P,
+for example, calling a `pthread_mutex_` function on a destroyed mutex,
+calling a `<dirent.h>` function on a null pointer, using `%n` with the
+printf(3) family, or using the scanf(3) `m` modifier incorrectly will
+all result in FORTIFY failures even for code not built with FORTIFY.
+
+More background information is available in our
+(FORTIFY in Android)[https://android-developers.googleblog.com/2017/04/fortify-in-android.html]
+blog post.
+
+The Android platform is built with `-D_FORTIFY_SOURCE=2`, but NDK users
+need to manually enable FORTIFY by setting that themselves in whatever
+build system they're using. The exact subset of FORTIFY available to
+NDK users will depend on their target ABI level, because when a FORTIFY
+check can't be guaranteed at compile-time, a call to a run-time `_chk`
+function is added.
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
index d5aad16..1018ef5 100644
--- a/libc/async_safe/async_safe_log.cpp
+++ b/libc/async_safe/async_safe_log.cpp
@@ -537,7 +537,7 @@
 
   // Log to stderr for the benefit of "adb shell" users and gtests.
   struct iovec iov[2] = {
-      {msg, os.total}, {const_cast<char*>("\n"), 1},
+      {msg, strlen(msg)}, {const_cast<char*>("\n"), 1},
   };
   TEMP_FAILURE_RETRY(writev(2, iov, 2));
 
diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp
index 2442fd9..2b3200c 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -221,9 +221,7 @@
     case _SC_LEVEL4_CACHE_LINESIZE:   return 0;
 
     default:
-      // Posix says EINVAL is the only error that shall be returned,
-      // but glibc uses ENOSYS.
-      errno = ENOSYS;
+      errno = EINVAL;
       return -1;
   }
 }
diff --git a/libc/kernel/tools/generate_uapi_headers.sh b/libc/kernel/tools/generate_uapi_headers.sh
index 4603fbe..575da31 100755
--- a/libc/kernel/tools/generate_uapi_headers.sh
+++ b/libc/kernel/tools/generate_uapi_headers.sh
@@ -248,6 +248,9 @@
 copy_hdrs "${KERNEL_DIR}/${src_dir}/drivers/staging/android/uapi" \
           "${ANDROID_KERNEL_DIR}/uapi/linux" "no-copy-dirs"
 
+# Remove ion.h, it's not fully supported by the upstream kernel (see b/77976082).
+rm "${ANDROID_KERNEL_DIR}/uapi/linux/ion.h"
+
 # Copy the generated headers.
 copy_hdrs "${KERNEL_DIR}/${src_dir}/include/generated/uapi" \
           "${ANDROID_KERNEL_DIR}/uapi"
diff --git a/libc/kernel/uapi/linux/ion.h b/libc/kernel/uapi/linux/ion.h
deleted file mode 100644
index 7c9e6d7..0000000
--- a/libc/kernel/uapi/linux/ion.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/****************************************************************************
- ****************************************************************************
- ***
- ***   This header was automatically generated from a Linux kernel header
- ***   of the same name, to make information necessary for userspace to
- ***   call into the kernel available to libc.  It contains only constants,
- ***   structures, and macros generated from the original header, and thus,
- ***   contains no copyrightable information.
- ***
- ***   To edit the content of this header, modify the corresponding
- ***   source file (e.g. under external/kernel-headers/original/) then
- ***   run bionic/libc/kernel/tools/update_all.py
- ***
- ***   Any manual change here will be lost the next time this script will
- ***   be run. You've been warned!
- ***
- ****************************************************************************
- ****************************************************************************/
-#ifndef _UAPI_LINUX_ION_H
-#define _UAPI_LINUX_ION_H
-#include <linux/ioctl.h>
-#include <linux/types.h>
-enum ion_heap_type {
-  ION_HEAP_TYPE_SYSTEM,
-  ION_HEAP_TYPE_SYSTEM_CONTIG,
-  ION_HEAP_TYPE_CARVEOUT,
-  ION_HEAP_TYPE_CHUNK,
-  ION_HEAP_TYPE_DMA,
-  ION_HEAP_TYPE_CUSTOM,
-};
-#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
-#define ION_FLAG_CACHED 1
-struct ion_allocation_data {
-  __u64 len;
-  __u32 heap_id_mask;
-  __u32 flags;
-  __u32 fd;
-  __u32 unused;
-};
-#define MAX_HEAP_NAME 32
-struct ion_heap_data {
-  char name[MAX_HEAP_NAME];
-  __u32 type;
-  __u32 heap_id;
-  __u32 reserved0;
-  __u32 reserved1;
-  __u32 reserved2;
-};
-struct ion_heap_query {
-  __u32 cnt;
-  __u32 reserved0;
-  __u64 heaps;
-  __u32 reserved1;
-  __u32 reserved2;
-};
-#define ION_IOC_MAGIC 'I'
-#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, struct ion_allocation_data)
-#define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, struct ion_heap_query)
-#endif
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
index f811a5e..85139e6 100644
--- a/libc/malloc_debug/PointerData.cpp
+++ b/libc/malloc_debug/PointerData.cpp
@@ -392,10 +392,12 @@
     FrameInfoType* b_frame = b.frame_info;
     if (a_frame == nullptr && b_frame != nullptr) {
       return false;
-    }
-    if (a_frame != nullptr && b_frame == nullptr) {
+    } else if (a_frame != nullptr && b_frame == nullptr) {
       return true;
+    } else if (a_frame == nullptr && b_frame == nullptr) {
+      return a.pointer < b.pointer;
     }
+
     // Put the pointers with longest backtrace first.
     if (a_frame->frames.size() != b_frame->frames.size()) {
       return a_frame->frames.size() > b_frame->frames.size();
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 8b28188..1504d06 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -1756,6 +1756,53 @@
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
 
+TEST_F(MallocDebugTest, backtrace_frame_data_nullptr_same_size) {
+  Init("backtrace=4");
+
+  size_t individual_size = GetInfoEntrySize(4);
+
+  void* pointers[4];
+  pointers[0] = debug_malloc(100);
+  ASSERT_TRUE(pointers[0] != nullptr);
+  pointers[1] = debug_malloc(100);
+  ASSERT_TRUE(pointers[1] != nullptr);
+  pointers[2] = debug_malloc(100);
+  ASSERT_TRUE(pointers[2] != nullptr);
+  pointers[3] = debug_malloc(100);
+  ASSERT_TRUE(pointers[3] != nullptr);
+
+  uint8_t* info;
+  size_t overall_size;
+  size_t info_size;
+  size_t total_memory;
+  size_t backtrace_size;
+
+  debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
+  ASSERT_TRUE(info != nullptr);
+  ASSERT_EQ(individual_size, overall_size);
+  EXPECT_EQ(individual_size, info_size);
+  EXPECT_EQ(400U, total_memory);
+  EXPECT_EQ(4U, backtrace_size);
+
+  EXPECT_EQ(100U, *reinterpret_cast<size_t*>(&info[0]));
+  EXPECT_EQ(4U, *reinterpret_cast<size_t*>(&info[sizeof(size_t)]));
+  uintptr_t* ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t)]);
+  EXPECT_EQ(0U, ips[0]);
+
+  debug_free_malloc_leak_info(info);
+
+  debug_free(pointers[0]);
+  debug_free(pointers[1]);
+  debug_free(pointers[2]);
+  debug_free(pointers[3]);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+      SIGRTMAX - 17, getpid());
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
 TEST_F(MallocDebugTest, overflow) {
   Init("guard fill_on_free");
 
diff --git a/libc/system_properties/context_node.cpp b/libc/system_properties/context_node.cpp
index 5496b5a..d392c0a 100644
--- a/libc/system_properties/context_node.cpp
+++ b/libc/system_properties/context_node.cpp
@@ -51,7 +51,7 @@
 
   char filename[PROP_FILENAME_MAX];
   int len = async_safe_format_buffer(filename, sizeof(filename), "%s/%s", filename_, context_);
-  if (len < 0 || len > PROP_FILENAME_MAX) {
+  if (len < 0 || len >= PROP_FILENAME_MAX) {
     lock_.unlock();
     return false;
   }
@@ -86,7 +86,7 @@
 bool ContextNode::CheckAccess() {
   char filename[PROP_FILENAME_MAX];
   int len = async_safe_format_buffer(filename, sizeof(filename), "%s/%s", filename_, context_);
-  if (len < 0 || len > PROP_FILENAME_MAX) {
+  if (len < 0 || len >= PROP_FILENAME_MAX) {
     return false;
   }
 
diff --git a/libc/system_properties/contexts_serialized.cpp b/libc/system_properties/contexts_serialized.cpp
index 062e8a5..12e9715 100644
--- a/libc/system_properties/contexts_serialized.cpp
+++ b/libc/system_properties/contexts_serialized.cpp
@@ -68,7 +68,7 @@
 bool ContextsSerialized::MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed) {
   char filename[PROP_FILENAME_MAX];
   int len = async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial", filename_);
-  if (len < 0 || len > PROP_FILENAME_MAX) {
+  if (len < 0 || len >= PROP_FILENAME_MAX) {
     serial_prop_area_ = nullptr;
     return false;
   }
diff --git a/libc/system_properties/contexts_split.cpp b/libc/system_properties/contexts_split.cpp
index 92baedd..11db7ec 100644
--- a/libc/system_properties/contexts_split.cpp
+++ b/libc/system_properties/contexts_split.cpp
@@ -196,7 +196,7 @@
 bool ContextsSplit::MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed) {
   char filename[PROP_FILENAME_MAX];
   int len = async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial", filename_);
-  if (len < 0 || len > PROP_FILENAME_MAX) {
+  if (len < 0 || len >= PROP_FILENAME_MAX) {
     serial_prop_area_ = nullptr;
     return false;
   }
diff --git a/libc/system_properties/system_properties.cpp b/libc/system_properties/system_properties.cpp
index 7c48b8e..d5c3647 100644
--- a/libc/system_properties/system_properties.cpp
+++ b/libc/system_properties/system_properties.cpp
@@ -67,7 +67,7 @@
     return true;
   }
 
-  if (strlen(filename) > PROP_FILENAME_MAX) {
+  if (strlen(filename) >= PROP_FILENAME_MAX) {
     return false;
   }
   strcpy(property_filename_, filename);
@@ -95,7 +95,7 @@
 }
 
 bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
-  if (strlen(filename) > PROP_FILENAME_MAX) {
+  if (strlen(filename) >= PROP_FILENAME_MAX) {
     return false;
   }
   strcpy(property_filename_, filename);
diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h
index 03520d7..cd8b09d 100644
--- a/linker/linker_namespaces.h
+++ b/linker/linker_namespaces.h
@@ -54,6 +54,9 @@
   }
 
   bool is_accessible(const char* soname) const {
+    if (soname == nullptr) {
+      return false;
+    }
     return allow_all_shared_libs_ || shared_lib_sonames_.find(soname) != shared_lib_sonames_.end();
   }
 
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index db4859b..fd99455 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -836,19 +836,23 @@
 #endif // defined(__BIONIC__)
 }
 
-#define VERIFY_SYSCONF_UNSUPPORTED(name) VerifySysconf(name, #name, [](long v){return v == -1;})
+#define VERIFY_SYSCONF_UNKNOWN(name) \
+  VerifySysconf(name, #name, [](long v){return v == -1 && errno == EINVAL;})
+
+#define VERIFY_SYSCONF_UNSUPPORTED(name) \
+  VerifySysconf(name, #name, [](long v){return v == -1 && errno == 0;})
 
 // sysconf() means unlimited when it returns -1 with errno unchanged.
 #define VERIFY_SYSCONF_POSITIVE(name) \
-  VerifySysconf(name, #name, [](long v){return (v > 0 || v == -1);})
+  VerifySysconf(name, #name, [](long v){return (v > 0 || v == -1) && errno == 0;})
 
 #define VERIFY_SYSCONF_POSIX_VERSION(name) \
-  VerifySysconf(name, #name, [](long v){return v == _POSIX_VERSION;})
+  VerifySysconf(name, #name, [](long v){return v == _POSIX_VERSION && errno == 0;})
 
 static void VerifySysconf(int option, const char *option_name, bool (*verify)(long)) {
   errno = 0;
   long ret = sysconf(option);
-  EXPECT_TRUE(0 == errno && verify(ret)) << "name = " << option_name << ", ret = "
+  EXPECT_TRUE(verify(ret)) << "name = " << option_name << ", ret = "
       << ret <<", Error Message: " << strerror(errno);
 }
 
@@ -879,17 +883,17 @@
   VERIFY_SYSCONF_POSITIVE(_SC_RE_DUP_MAX);
   VERIFY_SYSCONF_POSITIVE(_SC_STREAM_MAX);
   VERIFY_SYSCONF_POSITIVE(_SC_TZNAME_MAX);
-  VerifySysconf(_SC_XOPEN_VERSION, "_SC_XOPEN_VERSION", [](long v){return v == _XOPEN_VERSION;});
+  VerifySysconf(_SC_XOPEN_VERSION, "_SC_XOPEN_VERSION", [](long v){return v == _XOPEN_VERSION && errno == 0;});
   VERIFY_SYSCONF_POSITIVE(_SC_ATEXIT_MAX);
   VERIFY_SYSCONF_POSITIVE(_SC_IOV_MAX);
   VERIFY_SYSCONF_POSITIVE(_SC_PAGESIZE);
   VERIFY_SYSCONF_POSITIVE(_SC_PAGE_SIZE);
   VerifySysconf(_SC_PAGE_SIZE, "_SC_PAGE_SIZE",
-                [](long v){return v == sysconf(_SC_PAGESIZE) && v == getpagesize();});
+                [](long v){return v == sysconf(_SC_PAGESIZE) && errno == 0 && v == getpagesize();});
   VERIFY_SYSCONF_POSITIVE(_SC_XOPEN_UNIX);
   VERIFY_SYSCONF_POSITIVE(_SC_AIO_LISTIO_MAX);
   VERIFY_SYSCONF_POSITIVE(_SC_AIO_MAX);
-  VerifySysconf(_SC_AIO_PRIO_DELTA_MAX, "_SC_AIO_PRIO_DELTA_MAX", [](long v){return v >= 0;});
+  VerifySysconf(_SC_AIO_PRIO_DELTA_MAX, "_SC_AIO_PRIO_DELTA_MAX", [](long v){return v >= 0 && errno == 0;});
   VERIFY_SYSCONF_POSITIVE(_SC_DELAYTIMER_MAX);
   VERIFY_SYSCONF_POSITIVE(_SC_MQ_OPEN_MAX);
   VERIFY_SYSCONF_POSITIVE(_SC_MQ_PRIO_MAX);
@@ -1024,6 +1028,11 @@
   ASSERT_EQ(ARG_MAX, sysconf(_SC_ARG_MAX));
 }
 
+TEST(UNISTD_TEST, sysconf_unknown) {
+  VERIFY_SYSCONF_UNKNOWN(-1);
+  VERIFY_SYSCONF_UNKNOWN(666);
+}
+
 TEST(UNISTD_TEST, dup2_same) {
   // POSIX says of dup2:
   // If fildes2 is already a valid open file descriptor ...