1#pragma once
2#include <compiler/core.h>
3#include <compiler/wrapper.h>
4#include <stdarg.h>
5#include <stddef.h>
6#include <stdint.h>
7void *memcpy(void *dest, const void *src, size_t n) cc_access(write_only, 1, 3)
8cc_access(read_only, 2, 3) cc_nonnull(1, 2) cc_returns_nonnull;
9
10void *memset(void *s, int c, size_t n) cc_access(write_only, 1, 3) cc_nonnull(1)
11cc_returns_nonnull;
12
13void *memmove(void *dest, const void *src, size_t n) cc_access(write_only, 1, 3)
14cc_access(read_only, 2, 3) cc_nonnull(1, 2) cc_returns_nonnull;
15
16int memcmp(const void *s1, const void *s2, size_t n) cc_access(read_only, 1, 3)
17cc_access(read_only, 2, 3) cc_nonnull(1, 2) cc_pure;
18
19void *memchr(const void *s, int c, size_t n) cc_access(read_only, 1, 3)
20cc_nonnull(1) cc_pure;
21
22void *memrchr(const void *s, int c, size_t n) cc_access(read_only, 1, 3)
23cc_nonnull(1) cc_pure;
24
25void *memmem(const void *haystack, size_t haystack_len, const void *needle,
26 size_t needle_len) cc_access(read_only, 1, 2)
27cc_access(read_only, 3, 4) cc_nonnull(1, 3) cc_pure;
28
29void *mempcpy(void *dest, const void *src, size_t n) cc_access(write_only, 1, 3)
30cc_access(read_only, 2, 3) cc_nonnull(1, 2) cc_returns_nonnull;
31
32#define __STRING_FAST static inline __attribute__((always_inline, artificial))
33
34__STRING_FAST void *__memset_inline(void *s, int c, size_t n) {
35 void *ret = s;
36 uint64_t word = (uint64_t) (uint8_t) c * 0x0101010101010101ULL;
37 size_t qwords = n >> 3;
38 size_t rem = n & 7;
39
40 asm volatile("rep stosq" : "+D"(s), "+c"(qwords) : "a"(word) : "memory");
41 asm volatile("rep stosb" : "+D"(s), "+c"(rem) : "a"(word) : "memory");
42
43 return ret;
44}
45
46__STRING_FAST void *__memcpy_inline(void *dest, const void *src, size_t n) {
47 void *ret = dest;
48 size_t qwords = n >> 3;
49 size_t rem = n & 7;
50
51 asm volatile("rep movsq"
52 : "+D"(dest), "+S"(src), "+c"(qwords)
53 :
54 : "memory");
55 asm volatile("rep movsb" : "+D"(dest), "+S"(src), "+c"(rem) : : "memory");
56
57 return ret;
58}
59
60__STRING_FAST void *__memmove_inline(void *dest, const void *src, size_t n) {
61 if ((uintptr_t) dest - (uintptr_t) src >= n)
62 return __memcpy_inline(dest, src, n);
63
64 uint8_t *d = (uint8_t *) dest + n;
65 const uint8_t *s = (const uint8_t *) src + n;
66 while (n--)
67 *--d = *--s;
68
69 return dest;
70}
71
72__STRING_FAST int __memcmp_inline(const void *s1, const void *s2, size_t n) {
73 if (!n)
74 return 0;
75
76 const unsigned char *p1 = (const unsigned char *) s1;
77 const unsigned char *p2 = (const unsigned char *) s2;
78
79 asm volatile("repe cmpsb" : "+D"(p1), "+S"(p2), "+c"(n) : : "memory", "cc");
80
81 return (int) p1[-1] - (int) p2[-1];
82}
83
84cc_noreturn void fortify_panic(const char *fn, size_t want, size_t have);
85void __fortify_overflow(void)
86 cc_error("fortify: size provably exceeds the object it accesses");
87
88#define _fortify_obj(p) __builtin_dynamic_object_size((p), 0)
89
90#define _fortify_check(fn, p, n) \
91 ({ \
92 size_t _fortify_have_ = _fortify_obj(p); \
93 size_t _fortify_want_ = (n); \
94 if (__builtin_constant_p(_fortify_want_ > _fortify_have_) && \
95 _fortify_want_ > _fortify_have_) \
96 __fortify_overflow(); \
97 else if (cc_unlikely(_fortify_want_ > _fortify_have_)) \
98 fortify_panic(fn, _fortify_want_, _fortify_have_); \
99 })
100
101#define _fortify_str_check(fn, d, need_expr) \
102 ({ \
103 if (_fortify_obj(d) != SIZE_MAX) \
104 _fortify_check(fn, d, (need_expr)); \
105 })
106
107#define memset(s, c, n) \
108 ({ \
109 size_t _memset_n_ = (n); \
110 _fortify_check("memset", s, _memset_n_); \
111 __memset_inline((s), (c), _memset_n_); \
112 })
113#define memcpy(d, s, n) \
114 ({ \
115 size_t _memcpy_n_ = (n); \
116 _fortify_check("memcpy", d, _memcpy_n_); \
117 _fortify_check("memcpy", s, _memcpy_n_); \
118 __memcpy_inline((d), (s), _memcpy_n_); \
119 })
120#define memmove(d, s, n) \
121 ({ \
122 size_t _memmove_n_ = (n); \
123 _fortify_check("memmove", d, _memmove_n_); \
124 _fortify_check("memmove", s, _memmove_n_); \
125 __memmove_inline((d), (s), _memmove_n_); \
126 })
127#define memcmp(a, b, n) \
128 ({ \
129 size_t _memcmp_n_ = (n); \
130 _fortify_check("memcmp", a, _memcmp_n_); \
131 _fortify_check("memcmp", b, _memcmp_n_); \
132 __memcmp_inline((a), (b), _memcmp_n_); \
133 })
134
135size_t strlen(const char *str) cc_pure cc_nonnull(1);
136char *strcpy(char *dest, const char *src) cc_nonnull(1, 2) cc_returns_nonnull;
137/* Return the terminator */
138char *stpcpy(char *dest, const char *src) cc_nonnull(1, 2) cc_returns_nonnull;
139/* Pad to n bytes and return the first written NUL, or dest + n if truncated */
140char *stpncpy(char *dest, const char *src, size_t n) cc_nonnull(1, 2)
141cc_returns_nonnull;
142char *strcat(char *dest, const char *src) cc_nonnull(1, 2) cc_returns_nonnull;
143int strncmp(const char *s1, const char *s2, size_t n) cc_pure cc_nonnull(1, 2);
144int strcmp(const char *str1, const char *str2) cc_pure cc_nonnull(1, 2);
145char *strncpy(char *dest, const char *src, size_t n) cc_nonnull(1, 2)
146cc_returns_nonnull;
147char *strchr(const char *s, int c) cc_pure cc_nonnull(1);
148char *strrchr(const char *s, int c) cc_pure cc_nonnull(1);
149size_t strspn(const char *s, const char *accept) cc_pure cc_nonnull(1, 2);
150size_t strcspn(const char *s, const char *reject) cc_pure cc_nonnull(1, 2);
151char *strpbrk(const char *s, const char *accept) cc_pure cc_nonnull(1, 2);
152char *strstr(const char *haystack, const char *needle) cc_pure cc_nonnull(1, 2);
153char *strcasestr(const char *haystack, const char *needle) cc_pure
154cc_nonnull(1, 2);
155char *strnstr(const char *haystack, const char *needle, size_t len) cc_pure
156cc_nonnull(1, 2);
157char *strncasestr(const char *haystack, const char *needle, size_t len) cc_pure
158cc_nonnull(1, 2);
159
160char *strtok(char *str, const char *delim) cc_nonnull(2);
161char *strtok_r(char *str, const char *delim, char **saveptr) cc_nonnull(2, 3);
162
163char *strncat(char *dest, const char *src, size_t n) cc_nonnull(1, 2)
164cc_returns_nonnull;
165size_t strnlen(const char *s, size_t maxlen) cc_pure cc_nonnull(1);
166
167int islower(int c) cc_constfn;
168int isupper(int c) cc_constfn;
169int isdigit(int c) cc_constfn;
170int isalpha(int c) cc_constfn;
171int isalnum(int c) cc_constfn;
172int isspace(int c) cc_constfn;
173int isprint(int c) cc_constfn;
174int isblank(int c) cc_constfn;
175int iscntrl(int c) cc_constfn;
176int isgraph(int c) cc_constfn;
177int ispunct(int c) cc_constfn;
178int isxdigit(int c) cc_constfn;
179int toupper(int c) cc_constfn;
180int tolower(int c) cc_constfn;
181
182/* This is rather funny, but clang does string matching on
183 * string.h functionality and flags a vfree as a mismatch */
184#ifdef __clang_analyzer__
185#define strdup vstrdup
186#define strndup vstrndup
187#endif
188
189char *cc_nullable strdup(const char *str) cw_alloc() cc_warn_unused_result;
190char *cc_nullable strndup(const char *str, size_t n) cw_alloc()
191 cc_warn_unused_result;
192int strcasecmp(const char *s1, const char *s2) cc_pure cc_nonnull(1, 2);
193int strncasecmp(const char *s1, const char *s2, size_t n) cc_pure
194cc_nonnull(1, 2);
195
196char *strrev(char *s) cc_nonnull(1) cc_returns_nonnull;
197char *strtoupper(char *s) cc_nonnull(1) cc_returns_nonnull;
198char *strtolower(char *s) cc_nonnull(1) cc_returns_nonnull;
199
200int64_t atoi(const char *str) cc_pure cc_nonnull(1);
201size_t atoui(const char *str) cc_pure cc_nonnull(1);
202size_t atohex(const char *str) cc_pure cc_nonnull(1);
203
204char *itoa(int64_t value, char *buf, int base) cc_nonnull(2) cc_returns_nonnull;
205char *utoa(size_t value, char *buf, int base) cc_nonnull(2) cc_returns_nonnull;
206
207long strtol(const char *nptr, char **endptr, int base) cc_nonnull(1);
208long long strtoll(const char *nptr, char **endptr, int base) cc_nonnull(1);
209unsigned long strtoul(const char *nptr, char **endptr, int base) cc_nonnull(1);
210unsigned long long strtoull(const char *nptr, char **endptr, int base)
211 cc_nonnull(1);
212
213size_t strlcpy(char *dst, const char *src, size_t size) cc_nonnull(1, 2);
214size_t strlcat(char *dst, const char *src, size_t size) cc_nonnull(1, 2);
215char *strsep(char **stringp, const char *delim) cc_nonnull(1, 2);
216char *strchrnul(const char *s, int c) cc_pure cc_nonnull(1);
217
218int vsnprintf(char *buffer, int buffer_len, const char *format, va_list args)
219 cc_printf_like(3, 0) cc_nonnull(3);
220int snprintf(char *buffer, int buffer_len, const char *format, ...)
221 cc_printf_like(3, 4) cc_nonnull(3);
222int vasprintf(char **strp, const char *fmt, va_list args) cc_printf_like(2, 0);
223
224#define strcpy(d, s) \
225 ({ \
226 _fortify_str_check("strcpy", d, __builtin_strlen(s) + 1); \
227 (strcpy)((d), (s)); \
228 })
229#define stpcpy(d, s) \
230 ({ \
231 _fortify_str_check("stpcpy", d, __builtin_strlen(s) + 1); \
232 (stpcpy)((d), (s)); \
233 })
234#define strcat(d, s) \
235 ({ \
236 _fortify_str_check("strcat", d, \
237 __builtin_strlen(d) + __builtin_strlen(s) + 1); \
238 (strcat)((d), (s)); \
239 })
240#define strncpy(d, s, n) \
241 ({ \
242 size_t _strncpy_n_ = (n); \
243 _fortify_check("strncpy", d, _strncpy_n_); \
244 (strncpy)((d), (s), _strncpy_n_); \
245 })
246#define stpncpy(d, s, n) \
247 ({ \
248 size_t _stpncpy_n_ = (n); \
249 _fortify_check("stpncpy", d, _stpncpy_n_); \
250 (stpncpy)((d), (s), _stpncpy_n_); \
251 })
252#define strlcpy(d, s, n) \
253 ({ \
254 size_t _strlcpy_n_ = (n); \
255 _fortify_check("strlcpy", d, _strlcpy_n_); \
256 (strlcpy)((d), (s), _strlcpy_n_); \
257 })
258#define strlcat(d, s, n) \
259 ({ \
260 size_t _strlcat_n_ = (n); \
261 _fortify_check("strlcat", d, _strlcat_n_); \
262 (strlcat)((d), (s), _strlcat_n_); \
263 })
264#define snprintf(buf, len, ...) \
265 ({ \
266 int _snprintf_len_ = (len); \
267 if (_snprintf_len_ > 0) \
268 _fortify_check("snprintf", buf, (size_t) _snprintf_len_); \
269 (snprintf)((buf), _snprintf_len_, __VA_ARGS__); \
270 })
271#define vsnprintf(buf, len, fmt, args) \
272 ({ \
273 int _vsnprintf_len_ = (len); \
274 if (_vsnprintf_len_ > 0) \
275 _fortify_check("vsnprintf", buf, (size_t) _vsnprintf_len_); \
276 (vsnprintf)((buf), _vsnprintf_len_, (fmt), (args)); \
277 })
278int asprintf(char **strp, const char *fmt, ...) cc_printf_like(2, 3);
279