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, endptr: nullptr, base: 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(s: reject, c: 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(size: len + 1); |
120 | internal_memcpy(dest: s2, src: s, n: 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(s: src); |
182 | const uptr dstlen = internal_strnlen(s: dst, maxlen); |
183 | if (dstlen == maxlen) return maxlen + srclen; |
184 | if (srclen < maxlen - dstlen) { |
185 | internal_memmove(dest: dst + dstlen, src, n: srclen + 1); |
186 | } else { |
187 | internal_memmove(dest: dst + dstlen, src, n: 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(s: 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(s: src); |
212 | if (srclen < maxlen) { |
213 | internal_memmove(dest: dst, src, n: srclen + 1); |
214 | } else if (maxlen != 0) { |
215 | internal_memmove(dest: dst, src, n: 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(s: dst + i, c: '\0', n: 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(s: dst + i, c: 0, n: (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(s: haystack); |
246 | uptr len2 = internal_strlen(s: needle); |
247 | if (len1 < len2) return nullptr; |
248 | for (uptr pos = 0; pos <= len1 - len2; pos++) { |
249 | if (internal_memcmp(s1: haystack + pos, s2: needle, n: 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(c: *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(c: *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(a: (u64)INT64_MAX, b: 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(size: (uptr)beg, boundary: sizeof(uptr)); |
302 | uptr *aligned_end = (uptr *)RoundDownTo(x: (uptr)end, boundary: 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 | |