1//===-- sanitizer_libc.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//
9// This file is shared between AddressSanitizer and ThreadSanitizer
10// run-time libraries. See sanitizer_libc.h for details.
11//===----------------------------------------------------------------------===//
12
13// Do not redefine builtins; this file is defining the builtin replacements.
14#define SANITIZER_COMMON_NO_REDEFINE_BUILTINS
15
16#include "sanitizer_allocator_internal.h"
17#include "sanitizer_common.h"
18#include "sanitizer_libc.h"
19
20namespace __sanitizer {
21
22s64 internal_atoll(const char *nptr) {
23  return internal_simple_strtoll(nptr, nullptr, 10);
24}
25
26void *internal_memchr(const void *s, int c, uptr n) {
27  const char *t = (const char *)s;
28  for (uptr i = 0; i < n; ++i, ++t)
29    if (*t == c)
30      return reinterpret_cast<void *>(const_cast<char *>(t));
31  return nullptr;
32}
33
34void *internal_memrchr(const void *s, int c, uptr n) {
35  const char *t = (const char *)s;
36  void *res = nullptr;
37  for (uptr i = 0; i < n; ++i, ++t) {
38    if (*t == c) res = reinterpret_cast<void *>(const_cast<char *>(t));
39  }
40  return res;
41}
42
43int internal_memcmp(const void* s1, const void* s2, uptr n) {
44  const char *t1 = (const char *)s1;
45  const char *t2 = (const char *)s2;
46  for (uptr i = 0; i < n; ++i, ++t1, ++t2)
47    if (*t1 != *t2)
48      return *t1 < *t2 ? -1 : 1;
49  return 0;
50}
51
52extern "C" {
53SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memcpy(void *dest,
54                                                                const void *src,
55                                                                uptr n) {
56  char *d = (char*)dest;
57  const char *s = (const char *)src;
58  for (uptr i = 0; i < n; ++i)
59    d[i] = s[i];
60  return dest;
61}
62
63SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memmove(
64    void *dest, const void *src, uptr n) {
65  char *d = (char*)dest;
66  const char *s = (const char *)src;
67  sptr i, signed_n = (sptr)n;
68  CHECK_GE(signed_n, 0);
69  if (d < s) {
70    for (i = 0; i < signed_n; ++i)
71      d[i] = s[i];
72  } else {
73    if (d > s && signed_n > 0) {
74      for (i = signed_n - 1; i >= 0; --i) {
75        d[i] = s[i];
76      }
77    }
78  }
79  return dest;
80}
81
82SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memset(void *s, int c,
83                                                                uptr n) {
84  // Optimize for the most performance-critical case:
85  if ((reinterpret_cast<uptr>(s) % 16) == 0 && (n % 16) == 0) {
86    u64 *p = reinterpret_cast<u64*>(s);
87    u64 *e = p + n / 8;
88    u64 v = c;
89    v |= v << 8;
90    v |= v << 16;
91    v |= v << 32;
92    for (; p < e; p += 2)
93      p[0] = p[1] = v;
94    return s;
95  }
96  // The next line prevents Clang from making a call to memset() instead of the
97  // loop below.
98  // FIXME: building the runtime with -ffreestanding is a better idea. However
99  // there currently are linktime problems due to PR12396.
100  char volatile *t = (char*)s;
101  for (uptr i = 0; i < n; ++i, ++t) {
102    *t = c;
103  }
104  return s;
105}
106}  // extern "C"
107
108uptr internal_strcspn(const char *s, const char *reject) {
109  uptr i;
110  for (i = 0; s[i]; i++) {
111    if (internal_strchr(reject, s[i]))
112      return i;
113  }
114  return i;
115}
116
117char* internal_strdup(const char *s) {
118  uptr len = internal_strlen(s);
119  char *s2 = (char*)InternalAlloc(len + 1);
120  internal_memcpy(s2, s, len);
121  s2[len] = 0;
122  return s2;
123}
124
125int internal_strcmp(const char *s1, const char *s2) {
126  while (true) {
127    unsigned c1 = *s1;
128    unsigned c2 = *s2;
129    if (c1 != c2) return (c1 < c2) ? -1 : 1;
130    if (c1 == 0) break;
131    s1++;
132    s2++;
133  }
134  return 0;
135}
136
137int internal_strncmp(const char *s1, const char *s2, uptr n) {
138  for (uptr i = 0; i < n; i++) {
139    unsigned c1 = *s1;
140    unsigned c2 = *s2;
141    if (c1 != c2) return (c1 < c2) ? -1 : 1;
142    if (c1 == 0) break;
143    s1++;
144    s2++;
145  }
146  return 0;
147}
148
149char* internal_strchr(const char *s, int c) {
150  while (true) {
151    if (*s == (char)c)
152      return const_cast<char *>(s);
153    if (*s == 0)
154      return nullptr;
155    s++;
156  }
157}
158
159char *internal_strchrnul(const char *s, int c) {
160  char *res = internal_strchr(s, c);
161  if (!res)
162    res = const_cast<char *>(s) + internal_strlen(s);
163  return res;
164}
165
166char *internal_strrchr(const char *s, int c) {
167  const char *res = nullptr;
168  for (uptr i = 0; s[i]; i++) {
169    if (s[i] == c) res = s + i;
170  }
171  return const_cast<char *>(res);
172}
173
174uptr internal_strlen(const char *s) {
175  uptr i = 0;
176  while (s[i]) i++;
177  return i;
178}
179
180uptr internal_strlcat(char *dst, const char *src, uptr maxlen) {
181  const uptr srclen = internal_strlen(src);
182  const uptr dstlen = internal_strnlen(dst, maxlen);
183  if (dstlen == maxlen) return maxlen + srclen;
184  if (srclen < maxlen - dstlen) {
185    internal_memmove(dst + dstlen, src, srclen + 1);
186  } else {
187    internal_memmove(dst + dstlen, src, maxlen - dstlen - 1);
188    dst[maxlen - 1] = '\0';
189  }
190  return dstlen + srclen;
191}
192
193char *internal_strncat(char *dst, const char *src, uptr n) {
194  uptr len = internal_strlen(dst);
195  uptr i;
196  for (i = 0; i < n && src[i]; i++)
197    dst[len + i] = src[i];
198  dst[len + i] = 0;
199  return dst;
200}
201
202wchar_t *internal_wcscpy(wchar_t *dst, const wchar_t *src) {
203  wchar_t *dst_it = dst;
204  do {
205    *dst_it++ = *src++;
206  } while (*src);
207  return dst;
208}
209
210uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) {
211  const uptr srclen = internal_strlen(src);
212  if (srclen < maxlen) {
213    internal_memmove(dst, src, srclen + 1);
214  } else if (maxlen != 0) {
215    internal_memmove(dst, src, maxlen - 1);
216    dst[maxlen - 1] = '\0';
217  }
218  return srclen;
219}
220
221char *internal_strncpy(char *dst, const char *src, uptr n) {
222  uptr i;
223  for (i = 0; i < n && src[i]; i++)
224    dst[i] = src[i];
225  internal_memset(dst + i, '\0', n - i);
226  return dst;
227}
228
229wchar_t *internal_wcsncpy(wchar_t *dst, const wchar_t *src, uptr n) {
230  uptr i;
231  for (i = 0; i < n && src[i]; ++i)
232    dst[i] = src[i];
233  internal_memset(dst + i, 0, (n - i) * sizeof(wchar_t));
234  return dst;
235}
236
237uptr internal_strnlen(const char *s, uptr maxlen) {
238  uptr i = 0;
239  while (i < maxlen && s[i]) i++;
240  return i;
241}
242
243char *internal_strstr(const char *haystack, const char *needle) {
244  // This is O(N^2), but we are not using it in hot places.
245  uptr len1 = internal_strlen(haystack);
246  uptr len2 = internal_strlen(needle);
247  if (len1 < len2) return nullptr;
248  for (uptr pos = 0; pos <= len1 - len2; pos++) {
249    if (internal_memcmp(haystack + pos, needle, len2) == 0)
250      return const_cast<char *>(haystack) + pos;
251  }
252  return nullptr;
253}
254
255s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base) {
256  CHECK_EQ(base, 10);
257  while (IsSpace(*nptr)) nptr++;
258  int sgn = 1;
259  u64 res = 0;
260  bool have_digits = false;
261  char *old_nptr = const_cast<char *>(nptr);
262  if (*nptr == '+') {
263    sgn = 1;
264    nptr++;
265  } else if (*nptr == '-') {
266    sgn = -1;
267    nptr++;
268  }
269  while (IsDigit(*nptr)) {
270    res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX;
271    int digit = ((*nptr) - '0');
272    res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX;
273    have_digits = true;
274    nptr++;
275  }
276  if (endptr) {
277    *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr;
278  }
279  if (sgn > 0) {
280    return (s64)(Min((u64)INT64_MAX, res));
281  } else {
282    return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1);
283  }
284}
285
286uptr internal_wcslen(const wchar_t *s) {
287  uptr i = 0;
288  while (s[i]) i++;
289  return i;
290}
291
292uptr internal_wcsnlen(const wchar_t *s, uptr maxlen) {
293  uptr i = 0;
294  while (i < maxlen && s[i]) i++;
295  return i;
296}
297
298bool mem_is_zero(const char *beg, uptr size) {
299  CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40));  // Sanity check.
300  const char *end = beg + size;
301  uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr));
302  uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr));
303  uptr all = 0;
304  // Prologue.
305  for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++)
306    all |= *mem;
307  // Aligned loop.
308  for (; aligned_beg < aligned_end; aligned_beg++)
309    all |= *aligned_beg;
310  // Epilogue.
311  if ((char *)aligned_end >= beg) {
312    for (const char *mem = (char *)aligned_end; mem < end; mem++) all |= *mem;
313  }
314  return all == 0;
315}
316
317} // namespace __sanitizer
318