1//===-- sanitizer_libc_test.cc --------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9// Tests for sanitizer_libc.h.
10//===----------------------------------------------------------------------===//
11#include <algorithm>
12
13#include "sanitizer_common/sanitizer_common.h"
14#include "sanitizer_common/sanitizer_libc.h"
15#include "sanitizer_common/sanitizer_platform.h"
16#include "gtest/gtest.h"
17
18#if SANITIZER_WINDOWS
19#define NOMINMAX
20#include <windows.h>
21#undef NOMINMAX
22#endif
23#if SANITIZER_POSIX
24# include <sys/stat.h>
25# include "sanitizer_common/sanitizer_posix.h"
26#endif
27
28// A regression test for internal_memmove() implementation.
29TEST(SanitizerCommon, InternalMemmoveRegression) {
30  char src[] = "Hello World";
31  char *dest = src + 6;
32  __sanitizer::internal_memmove(dest, src, 5);
33  EXPECT_EQ(dest[0], src[0]);
34  EXPECT_EQ(dest[4], src[4]);
35}
36
37TEST(SanitizerCommon, mem_is_zero) {
38  size_t size = 128;
39  char *x = new char[size];
40  memset(x, 0, size);
41  for (size_t pos = 0; pos < size; pos++) {
42    x[pos] = 1;
43    for (size_t beg = 0; beg < size; beg++) {
44      for (size_t end = beg; end < size; end++) {
45        // fprintf(stderr, "pos %zd beg %zd end %zd \n", pos, beg, end);
46        if (beg <= pos && pos < end)
47          EXPECT_FALSE(__sanitizer::mem_is_zero(x + beg, end - beg));
48        else
49          EXPECT_TRUE(__sanitizer::mem_is_zero(x + beg, end - beg));
50      }
51    }
52    x[pos] = 0;
53  }
54  delete [] x;
55}
56
57struct stat_and_more {
58  struct stat st;
59  unsigned char z;
60};
61
62static void temp_file_name(char *buf, size_t bufsize, const char *prefix) {
63#if SANITIZER_WINDOWS
64  buf[0] = '\0';
65  char tmp_dir[MAX_PATH];
66  if (!::GetTempPathA(MAX_PATH, tmp_dir))
67    return;
68  // GetTempFileNameA needs a MAX_PATH buffer.
69  char tmp_path[MAX_PATH];
70  if (!::GetTempFileNameA(tmp_dir, prefix, 0, tmp_path))
71    return;
72  internal_strncpy(buf, tmp_path, bufsize);
73#else
74  const char *tmpdir = "/tmp";
75#if SANITIZER_ANDROID
76  // I don't know a way to query temp directory location on Android without
77  // going through Java interfaces. The code below is not ideal, but should
78  // work. May require "adb root", but it is needed for almost any use of ASan
79  // on Android already.
80  tmpdir = GetEnv("EXTERNAL_STORAGE");
81#endif
82  u32 uid = GetUid();
83  internal_snprintf(buf, bufsize, "%s/%s%d", tmpdir, prefix, uid);
84#endif
85}
86
87TEST(SanitizerCommon, FileOps) {
88  const char *str1 = "qwerty";
89  uptr len1 = internal_strlen(str1);
90  const char *str2 = "zxcv";
91  uptr len2 = internal_strlen(str2);
92
93  char tmpfile[128];
94  temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp.");
95  fd_t fd = OpenFile(tmpfile, WrOnly);
96  ASSERT_NE(fd, kInvalidFd);
97  uptr bytes_written = 0;
98  EXPECT_TRUE(WriteToFile(fd, str1, len1, &bytes_written));
99  EXPECT_EQ(len1, bytes_written);
100  EXPECT_TRUE(WriteToFile(fd, str2, len2, &bytes_written));
101  EXPECT_EQ(len2, bytes_written);
102  CloseFile(fd);
103
104  EXPECT_TRUE(FileExists(tmpfile));
105
106  fd = OpenFile(tmpfile, RdOnly);
107  ASSERT_NE(fd, kInvalidFd);
108
109#if SANITIZER_POSIX
110  // The stat wrappers are posix-only.
111  uptr fsize = internal_filesize(fd);
112  EXPECT_EQ(len1 + len2, fsize);
113
114  struct stat st1, st2, st3;
115  EXPECT_EQ(0u, internal_stat(tmpfile, &st1));
116  EXPECT_EQ(0u, internal_lstat(tmpfile, &st2));
117  EXPECT_EQ(0u, internal_fstat(fd, &st3));
118  EXPECT_EQ(fsize, (uptr)st3.st_size);
119
120  // Verify that internal_fstat does not write beyond the end of the supplied
121  // buffer.
122  struct stat_and_more sam;
123  memset(&sam, 0xAB, sizeof(sam));
124  EXPECT_EQ(0u, internal_fstat(fd, &sam.st));
125  EXPECT_EQ(0xAB, sam.z);
126  EXPECT_NE(0xAB, sam.st.st_size);
127  EXPECT_NE(0, sam.st.st_size);
128#endif
129
130  char buf[64] = {};
131  uptr bytes_read = 0;
132  EXPECT_TRUE(ReadFromFile(fd, buf, len1, &bytes_read));
133  EXPECT_EQ(len1, bytes_read);
134  EXPECT_EQ(0, internal_memcmp(buf, str1, len1));
135  EXPECT_EQ((char)0, buf[len1 + 1]);
136  internal_memset(buf, 0, len1);
137  EXPECT_TRUE(ReadFromFile(fd, buf, len2, &bytes_read));
138  EXPECT_EQ(len2, bytes_read);
139  EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
140  CloseFile(fd);
141
142#if SANITIZER_WINDOWS
143  // No sanitizer needs to delete a file on Windows yet. If we ever do, we can
144  // add a portable wrapper and test it from here.
145  ::DeleteFileA(&tmpfile[0]);
146#else
147  internal_unlink(tmpfile);
148#endif
149}
150
151static const size_t kStrlcpyBufSize = 8;
152void test_internal_strlcpy(char *dbuf, const char *sbuf) {
153  uptr retval = 0;
154  retval = internal_strlcpy(dbuf, sbuf, kStrlcpyBufSize);
155  EXPECT_EQ(internal_strncmp(dbuf, sbuf, kStrlcpyBufSize - 1), 0);
156  EXPECT_EQ(internal_strlen(dbuf),
157            std::min(internal_strlen(sbuf), (uptr)(kStrlcpyBufSize - 1)));
158  EXPECT_EQ(retval, internal_strlen(sbuf));
159
160  // Test with shorter maxlen.
161  uptr maxlen = 2;
162  if (internal_strlen(sbuf) > maxlen) {
163    retval = internal_strlcpy(dbuf, sbuf, maxlen);
164    EXPECT_EQ(internal_strncmp(dbuf, sbuf, maxlen - 1), 0);
165    EXPECT_EQ(internal_strlen(dbuf), maxlen - 1);
166  }
167}
168
169TEST(SanitizerCommon, InternalStrFunctions) {
170  const char *haystack = "haystack";
171  EXPECT_EQ(haystack + 2, internal_strchr(haystack, 'y'));
172  EXPECT_EQ(haystack + 2, internal_strchrnul(haystack, 'y'));
173  EXPECT_EQ(0, internal_strchr(haystack, 'z'));
174  EXPECT_EQ(haystack + 8, internal_strchrnul(haystack, 'z'));
175
176  char dbuf[kStrlcpyBufSize] = {};
177  const char *samesizestr = "1234567";
178  const char *shortstr = "123";
179  const char *longerstr = "123456789";
180
181  // Test internal_strlcpy.
182  internal_strlcpy(dbuf, shortstr, 0);
183  EXPECT_EQ(dbuf[0], 0);
184  EXPECT_EQ(dbuf[0], 0);
185  test_internal_strlcpy(dbuf, samesizestr);
186  test_internal_strlcpy(dbuf, shortstr);
187  test_internal_strlcpy(dbuf, longerstr);
188
189  // Test internal_strlcat.
190  char dcatbuf[kStrlcpyBufSize] = {};
191  uptr retval = 0;
192  retval = internal_strlcat(dcatbuf, "aaa", 0);
193  EXPECT_EQ(internal_strlen(dcatbuf), (uptr)0);
194  EXPECT_EQ(retval, (uptr)3);
195
196  retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
197  EXPECT_EQ(internal_strcmp(dcatbuf, "123"), 0);
198  EXPECT_EQ(internal_strlen(dcatbuf), (uptr)3);
199  EXPECT_EQ(retval, (uptr)3);
200
201  retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
202  EXPECT_EQ(internal_strcmp(dcatbuf, "123123"), 0);
203  EXPECT_EQ(internal_strlen(dcatbuf), (uptr)6);
204  EXPECT_EQ(retval, (uptr)6);
205
206  retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
207  EXPECT_EQ(internal_strcmp(dcatbuf, "1231231"), 0);
208  EXPECT_EQ(internal_strlen(dcatbuf), (uptr)7);
209  EXPECT_EQ(retval, (uptr)9);
210}
211
212// FIXME: File manipulations are not yet supported on Windows
213#if SANITIZER_POSIX && !SANITIZER_MAC
214TEST(SanitizerCommon, InternalMmapWithOffset) {
215  char tmpfile[128];
216  temp_file_name(tmpfile, sizeof(tmpfile),
217                 "sanitizer_common.internalmmapwithoffset.tmp.");
218  fd_t fd = OpenFile(tmpfile, RdWr);
219  ASSERT_NE(fd, kInvalidFd);
220
221  uptr page_size = GetPageSizeCached();
222  uptr res = internal_ftruncate(fd, page_size * 2);
223  ASSERT_FALSE(internal_iserror(res));
224
225  res = internal_lseek(fd, page_size, SEEK_SET);
226  ASSERT_FALSE(internal_iserror(res));
227
228  res = internal_write(fd, "AB", 2);
229  ASSERT_FALSE(internal_iserror(res));
230
231  char *p = (char *)MapWritableFileToMemory(nullptr, page_size, fd, page_size);
232  ASSERT_NE(nullptr, p);
233
234  ASSERT_EQ('A', p[0]);
235  ASSERT_EQ('B', p[1]);
236
237  CloseFile(fd);
238  UnmapOrDie(p, page_size);
239  internal_unlink(tmpfile);
240}
241#endif
242