]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //===-- sanitizer_libc.cc -------------------------------------------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This file is shared between AddressSanitizer and ThreadSanitizer | |
11 | // run-time libraries. See sanitizer_libc.h for details. | |
12 | //===----------------------------------------------------------------------===// | |
92a42be0 | 13 | |
1a4d82fc JJ |
14 | #include "sanitizer_allocator_internal.h" |
15 | #include "sanitizer_common.h" | |
16 | #include "sanitizer_libc.h" | |
17 | ||
18 | namespace __sanitizer { | |
19 | ||
1a4d82fc | 20 | s64 internal_atoll(const char *nptr) { |
92a42be0 | 21 | return internal_simple_strtoll(nptr, nullptr, 10); |
1a4d82fc JJ |
22 | } |
23 | ||
24 | void *internal_memchr(const void *s, int c, uptr n) { | |
92a42be0 | 25 | const char *t = (const char *)s; |
1a4d82fc JJ |
26 | for (uptr i = 0; i < n; ++i, ++t) |
27 | if (*t == c) | |
92a42be0 SL |
28 | return reinterpret_cast<void *>(const_cast<char *>(t)); |
29 | return nullptr; | |
30 | } | |
31 | ||
32 | void *internal_memrchr(const void *s, int c, uptr n) { | |
33 | const char *t = (const char *)s; | |
34 | void *res = nullptr; | |
35 | for (uptr i = 0; i < n; ++i, ++t) { | |
36 | if (*t == c) res = reinterpret_cast<void *>(const_cast<char *>(t)); | |
37 | } | |
38 | return res; | |
1a4d82fc JJ |
39 | } |
40 | ||
41 | int internal_memcmp(const void* s1, const void* s2, uptr n) { | |
92a42be0 SL |
42 | const char *t1 = (const char *)s1; |
43 | const char *t2 = (const char *)s2; | |
1a4d82fc JJ |
44 | for (uptr i = 0; i < n; ++i, ++t1, ++t2) |
45 | if (*t1 != *t2) | |
46 | return *t1 < *t2 ? -1 : 1; | |
47 | return 0; | |
48 | } | |
49 | ||
50 | void *internal_memcpy(void *dest, const void *src, uptr n) { | |
51 | char *d = (char*)dest; | |
92a42be0 | 52 | const char *s = (const char *)src; |
1a4d82fc JJ |
53 | for (uptr i = 0; i < n; ++i) |
54 | d[i] = s[i]; | |
55 | return dest; | |
56 | } | |
57 | ||
58 | void *internal_memmove(void *dest, const void *src, uptr n) { | |
59 | char *d = (char*)dest; | |
92a42be0 | 60 | const char *s = (const char *)src; |
1a4d82fc JJ |
61 | sptr i, signed_n = (sptr)n; |
62 | CHECK_GE(signed_n, 0); | |
63 | if (d < s) { | |
64 | for (i = 0; i < signed_n; ++i) | |
65 | d[i] = s[i]; | |
66 | } else { | |
67 | if (d > s && signed_n > 0) | |
68 | for (i = signed_n - 1; i >= 0 ; --i) { | |
69 | d[i] = s[i]; | |
70 | } | |
71 | } | |
72 | return dest; | |
73 | } | |
74 | ||
75 | // Semi-fast bzero for 16-aligned data. Still far from peak performance. | |
76 | void internal_bzero_aligned16(void *s, uptr n) { | |
77 | struct S16 { u64 a, b; } ALIGNED(16); | |
78 | CHECK_EQ((reinterpret_cast<uptr>(s) | n) & 15, 0); | |
79 | for (S16 *p = reinterpret_cast<S16*>(s), *end = p + n / 16; p < end; p++) { | |
80 | p->a = p->b = 0; | |
92a42be0 SL |
81 | // Make sure this does not become memset. |
82 | SanitizerBreakOptimization(nullptr); | |
1a4d82fc JJ |
83 | } |
84 | } | |
85 | ||
86 | void *internal_memset(void* s, int c, uptr n) { | |
87 | // The next line prevents Clang from making a call to memset() instead of the | |
88 | // loop below. | |
89 | // FIXME: building the runtime with -ffreestanding is a better idea. However | |
90 | // there currently are linktime problems due to PR12396. | |
91 | char volatile *t = (char*)s; | |
92 | for (uptr i = 0; i < n; ++i, ++t) { | |
93 | *t = c; | |
94 | } | |
95 | return s; | |
96 | } | |
97 | ||
98 | uptr internal_strcspn(const char *s, const char *reject) { | |
99 | uptr i; | |
100 | for (i = 0; s[i]; i++) { | |
92a42be0 | 101 | if (internal_strchr(reject, s[i])) |
1a4d82fc JJ |
102 | return i; |
103 | } | |
104 | return i; | |
105 | } | |
106 | ||
107 | char* internal_strdup(const char *s) { | |
108 | uptr len = internal_strlen(s); | |
109 | char *s2 = (char*)InternalAlloc(len + 1); | |
110 | internal_memcpy(s2, s, len); | |
111 | s2[len] = 0; | |
112 | return s2; | |
113 | } | |
114 | ||
92a42be0 SL |
115 | char* internal_strndup(const char *s, uptr n) { |
116 | uptr len = internal_strnlen(s, n); | |
117 | char *s2 = (char*)InternalAlloc(len + 1); | |
118 | internal_memcpy(s2, s, len); | |
119 | s2[len] = 0; | |
120 | return s2; | |
121 | } | |
122 | ||
1a4d82fc JJ |
123 | int internal_strcmp(const char *s1, const char *s2) { |
124 | while (true) { | |
125 | unsigned c1 = *s1; | |
126 | unsigned c2 = *s2; | |
127 | if (c1 != c2) return (c1 < c2) ? -1 : 1; | |
128 | if (c1 == 0) break; | |
129 | s1++; | |
130 | s2++; | |
131 | } | |
132 | return 0; | |
133 | } | |
134 | ||
135 | int internal_strncmp(const char *s1, const char *s2, uptr n) { | |
136 | for (uptr i = 0; i < n; i++) { | |
137 | unsigned c1 = *s1; | |
138 | unsigned c2 = *s2; | |
139 | if (c1 != c2) return (c1 < c2) ? -1 : 1; | |
140 | if (c1 == 0) break; | |
141 | s1++; | |
142 | s2++; | |
143 | } | |
144 | return 0; | |
145 | } | |
146 | ||
147 | char* internal_strchr(const char *s, int c) { | |
148 | while (true) { | |
149 | if (*s == (char)c) | |
92a42be0 | 150 | return const_cast<char *>(s); |
1a4d82fc | 151 | if (*s == 0) |
92a42be0 | 152 | return nullptr; |
1a4d82fc JJ |
153 | s++; |
154 | } | |
155 | } | |
156 | ||
157 | char *internal_strchrnul(const char *s, int c) { | |
158 | char *res = internal_strchr(s, c); | |
159 | if (!res) | |
92a42be0 | 160 | res = const_cast<char *>(s) + internal_strlen(s); |
1a4d82fc JJ |
161 | return res; |
162 | } | |
163 | ||
164 | char *internal_strrchr(const char *s, int c) { | |
92a42be0 | 165 | const char *res = nullptr; |
1a4d82fc JJ |
166 | for (uptr i = 0; s[i]; i++) { |
167 | if (s[i] == c) res = s + i; | |
168 | } | |
92a42be0 | 169 | return const_cast<char *>(res); |
1a4d82fc JJ |
170 | } |
171 | ||
172 | uptr internal_strlen(const char *s) { | |
173 | uptr i = 0; | |
174 | while (s[i]) i++; | |
175 | return i; | |
176 | } | |
177 | ||
178 | char *internal_strncat(char *dst, const char *src, uptr n) { | |
179 | uptr len = internal_strlen(dst); | |
180 | uptr i; | |
181 | for (i = 0; i < n && src[i]; i++) | |
182 | dst[len + i] = src[i]; | |
183 | dst[len + i] = 0; | |
184 | return dst; | |
185 | } | |
186 | ||
187 | char *internal_strncpy(char *dst, const char *src, uptr n) { | |
188 | uptr i; | |
189 | for (i = 0; i < n && src[i]; i++) | |
190 | dst[i] = src[i]; | |
191 | internal_memset(dst + i, '\0', n - i); | |
192 | return dst; | |
193 | } | |
194 | ||
195 | uptr internal_strnlen(const char *s, uptr maxlen) { | |
196 | uptr i = 0; | |
197 | while (i < maxlen && s[i]) i++; | |
198 | return i; | |
199 | } | |
200 | ||
201 | char *internal_strstr(const char *haystack, const char *needle) { | |
202 | // This is O(N^2), but we are not using it in hot places. | |
203 | uptr len1 = internal_strlen(haystack); | |
204 | uptr len2 = internal_strlen(needle); | |
92a42be0 | 205 | if (len1 < len2) return nullptr; |
1a4d82fc JJ |
206 | for (uptr pos = 0; pos <= len1 - len2; pos++) { |
207 | if (internal_memcmp(haystack + pos, needle, len2) == 0) | |
92a42be0 | 208 | return const_cast<char *>(haystack) + pos; |
1a4d82fc | 209 | } |
92a42be0 | 210 | return nullptr; |
1a4d82fc JJ |
211 | } |
212 | ||
213 | s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) { | |
214 | CHECK_EQ(base, 10); | |
215 | while (IsSpace(*nptr)) nptr++; | |
216 | int sgn = 1; | |
217 | u64 res = 0; | |
218 | bool have_digits = false; | |
92a42be0 | 219 | char *old_nptr = const_cast<char *>(nptr); |
1a4d82fc JJ |
220 | if (*nptr == '+') { |
221 | sgn = 1; | |
222 | nptr++; | |
223 | } else if (*nptr == '-') { | |
224 | sgn = -1; | |
225 | nptr++; | |
226 | } | |
227 | while (IsDigit(*nptr)) { | |
228 | res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX; | |
229 | int digit = ((*nptr) - '0'); | |
230 | res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX; | |
231 | have_digits = true; | |
232 | nptr++; | |
233 | } | |
92a42be0 SL |
234 | if (endptr) { |
235 | *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr; | |
1a4d82fc JJ |
236 | } |
237 | if (sgn > 0) { | |
238 | return (s64)(Min((u64)INT64_MAX, res)); | |
239 | } else { | |
240 | return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1); | |
241 | } | |
242 | } | |
243 | ||
244 | bool mem_is_zero(const char *beg, uptr size) { | |
245 | CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40)); // Sanity check. | |
246 | const char *end = beg + size; | |
247 | uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr)); | |
248 | uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr)); | |
249 | uptr all = 0; | |
250 | // Prologue. | |
251 | for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++) | |
252 | all |= *mem; | |
253 | // Aligned loop. | |
254 | for (; aligned_beg < aligned_end; aligned_beg++) | |
255 | all |= *aligned_beg; | |
256 | // Epilogue. | |
257 | if ((char*)aligned_end >= beg) | |
258 | for (const char *mem = (char*)aligned_end; mem < end; mem++) | |
259 | all |= *mem; | |
260 | return all == 0; | |
261 | } | |
262 | ||
92a42be0 | 263 | } // namespace __sanitizer |