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