168d75effSDimitry Andric //===-- sanitizer_libc.cpp ------------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer 1068d75effSDimitry Andric // run-time libraries. See sanitizer_libc.h for details. 1168d75effSDimitry Andric //===----------------------------------------------------------------------===// 1268d75effSDimitry Andric 1306c3fb27SDimitry Andric // Do not redefine builtins; this file is defining the builtin replacements. 1406c3fb27SDimitry Andric #define SANITIZER_COMMON_NO_REDEFINE_BUILTINS 1506c3fb27SDimitry Andric 1668d75effSDimitry Andric #include "sanitizer_allocator_internal.h" 1768d75effSDimitry Andric #include "sanitizer_common.h" 1868d75effSDimitry Andric #include "sanitizer_libc.h" 1968d75effSDimitry Andric 2068d75effSDimitry Andric namespace __sanitizer { 2168d75effSDimitry Andric 2268d75effSDimitry Andric s64 internal_atoll(const char *nptr) { 2368d75effSDimitry Andric return internal_simple_strtoll(nptr, nullptr, 10); 2468d75effSDimitry Andric } 2568d75effSDimitry Andric 2668d75effSDimitry Andric void *internal_memchr(const void *s, int c, uptr n) { 2768d75effSDimitry Andric const char *t = (const char *)s; 2868d75effSDimitry Andric for (uptr i = 0; i < n; ++i, ++t) 2968d75effSDimitry Andric if (*t == c) 3068d75effSDimitry Andric return reinterpret_cast<void *>(const_cast<char *>(t)); 3168d75effSDimitry Andric return nullptr; 3268d75effSDimitry Andric } 3368d75effSDimitry Andric 3468d75effSDimitry Andric void *internal_memrchr(const void *s, int c, uptr n) { 3568d75effSDimitry Andric const char *t = (const char *)s; 3668d75effSDimitry Andric void *res = nullptr; 3768d75effSDimitry Andric for (uptr i = 0; i < n; ++i, ++t) { 3868d75effSDimitry Andric if (*t == c) res = reinterpret_cast<void *>(const_cast<char *>(t)); 3968d75effSDimitry Andric } 4068d75effSDimitry Andric return res; 4168d75effSDimitry Andric } 4268d75effSDimitry Andric 4368d75effSDimitry Andric int internal_memcmp(const void* s1, const void* s2, uptr n) { 4468d75effSDimitry Andric const char *t1 = (const char *)s1; 4568d75effSDimitry Andric const char *t2 = (const char *)s2; 4668d75effSDimitry Andric for (uptr i = 0; i < n; ++i, ++t1, ++t2) 4768d75effSDimitry Andric if (*t1 != *t2) 4868d75effSDimitry Andric return *t1 < *t2 ? -1 : 1; 4968d75effSDimitry Andric return 0; 5068d75effSDimitry Andric } 5168d75effSDimitry Andric 5206c3fb27SDimitry Andric extern "C" { 5306c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memcpy(void *dest, 5406c3fb27SDimitry Andric const void *src, 5506c3fb27SDimitry Andric uptr n) { 5668d75effSDimitry Andric char *d = (char*)dest; 5768d75effSDimitry Andric const char *s = (const char *)src; 5868d75effSDimitry Andric for (uptr i = 0; i < n; ++i) 5968d75effSDimitry Andric d[i] = s[i]; 6068d75effSDimitry Andric return dest; 6168d75effSDimitry Andric } 6268d75effSDimitry Andric 6306c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memmove( 6406c3fb27SDimitry Andric void *dest, const void *src, uptr n) { 6568d75effSDimitry Andric char *d = (char*)dest; 6668d75effSDimitry Andric const char *s = (const char *)src; 6768d75effSDimitry Andric sptr i, signed_n = (sptr)n; 6868d75effSDimitry Andric CHECK_GE(signed_n, 0); 6968d75effSDimitry Andric if (d < s) { 7068d75effSDimitry Andric for (i = 0; i < signed_n; ++i) 7168d75effSDimitry Andric d[i] = s[i]; 7268d75effSDimitry Andric } else { 7368d75effSDimitry Andric if (d > s && signed_n > 0) { 7468d75effSDimitry Andric for (i = signed_n - 1; i >= 0; --i) { 7568d75effSDimitry Andric d[i] = s[i]; 7668d75effSDimitry Andric } 7768d75effSDimitry Andric } 7868d75effSDimitry Andric } 7968d75effSDimitry Andric return dest; 8068d75effSDimitry Andric } 8168d75effSDimitry Andric 8206c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memset(void *s, int c, 8306c3fb27SDimitry Andric uptr n) { 8468d75effSDimitry Andric // Optimize for the most performance-critical case: 8568d75effSDimitry Andric if ((reinterpret_cast<uptr>(s) % 16) == 0 && (n % 16) == 0) { 8668d75effSDimitry Andric u64 *p = reinterpret_cast<u64*>(s); 8768d75effSDimitry Andric u64 *e = p + n / 8; 8868d75effSDimitry Andric u64 v = c; 8968d75effSDimitry Andric v |= v << 8; 9068d75effSDimitry Andric v |= v << 16; 9168d75effSDimitry Andric v |= v << 32; 9268d75effSDimitry Andric for (; p < e; p += 2) 9368d75effSDimitry Andric p[0] = p[1] = v; 9468d75effSDimitry Andric return s; 9568d75effSDimitry Andric } 9668d75effSDimitry Andric // The next line prevents Clang from making a call to memset() instead of the 9768d75effSDimitry Andric // loop below. 9868d75effSDimitry Andric // FIXME: building the runtime with -ffreestanding is a better idea. However 9968d75effSDimitry Andric // there currently are linktime problems due to PR12396. 10068d75effSDimitry Andric char volatile *t = (char*)s; 10168d75effSDimitry Andric for (uptr i = 0; i < n; ++i, ++t) { 10268d75effSDimitry Andric *t = c; 10368d75effSDimitry Andric } 10468d75effSDimitry Andric return s; 10568d75effSDimitry Andric } 10606c3fb27SDimitry Andric } // extern "C" 10768d75effSDimitry Andric 10868d75effSDimitry Andric uptr internal_strcspn(const char *s, const char *reject) { 10968d75effSDimitry Andric uptr i; 11068d75effSDimitry Andric for (i = 0; s[i]; i++) { 11168d75effSDimitry Andric if (internal_strchr(reject, s[i])) 11268d75effSDimitry Andric return i; 11368d75effSDimitry Andric } 11468d75effSDimitry Andric return i; 11568d75effSDimitry Andric } 11668d75effSDimitry Andric 11768d75effSDimitry Andric char* internal_strdup(const char *s) { 11868d75effSDimitry Andric uptr len = internal_strlen(s); 11968d75effSDimitry Andric char *s2 = (char*)InternalAlloc(len + 1); 12068d75effSDimitry Andric internal_memcpy(s2, s, len); 12168d75effSDimitry Andric s2[len] = 0; 12268d75effSDimitry Andric return s2; 12368d75effSDimitry Andric } 12468d75effSDimitry Andric 12568d75effSDimitry Andric int internal_strcmp(const char *s1, const char *s2) { 12668d75effSDimitry Andric while (true) { 12768d75effSDimitry Andric unsigned c1 = *s1; 12868d75effSDimitry Andric unsigned c2 = *s2; 12968d75effSDimitry Andric if (c1 != c2) return (c1 < c2) ? -1 : 1; 13068d75effSDimitry Andric if (c1 == 0) break; 13168d75effSDimitry Andric s1++; 13268d75effSDimitry Andric s2++; 13368d75effSDimitry Andric } 13468d75effSDimitry Andric return 0; 13568d75effSDimitry Andric } 13668d75effSDimitry Andric 13768d75effSDimitry Andric int internal_strncmp(const char *s1, const char *s2, uptr n) { 13868d75effSDimitry Andric for (uptr i = 0; i < n; i++) { 13968d75effSDimitry Andric unsigned c1 = *s1; 14068d75effSDimitry Andric unsigned c2 = *s2; 14168d75effSDimitry Andric if (c1 != c2) return (c1 < c2) ? -1 : 1; 14268d75effSDimitry Andric if (c1 == 0) break; 14368d75effSDimitry Andric s1++; 14468d75effSDimitry Andric s2++; 14568d75effSDimitry Andric } 14668d75effSDimitry Andric return 0; 14768d75effSDimitry Andric } 14868d75effSDimitry Andric 14968d75effSDimitry Andric char* internal_strchr(const char *s, int c) { 15068d75effSDimitry Andric while (true) { 15168d75effSDimitry Andric if (*s == (char)c) 15268d75effSDimitry Andric return const_cast<char *>(s); 15368d75effSDimitry Andric if (*s == 0) 15468d75effSDimitry Andric return nullptr; 15568d75effSDimitry Andric s++; 15668d75effSDimitry Andric } 15768d75effSDimitry Andric } 15868d75effSDimitry Andric 15968d75effSDimitry Andric char *internal_strchrnul(const char *s, int c) { 16068d75effSDimitry Andric char *res = internal_strchr(s, c); 16168d75effSDimitry Andric if (!res) 16268d75effSDimitry Andric res = const_cast<char *>(s) + internal_strlen(s); 16368d75effSDimitry Andric return res; 16468d75effSDimitry Andric } 16568d75effSDimitry Andric 16668d75effSDimitry Andric char *internal_strrchr(const char *s, int c) { 16768d75effSDimitry Andric const char *res = nullptr; 16868d75effSDimitry Andric for (uptr i = 0; s[i]; i++) { 16968d75effSDimitry Andric if (s[i] == c) res = s + i; 17068d75effSDimitry Andric } 17168d75effSDimitry Andric return const_cast<char *>(res); 17268d75effSDimitry Andric } 17368d75effSDimitry Andric 17468d75effSDimitry Andric uptr internal_strlen(const char *s) { 17568d75effSDimitry Andric uptr i = 0; 17668d75effSDimitry Andric while (s[i]) i++; 17768d75effSDimitry Andric return i; 17868d75effSDimitry Andric } 17968d75effSDimitry Andric 18068d75effSDimitry Andric uptr internal_strlcat(char *dst, const char *src, uptr maxlen) { 18168d75effSDimitry Andric const uptr srclen = internal_strlen(src); 18268d75effSDimitry Andric const uptr dstlen = internal_strnlen(dst, maxlen); 18368d75effSDimitry Andric if (dstlen == maxlen) return maxlen + srclen; 18468d75effSDimitry Andric if (srclen < maxlen - dstlen) { 18568d75effSDimitry Andric internal_memmove(dst + dstlen, src, srclen + 1); 18668d75effSDimitry Andric } else { 18768d75effSDimitry Andric internal_memmove(dst + dstlen, src, maxlen - dstlen - 1); 18868d75effSDimitry Andric dst[maxlen - 1] = '\0'; 18968d75effSDimitry Andric } 19068d75effSDimitry Andric return dstlen + srclen; 19168d75effSDimitry Andric } 19268d75effSDimitry Andric 19368d75effSDimitry Andric char *internal_strncat(char *dst, const char *src, uptr n) { 19468d75effSDimitry Andric uptr len = internal_strlen(dst); 19568d75effSDimitry Andric uptr i; 19668d75effSDimitry Andric for (i = 0; i < n && src[i]; i++) 19768d75effSDimitry Andric dst[len + i] = src[i]; 19868d75effSDimitry Andric dst[len + i] = 0; 19968d75effSDimitry Andric return dst; 20068d75effSDimitry Andric } 20168d75effSDimitry Andric 202*5f757f3fSDimitry Andric wchar_t *internal_wcscpy(wchar_t *dst, const wchar_t *src) { 203*5f757f3fSDimitry Andric wchar_t *dst_it = dst; 204*5f757f3fSDimitry Andric do { 205*5f757f3fSDimitry Andric *dst_it++ = *src++; 206*5f757f3fSDimitry Andric } while (*src); 207*5f757f3fSDimitry Andric return dst; 208*5f757f3fSDimitry Andric } 209*5f757f3fSDimitry Andric 21068d75effSDimitry Andric uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) { 21168d75effSDimitry Andric const uptr srclen = internal_strlen(src); 21268d75effSDimitry Andric if (srclen < maxlen) { 21368d75effSDimitry Andric internal_memmove(dst, src, srclen + 1); 21468d75effSDimitry Andric } else if (maxlen != 0) { 21568d75effSDimitry Andric internal_memmove(dst, src, maxlen - 1); 21668d75effSDimitry Andric dst[maxlen - 1] = '\0'; 21768d75effSDimitry Andric } 21868d75effSDimitry Andric return srclen; 21968d75effSDimitry Andric } 22068d75effSDimitry Andric 22168d75effSDimitry Andric char *internal_strncpy(char *dst, const char *src, uptr n) { 22268d75effSDimitry Andric uptr i; 22368d75effSDimitry Andric for (i = 0; i < n && src[i]; i++) 22468d75effSDimitry Andric dst[i] = src[i]; 22568d75effSDimitry Andric internal_memset(dst + i, '\0', n - i); 22668d75effSDimitry Andric return dst; 22768d75effSDimitry Andric } 22868d75effSDimitry Andric 229*5f757f3fSDimitry Andric wchar_t *internal_wcsncpy(wchar_t *dst, const wchar_t *src, uptr n) { 230*5f757f3fSDimitry Andric uptr i; 231*5f757f3fSDimitry Andric for (i = 0; i < n && src[i]; ++i) 232*5f757f3fSDimitry Andric dst[i] = src[i]; 233*5f757f3fSDimitry Andric internal_memset(dst + i, 0, (n - i) * sizeof(wchar_t)); 234*5f757f3fSDimitry Andric return dst; 235*5f757f3fSDimitry Andric } 236*5f757f3fSDimitry Andric 23768d75effSDimitry Andric uptr internal_strnlen(const char *s, uptr maxlen) { 23868d75effSDimitry Andric uptr i = 0; 23968d75effSDimitry Andric while (i < maxlen && s[i]) i++; 24068d75effSDimitry Andric return i; 24168d75effSDimitry Andric } 24268d75effSDimitry Andric 24368d75effSDimitry Andric char *internal_strstr(const char *haystack, const char *needle) { 24468d75effSDimitry Andric // This is O(N^2), but we are not using it in hot places. 24568d75effSDimitry Andric uptr len1 = internal_strlen(haystack); 24668d75effSDimitry Andric uptr len2 = internal_strlen(needle); 24768d75effSDimitry Andric if (len1 < len2) return nullptr; 24868d75effSDimitry Andric for (uptr pos = 0; pos <= len1 - len2; pos++) { 24968d75effSDimitry Andric if (internal_memcmp(haystack + pos, needle, len2) == 0) 25068d75effSDimitry Andric return const_cast<char *>(haystack) + pos; 25168d75effSDimitry Andric } 25268d75effSDimitry Andric return nullptr; 25368d75effSDimitry Andric } 25468d75effSDimitry Andric 25568d75effSDimitry Andric s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base) { 25668d75effSDimitry Andric CHECK_EQ(base, 10); 25768d75effSDimitry Andric while (IsSpace(*nptr)) nptr++; 25868d75effSDimitry Andric int sgn = 1; 25968d75effSDimitry Andric u64 res = 0; 26068d75effSDimitry Andric bool have_digits = false; 26168d75effSDimitry Andric char *old_nptr = const_cast<char *>(nptr); 26268d75effSDimitry Andric if (*nptr == '+') { 26368d75effSDimitry Andric sgn = 1; 26468d75effSDimitry Andric nptr++; 26568d75effSDimitry Andric } else if (*nptr == '-') { 26668d75effSDimitry Andric sgn = -1; 26768d75effSDimitry Andric nptr++; 26868d75effSDimitry Andric } 26968d75effSDimitry Andric while (IsDigit(*nptr)) { 27068d75effSDimitry Andric res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX; 27168d75effSDimitry Andric int digit = ((*nptr) - '0'); 27268d75effSDimitry Andric res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX; 27368d75effSDimitry Andric have_digits = true; 27468d75effSDimitry Andric nptr++; 27568d75effSDimitry Andric } 27668d75effSDimitry Andric if (endptr) { 27768d75effSDimitry Andric *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr; 27868d75effSDimitry Andric } 27968d75effSDimitry Andric if (sgn > 0) { 28068d75effSDimitry Andric return (s64)(Min((u64)INT64_MAX, res)); 28168d75effSDimitry Andric } else { 28268d75effSDimitry Andric return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1); 28368d75effSDimitry Andric } 28468d75effSDimitry Andric } 28568d75effSDimitry Andric 286349cc55cSDimitry Andric uptr internal_wcslen(const wchar_t *s) { 287349cc55cSDimitry Andric uptr i = 0; 288349cc55cSDimitry Andric while (s[i]) i++; 289349cc55cSDimitry Andric return i; 290349cc55cSDimitry Andric } 291349cc55cSDimitry Andric 292349cc55cSDimitry Andric uptr internal_wcsnlen(const wchar_t *s, uptr maxlen) { 293349cc55cSDimitry Andric uptr i = 0; 294349cc55cSDimitry Andric while (i < maxlen && s[i]) i++; 295349cc55cSDimitry Andric return i; 296349cc55cSDimitry Andric } 297349cc55cSDimitry Andric 29868d75effSDimitry Andric bool mem_is_zero(const char *beg, uptr size) { 29968d75effSDimitry Andric CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40)); // Sanity check. 30068d75effSDimitry Andric const char *end = beg + size; 30168d75effSDimitry Andric uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr)); 30268d75effSDimitry Andric uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr)); 30368d75effSDimitry Andric uptr all = 0; 30468d75effSDimitry Andric // Prologue. 30568d75effSDimitry Andric for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++) 30668d75effSDimitry Andric all |= *mem; 30768d75effSDimitry Andric // Aligned loop. 30868d75effSDimitry Andric for (; aligned_beg < aligned_end; aligned_beg++) 30968d75effSDimitry Andric all |= *aligned_beg; 31068d75effSDimitry Andric // Epilogue. 31168d75effSDimitry Andric if ((char *)aligned_end >= beg) { 31268d75effSDimitry Andric for (const char *mem = (char *)aligned_end; mem < end; mem++) all |= *mem; 31368d75effSDimitry Andric } 31468d75effSDimitry Andric return all == 0; 31568d75effSDimitry Andric } 31668d75effSDimitry Andric 31768d75effSDimitry Andric } // namespace __sanitizer 318