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 temp_file_name(char *buf, size_t bufsize, const char *prefix) {
67 #if SANITIZER_WINDOWS
68   buf[0] = '\0';
69   char tmp_dir[MAX_PATH];
70   if (!::GetTempPathA(MAX_PATH, tmp_dir))
71     return;
72   // GetTempFileNameA needs a MAX_PATH buffer.
73   char tmp_path[MAX_PATH];
74   if (!::GetTempFileNameA(tmp_dir, prefix, 0, tmp_path))
75     return;
76   internal_strncpy(buf, tmp_path, bufsize);
77 #else
78   const char *tmpdir = "/tmp";
79 #if SANITIZER_ANDROID
80   tmpdir = GetEnv("TMPDIR");
81 #endif
82   internal_snprintf(buf, bufsize, "%s/%sXXXXXX", tmpdir, prefix);
83   ASSERT_TRUE(mkstemp(buf));
84 #endif
85 }
86 
87 static void Unlink(const char *path) {
88 #if SANITIZER_WINDOWS
89   // No sanitizer needs to delete a file on Windows yet. If we ever do, we can
90   // add a portable wrapper and test it from here.
91   ::DeleteFileA(&path[0]);
92 #else
93   internal_unlink(path);
94 #endif
95 }
96 
97 TEST(SanitizerCommon, FileOps) {
98   const char *str1 = "qwerty";
99   uptr len1 = internal_strlen(str1);
100   const char *str2 = "zxcv";
101   uptr len2 = internal_strlen(str2);
102 
103   char tmpfile[128];
104   temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp.");
105   fd_t fd = OpenFile(tmpfile, WrOnly);
106   ASSERT_NE(fd, kInvalidFd);
107   ASSERT_TRUE(WriteToFile(fd, "A", 1));
108   CloseFile(fd);
109 
110   fd = OpenFile(tmpfile, WrOnly);
111   ASSERT_NE(fd, kInvalidFd);
112 #if SANITIZER_POSIX && !SANITIZER_MAC
113   EXPECT_EQ(internal_lseek(fd, 0, SEEK_END), 0u);
114 #endif
115   uptr bytes_written = 0;
116   EXPECT_TRUE(WriteToFile(fd, str1, len1, &bytes_written));
117   EXPECT_EQ(len1, bytes_written);
118   EXPECT_TRUE(WriteToFile(fd, str2, len2, &bytes_written));
119   EXPECT_EQ(len2, bytes_written);
120   CloseFile(fd);
121 
122   EXPECT_TRUE(FileExists(tmpfile));
123 
124   fd = OpenFile(tmpfile, RdOnly);
125   ASSERT_NE(fd, kInvalidFd);
126 
127 #if SANITIZER_POSIX
128   // The stat wrappers are posix-only.
129   uptr fsize = internal_filesize(fd);
130   EXPECT_EQ(len1 + len2, fsize);
131 
132   struct stat st1, st2, st3;
133   EXPECT_EQ(0u, internal_stat(tmpfile, &st1));
134   EXPECT_EQ(0u, internal_lstat(tmpfile, &st2));
135   EXPECT_EQ(0u, internal_fstat(fd, &st3));
136   EXPECT_EQ(fsize, (uptr)st3.st_size);
137 
138   // Verify that internal_fstat does not write beyond the end of the supplied
139   // buffer.
140   struct stat_and_more sam;
141   memset(&sam, 0xAB, sizeof(sam));
142   EXPECT_EQ(0u, internal_fstat(fd, &sam.st));
143   EXPECT_EQ(0xAB, sam.z);
144   EXPECT_NE(0xAB, sam.st.st_size);
145   EXPECT_NE(0, sam.st.st_size);
146 #endif
147 
148   char buf[64] = {};
149   uptr bytes_read = 0;
150   EXPECT_TRUE(ReadFromFile(fd, buf, len1, &bytes_read));
151   EXPECT_EQ(len1, bytes_read);
152   EXPECT_EQ(0, internal_memcmp(buf, str1, len1));
153   EXPECT_EQ((char)0, buf[len1 + 1]);
154   internal_memset(buf, 0, len1);
155   EXPECT_TRUE(ReadFromFile(fd, buf, len2, &bytes_read));
156   EXPECT_EQ(len2, bytes_read);
157   EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
158   CloseFile(fd);
159 
160   Unlink(tmpfile);
161 }
162 
163 class SanitizerCommonFileTest : public ::testing::TestWithParam<uptr> {
164   void SetUp() override {
165     data_.resize(GetParam());
166     std::generate(data_.begin(), data_.end(), [] { return rand() % 256; });
167 
168     temp_file_name(file_name_, sizeof(file_name_),
169                    "sanitizer_common.ReadFile.tmp.");
170 
171     if (FILE *f = fopen(file_name_, "wb")) {
172       if (!data_.empty())
173         fwrite(data_.data(), data_.size(), 1, f);
174       fclose(f);
175     }
176   }
177 
178   void TearDown() override { Unlink(file_name_); }
179 
180  protected:
181   char file_name_[256];
182   std::vector<char> data_;
183 };
184 
185 TEST_P(SanitizerCommonFileTest, ReadFileToBuffer) {
186   char *buff;
187   uptr size;
188   uptr len;
189   EXPECT_TRUE(ReadFileToBuffer(file_name_, &buff, &len, &size));
190   EXPECT_EQ(data_, std::vector<char>(buff, buff + size));
191   UnmapOrDie(buff, len);
192 }
193 
194 TEST_P(SanitizerCommonFileTest, ReadFileToBufferHalf) {
195   char *buff;
196   uptr size;
197   uptr len;
198   data_.resize(data_.size() / 2);
199   EXPECT_TRUE(ReadFileToBuffer(file_name_, &buff, &len, &size, data_.size()));
200   EXPECT_EQ(data_, std::vector<char>(buff, buff + size));
201   UnmapOrDie(buff, len);
202 }
203 
204 TEST_P(SanitizerCommonFileTest, ReadFileToVector) {
205   InternalMmapVector<char> buff;
206   EXPECT_TRUE(ReadFileToVector(file_name_, &buff));
207   EXPECT_EQ(data_, std::vector<char>(buff.begin(), buff.end()));
208 }
209 
210 TEST_P(SanitizerCommonFileTest, ReadFileToVectorHalf) {
211   InternalMmapVector<char> buff;
212   data_.resize(data_.size() / 2);
213   EXPECT_TRUE(ReadFileToVector(file_name_, &buff, data_.size()));
214   EXPECT_EQ(data_, std::vector<char>(buff.begin(), buff.end()));
215 }
216 
217 INSTANTIATE_TEST_SUITE_P(FileSizes, SanitizerCommonFileTest,
218                          ::testing::Values(0, 1, 7, 13, 32, 4096, 4097, 1048575,
219                                            1048576, 1048577));
220 
221 static const size_t kStrlcpyBufSize = 8;
222 void test_internal_strlcpy(char *dbuf, const char *sbuf) {
223   uptr retval = 0;
224   retval = internal_strlcpy(dbuf, sbuf, kStrlcpyBufSize);
225   EXPECT_EQ(internal_strncmp(dbuf, sbuf, kStrlcpyBufSize - 1), 0);
226   EXPECT_EQ(internal_strlen(dbuf),
227             std::min(internal_strlen(sbuf), (uptr)(kStrlcpyBufSize - 1)));
228   EXPECT_EQ(retval, internal_strlen(sbuf));
229 
230   // Test with shorter maxlen.
231   uptr maxlen = 2;
232   if (internal_strlen(sbuf) > maxlen) {
233     retval = internal_strlcpy(dbuf, sbuf, maxlen);
234     EXPECT_EQ(internal_strncmp(dbuf, sbuf, maxlen - 1), 0);
235     EXPECT_EQ(internal_strlen(dbuf), maxlen - 1);
236   }
237 }
238 
239 TEST(SanitizerCommon, InternalStrFunctions) {
240   const char *haystack = "haystack";
241   EXPECT_EQ(haystack + 2, internal_strchr(haystack, 'y'));
242   EXPECT_EQ(haystack + 2, internal_strchrnul(haystack, 'y'));
243   EXPECT_EQ(0, internal_strchr(haystack, 'z'));
244   EXPECT_EQ(haystack + 8, internal_strchrnul(haystack, 'z'));
245 
246   char dbuf[kStrlcpyBufSize] = {};
247   const char *samesizestr = "1234567";
248   const char *shortstr = "123";
249   const char *longerstr = "123456789";
250 
251   // Test internal_strlcpy.
252   internal_strlcpy(dbuf, shortstr, 0);
253   EXPECT_EQ(dbuf[0], 0);
254   EXPECT_EQ(dbuf[0], 0);
255   test_internal_strlcpy(dbuf, samesizestr);
256   test_internal_strlcpy(dbuf, shortstr);
257   test_internal_strlcpy(dbuf, longerstr);
258 
259   // Test internal_strlcat.
260   char dcatbuf[kStrlcpyBufSize] = {};
261   uptr retval = 0;
262   retval = internal_strlcat(dcatbuf, "aaa", 0);
263   EXPECT_EQ(internal_strlen(dcatbuf), (uptr)0);
264   EXPECT_EQ(retval, (uptr)3);
265 
266   retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
267   EXPECT_EQ(internal_strcmp(dcatbuf, "123"), 0);
268   EXPECT_EQ(internal_strlen(dcatbuf), (uptr)3);
269   EXPECT_EQ(retval, (uptr)3);
270 
271   retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
272   EXPECT_EQ(internal_strcmp(dcatbuf, "123123"), 0);
273   EXPECT_EQ(internal_strlen(dcatbuf), (uptr)6);
274   EXPECT_EQ(retval, (uptr)6);
275 
276   retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
277   EXPECT_EQ(internal_strcmp(dcatbuf, "1231231"), 0);
278   EXPECT_EQ(internal_strlen(dcatbuf), (uptr)7);
279   EXPECT_EQ(retval, (uptr)9);
280 }
281 
282 TEST(SanitizerCommon, InternalWideStringFunctions) {
283   const wchar_t *emptystr = L"";
284   const wchar_t *samesizestr = L"1234567";
285   const wchar_t *shortstr = L"123";
286   const wchar_t *longerstr = L"123456789";
287 
288   ASSERT_EQ(internal_wcslen(emptystr), 0ul);
289   ASSERT_EQ(internal_wcslen(samesizestr), 7ul);
290   ASSERT_EQ(internal_wcslen(shortstr), 3ul);
291   ASSERT_EQ(internal_wcslen(longerstr), 9ul);
292 
293   ASSERT_EQ(internal_wcsnlen(emptystr, 7), 0ul);
294   ASSERT_EQ(internal_wcsnlen(samesizestr, 7), 7ul);
295   ASSERT_EQ(internal_wcsnlen(shortstr, 7), 3ul);
296   ASSERT_EQ(internal_wcsnlen(longerstr, 7), 7ul);
297 }
298 
299 // FIXME: File manipulations are not yet supported on Windows
300 #if SANITIZER_POSIX && !SANITIZER_MAC
301 TEST(SanitizerCommon, InternalMmapWithOffset) {
302   char tmpfile[128];
303   temp_file_name(tmpfile, sizeof(tmpfile),
304                  "sanitizer_common.internalmmapwithoffset.tmp.");
305   fd_t fd = OpenFile(tmpfile, RdWr);
306   ASSERT_NE(fd, kInvalidFd);
307 
308   uptr page_size = GetPageSizeCached();
309   uptr res = internal_ftruncate(fd, page_size * 2);
310   ASSERT_FALSE(internal_iserror(res));
311 
312   res = internal_lseek(fd, page_size, SEEK_SET);
313   ASSERT_FALSE(internal_iserror(res));
314 
315   res = internal_write(fd, "AB", 2);
316   ASSERT_FALSE(internal_iserror(res));
317 
318   char *p = (char *)MapWritableFileToMemory(nullptr, page_size, fd, page_size);
319   ASSERT_NE(nullptr, p);
320 
321   ASSERT_EQ('A', p[0]);
322   ASSERT_EQ('B', p[1]);
323 
324   CloseFile(fd);
325   UnmapOrDie(p, page_size);
326   internal_unlink(tmpfile);
327 }
328 #endif
329 
330 TEST(SanitizerCommon, ReportFile) {
331   SpinMutex report_file_mu;
332   ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
333   char tmpfile[128];
334   temp_file_name(tmpfile, sizeof(tmpfile),
335                  "dir/sanitizer_common.reportfile.tmp.");
336   report_file.SetReportPath(tmpfile);
337   const char *path = report_file.GetReportPath();
338   EXPECT_EQ(internal_strncmp(tmpfile, path, strlen(tmpfile)), 0);
339   // This will close tmpfile.
340   report_file.SetReportPath("stderr");
341   Unlink(tmpfile);
342 }
343