373 lines · cpp
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-exception6//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_WINDOWS21#define NOMINMAX22#include <windows.h>23#undef NOMINMAX24#endif25#if SANITIZER_POSIX26# include <sys/stat.h>27# include "sanitizer_common/sanitizer_posix.h"28#endif29 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, 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 else53 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_WINDOWS68 buf[0] = '\0';69 if (!::GetTempPathA(bufsize, buf))70 return;71#else72 const char *tmpdir = "/tmp";73# if SANITIZER_ANDROID74 tmpdir = GetEnv("TMPDIR");75# endif76 internal_snprintf(buf, bufsize, "%s", tmpdir);77#endif78}79 80static void temp_file_name(char *buf, size_t bufsize, const char *prefix) {81#if SANITIZER_WINDOWS82 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#else92 const char *tmpdir = "/tmp";93#if SANITIZER_ANDROID94 tmpdir = GetEnv("TMPDIR");95#endif96 internal_snprintf(buf, bufsize, "%s/%sXXXXXX", tmpdir, prefix);97 ASSERT_TRUE(mkstemp(buf));98#endif99}100 101static void Unlink(const char *path) {102#if SANITIZER_WINDOWS103 // No sanitizer needs to delete a file on Windows yet. If we ever do, we can104 // add a portable wrapper and test it from here.105 ::DeleteFileA(&path[0]);106#else107 internal_unlink(path);108#endif109}110 111TEST(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_APPLE127 EXPECT_EQ(internal_lseek(fd, 0, SEEK_END), 0u);128#endif129 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_POSIX142 // 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 supplied153 // 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#endif161 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 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(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 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(buff, 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(buff, 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(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 253TEST(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 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(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 Windows314#if SANITIZER_POSIX && !SANITIZER_APPLE315TEST(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#endif343 344TEST(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 Unlink(path);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