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");