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