xref: /xnu-11215/osfmk/libsa/string.h (revision 8d741a5d)
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