[MTE] test for exception cleanup.
This depends on the LLVM change https://reviews.llvm.org/D135639.
Test: adb shell /data/local/tmp/stack_tagging_helper exception_cleanup
Bug: 174878242
Change-Id: Ia1dfdbe482b40c174acaf6c1ac4ad054470d10b8
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 0c9a2e0..8ae2257 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -1661,6 +1661,7 @@
},
},
header_libs: ["bionic_libc_platform_headers"],
+ cflags: ["-fexceptions"],
}
cc_test {
@@ -1676,6 +1677,7 @@
},
},
header_libs: ["bionic_libc_platform_headers"],
+ cflags: ["-fexceptions"],
}
cc_genrule {
diff --git a/tests/libs/stack_tagging_helper.cpp b/tests/libs/stack_tagging_helper.cpp
index a239dc1..d29844d 100644
--- a/tests/libs/stack_tagging_helper.cpp
+++ b/tests/libs/stack_tagging_helper.cpp
@@ -260,6 +260,81 @@
CHECK(memtag_stack);
}
+static uintptr_t GetTag(void* addr) {
+ return reinterpret_cast<uintptr_t>(addr) & (0xFULL << 56);
+}
+
+static uintptr_t GetTag(volatile void* addr) {
+ return GetTag(const_cast<void*>(addr));
+}
+
+static volatile char* throw_frame;
+static volatile char* skip_frame3_frame;
+volatile char *x;
+
+__attribute__((noinline)) void throws() {
+ // Prevent optimization.
+ if (getpid() == 0) return;
+ throw_frame = reinterpret_cast<char*>(__builtin_frame_address(0));
+ throw "error";
+}
+
+__attribute__((noinline)) void maybe_throws() {
+ // These are all unique sizes so in case of a failure, we can see which ones
+ // are not untagged from the tag dump.
+ volatile char y[5 * 16]= {};
+ x = y;
+ // Make sure y is tagged.
+ CHECK(GetTag(&y) != GetTag(__builtin_frame_address(0)));
+ throws();
+}
+
+__attribute__((noinline, no_sanitize("memtag"))) void skip_frame() {
+ volatile char y[6*16] = {};
+ x = y;
+ // Make sure y is not tagged.
+ CHECK(GetTag(&y) == GetTag(__builtin_frame_address(0)));
+ maybe_throws();
+}
+
+__attribute__((noinline)) void skip_frame2() {
+ volatile char y[7*16] = {};
+ x = y;
+ // Make sure y is tagged.
+ CHECK(GetTag(&y) != GetTag(__builtin_frame_address(0)));
+ skip_frame();
+}
+
+__attribute__((noinline, no_sanitize("memtag"))) void skip_frame3() {
+ volatile char y[8*16] = {};
+ x = y;
+ skip_frame3_frame = reinterpret_cast<char*>(__builtin_frame_address(0));
+ // Make sure y is not tagged.
+ CHECK(GetTag(&y) == GetTag(__builtin_frame_address(0)));
+ skip_frame2();
+}
+
+void test_exception_cleanup() {
+ // This is here for debugging purposes, if something goes wrong we can
+ // verify that this placeholder did not get untagged.
+ volatile char placeholder[16*16] = {};
+ x = placeholder;
+ try {
+ skip_frame3();
+ } catch (const char* e) {
+ }
+ if (throw_frame >= skip_frame3_frame) {
+ fprintf(stderr, "invalid throw frame");
+ exit(1);
+ }
+ for (char* b = const_cast<char*>(throw_frame); b < skip_frame3_frame; ++b) {
+ if (mte_get_tag(b) != b) {
+ fprintf(stderr, "invalid tag at %p", b);
+ exit(1);
+ }
+ }
+}
+
int main(int argc, char** argv) {
if (argc < 2) {
printf("nothing to do\n");
@@ -296,6 +371,11 @@
return 0;
}
+ if (strcmp(argv[1], "exception_cleanup") == 0) {
+ test_exception_cleanup();
+ return 0;
+ }
+
printf("unrecognized command: %s\n", argv[1]);
return 1;
}
diff --git a/tests/memtag_stack_test.cpp b/tests/memtag_stack_test.cpp
index 84ee8d1..97084ec 100644
--- a/tests/memtag_stack_test.cpp
+++ b/tests/memtag_stack_test.cpp
@@ -44,13 +44,13 @@
#endif
}
-INSTANTIATE_TEST_SUITE_P(, MemtagStackTest,
- testing::Combine(testing::Values("vfork_execve", "vfork_execl",
- "vfork_exit", "longjmp",
- "longjmp_sigaltstack", "android_mallopt"),
- testing::Bool()),
- [](const ::testing::TestParamInfo<MemtagStackTest::ParamType>& info) {
- std::string s = std::get<0>(info.param);
- if (std::get<1>(info.param)) s += "_static";
- return s;
- });
+INSTANTIATE_TEST_SUITE_P(
+ , MemtagStackTest,
+ testing::Combine(testing::Values("vfork_execve", "vfork_execl", "vfork_exit", "longjmp",
+ "longjmp_sigaltstack", "android_mallopt", "exception_cleanup"),
+ testing::Bool()),
+ [](const ::testing::TestParamInfo<MemtagStackTest::ParamType>& info) {
+ std::string s = std::get<0>(info.param);
+ if (std::get<1>(info.param)) s += "_static";
+ return s;
+ });