1 /*
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
30 * support for mandatory and extensible security protections. This notice
31 * is included in support of clause 2.2 (b) of the Apple Public License,
32 * Version 2.0.
33 */
34 /*
35 * HISTORY
36 * @OSF_COPYRIGHT@
37 */
38
39 #if (defined(__has_include) && __has_include(<__xnu_libcxx_sentinel.h>) && !defined(XNU_LIBCXX_SDKROOT))
40
41 #if !__has_include_next(<string.h>)
42 #error Do not build with -nostdinc (use GCC_USE_STANDARD_INCLUDE_SEARCHING=NO)
43 #endif /* !__has_include_next(<string.h>) */
44
45 #include_next <string.h>
46
47 #else /* (defined(__has_include) && __has_include(<__xnu_libcxx_sentinel.h>) && !defined(XNU_LIBCXX_SDKROOT)) */
48
49 #ifndef _STRING_H_
50 #define _STRING_H_ 1
51
52 #include <sys/cdefs.h>
53 #ifdef MACH_KERNEL_PRIVATE
54 #include <types.h>
55 #else /* MACH_KERNEL_PRIVATE */
56 #include <sys/types.h>
57 #endif /* MACH_KERNEL_PRIVATE */
58
59 #ifdef KERNEL
60 #include <machine/trap.h>
61 #endif /* KERNEL */
62
63 __BEGIN_DECLS
64
65 #ifndef NULL
66 #if defined (__cplusplus)
67 #if __cplusplus >= 201103L
68 #define NULL nullptr
69 #else
70 #define NULL 0
71 #endif
72 #else
73 #define NULL ((void *)0)
74 #endif
75 #endif
76
77 /*
78 * Memory functions
79 *
80 * int bcmp(const void *s1, const void *s2, size_t n);
81 * int memcmp(const void *s1, const void *s2, size_t n);
82 * int timingsafe_bcmp(const void *b1, const void *b2, size_t n);
83 *
84 * void bzero(void *dst, size_t n);
85 * void *memset(void *s, int c, size_t n);
86 * int memset_s(void *s, size_t smax, int c, size_t n);
87 *
88 * void bcopy(const void *src, void *dst, size_t n);
89 * void *memcpy(void *dst, const void *src, size_t n);
90 * void *memove(void *dst, const void *src, size_t n);
91 *
92 *
93 * String functions
94 *
95 * size_t strlen(const char *s);
96 * size_t strnlen(const char *s, size_t n);
97 *
98 * int strcmp(const char *s1, const char *s2);
99 * int strncmp(const char *s1, const char *s2, size_t n);
100 * int strlcmp(const char *s1, const char *s2, size_t n);
101 * int strbufcmp(const char *s1, size_t n1, const char *s2, size_t n2);
102 * int strprefix(const char *s1, const char *s2);
103 * int strcasecmp(const char *s1, const char *s2);
104 * int strncasecmp(const char *s1, const char *s2, size_t n);
105 * int strlcasecmp(const char *s1, const char *s2, size_t n);
106 * int strbufcasecmp(const char *s1, size_t n1, const char *s2, size_t n2);
107 *
108 * char *strchr(const char *s, int c);
109 * char *strrchr(const char *s, int c);
110 * char *strnstr(const char *s, const char *find, size_t slen);
111 *
112 * size_t strlcpy(char *dst, const char *src, size_t n);
113 * const char *strbufcpy(char *dst, size_t dstlen, const char *src, size_t srclen);
114 * size_t strlcat(char *dst, const char *src, size_t n);
115 * const char *strbufcat(char *dst, size_t dstlen, const char *src, size_t srclen);
116 */
117
118
119 #pragma mark _FORTIFY_SOURCE helpers
120
121 /*
122 * If _FORTIFY_SOURCE is undefined, it is assumed to be 1.
123 *
124 * _FORTIFY_SOURCE > 0 will enable checked memory/string functions.
125 *
126 * _FORTIFY_SOURCE_STRICT will enable stricter checking (optional)
127 * for memcpy/memmove/bcopy and will check that copies do not go
128 * past the end of a struct member.
129 */
130 #if KASAN
131 # define __XNU_FORTIFY_SOURCE 0 /* kasan is a superset */
132 #elif defined (_FORTIFY_SOURCE) && _FORTIFY_SOURCE == 0
133 # define __XNU_FORTIFY_SOURCE 0 /* forcefully disabled */
134 #elif XNU_KERNEL_PRIVATE || defined(_FORTIFY_SOURCE_STRICT)
135 # define __XNU_FORTIFY_SOURCE 2
136 #else
137 # define __XNU_FORTIFY_SOURCE 1
138 #endif
139
140 /*
141 * The overloadable attribute is load bearing in two major ways:
142 * - __builtin_${function} from ${function} would be infinite recursion and UB,
143 * - we need to still expose the regular prototype for people wanting to take
144 * its address.
145 */
146 #define __xnu_string_inline \
147 static inline __attribute__((__always_inline__, __overloadable__))
148
149 /*
150 * We want to allow certain functions like strlen() to constant fold
151 * at compile time (such as strlen("foo")).
152 *
153 * In order to do so, we need an overload that has a similar looking
154 * signature but is different from the regular function so that it can
155 * call its matching builtin without causing UB due to inifinite recursion.
156 * We abuse that the pass_object_size class of attributes gives us
157 * precisely that semantics.
158 */
159 #define __xnu_force_overload __xnu_pass_object_size
160
161 /*
162 * The object_size extension defines two kinds of size: the "struct size" and
163 * the "member size". The "struct size" is the size of the buffer from the
164 * starting address to the end of the largest enclosing object. The "member
165 * size" is the size of the buffer from the starting address to the end of the
166 * immediately enclosing array. For instance, given this:
167 *
168 * struct foo {
169 * char a[20];
170 * char b[20];
171 * } my_foo;
172 *
173 * The "struct size" for &my_foo.a[10] is 30 (`sizeof(struct foo) -
174 * offsetof(struct foo, a[10])`), and the "member size" for it is 10
175 * (`sizeof(my_foo.a) - 10`).
176 *
177 * In general, you should use the member size for string operations (as it is
178 * always a mistake to go out of bounds of a char buffer with a string
179 * operation) and the struct size for bytewise operations (like bcopy, bzero,
180 * memset, etc). The object_size extension is intended to provide _some_ bounds
181 * safety at a low engineering cost, and various patterns intentionally
182 * overflowing from individual fields with bytewise operations have
183 * historically been tolerated both by engineers and the compiler (despite
184 * probably being undefined).
185 *
186 * As an important side note, -fbounds-safety does not allow naïvely
187 * overflowing from individual fields. -fbounds-safety bounds checks are always
188 * equivalent to checks against the member size.
189 */
190
191 #if __has_builtin(__builtin_dynamic_object_size)
192 # define __xnu_pass_struct_size __attribute__((__pass_dynamic_object_size__(0)))
193 # define __xnu_pass_member_size __attribute__((__pass_dynamic_object_size__(1)))
194 # define __xnu_struct_size(ptr) __builtin_dynamic_object_size(ptr, 0)
195 # define __xnu_member_size(ptr) __builtin_dynamic_object_size(ptr, 1)
196 #else
197 # define __xnu_pass_struct_size __attribute__((__pass_object_size__(0)))
198 # define __xnu_pass_member_size __attribute__((__pass_object_size__(1)))
199 # define __xnu_struct_size(ptr) __builtin_object_size(ptr, 0)
200 # define __xnu_member_size(ptr) __builtin_object_size(ptr, 1)
201 #endif
202
203 #if __XNU_FORTIFY_SOURCE == 0 || !__has_attribute(diagnose_if)
204 # define __xnu_struct_size_precondition(ptr, size, message)
205 # define __xnu_member_size_precondition(ptr, size, message)
206 #else
207 # define __xnu_struct_size_precondition(ptr, size, message) \
208 __attribute__((__diagnose_if__(__xnu_struct_size(ptr) < (size), message, "error")))
209 # define __xnu_member_size_precondition(ptr, size, message) \
210 __attribute__((__diagnose_if__(__xnu_member_size(ptr) < (size), message, "error")))
211 #endif
212
213
214 #if __XNU_FORTIFY_SOURCE > 1
215 # define __xnu_object_size_precondition(...) \
216 __xnu_member_size_precondition(__VA_ARGS__)
217 # define __xnu_object_size_check(...) \
218 __xnu_member_size_check(__VA_ARGS__)
219 # define __xnu_pass_object_size __xnu_pass_member_size
220 #else
221 # define __xnu_object_size_precondition(...) \
222 __xnu_struct_size_precondition(__VA_ARGS__)
223 # define __xnu_object_size_check(...) \
224 __xnu_struct_size_check(__VA_ARGS__)
225 # define __xnu_pass_object_size __xnu_pass_struct_size
226 #endif
227
228 #if __XNU_FORTIFY_SOURCE == 0 || __has_ptrcheck
229 #define __xnu_struct_size_check(ptr, size, how) ((void)0)
230 #define __xnu_member_size_check(ptr, size, how) ((void)0)
231 #else
232 __xnu_string_inline __cold __dead2 void
233 __xnu_fortify_trap_write(void)
234 {
235 ml_fatal_trap(0xbffe); /* XNU_HARD_TRAP_STRING_CHK */
236 }
237
238 __xnu_string_inline __cold void
239 __xnu_fortify_trap_read(void)
240 {
241 /* for now do not emit read traps yet */
242 #if 0
243 ml_recoverable_trap(0xfffe); /* XNU_SOFT_TRAP_STRING_CHK */
244 #endif
245 }
246
247 #define __xnu_struct_size_check(ptr, size, how) ({ \
248 if (__xnu_struct_size(ptr) < (size)) { \
249 __xnu_fortify_trap_ ## how(); \
250 } \
251 })
252 #define __xnu_member_size_check(ptr, size, how) ({ \
253 if (__xnu_member_size(ptr) < (size)) { \
254 __xnu_fortify_trap_ ## how(); \
255 } \
256 })
257 #endif
258
259 /*
260 * Verifies at compile-time that an expression is an array (of any type).
261 */
262 #if __has_builtin(__builtin_types_compatible_p)
263 #define __xnu_is_array(A) __builtin_types_compatible_p(typeof((A)[0])[], typeof(A))
264 #else
265 #define __xnu_is_array(A) 1
266 #endif
267 #define __xnu_assert_is_array(A, MSG) _Static_assert(__xnu_is_array(A), MSG)
268
269 #define __xnu_count_args1(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, N, ...) N
270 #define __xnu_count_args(...) \
271 __xnu_count_args1(, ##__VA_ARGS__, _9, _8, _7, _6, _5, _4, _3, _2, _1, _0)
272
273 #define __xnu_argc_overload1(base, N, ...) __CONCAT(base, N)(__VA_ARGS__)
274 #define __xnu_argc_overload(base, ...) \
275 __xnu_argc_overload1(base, __xnu_count_args(__VA_ARGS__), ##__VA_ARGS__)
276
277 #pragma mark memory functions
278
279
280 extern int bcmp(const void *s1 __sized_by(n), const void *s2 __sized_by(n), size_t n) __stateful_pure;
281
282 __xnu_string_inline __stateful_pure
283 int
bcmp(const void * const s1 __xnu_pass_struct_size __sized_by (n),const void * const s2 __xnu_pass_struct_size __sized_by (n),size_t n)284 bcmp(
285 const void *const s1 __xnu_pass_struct_size __sized_by(n),
286 const void *const s2 __xnu_pass_struct_size __sized_by(n),
287 size_t n)
288 __xnu_struct_size_precondition(s1, n, "read overflow (first argument)")
289 __xnu_struct_size_precondition(s2, n, "read overflow (second argument)")
290 {
291 extern int __xnu_bcmp(
292 const void * __sized_by(n),
293 const void * __sized_by(n),
294 size_t n) __asm("_bcmp");
295
296 __xnu_struct_size_check(s1, n, read);
297 __xnu_struct_size_check(s2, n, read);
298 #if __has_builtin(__builtin_bcmp)
299 return __builtin_bcmp(s1, s2, n);
300 #else
301 return __xnu_bcmp(s1, s2, n);
302 #endif
303 }
304
305
306 extern int memcmp(const void *s1 __sized_by(n), const void *s2 __sized_by(n), size_t n) __stateful_pure;
307
308 __xnu_string_inline __stateful_pure
309 int
memcmp(const void * const s1 __xnu_pass_struct_size __sized_by (n),const void * const s2 __xnu_pass_struct_size __sized_by (n),size_t n)310 memcmp(
311 const void *const s1 __xnu_pass_struct_size __sized_by(n),
312 const void *const s2 __xnu_pass_struct_size __sized_by(n),
313 size_t n)
314 __xnu_struct_size_precondition(s1, n, "read overflow (first argument)")
315 __xnu_struct_size_precondition(s2, n, "read overflow (second argument)")
316 {
317 extern int __xnu_memcmp(
318 const void *__sized_by(n),
319 const void *__sized_by(n),
320 size_t n) __asm("_memcmp");
321
322 __xnu_struct_size_check(s1, n, read);
323 __xnu_struct_size_check(s2, n, read);
324 #if __has_builtin(__builtin_memcmp)
325 return __builtin_memcmp(s1, s2, n);
326 #else
327 return __xnu_memcmp(s1, s2, n);
328 #endif
329 }
330
331
332 #ifdef XNU_KERNEL_PRIVATE
333 /*
334 * memcmp_zero_ptr_aligned() checks string s of n bytes contains all zeros.
335 * Address and size of the string s must be pointer-aligned.
336 * Return 0 if true, 1 otherwise. Also return 0 if n is 0.
337 */
338 extern unsigned long memcmp_zero_ptr_aligned(const void *s __sized_by(n), size_t n) __stateful_pure;
339 #endif
340
341
342 extern int timingsafe_bcmp(const void *b1 __sized_by(n), const void *b2 __sized_by(n), size_t n);
343
344
345 extern void bzero(void *s __sized_by(n), size_t n);
346
347 __xnu_string_inline
348 void
bzero(void * const s __xnu_pass_struct_size __sized_by (n),size_t n)349 bzero(
350 void *const s __xnu_pass_struct_size __sized_by(n),
351 size_t n)
352 __xnu_struct_size_precondition(s, n, "write overflow")
353 {
354 extern void __xnu_bzero(
355 const void *__sized_by(n),
356 size_t n) __asm("_bzero");
357
358 __xnu_struct_size_check(s, n, write);
359 #if __has_builtin(__builtin_bzero)
360 __builtin_bzero(s, n);
361 #else
362 __xnu_bzero(s, n);
363 #endif
364 }
365
366
367 extern void *memset(void *s __sized_by(n), int c, size_t n);
368
369 __xnu_string_inline
370 void *
__sized_by(n)371 __sized_by(n)
372 memset(
373 void *const s __xnu_pass_object_size __sized_by(n),
374 int c,
375 size_t n)
376 __xnu_object_size_precondition(s, n, "write overflow")
377 {
378 extern void __xnu_memset(
379 void *__sized_by(n),
380 int,
381 size_t n) __asm("_memset");
382
383 __xnu_object_size_check(s, n, write);
384 #if __has_builtin(__builtin_memset)
385 return __builtin_memset(s, c, n);
386 #else
387 return __xnu_memset(s, c, n);
388 #endif
389 }
390
391
392 extern int memset_s(void *s __sized_by(smax), size_t smax, int c, size_t n);
393
394
395 extern void *memmove(void *dst __sized_by(n), const void *src __sized_by(n), size_t n);
396
397 __xnu_string_inline
398 void *
__sized_by(n)399 __sized_by(n)
400 memmove(
401 void *const dst __xnu_pass_object_size __sized_by(n),
402 const void *const src __xnu_pass_object_size __sized_by(n),
403 size_t n)
404 __xnu_object_size_precondition(dst, n, "write overflow")
405 __xnu_object_size_precondition(src, n, "read overflow")
406 {
407 extern void *__xnu_memmove(
408 void *dst __sized_by(n),
409 const void *src __sized_by(n),
410 size_t n) __asm("_memmove");
411
412 __xnu_object_size_check(dst, n, write);
413 __xnu_object_size_check(src, n, read);
414 #if __has_builtin(__builtin_memmove)
415 return __builtin_memmove(dst, src, n);
416 #else
417 return __xnu_memmove(dst, src, n);
418 #endif
419 }
420
421 __xnu_string_inline
422 void *
__sized_by(n)423 __sized_by(n)
424 __nochk_memmove(
425 void *const dst __xnu_pass_struct_size __sized_by(n),
426 const void *const src __xnu_pass_struct_size __sized_by(n),
427 size_t n)
428 __xnu_struct_size_precondition(dst, n, "write overflow")
429 __xnu_struct_size_precondition(src, n, "read overflow")
430 {
431 extern void *__xnu_memmove(
432 void *dst __sized_by(n),
433 const void *src __sized_by(n),
434 size_t n) __asm("_memmove");
435
436 __xnu_struct_size_check(dst, n, write);
437 __xnu_struct_size_check(src, n, read);
438 #if __has_builtin(__builtin_memmove)
439 return __builtin_memmove(dst, src, n);
440 #else
441 return __xnu_memmove(dst, src, n);
442 #endif
443 }
444
445
446 extern void bcopy(const void *src __sized_by(n), void *dst __sized_by(n), size_t n);
447
448 __xnu_string_inline
449 void
bcopy(const void * const src __xnu_pass_object_size __sized_by (n),void * const dst __xnu_pass_object_size __sized_by (n),size_t n)450 bcopy(
451 const void *const src __xnu_pass_object_size __sized_by(n),
452 void *const dst __xnu_pass_object_size __sized_by(n),
453 size_t n)
454 __xnu_struct_size_precondition(dst, n, "write overflow")
455 __xnu_struct_size_precondition(src, n, "read overflow")
456 {
457 (void)memmove(dst, src, n);
458 }
459
460 __xnu_string_inline
461 void
__nochk_bcopy(const void * const src __xnu_pass_struct_size __sized_by (n),void * const dst __xnu_pass_struct_size __sized_by (n),size_t n)462 __nochk_bcopy(
463 const void *const src __xnu_pass_struct_size __sized_by(n),
464 void *const dst __xnu_pass_struct_size __sized_by(n),
465 size_t n)
466 __xnu_struct_size_precondition(dst, n, "write overflow")
467 __xnu_struct_size_precondition(src, n, "read overflow")
468 {
469 (void)__nochk_memmove(dst, src, n);
470 }
471
472
473 extern void *memcpy(void *dst __sized_by(n), const void *src __sized_by(n), size_t n);
474
475 __xnu_string_inline
476 void *
__sized_by(n)477 __sized_by(n)
478 memcpy(
479 void *const dst __xnu_pass_object_size __sized_by(n),
480 const void *const src __xnu_pass_object_size __sized_by(n),
481 size_t n)
482 __xnu_struct_size_precondition(dst, n, "write overflow")
483 __xnu_struct_size_precondition(src, n, "read overflow")
484 {
485 return memmove(dst, src, n);
486 }
487
488 __xnu_string_inline
489 void *
__sized_by(n)490 __sized_by(n)
491 __nochk_memcpy(
492 void *const dst __xnu_pass_struct_size __sized_by(n),
493 const void *const src __xnu_pass_struct_size __sized_by(n),
494 size_t n)
495 __xnu_struct_size_precondition(dst, n, "write overflow")
496 __xnu_struct_size_precondition(src, n, "read overflow")
497 {
498 return __nochk_memmove(dst, src, n);
499 }
500
501
502 #pragma mark string functions
503
504 extern size_t strlen(const char *__null_terminated s) __stateful_pure;
505
506 #if __has_builtin(__builtin_strlen)
507 __xnu_string_inline __stateful_pure
508 size_t
strlen(const char * const s __xnu_force_overload)509 strlen(const char * /* __null_terminated */ const s __xnu_force_overload)
510 {
511 return __builtin_strlen(s);
512 }
513 #endif
514
515
516 extern size_t strnlen(const char *__counted_by(n)s, size_t n) __stateful_pure;
517
518 #if __has_builtin(__builtin_strnlen)
519 __xnu_string_inline __stateful_pure
520 size_t
strnlen(const char * const __counted_by (n)s __xnu_force_overload,size_t n)521 strnlen(const char *const __counted_by(n) s __xnu_force_overload, size_t n)
522 {
523 return __builtin_strnlen(s, n);
524 }
525 #endif
526
527
528 /* strbuflen is the same as strnlen. */
529 #define strbuflen_1(BUF) ({ \
530 __xnu_assert_is_array(BUF, "argument is not an array"); \
531 strnlen((BUF), sizeof(BUF)); \
532 })
533 #define strbuflen_2(BUF, LEN) strnlen(BUF, LEN)
534 #define strbuflen(...) __xnu_argc_overload(strbuflen, __VA_ARGS__)
535
536
537 extern int strcmp(const char *__null_terminated s1, const char *__null_terminated s2) __stateful_pure;
538
539 #if __has_builtin(__builtin_strcmp)
540 __xnu_string_inline __stateful_pure
541 int
strcmp(const char * const s1 __xnu_force_overload,const char * const __null_terminated s2)542 strcmp(
543 const char *const /* __null_terminated */ s1 __xnu_force_overload,
544 const char *const __null_terminated s2)
545 {
546 return __builtin_strcmp(s1, s2);
547 }
548 #else
549 #endif
550
551
552 __ptrcheck_unavailable_r("strlcmp or strbufcmp")
553 extern int strncmp(const char *__unsafe_indexable s1, const char *__unsafe_indexable s2, size_t n) __stateful_pure;
554
555 #if __has_builtin(__builtin_strncmp)
556 __ptrcheck_unavailable_r("strlcmp or strbufcmp")
557 __xnu_string_inline __stateful_pure
558 int
strncmp(const char * const __unsafe_indexable s1 __xnu_force_overload,const char * const __unsafe_indexable s2,size_t n)559 strncmp(
560 const char *const __unsafe_indexable s1 __xnu_force_overload,
561 const char *const __unsafe_indexable s2, size_t n)
562 {
563 return __builtin_strncmp(s1, s2, n);
564 }
565 #endif
566
567 /*
568 * Use strlcmp if you want to compare one string with a known length (with or
569 * without a NUL terminator) and one string with an unknown length (that always
570 * has a NUL terminator).
571 * See docs/primitives/string-handling.md for more information.
572 */
573 extern int strlcmp(const char *__counted_by(n)s1, const char *s2, size_t n) __stateful_pure;
574
575 #if __has_builtin(__builtin_strncmp)
576 __xnu_string_inline __stateful_pure
577 int
strlcmp(const char * const __counted_by (s1len)s1 __xnu_force_overload,const char * const s2,size_t s1len)578 strlcmp(
579 const char *const __counted_by(s1len) s1 __xnu_force_overload,
580 const char *const s2, size_t s1len)
581 __xnu_member_size_precondition(s1, s1len, "read overflow")
582 {
583 extern int __xnu_strlcmp(
584 const char * __counted_by(s1len) s1,
585 const char *__null_terminated s2,
586 size_t s1len) __asm("_strlcmp");
587
588 __xnu_member_size_check(s1, s1len, read);
589 return __xnu_strlcmp(s1, s2, s1len);
590 }
591 #endif
592
593
594 /*
595 * Use strbufcmp if you want to compare two strings and you know both of their
596 * lengths. See docs/primitives/string-handling.md for more information.
597 */
598 extern int strbufcmp(const char *__counted_by(s1len)s1, size_t s1len, const char *__counted_by(s2len)s2, size_t s2len) __stateful_pure;
599
600 __xnu_string_inline __stateful_pure
601 int
strbufcmp(const char * const __counted_by (s1len)s1 __xnu_pass_member_size,size_t s1len,const char * const __counted_by (s2len)s2 __xnu_pass_member_size,size_t s2len)602 strbufcmp(
603 const char *const __counted_by(s1len) s1 __xnu_pass_member_size, size_t s1len,
604 const char *const __counted_by(s2len) s2 __xnu_pass_member_size, size_t s2len)
605 __xnu_member_size_precondition(s1, s1len, "read overflow")
606 __xnu_member_size_precondition(s2, s2len, "read overflow")
607 {
608 extern int __xnu_strbufcmp(
609 const char * __counted_by(s1len) s1,
610 size_t s1len,
611 const char *__counted_by(s2len) s2,
612 size_t s2len) __asm("_strbufcmp");
613
614 __xnu_member_size_check(s1, s1len, read);
615 __xnu_member_size_check(s2, s2len, read);
616 return __xnu_strbufcmp(s1, s1len, s2, s2len);
617 }
618
619 #define strbufcmp_2(A, B) ({ \
620 __xnu_assert_is_array(A, "first argument is not an array"); \
621 __xnu_assert_is_array(B, "second argument is not an array"); \
622 (strbufcmp)((A), sizeof(A), (B), sizeof(B)); \
623 })
624 #define strbufcmp_4 (strbufcmp)
625 #define strbufcmp(...) __xnu_argc_overload(strbufcmp, __VA_ARGS__)
626
627
628 extern int strprefix(const char *__null_terminated s1, const char *__null_terminated s2) __stateful_pure;
629
630
631 extern int strcasecmp(const char *__null_terminated s1, const char *__null_terminated s2) __stateful_pure;
632
633 #if __has_builtin(__builtin_strcasecmp)
634 __xnu_string_inline __stateful_pure
635 int
strcasecmp(const char * const s1 __xnu_force_overload,const char * const __null_terminated s2)636 strcasecmp(
637 const char *const /* __null_terminated */ s1 __xnu_force_overload,
638 const char *const __null_terminated s2)
639 {
640 return __builtin_strcasecmp(s1, s2);
641 }
642 #endif
643
644
645 __ptrcheck_unavailable_r("strlcasecmp or strbufcasecmp")
646 extern int strncasecmp(const char *__unsafe_indexable s1, const char *__unsafe_indexable s2, size_t n) __stateful_pure;
647
648 #if __has_builtin(__builtin_strncasecmp)
649 __ptrcheck_unavailable_r("strlcasecmp or strbufcasecmp")
650 __xnu_string_inline __stateful_pure
651 int
strncasecmp(const char * const __unsafe_indexable s1 __xnu_force_overload,const char * const __unsafe_indexable s2,size_t n)652 strncasecmp(
653 const char *const __unsafe_indexable s1 __xnu_force_overload,
654 const char *const __unsafe_indexable s2, size_t n)
655 {
656 return __builtin_strncasecmp(s1, s2, n);
657 }
658 #endif
659
660 /*
661 * Use strlcasecmp if you want to compare one string with a known length (with
662 * or without a NUL terminator) and one string with an unknown length (that
663 * always has a NUL terminator).
664 * See docs/primitives/string-handling.md for more information.
665 */
666 extern int strlcasecmp(const char *__counted_by(n)s1, const char *s2, size_t n) __stateful_pure;
667
668 __xnu_string_inline __stateful_pure
669 int
strlcasecmp(const char * const __counted_by (s1len)s1 __xnu_force_overload,const char * __null_terminated const s2,size_t s1len)670 strlcasecmp(
671 const char *const __counted_by(s1len) s1 __xnu_force_overload,
672 const char *__null_terminated const s2, size_t s1len)
673 __xnu_member_size_precondition(s1, s1len, "read overflow")
674 {
675 extern int __xnu_strlcasecmp(
676 const char * __counted_by(s1len) s1,
677 const char *__null_terminated s2,
678 size_t s1len) __asm("_strlcasecmp");
679
680 __xnu_member_size_check(s1, s1len, read);
681 return __xnu_strlcasecmp(s1, s2, s1len);
682 }
683
684
685 /*
686 * Use strbufcmp if you want to compare two strings and you know both of their
687 * lengths. See docs/primitives/string-handling.md for more information.
688 */
689 extern int strbufcasecmp(const char *__counted_by(s1len)s1, size_t s1len, const char *__counted_by(s2len)s2, size_t s2len) __stateful_pure;
690
691 __xnu_string_inline __stateful_pure
692 int
strbufcasecmp(const char * const __counted_by (s1len)s1 __xnu_pass_member_size,size_t s1len,const char * const __counted_by (s2len)s2 __xnu_pass_member_size,size_t s2len)693 strbufcasecmp(
694 const char *const __counted_by(s1len) s1 __xnu_pass_member_size, size_t s1len,
695 const char *const __counted_by(s2len) s2 __xnu_pass_member_size, size_t s2len)
696 __xnu_member_size_precondition(s1, s1len, "read overflow")
697 __xnu_member_size_precondition(s2, s2len, "read overflow")
698 {
699 extern int __xnu_strbufcasecmp(
700 const char * __counted_by(s1len) s1,
701 size_t s1len,
702 const char *__counted_by(s2len) s2,
703 size_t s2len) __asm("_strbufcasecmp");
704
705 __xnu_member_size_check(s1, s1len, read);
706 __xnu_member_size_check(s2, s2len, read);
707 return __xnu_strbufcasecmp(s1, s1len, s2, s2len);
708 }
709
710 #define strbufcasecmp_2(A, B) ({ \
711 __xnu_assert_is_array(A, "first argument is not an array"); \
712 __xnu_assert_is_array(B, "second argument is not an array"); \
713 (strbufcasecmp)((A), sizeof(A), (B), sizeof(B)); \
714 })
715 #define strbufcasecmp_4 (strbufcasecmp)
716 #define strbufcasecmp(...) __xnu_argc_overload(strbufcasecmp, __VA_ARGS__)
717
718
719 #if __has_builtin(__builtin_strchr)
720 __xnu_string_inline
721 char *__null_terminated
strchr(const char * const s __xnu_force_overload,int c)722 strchr(const char *const /* __null_terminated */ s __xnu_force_overload, int c)
723 {
724 return __unsafe_forge_null_terminated(char *, __builtin_strchr(s, c));
725 }
726 #endif
727
728
729 #if XNU_KERNEL_PRIVATE /* rdar://103276672 */
730 extern char *__null_terminated strrchr(const char *__null_terminated s, int c) __stateful_pure;
731
732 #if __has_builtin(__builtin_strrchr) && !__has_ptrcheck /* rdar://103265304 */
733 __xnu_string_inline
734 char *__null_terminated
strrchr(const char * const __null_terminated s __xnu_force_overload,int c)735 strrchr(const char *const __null_terminated s __xnu_force_overload, int c)
736 {
737 return __builtin_strrchr(s, c);
738 }
739 #endif
740 #endif
741
742
743 extern char *__null_terminated strnstr(const char *__null_terminated s, const char *__null_terminated find, size_t slen) __stateful_pure;
744
745
746 extern size_t strlcpy(char *__counted_by(n) dst, const char *__null_terminated src, size_t n);
747
748 __xnu_string_inline
749 size_t
strlcpy(char * const dst __xnu_pass_member_size __counted_by (n),const char * const src __null_terminated,size_t n)750 strlcpy(
751 char *const dst __xnu_pass_member_size __counted_by(n),
752 const char *const src __null_terminated,
753 size_t n)
754 __xnu_member_size_precondition(dst, n, "write overflow")
755 {
756 extern size_t __xnu_strlcpy(
757 char * __counted_by(n),
758 const char *__null_terminated,
759 size_t n) __asm("_strlcpy");
760
761 __xnu_member_size_check(dst, n, write);
762 #if __has_builtin(__builtin_strlcpy)
763 return __builtin_strlcpy(dst, src, n);
764 #else
765 return __xnu_strlcpy(dst, src, n);
766 #endif
767 }
768
769
770 /*
771 * strbufcpy returns its destination as a NUL-terminated string, which makes a
772 * difference when -fbounds-safety is enabled.
773 * See docs/primitives/string-handling.md for more information.
774 */
775 extern const char *__null_terminated
776 strbufcpy(
777 char *__counted_by(dstsz) dst,
778 size_t dstsz,
779 const char *__counted_by(srcsz) src,
780 size_t srcsz);
781
782 __xnu_string_inline
783 const char *
strbufcpy(char * const dst __xnu_pass_member_size __counted_by (dstsz),size_t dstsz,const char * const src __xnu_pass_member_size __counted_by (srcsz),size_t srcsz)784 strbufcpy(
785 char *const dst __xnu_pass_member_size __counted_by(dstsz),
786 size_t dstsz,
787 const char *const src __xnu_pass_member_size __counted_by(srcsz),
788 size_t srcsz)
789 __xnu_member_size_precondition(dst, dstsz, "write overflow")
790 __xnu_member_size_precondition(src, srcsz, "read overflow")
791 {
792 extern const char *__xnu_strbufcpy(
793 char *__counted_by(dstsz) dst,
794 size_t dstsz,
795 const char *__counted_by(srcsz) src,
796 size_t srcsz) __asm("_strbufcpy");
797
798 __xnu_member_size_check(dst, dstsz, write);
799 __xnu_member_size_check(src, srcsz, read);
800 return __xnu_strbufcpy(dst, dstsz, src, srcsz);
801 }
802
803 #define strbufcpy_2(DST, SRC) ({ \
804 __xnu_assert_is_array(DST, "dst is not an array"); \
805 __xnu_assert_is_array(SRC, "src is not an array"); \
806 (strbufcpy)((DST), sizeof(DST), (SRC), sizeof(SRC)); \
807 })
808 #define strbufcpy_4 (strbufcpy)
809 #define strbufcpy(...) __xnu_argc_overload(strbufcpy, __VA_ARGS__)
810
811 extern size_t strlcat(char *__counted_by(n) dst, const char *__null_terminated src, size_t n);
812
813 __xnu_string_inline
814 size_t
strlcat(char * const dst __xnu_pass_member_size __counted_by (n),const char * const src __null_terminated,size_t n)815 strlcat(
816 char *const dst __xnu_pass_member_size __counted_by(n),
817 const char *const src __null_terminated,
818 size_t n)
819 __xnu_member_size_precondition(dst, n, "write overflow")
820 {
821 extern size_t __xnu_strlcat(
822 char * __sized_by(n),
823 const char *__null_terminated,
824 size_t n) __asm("_strlcat");
825
826 __xnu_member_size_check(dst, n, write);
827 #if __has_builtin(__builtin_strlcat)
828 return __builtin_strlcat(dst, src, n);
829 #else
830 return __xnu_strlcat(dst, src, n);
831 #endif
832 }
833
834
835 /*
836 * strbufcat returns its destination as a NUL-terminated string, which makes a
837 * difference when -fbounds-safety is enabled.
838 * See docs/primitives/string-handling.md for more information.
839 */
840 extern const char *__null_terminated
841 strbufcat(
842 char *__counted_by(dstsz) dst,
843 size_t dstsz,
844 const char *__counted_by(srcsz) src,
845 size_t srcsz);
846
847 __xnu_string_inline
848 const char *
strbufcat(char * const dst __xnu_pass_member_size __counted_by (dstsz),size_t dstsz,const char * const src __xnu_pass_member_size __counted_by (srcsz),size_t srcsz)849 strbufcat(
850 char *const dst __xnu_pass_member_size __counted_by(dstsz),
851 size_t dstsz,
852 const char *const src __xnu_pass_member_size __counted_by(srcsz),
853 size_t srcsz)
854 __xnu_member_size_precondition(dst, dstsz, "write overflow")
855 __xnu_member_size_precondition(src, srcsz, "read overflow")
856 {
857 extern const char *__xnu_strbufcat(
858 char *__counted_by(dstsz) dst,
859 size_t dstsz,
860 const char *__counted_by(srcsz) src,
861 size_t srcsz) __asm("_strbufcat");
862
863 __xnu_member_size_check(dst, dstsz, write);
864 __xnu_member_size_check(src, srcsz, read);
865 return __xnu_strbufcat(dst, dstsz, src, srcsz);
866 }
867
868 #define strbufcat_2(DST, SRC) ({ \
869 __xnu_assert_is_array(DST, "dst is not an array"); \
870 __xnu_assert_is_array(SRC, "src is not an array"); \
871 (strbufcat)((DST), sizeof(DST), (SRC), sizeof(SRC)); \
872 })
873 #define strbufcat_4 (strbufcat)
874 #define strbufcat(...) __xnu_argc_overload(strbufcat, __VA_ARGS__)
875
876 #pragma mark deprecated functions
877 #if !__has_ptrcheck && !__has_include(<__xnu_libcxx_sentinel.h>)
878
879 /*
880 * char *strncat(char *dst, const char *src, size_t n);
881 * char *strncpy(char *dst, const char *src, size_t n);
882 *
883 * char *strcat(char *dst, const char *src);
884 * char *strcpy(char *, const char *);
885 *
886 * char *STRDUP(const char *, int);
887 */
888
889 __deprecated_msg("use strlcat")
890 __kpi_deprecated_arm64_macos_unavailable
891 extern char *strncat(char *dst, const char *src, size_t n);
892 #if __XNU_FORTIFY_SOURCE && __has_builtin(__builtin___strncat_chk)
893 #define strncat(dst, src, n) __builtin___strncat_chk(dst, src, n, __xnu_member_size(dst))
894 #endif
895
896
897 __deprecated_msg("use strlcpy")
898 __kpi_deprecated_arm64_macos_unavailable
899 extern char *strncpy(char *dst, const char *src, size_t n);
900 #if __XNU_FORTIFY_SOURCE && __has_builtin(__builtin___strncpy_chk)
901 #define strncpy(dst, src, n) __builtin___strncpy_chk(dst, src, n, __xnu_member_size(dst))
902 #endif
903
904 __deprecated_msg("use strlcpy")
905 __kpi_deprecated_arm64_macos_unavailable
906 extern char *strcpy(char *, const char *);
907 #if __XNU_FORTIFY_SOURCE && __has_builtin(__builtin___strcpy_chk)
908 /* rdar://103287225 */
909 #define strcpy(dst, src, len) __builtin___strcpy_chk(dst, src, __xnu_member_size(dst))
910 #endif
911
912 __deprecated_msg("use strlcat")
913 __kpi_deprecated_arm64_macos_unavailable
914 extern char *strcat(char *dst, const char *src);
915 #if __XNU_FORTIFY_SOURCE && __has_builtin(__builtin___strcat_chk)
916 #define strcat(dst, src) __builtin___strcat_chk(dst, src, __xnu_member_size(dst))
917 #endif
918
919 #if XNU_PLATFORM_MacOSX
920 #ifndef KERNEL_PRIVATE
921 extern char *STRDUP(const char *, int);
922 #endif
923 #endif /* XNU_PLATFORM_MacOSX */
924
925 #endif /* !__has_ptrcheck && !__has_include(<__xnu_libcxx_sentinel.h>) */
926
927 #if __has_include(<san/memintrinsics.h>)
928 #include <san/memintrinsics.h>
929 #endif
930
931 __END_DECLS
932
933 #endif /* _STRING_H_ */
934
935 #endif
936