Allow nested usage of ScopedDisableMTE.

An upcoming change to scudo will cause us to start calling
android_unsafe_frame_pointer_chase() from within the allocator. Since this
function uses ScopedDisableMTE, this would otherwise make it unsafe to use
the allocator from within ScopedDisableMTE. This seems like an unreasonable
restriction, so make ScopedDisableMTE save the PSTATE.TCO state in the
constructor and restore it in the destructor.

Bug: 135772972
Change-Id: I47e18d5fb2929efd5a58676488180cd85731007b
diff --git a/tests/mte_test.cpp b/tests/mte_test.cpp
index 2f922a2..8928805 100644
--- a/tests/mte_test.cpp
+++ b/tests/mte_test.cpp
@@ -16,17 +16,30 @@
 
 #include <gtest/gtest.h>
 
+#include <android-base/macros.h>
 #include <bionic/mte.h>
 
 __attribute__((no_sanitize("hwaddress")))
 static void test_tag_mismatch() {
-  ScopedDisableMTE x;
-#if defined(__aarch64__)
   std::unique_ptr<int[]> p = std::make_unique<int[]>(4);
   p[0] = 1;
-  int* mistagged_p = reinterpret_cast<int*>(reinterpret_cast<uintptr_t>(p.get()) + (1ULL << 56));
-  volatile int load = *mistagged_p;
-  (void)load;
+  int* mistagged_p ATTRIBUTE_UNUSED =
+      reinterpret_cast<int*>(reinterpret_cast<uintptr_t>(p.get()) + (1ULL << 56));
+  {
+    ScopedDisableMTE x;
+    { ScopedDisableMTE y; }
+#if defined(__aarch64__)
+    volatile int load ATTRIBUTE_UNUSED = *mistagged_p;
+#endif
+  }
+#if defined(__aarch64__)
+  if (mte_supported()) {
+    EXPECT_DEATH(
+        {
+          volatile int load ATTRIBUTE_UNUSED = *mistagged_p;
+        },
+        "");
+  }
 #endif
 }