1353944Sdim//===-- sanitizer_libc.cpp ------------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is shared between AddressSanitizer and ThreadSanitizer
10353944Sdim// run-time libraries. See sanitizer_libc.h for details.
11353944Sdim//===----------------------------------------------------------------------===//
12353944Sdim
13353944Sdim#include "sanitizer_allocator_internal.h"
14353944Sdim#include "sanitizer_common.h"
15353944Sdim#include "sanitizer_libc.h"
16353944Sdim
17353944Sdimnamespace __sanitizer {
18353944Sdim
19353944Sdims64 internal_atoll(const char *nptr) {
20353944Sdim  return internal_simple_strtoll(nptr, nullptr, 10);
21353944Sdim}
22353944Sdim
23353944Sdimvoid *internal_memchr(const void *s, int c, uptr n) {
24353944Sdim  const char *t = (const char *)s;
25353944Sdim  for (uptr i = 0; i < n; ++i, ++t)
26353944Sdim    if (*t == c)
27353944Sdim      return reinterpret_cast<void *>(const_cast<char *>(t));
28353944Sdim  return nullptr;
29353944Sdim}
30353944Sdim
31353944Sdimvoid *internal_memrchr(const void *s, int c, uptr n) {
32353944Sdim  const char *t = (const char *)s;
33353944Sdim  void *res = nullptr;
34353944Sdim  for (uptr i = 0; i < n; ++i, ++t) {
35353944Sdim    if (*t == c) res = reinterpret_cast<void *>(const_cast<char *>(t));
36353944Sdim  }
37353944Sdim  return res;
38353944Sdim}
39353944Sdim
40353944Sdimint internal_memcmp(const void* s1, const void* s2, uptr n) {
41353944Sdim  const char *t1 = (const char *)s1;
42353944Sdim  const char *t2 = (const char *)s2;
43353944Sdim  for (uptr i = 0; i < n; ++i, ++t1, ++t2)
44353944Sdim    if (*t1 != *t2)
45353944Sdim      return *t1 < *t2 ? -1 : 1;
46353944Sdim  return 0;
47353944Sdim}
48353944Sdim
49353944Sdimvoid *internal_memcpy(void *dest, const void *src, uptr n) {
50353944Sdim  char *d = (char*)dest;
51353944Sdim  const char *s = (const char *)src;
52353944Sdim  for (uptr i = 0; i < n; ++i)
53353944Sdim    d[i] = s[i];
54353944Sdim  return dest;
55353944Sdim}
56353944Sdim
57353944Sdimvoid *internal_memmove(void *dest, const void *src, uptr n) {
58353944Sdim  char *d = (char*)dest;
59353944Sdim  const char *s = (const char *)src;
60353944Sdim  sptr i, signed_n = (sptr)n;
61353944Sdim  CHECK_GE(signed_n, 0);
62353944Sdim  if (d < s) {
63353944Sdim    for (i = 0; i < signed_n; ++i)
64353944Sdim      d[i] = s[i];
65353944Sdim  } else {
66353944Sdim    if (d > s && signed_n > 0) {
67353944Sdim      for (i = signed_n - 1; i >= 0; --i) {
68353944Sdim        d[i] = s[i];
69353944Sdim      }
70353944Sdim    }
71353944Sdim  }
72353944Sdim  return dest;
73353944Sdim}
74353944Sdim
75353944Sdimvoid *internal_memset(void* s, int c, uptr n) {
76353944Sdim  // Optimize for the most performance-critical case:
77353944Sdim  if ((reinterpret_cast<uptr>(s) % 16) == 0 && (n % 16) == 0) {
78353944Sdim    u64 *p = reinterpret_cast<u64*>(s);
79353944Sdim    u64 *e = p + n / 8;
80353944Sdim    u64 v = c;
81353944Sdim    v |= v << 8;
82353944Sdim    v |= v << 16;
83353944Sdim    v |= v << 32;
84353944Sdim    for (; p < e; p += 2)
85353944Sdim      p[0] = p[1] = v;
86353944Sdim    return s;
87353944Sdim  }
88353944Sdim  // The next line prevents Clang from making a call to memset() instead of the
89353944Sdim  // loop below.
90353944Sdim  // FIXME: building the runtime with -ffreestanding is a better idea. However
91353944Sdim  // there currently are linktime problems due to PR12396.
92353944Sdim  char volatile *t = (char*)s;
93353944Sdim  for (uptr i = 0; i < n; ++i, ++t) {
94353944Sdim    *t = c;
95353944Sdim  }
96353944Sdim  return s;
97353944Sdim}
98353944Sdim
99353944Sdimuptr internal_strcspn(const char *s, const char *reject) {
100353944Sdim  uptr i;
101353944Sdim  for (i = 0; s[i]; i++) {
102353944Sdim    if (internal_strchr(reject, s[i]))
103353944Sdim      return i;
104353944Sdim  }
105353944Sdim  return i;
106353944Sdim}
107353944Sdim
108353944Sdimchar* internal_strdup(const char *s) {
109353944Sdim  uptr len = internal_strlen(s);
110353944Sdim  char *s2 = (char*)InternalAlloc(len + 1);
111353944Sdim  internal_memcpy(s2, s, len);
112353944Sdim  s2[len] = 0;
113353944Sdim  return s2;
114353944Sdim}
115353944Sdim
116353944Sdimint internal_strcmp(const char *s1, const char *s2) {
117353944Sdim  while (true) {
118353944Sdim    unsigned c1 = *s1;
119353944Sdim    unsigned c2 = *s2;
120353944Sdim    if (c1 != c2) return (c1 < c2) ? -1 : 1;
121353944Sdim    if (c1 == 0) break;
122353944Sdim    s1++;
123353944Sdim    s2++;
124353944Sdim  }
125353944Sdim  return 0;
126353944Sdim}
127353944Sdim
128353944Sdimint internal_strncmp(const char *s1, const char *s2, uptr n) {
129353944Sdim  for (uptr i = 0; i < n; i++) {
130353944Sdim    unsigned c1 = *s1;
131353944Sdim    unsigned c2 = *s2;
132353944Sdim    if (c1 != c2) return (c1 < c2) ? -1 : 1;
133353944Sdim    if (c1 == 0) break;
134353944Sdim    s1++;
135353944Sdim    s2++;
136353944Sdim  }
137353944Sdim  return 0;
138353944Sdim}
139353944Sdim
140353944Sdimchar* internal_strchr(const char *s, int c) {
141353944Sdim  while (true) {
142353944Sdim    if (*s == (char)c)
143353944Sdim      return const_cast<char *>(s);
144353944Sdim    if (*s == 0)
145353944Sdim      return nullptr;
146353944Sdim    s++;
147353944Sdim  }
148353944Sdim}
149353944Sdim
150353944Sdimchar *internal_strchrnul(const char *s, int c) {
151353944Sdim  char *res = internal_strchr(s, c);
152353944Sdim  if (!res)
153353944Sdim    res = const_cast<char *>(s) + internal_strlen(s);
154353944Sdim  return res;
155353944Sdim}
156353944Sdim
157353944Sdimchar *internal_strrchr(const char *s, int c) {
158353944Sdim  const char *res = nullptr;
159353944Sdim  for (uptr i = 0; s[i]; i++) {
160353944Sdim    if (s[i] == c) res = s + i;
161353944Sdim  }
162353944Sdim  return const_cast<char *>(res);
163353944Sdim}
164353944Sdim
165353944Sdimuptr internal_strlen(const char *s) {
166353944Sdim  uptr i = 0;
167353944Sdim  while (s[i]) i++;
168353944Sdim  return i;
169353944Sdim}
170353944Sdim
171353944Sdimuptr internal_strlcat(char *dst, const char *src, uptr maxlen) {
172353944Sdim  const uptr srclen = internal_strlen(src);
173353944Sdim  const uptr dstlen = internal_strnlen(dst, maxlen);
174353944Sdim  if (dstlen == maxlen) return maxlen + srclen;
175353944Sdim  if (srclen < maxlen - dstlen) {
176353944Sdim    internal_memmove(dst + dstlen, src, srclen + 1);
177353944Sdim  } else {
178353944Sdim    internal_memmove(dst + dstlen, src, maxlen - dstlen - 1);
179353944Sdim    dst[maxlen - 1] = '\0';
180353944Sdim  }
181353944Sdim  return dstlen + srclen;
182353944Sdim}
183353944Sdim
184353944Sdimchar *internal_strncat(char *dst, const char *src, uptr n) {
185353944Sdim  uptr len = internal_strlen(dst);
186353944Sdim  uptr i;
187353944Sdim  for (i = 0; i < n && src[i]; i++)
188353944Sdim    dst[len + i] = src[i];
189353944Sdim  dst[len + i] = 0;
190353944Sdim  return dst;
191353944Sdim}
192353944Sdim
193353944Sdimuptr internal_strlcpy(char *dst, const char *src, uptr maxlen) {
194353944Sdim  const uptr srclen = internal_strlen(src);
195353944Sdim  if (srclen < maxlen) {
196353944Sdim    internal_memmove(dst, src, srclen + 1);
197353944Sdim  } else if (maxlen != 0) {
198353944Sdim    internal_memmove(dst, src, maxlen - 1);
199353944Sdim    dst[maxlen - 1] = '\0';
200353944Sdim  }
201353944Sdim  return srclen;
202353944Sdim}
203353944Sdim
204353944Sdimchar *internal_strncpy(char *dst, const char *src, uptr n) {
205353944Sdim  uptr i;
206353944Sdim  for (i = 0; i < n && src[i]; i++)
207353944Sdim    dst[i] = src[i];
208353944Sdim  internal_memset(dst + i, '\0', n - i);
209353944Sdim  return dst;
210353944Sdim}
211353944Sdim
212353944Sdimuptr internal_strnlen(const char *s, uptr maxlen) {
213353944Sdim  uptr i = 0;
214353944Sdim  while (i < maxlen && s[i]) i++;
215353944Sdim  return i;
216353944Sdim}
217353944Sdim
218353944Sdimchar *internal_strstr(const char *haystack, const char *needle) {
219353944Sdim  // This is O(N^2), but we are not using it in hot places.
220353944Sdim  uptr len1 = internal_strlen(haystack);
221353944Sdim  uptr len2 = internal_strlen(needle);
222353944Sdim  if (len1 < len2) return nullptr;
223353944Sdim  for (uptr pos = 0; pos <= len1 - len2; pos++) {
224353944Sdim    if (internal_memcmp(haystack + pos, needle, len2) == 0)
225353944Sdim      return const_cast<char *>(haystack) + pos;
226353944Sdim  }
227353944Sdim  return nullptr;
228353944Sdim}
229353944Sdim
230353944Sdims64 internal_simple_strtoll(const char *nptr, const char **endptr, int base) {
231353944Sdim  CHECK_EQ(base, 10);
232353944Sdim  while (IsSpace(*nptr)) nptr++;
233353944Sdim  int sgn = 1;
234353944Sdim  u64 res = 0;
235353944Sdim  bool have_digits = false;
236353944Sdim  char *old_nptr = const_cast<char *>(nptr);
237353944Sdim  if (*nptr == '+') {
238353944Sdim    sgn = 1;
239353944Sdim    nptr++;
240353944Sdim  } else if (*nptr == '-') {
241353944Sdim    sgn = -1;
242353944Sdim    nptr++;
243353944Sdim  }
244353944Sdim  while (IsDigit(*nptr)) {
245353944Sdim    res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX;
246353944Sdim    int digit = ((*nptr) - '0');
247353944Sdim    res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX;
248353944Sdim    have_digits = true;
249353944Sdim    nptr++;
250353944Sdim  }
251353944Sdim  if (endptr) {
252353944Sdim    *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr;
253353944Sdim  }
254353944Sdim  if (sgn > 0) {
255353944Sdim    return (s64)(Min((u64)INT64_MAX, res));
256353944Sdim  } else {
257353944Sdim    return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1);
258353944Sdim  }
259353944Sdim}
260353944Sdim
261353944Sdimbool mem_is_zero(const char *beg, uptr size) {
262353944Sdim  CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40));  // Sanity check.
263353944Sdim  const char *end = beg + size;
264353944Sdim  uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr));
265353944Sdim  uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr));
266353944Sdim  uptr all = 0;
267353944Sdim  // Prologue.
268353944Sdim  for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++)
269353944Sdim    all |= *mem;
270353944Sdim  // Aligned loop.
271353944Sdim  for (; aligned_beg < aligned_end; aligned_beg++)
272353944Sdim    all |= *aligned_beg;
273353944Sdim  // Epilogue.
274353944Sdim  if ((char *)aligned_end >= beg) {
275353944Sdim    for (const char *mem = (char *)aligned_end; mem < end; mem++) all |= *mem;
276353944Sdim  }
277353944Sdim  return all == 0;
278353944Sdim}
279353944Sdim
280353944Sdim} // namespace __sanitizer
281