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 20 namespace __sanitizer { 21 22 s64 internal_atoll(const char *nptr) { 23 return internal_simple_strtoll(nptr, nullptr, 10); 24 } 25 26 void *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 34 void *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 43 int 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 52 extern "C" { 53 SANITIZER_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 63 SANITIZER_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 82 SANITIZER_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 108 void *internal_memcpy(void *dest, const void *src, uptr n) 109 ALIAS(__sanitizer_internal_memcpy); 110 void *internal_memmove(void *dest, const void *src, uptr n) 111 ALIAS(__sanitizer_internal_memmove); 112 void *internal_memset(void *s, int c, uptr n) 113 ALIAS(__sanitizer_internal_memset); 114 115 uptr internal_strcspn(const char *s, const char *reject) { 116 uptr i; 117 for (i = 0; s[i]; i++) { 118 if (internal_strchr(reject, s[i])) 119 return i; 120 } 121 return i; 122 } 123 124 char* internal_strdup(const char *s) { 125 uptr len = internal_strlen(s); 126 char *s2 = (char*)InternalAlloc(len + 1); 127 internal_memcpy(s2, s, len); 128 s2[len] = 0; 129 return s2; 130 } 131 132 int internal_strcmp(const char *s1, const char *s2) { 133 while (true) { 134 unsigned c1 = *s1; 135 unsigned c2 = *s2; 136 if (c1 != c2) return (c1 < c2) ? -1 : 1; 137 if (c1 == 0) break; 138 s1++; 139 s2++; 140 } 141 return 0; 142 } 143 144 int internal_strncmp(const char *s1, const char *s2, uptr n) { 145 for (uptr i = 0; i < n; i++) { 146 unsigned c1 = *s1; 147 unsigned c2 = *s2; 148 if (c1 != c2) return (c1 < c2) ? -1 : 1; 149 if (c1 == 0) break; 150 s1++; 151 s2++; 152 } 153 return 0; 154 } 155 156 char* internal_strchr(const char *s, int c) { 157 while (true) { 158 if (*s == (char)c) 159 return const_cast<char *>(s); 160 if (*s == 0) 161 return nullptr; 162 s++; 163 } 164 } 165 166 char *internal_strchrnul(const char *s, int c) { 167 char *res = internal_strchr(s, c); 168 if (!res) 169 res = const_cast<char *>(s) + internal_strlen(s); 170 return res; 171 } 172 173 char *internal_strrchr(const char *s, int c) { 174 const char *res = nullptr; 175 for (uptr i = 0; s[i]; i++) { 176 if (s[i] == c) res = s + i; 177 } 178 return const_cast<char *>(res); 179 } 180 181 uptr internal_strlen(const char *s) { 182 uptr i = 0; 183 while (s[i]) i++; 184 return i; 185 } 186 187 uptr internal_strlcat(char *dst, const char *src, uptr maxlen) { 188 const uptr srclen = internal_strlen(src); 189 const uptr dstlen = internal_strnlen(dst, maxlen); 190 if (dstlen == maxlen) return maxlen + srclen; 191 if (srclen < maxlen - dstlen) { 192 internal_memmove(dst + dstlen, src, srclen + 1); 193 } else { 194 internal_memmove(dst + dstlen, src, maxlen - dstlen - 1); 195 dst[maxlen - 1] = '\0'; 196 } 197 return dstlen + srclen; 198 } 199 200 char *internal_strncat(char *dst, const char *src, uptr n) { 201 uptr len = internal_strlen(dst); 202 uptr i; 203 for (i = 0; i < n && src[i]; i++) 204 dst[len + i] = src[i]; 205 dst[len + i] = 0; 206 return dst; 207 } 208 209 uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) { 210 const uptr srclen = internal_strlen(src); 211 if (srclen < maxlen) { 212 internal_memmove(dst, src, srclen + 1); 213 } else if (maxlen != 0) { 214 internal_memmove(dst, src, maxlen - 1); 215 dst[maxlen - 1] = '\0'; 216 } 217 return srclen; 218 } 219 220 char *internal_strncpy(char *dst, const char *src, uptr n) { 221 uptr i; 222 for (i = 0; i < n && src[i]; i++) 223 dst[i] = src[i]; 224 internal_memset(dst + i, '\0', n - i); 225 return dst; 226 } 227 228 uptr internal_strnlen(const char *s, uptr maxlen) { 229 uptr i = 0; 230 while (i < maxlen && s[i]) i++; 231 return i; 232 } 233 234 char *internal_strstr(const char *haystack, const char *needle) { 235 // This is O(N^2), but we are not using it in hot places. 236 uptr len1 = internal_strlen(haystack); 237 uptr len2 = internal_strlen(needle); 238 if (len1 < len2) return nullptr; 239 for (uptr pos = 0; pos <= len1 - len2; pos++) { 240 if (internal_memcmp(haystack + pos, needle, len2) == 0) 241 return const_cast<char *>(haystack) + pos; 242 } 243 return nullptr; 244 } 245 246 s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base) { 247 CHECK_EQ(base, 10); 248 while (IsSpace(*nptr)) nptr++; 249 int sgn = 1; 250 u64 res = 0; 251 bool have_digits = false; 252 char *old_nptr = const_cast<char *>(nptr); 253 if (*nptr == '+') { 254 sgn = 1; 255 nptr++; 256 } else if (*nptr == '-') { 257 sgn = -1; 258 nptr++; 259 } 260 while (IsDigit(*nptr)) { 261 res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX; 262 int digit = ((*nptr) - '0'); 263 res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX; 264 have_digits = true; 265 nptr++; 266 } 267 if (endptr) { 268 *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr; 269 } 270 if (sgn > 0) { 271 return (s64)(Min((u64)INT64_MAX, res)); 272 } else { 273 return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1); 274 } 275 } 276 277 uptr internal_wcslen(const wchar_t *s) { 278 uptr i = 0; 279 while (s[i]) i++; 280 return i; 281 } 282 283 uptr internal_wcsnlen(const wchar_t *s, uptr maxlen) { 284 uptr i = 0; 285 while (i < maxlen && s[i]) i++; 286 return i; 287 } 288 289 bool mem_is_zero(const char *beg, uptr size) { 290 CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40)); // Sanity check. 291 const char *end = beg + size; 292 uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr)); 293 uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr)); 294 uptr all = 0; 295 // Prologue. 296 for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++) 297 all |= *mem; 298 // Aligned loop. 299 for (; aligned_beg < aligned_end; aligned_beg++) 300 all |= *aligned_beg; 301 // Epilogue. 302 if ((char *)aligned_end >= beg) { 303 for (const char *mem = (char *)aligned_end; mem < end; mem++) all |= *mem; 304 } 305 return all == 0; 306 } 307 308 } // namespace __sanitizer 309