blob: 13c853f40e0264ef8768e398e8f9d33a66526362 [file] [log] [blame]
Vitaly Bukaecf52a72021-05-24 21:40:44 -07001//===-- 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
15namespace scudo {
16
17TEST(MemtagBasicTest, 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
41class MemtagTest : public ::testing::Test {
42protected:
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
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
66TEST_F(MemtagTest, ArchMemoryTagGranuleSize) {
67 EXPECT_GT(archMemoryTagGranuleSize(), 1u);
68 EXPECT_TRUE(isPowerOfTwo(archMemoryTagGranuleSize()));
69}
70
71TEST_F(MemtagTest, ExtractTag) {
72 uptr Tags = 0;
73 // Try all value for the top byte and check the tags values are in the
74 // expected range.
75 for (u64 Top = 0; Top < 0x100; ++Top)
76 Tags = Tags | (1u << extractTag(Addr | (Top << 56)));
77 EXPECT_EQ(0xffff, Tags);
78}
79
80TEST_F(MemtagTest, AddFixedTag) {
81 for (uptr Tag = 0; Tag < 0x10; ++Tag)
82 EXPECT_EQ(Tag, extractTag(addFixedTag(Addr, Tag)));
83 if (SCUDO_DEBUG) {
84 EXPECT_DEBUG_DEATH(addFixedTag(Addr, 16), "");
85 EXPECT_DEBUG_DEATH(addFixedTag(~Addr, 0), "");
86 }
87}
88
89TEST_F(MemtagTest, UntagPointer) {
90 uptr UnTagMask = untagPointer(~uptr(0));
91 for (u64 Top = 0; Top < 0x100; ++Top) {
92 uptr Ptr = (Addr | (Top << 56)) & UnTagMask;
93 EXPECT_EQ(addFixedTag(Ptr, 0), untagPointer(Ptr));
94 }
95}
96
97TEST_F(MemtagTest, ScopedDisableMemoryTagChecks) {
98 u8 *P = reinterpret_cast<u8 *>(addFixedTag(Addr, 1));
99 EXPECT_NE(P, Buffer);
100
101 EXPECT_DEATH(*P = 20, "");
102 ScopedDisableMemoryTagChecks Disable;
103 *P = 10;
104}
105
106TEST_F(MemtagTest, SelectRandomTag) {
107 for (uptr SrcTag = 0; SrcTag < 0x10; ++SrcTag) {
108 uptr Ptr = addFixedTag(Addr, SrcTag);
109 uptr Tags = 0;
110 for (uptr I = 0; I < 100000; ++I)
111 Tags = Tags | (1u << extractTag(selectRandomTag(Ptr, 0)));
112 EXPECT_EQ(0xfffe, Tags);
113 }
114}
115
116TEST_F(MemtagTest, SelectRandomTagWithMask) {
117 for (uptr j = 0; j < 32; ++j) {
118 for (uptr i = 0; i < 1000; ++i)
119 EXPECT_NE(j, extractTag(selectRandomTag(Addr, 1ull << j)));
120 }
121}
122
123TEST_F(MemtagTest, SKIP_NO_DEBUG(LoadStoreTagUnaligned)) {
124 for (uptr P = Addr; P < Addr + 4 * archMemoryTagGranuleSize(); ++P) {
125 if (P % archMemoryTagGranuleSize() == 0)
126 continue;
127 EXPECT_DEBUG_DEATH(loadTag(P), "");
128 EXPECT_DEBUG_DEATH(storeTag(P), "");
129 }
130}
131
132TEST_F(MemtagTest, LoadStoreTag) {
133 uptr Base = Addr + 0x100;
134 uptr Tagged = addFixedTag(Base, 7);
135 storeTag(Tagged);
136
137 EXPECT_EQ(Base - archMemoryTagGranuleSize(),
138 loadTag(Base - archMemoryTagGranuleSize()));
139 EXPECT_EQ(Tagged, loadTag(Base));
140 EXPECT_EQ(Base + archMemoryTagGranuleSize(),
141 loadTag(Base + archMemoryTagGranuleSize()));
142}
143
144TEST_F(MemtagTest, SKIP_NO_DEBUG(StoreTagsUnaligned)) {
145 for (uptr P = Addr; P < Addr + 4 * archMemoryTagGranuleSize(); ++P) {
146 uptr Tagged = addFixedTag(P, 5);
147 if (Tagged % archMemoryTagGranuleSize() == 0)
148 continue;
149 EXPECT_DEBUG_DEATH(storeTags(Tagged, Tagged), "");
150 }
151}
152
153TEST_F(MemtagTest, StoreTags) {
154 const uptr MaxTaggedSize = 4 * archMemoryTagGranuleSize();
155 for (uptr Size = 0; Size <= MaxTaggedSize; ++Size) {
156 uptr NoTagBegin = Addr + archMemoryTagGranuleSize();
157 uptr NoTagEnd = NoTagBegin + Size;
158
159 u8 Tag = 5;
160
161 uptr TaggedBegin = addFixedTag(NoTagBegin, Tag);
162 uptr TaggedEnd = addFixedTag(NoTagEnd, Tag);
163
164 EXPECT_EQ(roundUpTo(TaggedEnd, archMemoryTagGranuleSize()),
165 storeTags(TaggedBegin, TaggedEnd));
166
167 uptr LoadPtr = Addr;
168 // Untagged left granule.
169 EXPECT_EQ(LoadPtr, loadTag(LoadPtr));
170
171 for (LoadPtr += archMemoryTagGranuleSize(); LoadPtr < NoTagEnd;
172 LoadPtr += archMemoryTagGranuleSize()) {
173 EXPECT_EQ(addFixedTag(LoadPtr, 5), loadTag(LoadPtr));
174 }
175
176 // Untagged right granule.
177 EXPECT_EQ(LoadPtr, loadTag(LoadPtr));
178
179 // Reset tags without using StoreTags.
180 releasePagesToOS(Addr, 0, BufferSize, &Data);
181 }
182}
183
184} // namespace scudo
185
186#endif