xref: /llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_libc.cpp (revision d8626c3099cedb72a53f0f085a0bb05a179c8c7d)
165492d95SNico Weber //===-- sanitizer_libc.cpp ------------------------------------------------===//
265492d95SNico Weber //
365492d95SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
465492d95SNico Weber // See https://llvm.org/LICENSE.txt for license information.
565492d95SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
665492d95SNico Weber //
765492d95SNico Weber //===----------------------------------------------------------------------===//
865492d95SNico Weber //
965492d95SNico Weber // This file is shared between AddressSanitizer and ThreadSanitizer
1065492d95SNico Weber // run-time libraries. See sanitizer_libc.h for details.
1165492d95SNico Weber //===----------------------------------------------------------------------===//
1265492d95SNico Weber 
130a71e25eSMarco Elver // Do not redefine builtins; this file is defining the builtin replacements.
140a71e25eSMarco Elver #define SANITIZER_COMMON_NO_REDEFINE_BUILTINS
150a71e25eSMarco Elver 
1665492d95SNico Weber #include "sanitizer_allocator_internal.h"
1765492d95SNico Weber #include "sanitizer_common.h"
1865492d95SNico Weber #include "sanitizer_libc.h"
1965492d95SNico Weber 
2065492d95SNico Weber namespace __sanitizer {
2165492d95SNico Weber 
internal_atoll(const char * nptr)2265492d95SNico Weber s64 internal_atoll(const char *nptr) {
2365492d95SNico Weber   return internal_simple_strtoll(nptr, nullptr, 10);
2465492d95SNico Weber }
2565492d95SNico Weber 
internal_memchr(const void * s,int c,uptr n)2665492d95SNico Weber void *internal_memchr(const void *s, int c, uptr n) {
2765492d95SNico Weber   const char *t = (const char *)s;
2865492d95SNico Weber   for (uptr i = 0; i < n; ++i, ++t)
2965492d95SNico Weber     if (*t == c)
3065492d95SNico Weber       return reinterpret_cast<void *>(const_cast<char *>(t));
3165492d95SNico Weber   return nullptr;
3265492d95SNico Weber }
3365492d95SNico Weber 
internal_memrchr(const void * s,int c,uptr n)3465492d95SNico Weber void *internal_memrchr(const void *s, int c, uptr n) {
3565492d95SNico Weber   const char *t = (const char *)s;
3665492d95SNico Weber   void *res = nullptr;
3765492d95SNico Weber   for (uptr i = 0; i < n; ++i, ++t) {
3865492d95SNico Weber     if (*t == c) res = reinterpret_cast<void *>(const_cast<char *>(t));
3965492d95SNico Weber   }
4065492d95SNico Weber   return res;
4165492d95SNico Weber }
4265492d95SNico Weber 
internal_memcmp(const void * s1,const void * s2,uptr n)4365492d95SNico Weber int internal_memcmp(const void* s1, const void* s2, uptr n) {
4465492d95SNico Weber   const char *t1 = (const char *)s1;
4565492d95SNico Weber   const char *t2 = (const char *)s2;
4665492d95SNico Weber   for (uptr i = 0; i < n; ++i, ++t1, ++t2)
4765492d95SNico Weber     if (*t1 != *t2)
4865492d95SNico Weber       return *t1 < *t2 ? -1 : 1;
4965492d95SNico Weber   return 0;
5065492d95SNico Weber }
5165492d95SNico Weber 
520a71e25eSMarco Elver extern "C" {
__sanitizer_internal_memcpy(void * dest,const void * src,uptr n)530a71e25eSMarco Elver SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memcpy(void *dest,
540a71e25eSMarco Elver                                                                 const void *src,
550a71e25eSMarco Elver                                                                 uptr n) {
5665492d95SNico Weber   char *d = (char*)dest;
5765492d95SNico Weber   const char *s = (const char *)src;
5865492d95SNico Weber   for (uptr i = 0; i < n; ++i)
5965492d95SNico Weber     d[i] = s[i];
6065492d95SNico Weber   return dest;
6165492d95SNico Weber }
6265492d95SNico Weber 
__sanitizer_internal_memmove(void * dest,const void * src,uptr n)630a71e25eSMarco Elver SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memmove(
640a71e25eSMarco Elver     void *dest, const void *src, uptr n) {
6565492d95SNico Weber   char *d = (char*)dest;
6665492d95SNico Weber   const char *s = (const char *)src;
6765492d95SNico Weber   sptr i, signed_n = (sptr)n;
6865492d95SNico Weber   CHECK_GE(signed_n, 0);
6965492d95SNico Weber   if (d < s) {
7065492d95SNico Weber     for (i = 0; i < signed_n; ++i)
7165492d95SNico Weber       d[i] = s[i];
7265492d95SNico Weber   } else {
73d2af368aSVitaly Buka     if (d > s && signed_n > 0) {
7465492d95SNico Weber       for (i = signed_n - 1; i >= 0; --i) {
7565492d95SNico Weber         d[i] = s[i];
7665492d95SNico Weber       }
7765492d95SNico Weber     }
78d2af368aSVitaly Buka   }
7965492d95SNico Weber   return dest;
8065492d95SNico Weber }
8165492d95SNico Weber 
__sanitizer_internal_memset(void * s,int c,uptr n)820a71e25eSMarco Elver SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memset(void *s, int c,
830a71e25eSMarco Elver                                                                 uptr n) {
8465492d95SNico Weber   // Optimize for the most performance-critical case:
8565492d95SNico Weber   if ((reinterpret_cast<uptr>(s) % 16) == 0 && (n % 16) == 0) {
8665492d95SNico Weber     u64 *p = reinterpret_cast<u64*>(s);
8765492d95SNico Weber     u64 *e = p + n / 8;
8865492d95SNico Weber     u64 v = c;
8965492d95SNico Weber     v |= v << 8;
9065492d95SNico Weber     v |= v << 16;
9165492d95SNico Weber     v |= v << 32;
9265492d95SNico Weber     for (; p < e; p += 2)
9365492d95SNico Weber       p[0] = p[1] = v;
9465492d95SNico Weber     return s;
9565492d95SNico Weber   }
9665492d95SNico Weber   // The next line prevents Clang from making a call to memset() instead of the
9765492d95SNico Weber   // loop below.
9865492d95SNico Weber   // FIXME: building the runtime with -ffreestanding is a better idea. However
9965492d95SNico Weber   // there currently are linktime problems due to PR12396.
10065492d95SNico Weber   char volatile *t = (char*)s;
10165492d95SNico Weber   for (uptr i = 0; i < n; ++i, ++t) {
10265492d95SNico Weber     *t = c;
10365492d95SNico Weber   }
10465492d95SNico Weber   return s;
10565492d95SNico Weber }
1060a71e25eSMarco Elver }  // extern "C"
10765492d95SNico Weber 
internal_strcspn(const char * s,const char * reject)10865492d95SNico Weber uptr internal_strcspn(const char *s, const char *reject) {
10965492d95SNico Weber   uptr i;
11065492d95SNico Weber   for (i = 0; s[i]; i++) {
11165492d95SNico Weber     if (internal_strchr(reject, s[i]))
11265492d95SNico Weber       return i;
11365492d95SNico Weber   }
11465492d95SNico Weber   return i;
11565492d95SNico Weber }
11665492d95SNico Weber 
internal_strdup(const char * s)11765492d95SNico Weber char* internal_strdup(const char *s) {
11865492d95SNico Weber   uptr len = internal_strlen(s);
11965492d95SNico Weber   char *s2 = (char*)InternalAlloc(len + 1);
12065492d95SNico Weber   internal_memcpy(s2, s, len);
12165492d95SNico Weber   s2[len] = 0;
12265492d95SNico Weber   return s2;
12365492d95SNico Weber }
12465492d95SNico Weber 
internal_strcmp(const char * s1,const char * s2)12565492d95SNico Weber int internal_strcmp(const char *s1, const char *s2) {
12665492d95SNico Weber   while (true) {
12765492d95SNico Weber     unsigned c1 = *s1;
12865492d95SNico Weber     unsigned c2 = *s2;
12965492d95SNico Weber     if (c1 != c2) return (c1 < c2) ? -1 : 1;
13065492d95SNico Weber     if (c1 == 0) break;
13165492d95SNico Weber     s1++;
13265492d95SNico Weber     s2++;
13365492d95SNico Weber   }
13465492d95SNico Weber   return 0;
13565492d95SNico Weber }
13665492d95SNico Weber 
internal_strncmp(const char * s1,const char * s2,uptr n)13765492d95SNico Weber int internal_strncmp(const char *s1, const char *s2, uptr n) {
13865492d95SNico Weber   for (uptr i = 0; i < n; i++) {
13965492d95SNico Weber     unsigned c1 = *s1;
14065492d95SNico Weber     unsigned c2 = *s2;
14165492d95SNico Weber     if (c1 != c2) return (c1 < c2) ? -1 : 1;
14265492d95SNico Weber     if (c1 == 0) break;
14365492d95SNico Weber     s1++;
14465492d95SNico Weber     s2++;
14565492d95SNico Weber   }
14665492d95SNico Weber   return 0;
14765492d95SNico Weber }
14865492d95SNico Weber 
internal_strchr(const char * s,int c)14965492d95SNico Weber char* internal_strchr(const char *s, int c) {
15065492d95SNico Weber   while (true) {
15165492d95SNico Weber     if (*s == (char)c)
15265492d95SNico Weber       return const_cast<char *>(s);
15365492d95SNico Weber     if (*s == 0)
15465492d95SNico Weber       return nullptr;
15565492d95SNico Weber     s++;
15665492d95SNico Weber   }
15765492d95SNico Weber }
15865492d95SNico Weber 
internal_strchrnul(const char * s,int c)15965492d95SNico Weber char *internal_strchrnul(const char *s, int c) {
16065492d95SNico Weber   char *res = internal_strchr(s, c);
16165492d95SNico Weber   if (!res)
16265492d95SNico Weber     res = const_cast<char *>(s) + internal_strlen(s);
16365492d95SNico Weber   return res;
16465492d95SNico Weber }
16565492d95SNico Weber 
internal_strrchr(const char * s,int c)16665492d95SNico Weber char *internal_strrchr(const char *s, int c) {
16765492d95SNico Weber   const char *res = nullptr;
16865492d95SNico Weber   for (uptr i = 0; s[i]; i++) {
16965492d95SNico Weber     if (s[i] == c) res = s + i;
17065492d95SNico Weber   }
17165492d95SNico Weber   return const_cast<char *>(res);
17265492d95SNico Weber }
17365492d95SNico Weber 
internal_strlen(const char * s)17465492d95SNico Weber uptr internal_strlen(const char *s) {
17565492d95SNico Weber   uptr i = 0;
17665492d95SNico Weber   while (s[i]) i++;
17765492d95SNico Weber   return i;
17865492d95SNico Weber }
17965492d95SNico Weber 
internal_strlcat(char * dst,const char * src,uptr maxlen)18065492d95SNico Weber uptr internal_strlcat(char *dst, const char *src, uptr maxlen) {
18165492d95SNico Weber   const uptr srclen = internal_strlen(src);
18265492d95SNico Weber   const uptr dstlen = internal_strnlen(dst, maxlen);
18365492d95SNico Weber   if (dstlen == maxlen) return maxlen + srclen;
18465492d95SNico Weber   if (srclen < maxlen - dstlen) {
18565492d95SNico Weber     internal_memmove(dst + dstlen, src, srclen + 1);
18665492d95SNico Weber   } else {
18765492d95SNico Weber     internal_memmove(dst + dstlen, src, maxlen - dstlen - 1);
18865492d95SNico Weber     dst[maxlen - 1] = '\0';
18965492d95SNico Weber   }
19065492d95SNico Weber   return dstlen + srclen;
19165492d95SNico Weber }
19265492d95SNico Weber 
internal_strncat(char * dst,const char * src,uptr n)19365492d95SNico Weber char *internal_strncat(char *dst, const char *src, uptr n) {
19465492d95SNico Weber   uptr len = internal_strlen(dst);
19565492d95SNico Weber   uptr i;
19665492d95SNico Weber   for (i = 0; i < n && src[i]; i++)
19765492d95SNico Weber     dst[len + i] = src[i];
19865492d95SNico Weber   dst[len + i] = 0;
19965492d95SNico Weber   return dst;
20065492d95SNico Weber }
20165492d95SNico Weber 
internal_wcscpy(wchar_t * dst,const wchar_t * src)202*d8626c30Snicole mazzuca wchar_t *internal_wcscpy(wchar_t *dst, const wchar_t *src) {
203*d8626c30Snicole mazzuca   wchar_t *dst_it = dst;
204*d8626c30Snicole mazzuca   do {
205*d8626c30Snicole mazzuca     *dst_it++ = *src++;
206*d8626c30Snicole mazzuca   } while (*src);
207*d8626c30Snicole mazzuca   return dst;
208*d8626c30Snicole mazzuca }
209*d8626c30Snicole mazzuca 
internal_strlcpy(char * dst,const char * src,uptr maxlen)21065492d95SNico Weber uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) {
21165492d95SNico Weber   const uptr srclen = internal_strlen(src);
21265492d95SNico Weber   if (srclen < maxlen) {
21365492d95SNico Weber     internal_memmove(dst, src, srclen + 1);
21465492d95SNico Weber   } else if (maxlen != 0) {
21565492d95SNico Weber     internal_memmove(dst, src, maxlen - 1);
21665492d95SNico Weber     dst[maxlen - 1] = '\0';
21765492d95SNico Weber   }
21865492d95SNico Weber   return srclen;
21965492d95SNico Weber }
22065492d95SNico Weber 
internal_strncpy(char * dst,const char * src,uptr n)22165492d95SNico Weber char *internal_strncpy(char *dst, const char *src, uptr n) {
22265492d95SNico Weber   uptr i;
22365492d95SNico Weber   for (i = 0; i < n && src[i]; i++)
22465492d95SNico Weber     dst[i] = src[i];
22565492d95SNico Weber   internal_memset(dst + i, '\0', n - i);
22665492d95SNico Weber   return dst;
22765492d95SNico Weber }
22865492d95SNico Weber 
internal_wcsncpy(wchar_t * dst,const wchar_t * src,uptr n)229*d8626c30Snicole mazzuca wchar_t *internal_wcsncpy(wchar_t *dst, const wchar_t *src, uptr n) {
230*d8626c30Snicole mazzuca   uptr i;
231*d8626c30Snicole mazzuca   for (i = 0; i < n && src[i]; ++i)
232*d8626c30Snicole mazzuca     dst[i] = src[i];
233*d8626c30Snicole mazzuca   internal_memset(dst + i, 0, (n - i) * sizeof(wchar_t));
234*d8626c30Snicole mazzuca   return dst;
235*d8626c30Snicole mazzuca }
236*d8626c30Snicole mazzuca 
internal_strnlen(const char * s,uptr maxlen)23765492d95SNico Weber uptr internal_strnlen(const char *s, uptr maxlen) {
23865492d95SNico Weber   uptr i = 0;
23965492d95SNico Weber   while (i < maxlen && s[i]) i++;
24065492d95SNico Weber   return i;
24165492d95SNico Weber }
24265492d95SNico Weber 
internal_strstr(const char * haystack,const char * needle)24365492d95SNico Weber char *internal_strstr(const char *haystack, const char *needle) {
24465492d95SNico Weber   // This is O(N^2), but we are not using it in hot places.
245685c94c6SBharadwaj, Ritanya B   uptr len1 = internal_strlen(haystack);
2466396a443SVitaly Buka   uptr len2 = internal_strlen(needle);
24765492d95SNico Weber   if (len1 < len2) return nullptr;
24865492d95SNico Weber   for (uptr pos = 0; pos <= len1 - len2; pos++) {
24965492d95SNico Weber     if (internal_memcmp(haystack + pos, needle, len2) == 0)
25065492d95SNico Weber       return const_cast<char *>(haystack) + pos;
25165492d95SNico Weber   }
25265492d95SNico Weber   return nullptr;
25365492d95SNico Weber }
25465492d95SNico Weber 
internal_simple_strtoll(const char * nptr,const char ** endptr,int base)25565492d95SNico Weber s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base) {
25665492d95SNico Weber   CHECK_EQ(base, 10);
25765492d95SNico Weber   while (IsSpace(*nptr)) nptr++;
25865492d95SNico Weber   int sgn = 1;
25965492d95SNico Weber   u64 res = 0;
26065492d95SNico Weber   bool have_digits = false;
26165492d95SNico Weber   char *old_nptr = const_cast<char *>(nptr);
26265492d95SNico Weber   if (*nptr == '+') {
26365492d95SNico Weber     sgn = 1;
26465492d95SNico Weber     nptr++;
26565492d95SNico Weber   } else if (*nptr == '-') {
26665492d95SNico Weber     sgn = -1;
26765492d95SNico Weber     nptr++;
26865492d95SNico Weber   }
26965492d95SNico Weber   while (IsDigit(*nptr)) {
27065492d95SNico Weber     res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX;
27165492d95SNico Weber     int digit = ((*nptr) - '0');
27265492d95SNico Weber     res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX;
27365492d95SNico Weber     have_digits = true;
27465492d95SNico Weber     nptr++;
27565492d95SNico Weber   }
27665492d95SNico Weber   if (endptr) {
27765492d95SNico Weber     *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr;
27865492d95SNico Weber   }
27965492d95SNico Weber   if (sgn > 0) {
28065492d95SNico Weber     return (s64)(Min((u64)INT64_MAX, res));
28165492d95SNico Weber   } else {
28265492d95SNico Weber     return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1);
28365492d95SNico Weber   }
28465492d95SNico Weber }
28565492d95SNico Weber 
internal_wcslen(const wchar_t * s)28640067b88SMichael Jones uptr internal_wcslen(const wchar_t *s) {
28740067b88SMichael Jones   uptr i = 0;
28840067b88SMichael Jones   while (s[i]) i++;
28940067b88SMichael Jones   return i;
29040067b88SMichael Jones }
29140067b88SMichael Jones 
internal_wcsnlen(const wchar_t * s,uptr maxlen)29240067b88SMichael Jones uptr internal_wcsnlen(const wchar_t *s, uptr maxlen) {
29340067b88SMichael Jones   uptr i = 0;
29440067b88SMichael Jones   while (i < maxlen && s[i]) i++;
29540067b88SMichael Jones   return i;
29640067b88SMichael Jones }
29740067b88SMichael Jones 
mem_is_zero(const char * beg,uptr size)29865492d95SNico Weber bool mem_is_zero(const char *beg, uptr size) {
29965492d95SNico Weber   CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40));  // Sanity check.
30065492d95SNico Weber   const char *end = beg + size;
30165492d95SNico Weber   uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr));
30265492d95SNico Weber   uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr));
30365492d95SNico Weber   uptr all = 0;
30465492d95SNico Weber   // Prologue.
30565492d95SNico Weber   for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++)
30665492d95SNico Weber     all |= *mem;
30765492d95SNico Weber   // Aligned loop.
30865492d95SNico Weber   for (; aligned_beg < aligned_end; aligned_beg++)
30965492d95SNico Weber     all |= *aligned_beg;
31065492d95SNico Weber   // Epilogue.
311d2af368aSVitaly Buka   if ((char *)aligned_end >= beg) {
312d2af368aSVitaly Buka     for (const char *mem = (char *)aligned_end; mem < end; mem++) all |= *mem;
313d2af368aSVitaly Buka   }
31465492d95SNico Weber   return all == 0;
31565492d95SNico Weber }
31665492d95SNico Weber 
31765492d95SNico Weber } // namespace __sanitizer
318