1 //===-- sanitizer_libc_test.cpp -------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
8 // Tests for sanitizer_libc.h.
9 //===----------------------------------------------------------------------===//
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"
26 # include <sys/stat.h>
27 # include "sanitizer_common/sanitizer_posix.h"
30 using namespace __sanitizer
;
32 // A regression test for internal_memmove() implementation.
33 TEST(SanitizerCommon
, InternalMemmoveRegression
) {
34 char src
[] = "Hello World";
36 __sanitizer::internal_memmove(dest
, src
, 5);
37 EXPECT_EQ(dest
[0], src
[0]);
38 EXPECT_EQ(dest
[4], src
[4]);
41 TEST(SanitizerCommon
, mem_is_zero
) {
43 char *x
= new char[size
];
45 for (size_t pos
= 0; pos
< size
; pos
++) {
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
));
53 EXPECT_TRUE(__sanitizer::mem_is_zero(x
+ beg
, end
- beg
));
61 struct stat_and_more
{
66 static void get_temp_dir(char *buf
, size_t bufsize
) {
69 if (!::GetTempPathA(bufsize
, buf
))
72 const char *tmpdir
= "/tmp";
73 # if SANITIZER_ANDROID
74 tmpdir
= GetEnv("TMPDIR");
76 internal_snprintf(buf
, bufsize
, "%s", tmpdir
);
80 static void temp_file_name(char *buf
, size_t bufsize
, const char *prefix
) {
83 char tmp_dir
[MAX_PATH
];
84 if (!::GetTempPathA(MAX_PATH
, tmp_dir
))
86 // GetTempFileNameA needs a MAX_PATH buffer.
87 char tmp_path
[MAX_PATH
];
88 if (!::GetTempFileNameA(tmp_dir
, prefix
, 0, tmp_path
))
90 internal_strncpy(buf
, tmp_path
, bufsize
);
92 const char *tmpdir
= "/tmp";
94 tmpdir
= GetEnv("TMPDIR");
96 internal_snprintf(buf
, bufsize
, "%s/%sXXXXXX", tmpdir
, prefix
);
97 ASSERT_TRUE(mkstemp(buf
));
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]);
107 internal_unlink(path
);
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
);
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));
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);
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
);
136 EXPECT_TRUE(FileExists(tmpfile
));
138 fd
= OpenFile(tmpfile
, RdOnly
);
139 ASSERT_NE(fd
, kInvalidFd
);
142 // The stat wrappers are posix-only.
143 uptr fsize
= internal_filesize(fd
);
144 EXPECT_EQ(len1
+ len2
, fsize
);
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
);
152 // Verify that internal_fstat does not write beyond the end of the supplied
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
);
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
));
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; });
182 temp_file_name(file_name_
, sizeof(file_name_
),
183 "sanitizer_common.ReadFile.tmp.");
185 if (FILE *f
= fopen(file_name_
, "wb")) {
187 fwrite(data_
.data(), data_
.size(), 1, f
);
192 void TearDown() override
{ Unlink(file_name_
); }
195 char file_name_
[256];
196 std::vector
<char> data_
;
199 TEST_P(SanitizerCommonFileTest
, ReadFileToBuffer
) {
203 EXPECT_TRUE(ReadFileToBuffer(file_name_
, &buff
, &len
, &size
));
204 EXPECT_EQ(data_
, std::vector
<char>(buff
, buff
+ size
));
205 UnmapOrDie(buff
, len
);
208 TEST_P(SanitizerCommonFileTest
, ReadFileToBufferHalf
) {
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
);
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()));
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()));
231 INSTANTIATE_TEST_SUITE_P(FileSizes
, SanitizerCommonFileTest
,
232 ::testing::Values(0, 1, 7, 13, 32, 4096, 4097, 1048575,
235 static const size_t kStrlcpyBufSize
= 8;
236 void test_internal_strlcpy(char *dbuf
, const char *sbuf
) {
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
));
244 // Test with shorter maxlen.
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);
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'));
260 char dbuf
[kStrlcpyBufSize
] = {};
261 const char *samesizestr
= "1234567";
262 const char *shortstr
= "123";
263 const char *longerstr
= "123456789";
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
);
273 // Test internal_strlcat.
274 char dcatbuf
[kStrlcpyBufSize
] = {};
276 retval
= internal_strlcat(dcatbuf
, "aaa", 0);
277 EXPECT_EQ(internal_strlen(dcatbuf
), (uptr
)0);
278 EXPECT_EQ(retval
, (uptr
)3);
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);
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);
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);
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";
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);
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);
313 // FIXME: File manipulations are not yet supported on Windows
314 #if SANITIZER_POSIX && !SANITIZER_APPLE
315 TEST(SanitizerCommon
, InternalMmapWithOffset
) {
317 temp_file_name(tmpfile
, sizeof(tmpfile
),
318 "sanitizer_common.internalmmapwithoffset.tmp.");
319 fd_t fd
= OpenFile(tmpfile
, RdWr
);
320 ASSERT_NE(fd
, kInvalidFd
);
322 uptr page_size
= GetPageSizeCached();
323 uptr res
= internal_ftruncate(fd
, page_size
* 2);
324 ASSERT_FALSE(internal_iserror(res
));
326 res
= internal_lseek(fd
, page_size
, SEEK_SET
);
327 ASSERT_FALSE(internal_iserror(res
));
329 res
= internal_write(fd
, "AB", 2);
330 ASSERT_FALSE(internal_iserror(res
));
332 char *p
= (char *)MapWritableFileToMemory(nullptr, page_size
, fd
, page_size
);
333 ASSERT_NE(nullptr, p
);
335 ASSERT_EQ('A', p
[0]);
336 ASSERT_EQ('B', p
[1]);
339 UnmapOrDie(p
, page_size
);
340 internal_unlink(tmpfile
);
344 TEST(SanitizerCommon
, ReportFile
) {
345 SpinMutex report_file_mu
;
346 ReportFile report_file
= {&report_file_mu
, kStderrFd
, "", "", 0};
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");
357 TEST(SanitizerCommon
, FileExists
) {
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
));
367 TEST(SanitizerCommon
, DirExists
) {
369 get_temp_dir(tmpdir
, sizeof(tmpdir
));
370 EXPECT_TRUE(DirExists(tmpdir
));