1//===-- sanitizer_libc_test.cpp -------------------------------------------===//
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// Tests for sanitizer_libc.h.
9//===----------------------------------------------------------------------===//
10#include <algorithm>
11#include <vector>
12#include <stdio.h>
13
14#include "sanitizer_common/sanitizer_common.h"
15#include "sanitizer_common/sanitizer_file.h"
16#include "sanitizer_common/sanitizer_libc.h"
17#include "sanitizer_common/sanitizer_platform.h"
18#include "gtest/gtest.h"
19
20#if SANITIZER_WINDOWS
21#define NOMINMAX
22#include <windows.h>
23#undef NOMINMAX
24#endif
25#if SANITIZER_POSIX
26# include <sys/stat.h>
27# include "sanitizer_common/sanitizer_posix.h"
28#endif
29
30using namespace __sanitizer;
31
32// A regression test for internal_memmove() implementation.
33TEST(SanitizerCommon, InternalMemmoveRegression) {
34 char src[] = "Hello World";
35 char *dest = src + 6;
36 __sanitizer::internal_memmove(dest, src, n: 5);
37 EXPECT_EQ(dest[0], src[0]);
38 EXPECT_EQ(dest[4], src[4]);
39}
40
41TEST(SanitizerCommon, mem_is_zero) {
42 size_t size = 128;
43 char *x = new char[size];
44 memset(x, 0, size);
45 for (size_t pos = 0; pos < size; pos++) {
46 x[pos] = 1;
47 for (size_t beg = 0; beg < size; beg++) {
48 for (size_t end = beg; end < size; end++) {
49 // fprintf(stderr, "pos %zd beg %zd end %zd \n", pos, beg, end);
50 if (beg <= pos && pos < end)
51 EXPECT_FALSE(__sanitizer::mem_is_zero(x + beg, end - beg));
52 else
53 EXPECT_TRUE(__sanitizer::mem_is_zero(x + beg, end - beg));
54 }
55 }
56 x[pos] = 0;
57 }
58 delete [] x;
59}
60
61struct stat_and_more {
62 struct stat st;
63 unsigned char z;
64};
65
66static void get_temp_dir(char *buf, size_t bufsize) {
67#if SANITIZER_WINDOWS
68 buf[0] = '\0';
69 if (!::GetTempPathA(bufsize, buf))
70 return;
71#else
72 const char *tmpdir = "/tmp";
73# if SANITIZER_ANDROID
74 tmpdir = GetEnv("TMPDIR");
75# endif
76 internal_snprintf(buffer: buf, length: bufsize, format: "%s", tmpdir);
77#endif
78}
79
80static void temp_file_name(char *buf, size_t bufsize, const char *prefix) {
81#if SANITIZER_WINDOWS
82 buf[0] = '\0';
83 char tmp_dir[MAX_PATH];
84 if (!::GetTempPathA(MAX_PATH, tmp_dir))
85 return;
86 // GetTempFileNameA needs a MAX_PATH buffer.
87 char tmp_path[MAX_PATH];
88 if (!::GetTempFileNameA(tmp_dir, prefix, 0, tmp_path))
89 return;
90 internal_strncpy(buf, tmp_path, bufsize);
91#else
92 const char *tmpdir = "/tmp";
93#if SANITIZER_ANDROID
94 tmpdir = GetEnv("TMPDIR");
95#endif
96 internal_snprintf(buffer: buf, length: bufsize, format: "%s/%sXXXXXX", tmpdir, prefix);
97 ASSERT_TRUE(mkstemp(buf));
98#endif
99}
100
101static void Unlink(const char *path) {
102#if SANITIZER_WINDOWS
103 // No sanitizer needs to delete a file on Windows yet. If we ever do, we can
104 // add a portable wrapper and test it from here.
105 ::DeleteFileA(&path[0]);
106#else
107 internal_unlink(path);
108#endif
109}
110
111TEST(SanitizerCommon, FileOps) {
112 const char *str1 = "qwerty";
113 uptr len1 = internal_strlen(s: str1);
114 const char *str2 = "zxcv";
115 uptr len2 = internal_strlen(s: str2);
116
117 char tmpfile[128];
118 temp_file_name(buf: tmpfile, bufsize: sizeof(tmpfile), prefix: "sanitizer_common.fileops.tmp.");
119 fd_t fd = OpenFile(filename: tmpfile, mode: WrOnly);
120 ASSERT_NE(fd, kInvalidFd);
121 ASSERT_TRUE(WriteToFile(fd, buff: "A", buff_size: 1));
122 CloseFile(fd);
123
124 fd = OpenFile(filename: tmpfile, mode: WrOnly);
125 ASSERT_NE(fd, kInvalidFd);
126#if SANITIZER_POSIX && !SANITIZER_APPLE
127 EXPECT_EQ(internal_lseek(fd, offset: 0, SEEK_END), 0u);
128#endif
129 uptr bytes_written = 0;
130 EXPECT_TRUE(WriteToFile(fd, buff: str1, buff_size: len1, bytes_written: &bytes_written));
131 EXPECT_EQ(len1, bytes_written);
132 EXPECT_TRUE(WriteToFile(fd, buff: str2, buff_size: len2, bytes_written: &bytes_written));
133 EXPECT_EQ(len2, bytes_written);
134 CloseFile(fd);
135
136 EXPECT_TRUE(FileExists(filename: tmpfile));
137
138 fd = OpenFile(filename: tmpfile, mode: RdOnly);
139 ASSERT_NE(fd, kInvalidFd);
140
141#if SANITIZER_POSIX
142 // The stat wrappers are posix-only.
143 uptr fsize = internal_filesize(fd);
144 EXPECT_EQ(len1 + len2, fsize);
145
146 struct stat st1, st2, st3;
147 EXPECT_EQ(0u, internal_stat(path: tmpfile, buf: &st1));
148 EXPECT_EQ(0u, internal_lstat(path: tmpfile, buf: &st2));
149 EXPECT_EQ(0u, internal_fstat(fd, buf: &st3));
150 EXPECT_EQ(fsize, (uptr)st3.st_size);
151
152 // Verify that internal_fstat does not write beyond the end of the supplied
153 // buffer.
154 struct stat_and_more sam;
155 memset(&sam, 0xAB, sizeof(sam));
156 EXPECT_EQ(0u, internal_fstat(fd, buf: &sam.st));
157 EXPECT_EQ(0xAB, sam.z);
158 EXPECT_NE(0xAB, sam.st.st_size);
159 EXPECT_NE(0, sam.st.st_size);
160#endif
161
162 char buf[64] = {};
163 uptr bytes_read = 0;
164 EXPECT_TRUE(ReadFromFile(fd, buff: buf, buff_size: len1, bytes_read: &bytes_read));
165 EXPECT_EQ(len1, bytes_read);
166 EXPECT_EQ(0, internal_memcmp(s1: buf, s2: str1, n: len1));
167 EXPECT_EQ((char)0, buf[len1 + 1]);
168 internal_memset(s: buf, c: 0, n: len1);
169 EXPECT_TRUE(ReadFromFile(fd, buff: buf, buff_size: len2, bytes_read: &bytes_read));
170 EXPECT_EQ(len2, bytes_read);
171 EXPECT_EQ(0, internal_memcmp(s1: buf, s2: str2, n: len2));
172 CloseFile(fd);
173
174 Unlink(path: tmpfile);
175}
176
177class SanitizerCommonFileTest : public ::testing::TestWithParam<uptr> {
178 void SetUp() override {
179 data_.resize(GetParam());
180 std::generate(data_.begin(), data_.end(), [] { return rand() % 256; });
181
182 temp_file_name(buf: file_name_, bufsize: sizeof(file_name_),
183 prefix: "sanitizer_common.ReadFile.tmp.");
184
185 if (FILE *f = fopen(filename: file_name_, modes: "wb")) {
186 if (!data_.empty())
187 fwrite(data_.data(), data_.size(), 1, f);
188 fclose(stream: f);
189 }
190 }
191
192 void TearDown() override { Unlink(path: file_name_); }
193
194 protected:
195 char file_name_[256];
196 std::vector<char> data_;
197};
198
199TEST_P(SanitizerCommonFileTest, ReadFileToBuffer) {
200 char *buff;
201 uptr size;
202 uptr len;
203 EXPECT_TRUE(ReadFileToBuffer(file_name_, &buff, &len, &size));
204 EXPECT_EQ(data_, std::vector<char>(buff, buff + size));
205 UnmapOrDie(addr: buff, size: len);
206}
207
208TEST_P(SanitizerCommonFileTest, ReadFileToBufferHalf) {
209 char *buff;
210 uptr size;
211 uptr len;
212 data_.resize(data_.size() / 2);
213 EXPECT_TRUE(ReadFileToBuffer(file_name_, &buff, &len, &size, data_.size()));
214 EXPECT_EQ(data_, std::vector<char>(buff, buff + size));
215 UnmapOrDie(addr: buff, size: len);
216}
217
218TEST_P(SanitizerCommonFileTest, ReadFileToVector) {
219 InternalMmapVector<char> buff;
220 EXPECT_TRUE(ReadFileToVector(file_name_, &buff));
221 EXPECT_EQ(data_, std::vector<char>(buff.begin(), buff.end()));
222}
223
224TEST_P(SanitizerCommonFileTest, ReadFileToVectorHalf) {
225 InternalMmapVector<char> buff;
226 data_.resize(data_.size() / 2);
227 EXPECT_TRUE(ReadFileToVector(file_name_, &buff, data_.size()));
228 EXPECT_EQ(data_, std::vector<char>(buff.begin(), buff.end()));
229}
230
231INSTANTIATE_TEST_SUITE_P(FileSizes, SanitizerCommonFileTest,
232 ::testing::Values(0, 1, 7, 13, 32, 4096, 4097, 1048575,
233 1048576, 1048577));
234
235static const size_t kStrlcpyBufSize = 8;
236void test_internal_strlcpy(char *dbuf, const char *sbuf) {
237 uptr retval = 0;
238 retval = internal_strlcpy(dst: dbuf, src: sbuf, maxlen: kStrlcpyBufSize);
239 EXPECT_EQ(internal_strncmp(s1: dbuf, s2: sbuf, n: kStrlcpyBufSize - 1), 0);
240 EXPECT_EQ(internal_strlen(dbuf),
241 std::min(internal_strlen(sbuf), (uptr)(kStrlcpyBufSize - 1)));
242 EXPECT_EQ(retval, internal_strlen(s: sbuf));
243
244 // Test with shorter maxlen.
245 uptr maxlen = 2;
246 if (internal_strlen(s: sbuf) > maxlen) {
247 retval = internal_strlcpy(dst: dbuf, src: sbuf, maxlen);
248 EXPECT_EQ(internal_strncmp(s1: dbuf, s2: sbuf, n: maxlen - 1), 0);
249 EXPECT_EQ(internal_strlen(s: dbuf), maxlen - 1);
250 }
251}
252
253TEST(SanitizerCommon, InternalStrFunctions) {
254 const char *haystack = "haystack";
255 EXPECT_EQ(haystack + 2, internal_strchr(s: haystack, c: 'y'));
256 EXPECT_EQ(haystack + 2, internal_strchrnul(s: haystack, c: 'y'));
257 EXPECT_EQ(0, internal_strchr(s: haystack, c: 'z'));
258 EXPECT_EQ(haystack + 8, internal_strchrnul(s: haystack, c: 'z'));
259
260 char dbuf[kStrlcpyBufSize] = {};
261 const char *samesizestr = "1234567";
262 const char *shortstr = "123";
263 const char *longerstr = "123456789";
264
265 // Test internal_strlcpy.
266 internal_strlcpy(dst: dbuf, src: shortstr, maxlen: 0);
267 EXPECT_EQ(dbuf[0], 0);
268 EXPECT_EQ(dbuf[0], 0);
269 test_internal_strlcpy(dbuf, sbuf: samesizestr);
270 test_internal_strlcpy(dbuf, sbuf: shortstr);
271 test_internal_strlcpy(dbuf, sbuf: longerstr);
272
273 // Test internal_strlcat.
274 char dcatbuf[kStrlcpyBufSize] = {};
275 uptr retval = 0;
276 retval = internal_strlcat(dst: dcatbuf, src: "aaa", maxlen: 0);
277 EXPECT_EQ(internal_strlen(s: dcatbuf), (uptr)0);
278 EXPECT_EQ(retval, (uptr)3);
279
280 retval = internal_strlcat(dst: dcatbuf, src: "123", maxlen: kStrlcpyBufSize);
281 EXPECT_EQ(internal_strcmp(s1: dcatbuf, s2: "123"), 0);
282 EXPECT_EQ(internal_strlen(s: dcatbuf), (uptr)3);
283 EXPECT_EQ(retval, (uptr)3);
284
285 retval = internal_strlcat(dst: dcatbuf, src: "123", maxlen: kStrlcpyBufSize);
286 EXPECT_EQ(internal_strcmp(s1: dcatbuf, s2: "123123"), 0);
287 EXPECT_EQ(internal_strlen(s: dcatbuf), (uptr)6);
288 EXPECT_EQ(retval, (uptr)6);
289
290 retval = internal_strlcat(dst: dcatbuf, src: "123", maxlen: kStrlcpyBufSize);
291 EXPECT_EQ(internal_strcmp(s1: dcatbuf, s2: "1231231"), 0);
292 EXPECT_EQ(internal_strlen(s: dcatbuf), (uptr)7);
293 EXPECT_EQ(retval, (uptr)9);
294}
295
296TEST(SanitizerCommon, InternalWideStringFunctions) {
297 const wchar_t *emptystr = L"";
298 const wchar_t *samesizestr = L"1234567";
299 const wchar_t *shortstr = L"123";
300 const wchar_t *longerstr = L"123456789";
301
302 ASSERT_EQ(internal_wcslen(s: emptystr), 0ul);
303 ASSERT_EQ(internal_wcslen(s: samesizestr), 7ul);
304 ASSERT_EQ(internal_wcslen(s: shortstr), 3ul);
305 ASSERT_EQ(internal_wcslen(s: longerstr), 9ul);
306
307 ASSERT_EQ(internal_wcsnlen(s: emptystr, maxlen: 7), 0ul);
308 ASSERT_EQ(internal_wcsnlen(s: samesizestr, maxlen: 7), 7ul);
309 ASSERT_EQ(internal_wcsnlen(s: shortstr, maxlen: 7), 3ul);
310 ASSERT_EQ(internal_wcsnlen(s: longerstr, maxlen: 7), 7ul);
311}
312
313// FIXME: File manipulations are not yet supported on Windows
314#if SANITIZER_POSIX && !SANITIZER_APPLE
315TEST(SanitizerCommon, InternalMmapWithOffset) {
316 char tmpfile[128];
317 temp_file_name(buf: tmpfile, bufsize: sizeof(tmpfile),
318 prefix: "sanitizer_common.internalmmapwithoffset.tmp.");
319 fd_t fd = OpenFile(filename: tmpfile, mode: RdWr);
320 ASSERT_NE(fd, kInvalidFd);
321
322 uptr page_size = GetPageSizeCached();
323 uptr res = internal_ftruncate(fd, size: page_size * 2);
324 ASSERT_FALSE(internal_iserror(retval: res));
325
326 res = internal_lseek(fd, offset: page_size, SEEK_SET);
327 ASSERT_FALSE(internal_iserror(retval: res));
328
329 res = internal_write(fd, buf: "AB", count: 2);
330 ASSERT_FALSE(internal_iserror(retval: res));
331
332 char *p = (char *)MapWritableFileToMemory(addr: nullptr, size: page_size, fd, offset: page_size);
333 ASSERT_NE(nullptr, p);
334
335 ASSERT_EQ('A', p[0]);
336 ASSERT_EQ('B', p[1]);
337
338 CloseFile(fd);
339 UnmapOrDie(addr: p, size: page_size);
340 internal_unlink(path: tmpfile);
341}
342#endif
343
344TEST(SanitizerCommon, ReportFile) {
345 SpinMutex report_file_mu;
346 ReportFile report_file = {.mu: &report_file_mu, kStderrFd, .path_prefix: "", .full_path: "", .fd_pid: 0};
347 char tmpfile[128];
348 temp_file_name(buf: tmpfile, bufsize: sizeof(tmpfile),
349 prefix: "dir/sanitizer_common.reportfile.tmp.");
350 report_file.SetReportPath(tmpfile);
351 const char *path = report_file.GetReportPath();
352 EXPECT_EQ(internal_strncmp(tmpfile, path, strlen(tmpfile)), 0);
353 // This will close tmpfile.
354 report_file.SetReportPath("stderr");
355 Unlink(path: tmpfile);
356}
357
358TEST(SanitizerCommon, FileExists) {
359 char tmpfile[128];
360 temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileexists.tmp.");
361 fd_t fd = OpenFile(tmpfile, WrOnly);
362 ASSERT_NE(fd, kInvalidFd);
363 EXPECT_TRUE(FileExists(tmpfile));
364 CloseFile(fd);
365 Unlink(tmpfile);
366}
367
368TEST(SanitizerCommon, DirExists) {
369 char tmpdir[128];
370 get_temp_dir(tmpdir, sizeof(tmpdir));
371 EXPECT_TRUE(DirExists(tmpdir));
372}
373

source code of compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cpp