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
15TEST(ScudoStringsTest, Constructor) {
16 scudo::ScopedString Str;
17 EXPECT_EQ(0ul, Str.length());
18 EXPECT_EQ('\0', *Str.data());
19}
20
21TEST(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
37TEST(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
45TEST(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
56TEST(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
75static void fillString(scudo::ScopedString &Str, scudo::uptr Size) {
76 for (scudo::uptr I = 0; I < Size; I++)
77 Str.append(Format: "A");
78}
79
80TEST(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
99template <typename T>
100static 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
109TEST(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
118TEST(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
135TEST(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

source code of compiler-rt/lib/scudo/standalone/tests/strings_test.cpp