Merge "Fix mistake in fdsan documentation."
diff --git a/libc/bionic/android_set_abort_message.cpp b/libc/bionic/android_set_abort_message.cpp
index 268c4f3..58f24cf 100644
--- a/libc/bionic/android_set_abort_message.cpp
+++ b/libc/bionic/android_set_abort_message.cpp
@@ -29,6 +29,8 @@
 #include <android/set_abort_message.h>
 
 #include <pthread.h>
+#include <stdint.h>
+#include <stddef.h>
 #include <string.h>
 #include <sys/mman.h>
 
@@ -41,9 +43,32 @@
   size_t size;
   char msg[0];
 };
+static_assert(
+    offsetof(abort_msg_t, msg) == sizeof(size_t),
+    "The in-memory layout of abort_msg_t is not consistent with what libdebuggerd expects.");
+
+struct magic_abort_msg_t {
+  uint64_t magic1;
+  uint64_t magic2;
+  abort_msg_t msg;
+};
+static_assert(offsetof(magic_abort_msg_t, msg) == 2 * sizeof(uint64_t),
+              "The in-memory layout of magic_abort_msg_t is not consistent with what automated "
+              "tools expect.");
 
 abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common.
 
+[[clang::optnone]]
+static void fill_abort_message_magic(magic_abort_msg_t* new_magic_abort_message) {
+  // 128-bit magic for the abort message. Chosen by fair dice roll.
+  // This function is intentionally deoptimized to avoid the magic to be present
+  // in the final binary. This causes clang to only use instructions where parts
+  // of the magic are encoded into immediate arguments for the instructions in
+  // all supported architectures.
+  new_magic_abort_message->magic1 = 0xb18e40886ac388f0ULL;
+  new_magic_abort_message->magic2 = 0xc6dfba755a1de0b5ULL;
+}
+
 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
 void android_set_abort_message(const char* msg) {
   ScopedPthreadMutexLocker locker(&g_abort_msg_lock);
@@ -59,14 +84,15 @@
     return;
   }
 
-  size_t size = sizeof(abort_msg_t) + strlen(msg) + 1;
+  size_t size = sizeof(magic_abort_msg_t) + strlen(msg) + 1;
   void* map = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
   if (map == MAP_FAILED) {
     return;
   }
 
-  abort_msg_t* new_abort_message = reinterpret_cast<abort_msg_t*>(map);
-  new_abort_message->size = size;
-  strcpy(new_abort_message->msg, msg);
-  *__abort_message_ptr = new_abort_message;
+  magic_abort_msg_t* new_magic_abort_message = reinterpret_cast<magic_abort_msg_t*>(map);
+  fill_abort_message_magic(new_magic_abort_message);
+  new_magic_abort_message->msg.size = size;
+  strcpy(new_magic_abort_message->msg.msg, msg);
+  *__abort_message_ptr = &new_magic_abort_message->msg;
 }
diff --git a/libc/stdio/vfprintf.cpp b/libc/stdio/vfprintf.cpp
index 8b247e9..d99d09c 100644
--- a/libc/stdio/vfprintf.cpp
+++ b/libc/stdio/vfprintf.cpp
@@ -453,7 +453,7 @@
       case 'n':
         __fortify_fatal("%%n not allowed on Android");
       case 'm':
-        cp = strerror(caller_errno);
+        cp = strerror_r(caller_errno, buf, sizeof(buf));
         goto string;
       case 'O':
         flags |= LONGINT;
diff --git a/libc/stdio/vfwprintf.cpp b/libc/stdio/vfwprintf.cpp
index 19cce17..dd51eec 100644
--- a/libc/stdio/vfwprintf.cpp
+++ b/libc/stdio/vfwprintf.cpp
@@ -439,7 +439,8 @@
         __fortify_fatal("%%n not allowed on Android");
       case 'm':
         free(convbuf);
-        convbuf = helpers::mbsconv(strerror(caller_errno), prec);
+        convbuf = helpers::mbsconv(strerror_r(caller_errno,
+                                              reinterpret_cast<char*>(buf), sizeof(buf)), prec);
         if (convbuf == nullptr) {
             fp->_flags |= __SERR;
             goto error;
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 4107a74..54b913a 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -2369,6 +2369,16 @@
   ASSERT_STREQ("<Invalid argument>", buf);
 }
 
+TEST(STDIO_TEST, printf_m_does_not_clobber_strerror) {
+  char buf[BUFSIZ];
+  const char* m = strerror(-1);
+  ASSERT_STREQ("Unknown error -1", m);
+  errno = -2;
+  snprintf(buf, sizeof(buf), "<%m>");
+  ASSERT_STREQ("<Unknown error -2>", buf);
+  ASSERT_STREQ("Unknown error -1", m);
+}
+
 TEST(STDIO_TEST, wprintf_m) {
   wchar_t buf[BUFSIZ];
   errno = 0;
@@ -2382,6 +2392,16 @@
   ASSERT_EQ(std::wstring(L"<Invalid argument>"), buf);
 }
 
+TEST(STDIO_TEST, wprintf_m_does_not_clobber_strerror) {
+  wchar_t buf[BUFSIZ];
+  const char* m = strerror(-1);
+  ASSERT_STREQ("Unknown error -1", m);
+  errno = -2;
+  swprintf(buf, sizeof(buf), L"<%m>");
+  ASSERT_EQ(std::wstring(L"<Unknown error -2>"), buf);
+  ASSERT_STREQ("Unknown error -1", m);
+}
+
 TEST(STDIO_TEST, fopen_append_mode_and_ftell) {
   TemporaryFile tf;
   SetFileTo(tf.filename, "0123456789");