xref: /openbsd-src/gnu/llvm/compiler-rt/lib/scudo/standalone/tests/memtag_test.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
1 //===-- memtag_test.cpp -----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "common.h"
10 #include "memtag.h"
11 #include "platform.h"
12 #include "tests/scudo_unit_test.h"
13 
14 #if SCUDO_LINUX
15 namespace scudo {
16 
TEST(MemtagBasicDeathTest,Unsupported)17 TEST(MemtagBasicDeathTest, Unsupported) {
18   if (archSupportsMemoryTagging())
19     GTEST_SKIP();
20 
21   EXPECT_DEATH(archMemoryTagGranuleSize(), "not supported");
22   EXPECT_DEATH(untagPointer((uptr)0), "not supported");
23   EXPECT_DEATH(extractTag((uptr)0), "not supported");
24 
25   EXPECT_DEATH(systemSupportsMemoryTagging(), "not supported");
26   EXPECT_DEATH(systemDetectsMemoryTagFaultsTestOnly(), "not supported");
27   EXPECT_DEATH(enableSystemMemoryTaggingTestOnly(), "not supported");
28 
29   EXPECT_DEATH(selectRandomTag((uptr)0, 0), "not supported");
30   EXPECT_DEATH(addFixedTag((uptr)0, 1), "not supported");
31   EXPECT_DEATH(storeTags((uptr)0, (uptr)0 + sizeof(0)), "not supported");
32   EXPECT_DEATH(storeTag((uptr)0), "not supported");
33   EXPECT_DEATH(loadTag((uptr)0), "not supported");
34 
35   EXPECT_DEATH(setRandomTag(nullptr, 64, 0, nullptr, nullptr), "not supported");
36   EXPECT_DEATH(untagPointer(nullptr), "not supported");
37   EXPECT_DEATH(loadTag(nullptr), "not supported");
38   EXPECT_DEATH(addFixedTag(nullptr, 0), "not supported");
39 }
40 
41 class MemtagTest : public Test {
42 protected:
SetUp()43   void SetUp() override {
44     if (!archSupportsMemoryTagging() || !systemDetectsMemoryTagFaultsTestOnly())
45       GTEST_SKIP() << "Memory tagging is not supported";
46 
47     BufferSize = getPageSizeCached();
48     Buffer = reinterpret_cast<u8 *>(
49         map(nullptr, BufferSize, "MemtagTest", MAP_MEMTAG, &Data));
50     Addr = reinterpret_cast<uptr>(Buffer);
51     EXPECT_TRUE(isAligned(Addr, archMemoryTagGranuleSize()));
52     EXPECT_EQ(Addr, untagPointer(Addr));
53   }
54 
TearDown()55   void TearDown() override {
56     if (Buffer)
57       unmap(Buffer, BufferSize, 0, &Data);
58   }
59 
60   uptr BufferSize = 0;
61   MapPlatformData Data = {};
62   u8 *Buffer = nullptr;
63   uptr Addr = 0;
64 };
65 
66 using MemtagDeathTest = MemtagTest;
67 
TEST_F(MemtagTest,ArchMemoryTagGranuleSize)68 TEST_F(MemtagTest, ArchMemoryTagGranuleSize) {
69   EXPECT_GT(archMemoryTagGranuleSize(), 1u);
70   EXPECT_TRUE(isPowerOfTwo(archMemoryTagGranuleSize()));
71 }
72 
TEST_F(MemtagTest,ExtractTag)73 TEST_F(MemtagTest, ExtractTag) {
74   uptr Tags = 0;
75   // Try all value for the top byte and check the tags values are in the
76   // expected range.
77   for (u64 Top = 0; Top < 0x100; ++Top)
78     Tags = Tags | (1u << extractTag(Addr | (Top << 56)));
79   EXPECT_EQ(0xffffull, Tags);
80 }
81 
TEST_F(MemtagDeathTest,AddFixedTag)82 TEST_F(MemtagDeathTest, AddFixedTag) {
83   for (uptr Tag = 0; Tag < 0x10; ++Tag)
84     EXPECT_EQ(Tag, extractTag(addFixedTag(Addr, Tag)));
85   if (SCUDO_DEBUG) {
86     EXPECT_DEBUG_DEATH(addFixedTag(Addr, 16), "");
87     EXPECT_DEBUG_DEATH(addFixedTag(~Addr, 0), "");
88   }
89 }
90 
TEST_F(MemtagTest,UntagPointer)91 TEST_F(MemtagTest, UntagPointer) {
92   uptr UnTagMask = untagPointer(~uptr(0));
93   for (u64 Top = 0; Top < 0x100; ++Top) {
94     uptr Ptr = (Addr | (Top << 56)) & UnTagMask;
95     EXPECT_EQ(addFixedTag(Ptr, 0), untagPointer(Ptr));
96   }
97 }
98 
TEST_F(MemtagDeathTest,ScopedDisableMemoryTagChecks)99 TEST_F(MemtagDeathTest, ScopedDisableMemoryTagChecks) {
100   u8 *P = reinterpret_cast<u8 *>(addFixedTag(Addr, 1));
101   EXPECT_NE(P, Buffer);
102 
103   EXPECT_DEATH(*P = 20, "");
104   ScopedDisableMemoryTagChecks Disable;
105   *P = 10;
106 }
107 
TEST_F(MemtagTest,SelectRandomTag)108 TEST_F(MemtagTest, SelectRandomTag) {
109   for (uptr SrcTag = 0; SrcTag < 0x10; ++SrcTag) {
110     uptr Ptr = addFixedTag(Addr, SrcTag);
111     uptr Tags = 0;
112     for (uptr I = 0; I < 100000; ++I)
113       Tags = Tags | (1u << extractTag(selectRandomTag(Ptr, 0)));
114     EXPECT_EQ(0xfffeull, Tags);
115   }
116 }
117 
TEST_F(MemtagTest,SelectRandomTagWithMask)118 TEST_F(MemtagTest, SelectRandomTagWithMask) {
119   for (uptr j = 0; j < 32; ++j) {
120     for (uptr i = 0; i < 1000; ++i)
121       EXPECT_NE(j, extractTag(selectRandomTag(Addr, 1ull << j)));
122   }
123 }
124 
TEST_F(MemtagDeathTest,SKIP_NO_DEBUG (LoadStoreTagUnaligned))125 TEST_F(MemtagDeathTest, SKIP_NO_DEBUG(LoadStoreTagUnaligned)) {
126   for (uptr P = Addr; P < Addr + 4 * archMemoryTagGranuleSize(); ++P) {
127     if (P % archMemoryTagGranuleSize() == 0)
128       continue;
129     EXPECT_DEBUG_DEATH(loadTag(P), "");
130     EXPECT_DEBUG_DEATH(storeTag(P), "");
131   }
132 }
133 
TEST_F(MemtagTest,LoadStoreTag)134 TEST_F(MemtagTest, LoadStoreTag) {
135   uptr Base = Addr + 0x100;
136   uptr Tagged = addFixedTag(Base, 7);
137   storeTag(Tagged);
138 
139   EXPECT_EQ(Base - archMemoryTagGranuleSize(),
140             loadTag(Base - archMemoryTagGranuleSize()));
141   EXPECT_EQ(Tagged, loadTag(Base));
142   EXPECT_EQ(Base + archMemoryTagGranuleSize(),
143             loadTag(Base + archMemoryTagGranuleSize()));
144 }
145 
TEST_F(MemtagDeathTest,SKIP_NO_DEBUG (StoreTagsUnaligned))146 TEST_F(MemtagDeathTest, SKIP_NO_DEBUG(StoreTagsUnaligned)) {
147   for (uptr P = Addr; P < Addr + 4 * archMemoryTagGranuleSize(); ++P) {
148     uptr Tagged = addFixedTag(P, 5);
149     if (Tagged % archMemoryTagGranuleSize() == 0)
150       continue;
151     EXPECT_DEBUG_DEATH(storeTags(Tagged, Tagged), "");
152   }
153 }
154 
TEST_F(MemtagTest,StoreTags)155 TEST_F(MemtagTest, StoreTags) {
156   const uptr MaxTaggedSize = 4 * archMemoryTagGranuleSize();
157   for (uptr Size = 0; Size <= MaxTaggedSize; ++Size) {
158     uptr NoTagBegin = Addr + archMemoryTagGranuleSize();
159     uptr NoTagEnd = NoTagBegin + Size;
160 
161     u8 Tag = 5;
162 
163     uptr TaggedBegin = addFixedTag(NoTagBegin, Tag);
164     uptr TaggedEnd = addFixedTag(NoTagEnd, Tag);
165 
166     EXPECT_EQ(roundUpTo(TaggedEnd, archMemoryTagGranuleSize()),
167               storeTags(TaggedBegin, TaggedEnd));
168 
169     uptr LoadPtr = Addr;
170     // Untagged left granule.
171     EXPECT_EQ(LoadPtr, loadTag(LoadPtr));
172 
173     for (LoadPtr += archMemoryTagGranuleSize(); LoadPtr < NoTagEnd;
174          LoadPtr += archMemoryTagGranuleSize()) {
175       EXPECT_EQ(addFixedTag(LoadPtr, 5), loadTag(LoadPtr));
176     }
177 
178     // Untagged right granule.
179     EXPECT_EQ(LoadPtr, loadTag(LoadPtr));
180 
181     // Reset tags without using StoreTags.
182     releasePagesToOS(Addr, 0, BufferSize, &Data);
183   }
184 }
185 
186 } // namespace scudo
187 
188 #endif
189