xref: /freebsd/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_libc.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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