1 | //===-- strings_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 "tests/scudo_unit_test.h" |
10 | |
11 | #include "string_utils.h" |
12 | |
13 | #include <limits.h> |
14 | |
15 | TEST(ScudoStringsTest, Constructor) { |
16 | scudo::ScopedString Str; |
17 | EXPECT_EQ(0ul, Str.length()); |
18 | EXPECT_EQ('\0', *Str.data()); |
19 | } |
20 | |
21 | TEST(ScudoStringsTest, Basic) { |
22 | scudo::ScopedString Str; |
23 | Str.append(Format: "a%db%zdc%ue%zuf%xh%zxq%pe%sr" , static_cast<int>(-1), |
24 | static_cast<scudo::uptr>(-2), static_cast<unsigned>(-4), |
25 | static_cast<scudo::uptr>(5), static_cast<unsigned>(10), |
26 | static_cast<scudo::uptr>(11), reinterpret_cast<void *>(0x123), |
27 | "_string_" ); |
28 | EXPECT_EQ(Str.length(), strlen(s: Str.data())); |
29 | |
30 | std::string expectedString = "a-1b-2c4294967292e5fahbq0x" ; |
31 | expectedString += std::string(SCUDO_POINTER_FORMAT_LENGTH - 3, '0'); |
32 | expectedString += "123e_string_r" ; |
33 | EXPECT_EQ(Str.length(), strlen(s: Str.data())); |
34 | EXPECT_STREQ(expectedString.c_str(), Str.data()); |
35 | } |
36 | |
37 | TEST(ScudoStringsTest, Clear) { |
38 | scudo::ScopedString Str; |
39 | Str.append(Format: "123" ); |
40 | Str.clear(); |
41 | EXPECT_EQ(0ul, Str.length()); |
42 | EXPECT_EQ('\0', *Str.data()); |
43 | } |
44 | |
45 | TEST(ScudoStringsTest, ClearLarge) { |
46 | constexpr char appendString[] = "123" ; |
47 | scudo::ScopedString Str; |
48 | Str.reserve(Size: sizeof(appendString) * 10000); |
49 | for (int i = 0; i < 10000; ++i) |
50 | Str.append(Format: appendString); |
51 | Str.clear(); |
52 | EXPECT_EQ(0ul, Str.length()); |
53 | EXPECT_EQ('\0', *Str.data()); |
54 | } |
55 | |
56 | TEST(ScudoStringsTest, Precision) { |
57 | scudo::ScopedString Str; |
58 | Str.append(Format: "%.*s" , 3, "12345" ); |
59 | EXPECT_EQ(Str.length(), strlen(s: Str.data())); |
60 | EXPECT_STREQ("123" , Str.data()); |
61 | Str.clear(); |
62 | Str.append(Format: "%.*s" , 6, "12345" ); |
63 | EXPECT_EQ(Str.length(), strlen(s: Str.data())); |
64 | EXPECT_STREQ("12345" , Str.data()); |
65 | Str.clear(); |
66 | Str.append(Format: "%-6s" , "12345" ); |
67 | EXPECT_EQ(Str.length(), strlen(s: Str.data())); |
68 | EXPECT_STREQ("12345 " , Str.data()); |
69 | Str.clear(); |
70 | Str.append(Format: "%-8s" , "12345" ); |
71 | EXPECT_EQ(Str.length(), strlen(s: Str.data())); |
72 | EXPECT_STREQ("12345 " , Str.data()); |
73 | } |
74 | |
75 | static void fillString(scudo::ScopedString &Str, scudo::uptr Size) { |
76 | for (scudo::uptr I = 0; I < Size; I++) |
77 | Str.append(Format: "A" ); |
78 | } |
79 | |
80 | TEST(ScudoStringTest, PotentialOverflows) { |
81 | // Use a ScopedString that spans a page, and attempt to write past the end |
82 | // of it with variations of append. The expectation is for nothing to crash. |
83 | const scudo::uptr PageSize = scudo::getPageSizeCached(); |
84 | scudo::ScopedString Str; |
85 | Str.reserve(Size: 2 * PageSize); |
86 | Str.clear(); |
87 | fillString(Str, Size: 2 * PageSize); |
88 | Str.clear(); |
89 | fillString(Str, Size: PageSize - 64); |
90 | Str.append(Format: "%-128s" , "12345" ); |
91 | Str.clear(); |
92 | fillString(Str, Size: PageSize - 16); |
93 | Str.append(Format: "%024x" , 12345); |
94 | Str.clear(); |
95 | fillString(Str, Size: PageSize - 16); |
96 | Str.append(Format: "EEEEEEEEEEEEEEEEEEEEEEEE" ); |
97 | } |
98 | |
99 | template <typename T> |
100 | static void testAgainstLibc(const char *Format, T Arg1, T Arg2) { |
101 | scudo::ScopedString Str; |
102 | Str.append(Format, Arg1, Arg2); |
103 | char Buffer[128]; |
104 | snprintf(Buffer, sizeof(Buffer), Format, Arg1, Arg2); |
105 | EXPECT_EQ(Str.length(), strlen(s: Str.data())); |
106 | EXPECT_STREQ(Buffer, Str.data()); |
107 | } |
108 | |
109 | TEST(ScudoStringsTest, MinMax) { |
110 | testAgainstLibc<int>(Format: "%d-%d" , INT_MIN, INT_MAX); |
111 | testAgainstLibc<unsigned>(Format: "%u-%u" , Arg1: 0, UINT_MAX); |
112 | testAgainstLibc<unsigned>(Format: "%x-%x" , Arg1: 0, UINT_MAX); |
113 | testAgainstLibc<long>(Format: "%zd-%zd" , LONG_MIN, LONG_MAX); |
114 | testAgainstLibc<unsigned long>(Format: "%zu-%zu" , Arg1: 0, ULONG_MAX); |
115 | testAgainstLibc<unsigned long>(Format: "%zx-%zx" , Arg1: 0, ULONG_MAX); |
116 | } |
117 | |
118 | TEST(ScudoStringsTest, Padding) { |
119 | testAgainstLibc<int>(Format: "%3d - %3d" , Arg1: 1, Arg2: 0); |
120 | testAgainstLibc<int>(Format: "%3d - %3d" , Arg1: -1, Arg2: 123); |
121 | testAgainstLibc<int>(Format: "%3d - %3d" , Arg1: -1, Arg2: -123); |
122 | testAgainstLibc<int>(Format: "%3d - %3d" , Arg1: 12, Arg2: 1234); |
123 | testAgainstLibc<int>(Format: "%3d - %3d" , Arg1: -12, Arg2: -1234); |
124 | testAgainstLibc<int>(Format: "%03d - %03d" , Arg1: 1, Arg2: 0); |
125 | testAgainstLibc<int>(Format: "%03d - %03d" , Arg1: -1, Arg2: 123); |
126 | testAgainstLibc<int>(Format: "%03d - %03d" , Arg1: -1, Arg2: -123); |
127 | testAgainstLibc<int>(Format: "%03d - %03d" , Arg1: 12, Arg2: 1234); |
128 | testAgainstLibc<int>(Format: "%03d - %03d" , Arg1: -12, Arg2: -1234); |
129 | } |
130 | |
131 | #if defined(__linux__) |
132 | |
133 | #include <sys/resource.h> |
134 | |
135 | TEST(ScudoStringsTest, CapacityIncreaseFails) { |
136 | scudo::ScopedString Str; |
137 | |
138 | rlimit Limit = {}; |
139 | EXPECT_EQ(0, getrlimit(RLIMIT_AS, rlimits: &Limit)); |
140 | |
141 | rlimit EmptyLimit = {.rlim_cur = 0, .rlim_max = Limit.rlim_max}; |
142 | EXPECT_EQ(0, setrlimit(RLIMIT_AS, rlimits: &EmptyLimit)); |
143 | |
144 | // qemu does not honor the setrlimit, so verify before proceeding. |
145 | scudo::MemMapT MemMap; |
146 | if (MemMap.map(/*Addr=*/0U, Size: scudo::getPageSizeCached(), Name: "scudo:test" , |
147 | MAP_ALLOWNOMEM)) { |
148 | MemMap.unmap(Addr: MemMap.getBase(), Size: MemMap.getCapacity()); |
149 | setrlimit(RLIMIT_AS, rlimits: &Limit); |
150 | GTEST_SKIP() << "Limiting address space does not prevent mmap." ; |
151 | } |
152 | |
153 | // Test requires that the default length is at least 6 characters. |
154 | scudo::uptr MaxSize = Str.capacity(); |
155 | EXPECT_LE(6u, MaxSize); |
156 | |
157 | for (size_t i = 0; i < MaxSize - 5; i++) { |
158 | Str.append(Format: "B" ); |
159 | } |
160 | |
161 | // Attempt to append past the end of the current capacity. |
162 | Str.append(Format: "%d" , 12345678); |
163 | EXPECT_EQ(MaxSize, Str.capacity()); |
164 | EXPECT_STREQ("B12345" , &Str.data()[MaxSize - 6]); |
165 | |
166 | EXPECT_EQ(0, setrlimit(RLIMIT_AS, rlimits: &Limit)); |
167 | } |
168 | #endif |
169 | |