xref: /llvm-project/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cpp (revision 81349b84eb0fd2d64f836ddbf3e28638d4a254b8)
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 
30 using namespace __sanitizer;
31 
32 // A regression test for internal_memmove() implementation.
33 TEST(SanitizerCommon, InternalMemmoveRegression) {
34   char src[] = "Hello World";
35   char *dest = src + 6;
36   __sanitizer::internal_memmove(dest, src, 5);
37   EXPECT_EQ(dest[0], src[0]);
38   EXPECT_EQ(dest[4], src[4]);
39 }
40 
41 TEST(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 
61 struct stat_and_more {
62   struct stat st;
63   unsigned char z;
64 };
65 
66 static 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(buf, bufsize, "%s", tmpdir);
77 #endif
78 }
79 
80 static 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(buf, bufsize, "%s/%sXXXXXX", tmpdir, prefix);
97   ASSERT_TRUE(mkstemp(buf));
98 #endif
99 }
100 
101 static 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 
111 TEST(SanitizerCommon, FileOps) {
112   const char *str1 = "qwerty";
113   uptr len1 = internal_strlen(str1);
114   const char *str2 = "zxcv";
115   uptr len2 = internal_strlen(str2);
116 
117   char tmpfile[128];
118   temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp.");
119   fd_t fd = OpenFile(tmpfile, WrOnly);
120   ASSERT_NE(fd, kInvalidFd);
121   ASSERT_TRUE(WriteToFile(fd, "A", 1));
122   CloseFile(fd);
123 
124   fd = OpenFile(tmpfile, WrOnly);
125   ASSERT_NE(fd, kInvalidFd);
126 #if SANITIZER_POSIX && !SANITIZER_APPLE
127   EXPECT_EQ(internal_lseek(fd, 0, SEEK_END), 0u);
128 #endif
129   uptr bytes_written = 0;
130   EXPECT_TRUE(WriteToFile(fd, str1, len1, &bytes_written));
131   EXPECT_EQ(len1, bytes_written);
132   EXPECT_TRUE(WriteToFile(fd, str2, len2, &bytes_written));
133   EXPECT_EQ(len2, bytes_written);
134   CloseFile(fd);
135 
136   EXPECT_TRUE(FileExists(tmpfile));
137 
138   fd = OpenFile(tmpfile, 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(tmpfile, &st1));
148   EXPECT_EQ(0u, internal_lstat(tmpfile, &st2));
149   EXPECT_EQ(0u, internal_fstat(fd, &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, &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, buf, len1, &bytes_read));
165   EXPECT_EQ(len1, bytes_read);
166   EXPECT_EQ(0, internal_memcmp(buf, str1, len1));
167   EXPECT_EQ((char)0, buf[len1 + 1]);
168   internal_memset(buf, 0, len1);
169   EXPECT_TRUE(ReadFromFile(fd, buf, len2, &bytes_read));
170   EXPECT_EQ(len2, bytes_read);
171   EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
172   CloseFile(fd);
173 
174   Unlink(tmpfile);
175 }
176 
177 class 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(file_name_, sizeof(file_name_),
183                    "sanitizer_common.ReadFile.tmp.");
184 
185     if (FILE *f = fopen(file_name_, "wb")) {
186       if (!data_.empty())
187         fwrite(data_.data(), data_.size(), 1, f);
188       fclose(f);
189     }
190   }
191 
192   void TearDown() override { Unlink(file_name_); }
193 
194  protected:
195   char file_name_[256];
196   std::vector<char> data_;
197 };
198 
199 TEST_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(buff, len);
206 }
207 
208 TEST_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(buff, len);
216 }
217 
218 TEST_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 
224 TEST_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 
231 INSTANTIATE_TEST_SUITE_P(FileSizes, SanitizerCommonFileTest,
232                          ::testing::Values(0, 1, 7, 13, 32, 4096, 4097, 1048575,
233                                            1048576, 1048577));
234 
235 static const size_t kStrlcpyBufSize = 8;
236 void test_internal_strlcpy(char *dbuf, const char *sbuf) {
237   uptr retval = 0;
238   retval = internal_strlcpy(dbuf, sbuf, kStrlcpyBufSize);
239   EXPECT_EQ(internal_strncmp(dbuf, sbuf, kStrlcpyBufSize - 1), 0);
240   EXPECT_EQ(internal_strlen(dbuf),
241             std::min(internal_strlen(sbuf), (uptr)(kStrlcpyBufSize - 1)));
242   EXPECT_EQ(retval, internal_strlen(sbuf));
243 
244   // Test with shorter maxlen.
245   uptr maxlen = 2;
246   if (internal_strlen(sbuf) > maxlen) {
247     retval = internal_strlcpy(dbuf, sbuf, maxlen);
248     EXPECT_EQ(internal_strncmp(dbuf, sbuf, maxlen - 1), 0);
249     EXPECT_EQ(internal_strlen(dbuf), maxlen - 1);
250   }
251 }
252 
253 TEST(SanitizerCommon, InternalStrFunctions) {
254   const char *haystack = "haystack";
255   EXPECT_EQ(haystack + 2, internal_strchr(haystack, 'y'));
256   EXPECT_EQ(haystack + 2, internal_strchrnul(haystack, 'y'));
257   EXPECT_EQ(0, internal_strchr(haystack, 'z'));
258   EXPECT_EQ(haystack + 8, internal_strchrnul(haystack, '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(dbuf, shortstr, 0);
267   EXPECT_EQ(dbuf[0], 0);
268   EXPECT_EQ(dbuf[0], 0);
269   test_internal_strlcpy(dbuf, samesizestr);
270   test_internal_strlcpy(dbuf, shortstr);
271   test_internal_strlcpy(dbuf, longerstr);
272 
273   // Test internal_strlcat.
274   char dcatbuf[kStrlcpyBufSize] = {};
275   uptr retval = 0;
276   retval = internal_strlcat(dcatbuf, "aaa", 0);
277   EXPECT_EQ(internal_strlen(dcatbuf), (uptr)0);
278   EXPECT_EQ(retval, (uptr)3);
279 
280   retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
281   EXPECT_EQ(internal_strcmp(dcatbuf, "123"), 0);
282   EXPECT_EQ(internal_strlen(dcatbuf), (uptr)3);
283   EXPECT_EQ(retval, (uptr)3);
284 
285   retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
286   EXPECT_EQ(internal_strcmp(dcatbuf, "123123"), 0);
287   EXPECT_EQ(internal_strlen(dcatbuf), (uptr)6);
288   EXPECT_EQ(retval, (uptr)6);
289 
290   retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
291   EXPECT_EQ(internal_strcmp(dcatbuf, "1231231"), 0);
292   EXPECT_EQ(internal_strlen(dcatbuf), (uptr)7);
293   EXPECT_EQ(retval, (uptr)9);
294 }
295 
296 TEST(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(emptystr), 0ul);
303   ASSERT_EQ(internal_wcslen(samesizestr), 7ul);
304   ASSERT_EQ(internal_wcslen(shortstr), 3ul);
305   ASSERT_EQ(internal_wcslen(longerstr), 9ul);
306 
307   ASSERT_EQ(internal_wcsnlen(emptystr, 7), 0ul);
308   ASSERT_EQ(internal_wcsnlen(samesizestr, 7), 7ul);
309   ASSERT_EQ(internal_wcsnlen(shortstr, 7), 3ul);
310   ASSERT_EQ(internal_wcsnlen(longerstr, 7), 7ul);
311 }
312 
313 // FIXME: File manipulations are not yet supported on Windows
314 #if SANITIZER_POSIX && !SANITIZER_APPLE
315 TEST(SanitizerCommon, InternalMmapWithOffset) {
316   char tmpfile[128];
317   temp_file_name(tmpfile, sizeof(tmpfile),
318                  "sanitizer_common.internalmmapwithoffset.tmp.");
319   fd_t fd = OpenFile(tmpfile, RdWr);
320   ASSERT_NE(fd, kInvalidFd);
321 
322   uptr page_size = GetPageSizeCached();
323   uptr res = internal_ftruncate(fd, page_size * 2);
324   ASSERT_FALSE(internal_iserror(res));
325 
326   res = internal_lseek(fd, page_size, SEEK_SET);
327   ASSERT_FALSE(internal_iserror(res));
328 
329   res = internal_write(fd, "AB", 2);
330   ASSERT_FALSE(internal_iserror(res));
331 
332   char *p = (char *)MapWritableFileToMemory(nullptr, page_size, fd, 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(p, page_size);
340   internal_unlink(tmpfile);
341 }
342 #endif
343 
344 TEST(SanitizerCommon, ReportFile) {
345   SpinMutex report_file_mu;
346   ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
347   char tmpfile[128];
348   temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.reportfile.tmp.");
349   report_file.SetReportPath(tmpfile);
350   const char *path = report_file.GetReportPath();
351   EXPECT_EQ(internal_strncmp(tmpfile, path, strlen(tmpfile)), 0);
352   // This will close tmpfile.
353   report_file.SetReportPath("stderr");
354   Unlink(tmpfile);
355 }
356 
357 TEST(SanitizerCommon, FileExists) {
358   char tmpfile[128];
359   temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileexists.tmp.");
360   fd_t fd = OpenFile(tmpfile, WrOnly);
361   ASSERT_NE(fd, kInvalidFd);
362   EXPECT_TRUE(FileExists(tmpfile));
363   CloseFile(fd);
364   Unlink(tmpfile);
365 }
366 
367 TEST(SanitizerCommon, DirExists) {
368   char tmpdir[128];
369   get_temp_dir(tmpdir, sizeof(tmpdir));
370   EXPECT_TRUE(DirExists(tmpdir));
371 }
372