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