Merge "Cast ifunc resolver's return type"
diff --git a/docs/status.md b/docs/status.md
index 9521da8..bf246a6 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -50,7 +50,7 @@
Current libc symbols: https://android.googlesource.com/platform/bionic/+/master/libc/libc.map.txt
-New libc functions in T (API level 32):
+New libc functions in T (API level 33):
* `backtrace`, `backtrace_symbols`, `backtrace_symbols_fd` (`<execinfo.h>`).
* New system call wrappers: `preadv2`, `preadv64v2`, `pwritev2`,
`pwritev64v2`.
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
index 8b2a32b..2380e68 100644
--- a/libc/async_safe/async_safe_log.cpp
+++ b/libc/async_safe/async_safe_log.cpp
@@ -251,6 +251,7 @@
char sign = '\0';
int width = -1;
int prec = -1;
+ bool alternate = false;
size_t bytelen = sizeof(int);
int slen;
char buffer[32]; /* temporary buffer used to format numbers */
@@ -293,6 +294,9 @@
} else if (c == ' ' || c == '+') {
sign = c;
continue;
+ } else if (c == '#') {
+ alternate = true;
+ continue;
}
break;
}
@@ -344,9 +348,6 @@
if (c == 's') {
/* string */
str = va_arg(args, const char*);
- if (str == nullptr) {
- str = "(null)";
- }
} else if (c == 'c') {
/* character */
/* NOTE: char is promoted to int when passed through the stack */
@@ -357,6 +358,9 @@
buffer[0] = '0';
buffer[1] = 'x';
format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
+ } else if (c == 'm') {
+ char buf[256];
+ str = strerror_r(errno, buf, sizeof(buf));
} else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
/* integers - first read value from stack */
uint64_t value;
@@ -388,8 +392,19 @@
value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift);
}
- /* format the number properly into our buffer */
- format_integer(buffer, sizeof(buffer), value, c);
+ if (alternate && value != 0 && (c == 'x' || c == 'o')) {
+ if (c == 'x') {
+ buffer[0] = '0';
+ buffer[1] = 'x';
+ format_integer(buffer + 2, sizeof(buffer) - 2, value, c);
+ } else {
+ buffer[0] = '0';
+ format_integer(buffer + 1, sizeof(buffer) - 1, value, c);
+ }
+ } else {
+ /* format the number properly into our buffer */
+ format_integer(buffer, sizeof(buffer), value, c);
+ }
} else if (c == '%') {
buffer[0] = '%';
buffer[1] = '\0';
@@ -397,6 +412,10 @@
__assert(__FILE__, __LINE__, "conversion specifier unsupported");
}
+ if (str == nullptr) {
+ str = "(null)";
+ }
+
/* if we are here, 'str' points to the content that must be
* outputted. handle padding and alignment now */
diff --git a/tests/async_safe_test.cpp b/tests/async_safe_test.cpp
index 6c4758e..f52387e 100644
--- a/tests/async_safe_test.cpp
+++ b/tests/async_safe_test.cpp
@@ -64,6 +64,10 @@
async_safe_format_buffer(buf, sizeof(buf), "a%ldb", 70000L);
EXPECT_STREQ("a70000b", buf);
+ errno = EINVAL;
+ async_safe_format_buffer(buf, sizeof(buf), "a%mZ");
+ EXPECT_STREQ("aInvalid argumentZ", buf);
+
async_safe_format_buffer(buf, sizeof(buf), "a%pb", reinterpret_cast<void*>(0xb0001234));
EXPECT_STREQ("a0xb0001234b", buf);
@@ -97,6 +101,30 @@
async_safe_format_buffer(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5);
EXPECT_STREQ("a005:5:05z", buf);
+ async_safe_format_buffer(buf, sizeof(buf), "a%#xZ", 34);
+ EXPECT_STREQ("a0x22Z", buf);
+
+ async_safe_format_buffer(buf, sizeof(buf), "a%#xZ", 0);
+ EXPECT_STREQ("a0Z", buf);
+
+ async_safe_format_buffer(buf, sizeof(buf), "a%#5xZ", 20);
+ EXPECT_STREQ("a 0x14Z", buf);
+
+ snprintf(buf, sizeof(buf), "a%#08.8xZ", 1);
+ EXPECT_STREQ("a0x00000001Z", buf);
+
+ async_safe_format_buffer(buf, sizeof(buf), "a%#oZ", 777);
+ EXPECT_STREQ("a01411Z", buf);
+
+ async_safe_format_buffer(buf, sizeof(buf), "a%#oZ", 0);
+ EXPECT_STREQ("a0Z", buf);
+
+ async_safe_format_buffer(buf, sizeof(buf), "a%#6oZ", 15);
+ EXPECT_STREQ("a 017Z", buf);
+
+ snprintf(buf, sizeof(buf), "a%#08.8oZ", 11);
+ EXPECT_STREQ("a00000013Z", buf);
+
void* p = nullptr;
async_safe_format_buffer(buf, sizeof(buf), "a%d,%pz", 5, p);
EXPECT_STREQ("a5,0x0z", buf);
diff --git a/tests/cfi_test.cpp b/tests/cfi_test.cpp
index dd65a81..1c45946 100644
--- a/tests/cfi_test.cpp
+++ b/tests/cfi_test.cpp
@@ -19,7 +19,6 @@
#include <vector>
-#include <android-base/silent_death_test.h>
#include <gtest/gtest.h>
#include "gtest_globals.h"
@@ -36,7 +35,45 @@
size_t __cfi_shadow_size();
}
-using cfi_test_DeathTest = SilentDeathTest;
+// Disables debuggerd stack traces to speed up death tests, make them less
+// noisy in logcat, and avoid expected deaths from showing up in stability
+// metrics.
+// We don't use the usual libbase class because (a) we don't care about most
+// of the signals it blocks but (b) we do need to block SIGILL, which normal
+// death tests shouldn't ever hit. (It's possible that a design where a
+// deathtest always declares its expected signals up front is a better one,
+// and maybe that's an interesting future direction for libbase.)
+//
+// We include SIGSEGV because there's a test that passes heap addresses to
+// __cfi_slowpath and we only map the executable code shadow as readable.
+// We don't always get SIGSEGV there though: if the heap allocation happens
+// to be close enough to an executable mapping that its shadow is in the
+// same page as the executable shadow, we'll get SIGILL/SIGTRAP.
+class cfi_test_DeathTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ struct sigaction64 action = {.sa_handler = SIG_DFL};
+ sigaction64(SIGILL, &action, &previous_sigill_);
+ sigaction64(SIGSEGV, &action, &previous_sigsegv_);
+ sigaction64(SIGTRAP, &action, &previous_sigtrap_);
+ }
+
+ void TearDown() override {
+ sigaction64(SIGTRAP, &previous_sigtrap_, nullptr);
+ sigaction64(SIGSEGV, &previous_sigsegv_, nullptr);
+ sigaction64(SIGILL, &previous_sigill_, nullptr);
+ }
+
+ private:
+ struct sigaction64 previous_sigill_;
+ struct sigaction64 previous_sigsegv_;
+ struct sigaction64 previous_sigtrap_;
+};
+
+static bool KilledByCfi(int status) {
+ return WIFSIGNALED(status) &&
+ (WTERMSIG(status) == SIGTRAP || WTERMSIG(status) == SIGILL || WTERMSIG(status) == SIGSEGV);
+}
static void f() {}
@@ -102,7 +139,7 @@
// It's possible that this allocation could wind up in the same CFI granule as
// an unchecked library, which means the below might not crash. To force a
// crash keep allocating up to a max until there is a crash.
- EXPECT_DEATH(test_cfi_slowpath_with_alloc(), "");
+ EXPECT_EXIT(test_cfi_slowpath_with_alloc(), KilledByCfi, "");
// Check all the addresses.
const size_t bss_size = 1024 * 1024;
@@ -128,7 +165,7 @@
// CFI check for a function inside the unloaded DSO. This is always invalid and gets the process
// killed.
- EXPECT_DEATH(__cfi_slowpath(45, reinterpret_cast<void*>(code_ptr)), "");
+ EXPECT_EXIT(__cfi_slowpath(45, reinterpret_cast<void*>(code_ptr)), KilledByCfi, "");
#endif
}