Merge "Fix nullptr dereference during sort."
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/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();
   }