1 | /* |
2 | * Copyright (c) 2000-2020 Apple 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 | * @OSF_COPYRIGHT@ |
30 | */ |
31 | /* |
32 | *(C)UNIX System Laboratories, Inc. all or some portions of this file are |
33 | * derived from material licensed to the University of California by |
34 | * American Telephone and Telegraph Co. or UNIX System Laboratories, |
35 | * Inc. and are reproduced herein with the permission of UNIX System |
36 | * Laboratories, Inc. |
37 | */ |
38 | |
39 | /* |
40 | * Mach Operating System |
41 | * Copyright (c) 1993,1991,1990,1989,1988 Carnegie Mellon University |
42 | * All Rights Reserved. |
43 | * |
44 | * Permission to use, copy, modify and distribute this software and its |
45 | * documentation is hereby granted, provided that both the copyright |
46 | * notice and this permission notice appear in all copies of the |
47 | * software, derivative works or modified versions, and any portions |
48 | * thereof, and that both notices appear in supporting documentation. |
49 | * |
50 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" |
51 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR |
52 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. |
53 | * |
54 | * Carnegie Mellon requests users of this software to return to |
55 | * |
56 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU |
57 | * School of Computer Science |
58 | * Carnegie Mellon University |
59 | * Pittsburgh PA 15213-3890 |
60 | * |
61 | * any improvements or extensions that they make and grant Carnegie Mellon |
62 | * the rights to redistribute these changes. |
63 | */ |
64 | /* |
65 | */ |
66 | /* |
67 | * Copyright (c) 1988 Regents of the University of California. |
68 | * All rights reserved. |
69 | * |
70 | * Redistribution and use in source and binary forms, with or without |
71 | * modification, are permitted provided that the following conditions |
72 | * are met: |
73 | * 1. Redistributions of source code must retain the above copyright |
74 | * notice, this list of conditions and the following disclaimer. |
75 | * 2. Redistributions in binary form must reproduce the above copyright |
76 | * notice, this list of conditions and the following disclaimer in the |
77 | * documentation and/or other materials provided with the distribution. |
78 | * 3. All advertising materials mentioning features or use of this software |
79 | * must display the following acknowledgement: |
80 | * This product includes software developed by the University of |
81 | * California, Berkeley and its contributors. |
82 | * 4. Neither the name of the University nor the names of its contributors |
83 | * may be used to endorse or promote products derived from this software |
84 | * without specific prior written permission. |
85 | * |
86 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
87 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
88 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
89 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
90 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
91 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
92 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
93 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
94 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
95 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
96 | * SUCH DAMAGE. |
97 | */ |
98 | |
99 | /* |
100 | * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> |
101 | * All rights reserved. |
102 | * |
103 | * Redistribution and use in source and binary forms, with or without |
104 | * modification, are permitted provided that the following conditions |
105 | * are met: |
106 | * 1. Redistributions of source code must retain the above copyright |
107 | * notice, this list of conditions and the following disclaimer. |
108 | * 2. Redistributions in binary form must reproduce the above copyright |
109 | * notice, this list of conditions and the following disclaimer in the |
110 | * documentation and/or other materials provided with the distribution. |
111 | * 3. The name of the author may not be used to endorse or promote products |
112 | * derived from this software without specific prior written permission. |
113 | * |
114 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
115 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
116 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
117 | * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
118 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
119 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
120 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
121 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
122 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
123 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
124 | */ |
125 | |
126 | /* |
127 | * NOTICE: This file was modified by McAfee Research in 2004 to introduce |
128 | * support for mandatory and extensible security protections. This notice |
129 | * is included in support of clause 2.2 (b) of the Apple Public License, |
130 | * Version 2.0. |
131 | */ |
132 | /* |
133 | * Random device subroutines and stubs. |
134 | */ |
135 | |
136 | #if KERNEL |
137 | |
138 | #if defined (__i386__) || defined (__x86_64__) |
139 | #include "i386/string.h" |
140 | #elif defined (__arm__) || defined (__arm64__) |
141 | #include "arm/string.h" |
142 | #else |
143 | #error architecture not supported |
144 | #endif |
145 | |
146 | #include <vm/vm_kern.h> |
147 | #include <kern/misc_protos.h> |
148 | #include <kern/telemetry.h> |
149 | #include <libsa/stdlib.h> |
150 | #include <sys/malloc.h> |
151 | #include <libkern/section_keywords.h> |
152 | #include <machine/string.h> /* __arch_* defines */ |
153 | |
154 | /* |
155 | * Note to implementers, when adding new string/memory functions |
156 | * |
157 | * - add a prototype/wrapper to osfmk/libsa/string.h, |
158 | * and an impl prototype to osfmk/machine/string.h. |
159 | * |
160 | * - if the function has a "chk" variant, add support to osfmk/libsa/string.h |
161 | * and the implementation for the checked variant at the end of this file. |
162 | * |
163 | * - define the function with the "impl" name and wrap it inside |
164 | * an #ifndef __arch_${function} block to allow each architecture |
165 | * to provide an optimized version if they so desire. |
166 | */ |
167 | |
168 | static_assert(__arch_bcopy, "architecture must provide bcopy" ); |
169 | static_assert(__arch_bzero, "architecture must provide bzero" ); |
170 | static_assert(__arch_memcpy, "architecture must provide memcpy" ); |
171 | static_assert(__arch_memmove, "architecture must provide memmove" ); |
172 | static_assert(__arch_memset, "architecture must provide memset" ); |
173 | |
174 | #endif /* KERNEL */ |
175 | |
176 | #ifndef __arch_bcmp |
177 | int |
178 | bcmp_impl(const void *pa, const void *pb, size_t len) |
179 | { |
180 | const char *a = (const char *)pa; |
181 | const char *b = (const char *)pb; |
182 | |
183 | if (len == 0) { |
184 | return 0; |
185 | } |
186 | |
187 | do{ |
188 | if (*a++ != *b++) { |
189 | break; |
190 | } |
191 | } while (--len); |
192 | |
193 | /* |
194 | * Check for the overflow case but continue to handle the non-overflow |
195 | * case the same way just in case someone is using the return value |
196 | * as more than zero/non-zero |
197 | */ |
198 | if ((len & 0xFFFFFFFF00000000ULL) && !(len & 0x00000000FFFFFFFFULL)) { |
199 | return ~0; |
200 | } else { |
201 | return (int)len; |
202 | } |
203 | } |
204 | #endif /* __arch_bcmp */ |
205 | |
206 | #ifndef __arch_memcmp |
207 | MARK_AS_HIBERNATE_TEXT |
208 | int |
209 | memcmp_impl(const void *s1, const void *s2, size_t n) |
210 | { |
211 | if (n != 0) { |
212 | const unsigned char *p1 = s1, *p2 = s2; |
213 | |
214 | do { |
215 | if (*p1++ != *p2++) { |
216 | return *--p1 - *--p2; |
217 | } |
218 | } while (--n != 0); |
219 | } |
220 | return 0; |
221 | } |
222 | #endif /* __arch_memcmp */ |
223 | |
224 | #ifndef __arch_memcmp_zero_ptr_aligned |
225 | unsigned long |
226 | memcmp_zero_ptr_aligned_impl(const void *addr, size_t size) |
227 | { |
228 | const uint64_t *p = (const uint64_t *)addr; |
229 | uint64_t a = p[0]; |
230 | |
231 | static_assert(sizeof(unsigned long) == sizeof(uint64_t), |
232 | "uint64_t is not the same size as unsigned long" ); |
233 | |
234 | if (size < 4 * sizeof(uint64_t)) { |
235 | if (size > 1 * sizeof(uint64_t)) { |
236 | a |= p[1]; |
237 | if (size > 2 * sizeof(uint64_t)) { |
238 | a |= p[2]; |
239 | } |
240 | } |
241 | } else { |
242 | size_t count = size / sizeof(uint64_t); |
243 | uint64_t b = p[1]; |
244 | uint64_t c = p[2]; |
245 | uint64_t d = p[3]; |
246 | |
247 | /* |
248 | * note: for sizes not a multiple of 32 bytes, this will load |
249 | * the bytes [size % 32 .. 32) twice which is ok |
250 | */ |
251 | while (count > 4) { |
252 | count -= 4; |
253 | a |= p[count + 0]; |
254 | b |= p[count + 1]; |
255 | c |= p[count + 2]; |
256 | d |= p[count + 3]; |
257 | } |
258 | |
259 | a |= b | c | d; |
260 | } |
261 | |
262 | return a; |
263 | } |
264 | #endif /* __arch_memcmp_zero_ptr_aligned */ |
265 | |
266 | /* |
267 | * Abstract: |
268 | * strlen returns the number of characters in "string" preceeding |
269 | * the terminating null character. |
270 | */ |
271 | #ifndef __arch_strlen |
272 | size_t |
273 | strlen_impl(const char *string) |
274 | { |
275 | const char *ret = string; |
276 | |
277 | while (*string++ != '\0') { |
278 | continue; |
279 | } |
280 | return (size_t)(string - 1 - ret); |
281 | } |
282 | #endif /* __arch_strlen */ |
283 | |
284 | /* |
285 | * Does the same thing as strlen, except only looks up |
286 | * to max chars inside the buffer. |
287 | * Taken from archive/kern-stuff/sbf_machine.c in |
288 | * seatbelt. |
289 | * inputs: |
290 | * s string whose length is to be measured |
291 | * max maximum length of string to search for null |
292 | * outputs: |
293 | * length of s or max; whichever is smaller |
294 | */ |
295 | #ifndef __arch_strnlen |
296 | size_t |
297 | strnlen_impl(const char *s, size_t max) |
298 | { |
299 | const char *es = s + max, *p = s; |
300 | while (p != es && *p) { |
301 | p++; |
302 | } |
303 | |
304 | return (size_t)(p - s); |
305 | } |
306 | #endif /* __arch_strlen */ |
307 | |
308 | /* |
309 | * Abstract: |
310 | * strcmp (s1, s2) compares the strings "s1" and "s2". |
311 | * It returns 0 if the strings are identical. It returns |
312 | * > 0 if the first character that differs in the two strings |
313 | * is larger in s1 than in s2 or if s1 is longer than s2 and |
314 | * the contents are identical up to the length of s2. |
315 | * It returns < 0 if the first differing character is smaller |
316 | * in s1 than in s2 or if s1 is shorter than s2 and the |
317 | * contents are identical upto the length of s1. |
318 | * Deprecation Warning: |
319 | * strcmp() is being deprecated. Please use strncmp() instead. |
320 | */ |
321 | #ifndef __arch_strcmp |
322 | int |
323 | strcmp_impl(const char *s1, const char *s2) |
324 | { |
325 | int a, b; |
326 | |
327 | do { |
328 | a = *s1++; |
329 | b = *s2++; |
330 | if (a != b) { |
331 | return a - b; /* includes case when |
332 | * 'a' is zero and 'b' is not zero |
333 | * or vice versa */ |
334 | } |
335 | } while (a != '\0'); |
336 | |
337 | return 0; /* both are zero */ |
338 | } |
339 | #endif /* __arch_strcmp */ |
340 | |
341 | /* |
342 | * Abstract: |
343 | * strncmp (s1, s2, n) compares the strings "s1" and "s2" |
344 | * in exactly the same way as strcmp does. Except the |
345 | * comparison runs for at most "n" characters. |
346 | */ |
347 | |
348 | #ifndef __arch_strncmp |
349 | int |
350 | strncmp_impl(const char *s1, const char *s2, size_t n) |
351 | { |
352 | return strbufcmp_impl(s1, n, s2, n); |
353 | } |
354 | #endif /* __arch_strncmp */ |
355 | |
356 | #ifndef __arch_strlcmp |
357 | int |
358 | strlcmp_impl(const char *s1, const char *s2, size_t n) |
359 | { |
360 | return strbufcmp_impl(s1, n, s2, strlen(s: s2)); |
361 | } |
362 | #endif |
363 | |
364 | #ifndef __arch_strbufcmp |
365 | int |
366 | strbufcmp_impl( |
367 | const char *__counted_by(alen)a, |
368 | size_t alen, |
369 | const char *__counted_by(blen)b, |
370 | size_t blen) |
371 | { |
372 | int ca, cb; |
373 | size_t i, len; |
374 | |
375 | len = alen < blen ? alen : blen; |
376 | for (i = 0; i < len; ++i) { |
377 | ca = a[i]; |
378 | cb = b[i]; |
379 | if (ca != cb) { |
380 | return ca - cb; /* includes case when |
381 | * 'a' is zero and 'b' is not zero |
382 | * or vice versa */ |
383 | } |
384 | if (ca == '\0') { |
385 | return 0; /* both are zero */ |
386 | } |
387 | } |
388 | |
389 | /* if either string is not NUL-terminated, pretend the next character is a |
390 | * NUL */ |
391 | if (alen < blen) { |
392 | return 0 - b[len]; |
393 | } |
394 | if (blen < alen) { |
395 | return a[len] - 0; |
396 | } |
397 | return 0; |
398 | } |
399 | #endif /* __arch_strbufcmp */ |
400 | |
401 | #ifndef __arch_strprefix |
402 | /* |
403 | * Return TRUE(1) if string 2 is a prefix of string 1. |
404 | */ |
405 | int |
406 | strprefix_impl(const char *s1, const char *s2) |
407 | { |
408 | int c; |
409 | |
410 | while ((c = *s2++) != '\0') { |
411 | if (c != *s1++) { |
412 | return 0; |
413 | } |
414 | } |
415 | return 1; |
416 | } |
417 | #endif /* __arch_strprefix */ |
418 | |
419 | |
420 | // |
421 | // Lame implementation just for use by strcasecmp/strncasecmp |
422 | // |
423 | __header_always_inline int |
424 | tolower(int ch) |
425 | { |
426 | if (ch >= 'A' && ch <= 'Z') { |
427 | ch = 'a' + (ch - 'A'); |
428 | } |
429 | |
430 | return ch; |
431 | } |
432 | |
433 | #ifndef __arch_strcasecmp |
434 | int |
435 | strcasecmp_impl(const char *s1, const char *s2) |
436 | { |
437 | const unsigned char *us1 = (const u_char *)s1, |
438 | *us2 = (const u_char *)s2; |
439 | |
440 | while (tolower(ch: *us1) == tolower(ch: *us2++)) { |
441 | if (*us1++ == '\0') { |
442 | return 0; |
443 | } |
444 | } |
445 | return tolower(ch: *us1) - tolower(ch: *--us2); |
446 | } |
447 | #endif /* __arch_strcasecmp */ |
448 | |
449 | #ifndef __arch_strncasecmp |
450 | int |
451 | strncasecmp_impl(const char *s1, const char *s2, size_t n) |
452 | { |
453 | return strbufcasecmp_impl(s1, n, s2, n); |
454 | } |
455 | #endif /* __arch_strncasecmp */ |
456 | |
457 | #ifndef __arch_strlcasecmp |
458 | int |
459 | strlcasecmp_impl(const char *s1, const char *s2, size_t n) |
460 | { |
461 | return strbufcasecmp_impl(s1, n, s2, strlen(s: s2)); |
462 | } |
463 | #endif |
464 | |
465 | #ifndef __arch_strbufcasecmp |
466 | int |
467 | strbufcasecmp_impl( |
468 | const char *__counted_by(alen)a, |
469 | size_t alen, |
470 | const char *__counted_by(blen)b, |
471 | size_t blen) |
472 | { |
473 | int ca, cb; |
474 | size_t i, len; |
475 | |
476 | len = alen < blen ? alen : blen; |
477 | for (i = 0; i < len; ++i) { |
478 | ca = tolower(ch: a[i]); |
479 | cb = tolower(ch: b[i]); |
480 | if (ca != cb) { |
481 | return ca - cb; /* includes case when |
482 | * 'a' is zero and 'b' is not zero |
483 | * or vice versa */ |
484 | } |
485 | if (ca == '\0') { |
486 | return 0; /* both are zero */ |
487 | } |
488 | } |
489 | |
490 | /* if either string is not NUL-terminated, pretend the next character is a |
491 | * NUL */ |
492 | if (alen < blen) { |
493 | return 0 - tolower(ch: b[len]); |
494 | } |
495 | if (blen < alen) { |
496 | return tolower(ch: a[len]) - 0; |
497 | } |
498 | return 0; |
499 | } |
500 | #endif /* __arch_strbufcasecmp */ |
501 | |
502 | #ifndef __arch_strchr |
503 | char * |
504 | strchr_impl(const char *s, int c) |
505 | { |
506 | if (!s) { |
507 | return NULL; |
508 | } |
509 | |
510 | do { |
511 | if (*s == c) { |
512 | return __CAST_AWAY_QUALIFIER(s, const, char *); |
513 | } |
514 | } while (*s++); |
515 | |
516 | return NULL; |
517 | } |
518 | #endif /* __arch_strchr */ |
519 | |
520 | #ifndef __arch_strrchr |
521 | char * |
522 | strrchr_impl(const char *s, int c) |
523 | { |
524 | const char *found = NULL; |
525 | |
526 | if (!s) { |
527 | return NULL; |
528 | } |
529 | |
530 | do { |
531 | if (*s == c) { |
532 | found = s; |
533 | } |
534 | } while (*s++); |
535 | |
536 | return __CAST_AWAY_QUALIFIER(found, const, char *); |
537 | } |
538 | #endif /* __arch_strchr */ |
539 | |
540 | #if CONFIG_VSPRINTF |
541 | /* |
542 | * Abstract: |
543 | * strcpy copies the contents of the string "from" including |
544 | * the null terminator to the string "to". A pointer to "to" |
545 | * is returned. |
546 | * Deprecation Warning: |
547 | * strcpy() is being deprecated. Please use strlcpy() instead. |
548 | */ |
549 | char * |
550 | strcpy_impl(char *to, const char *from) |
551 | { |
552 | char *ret = to; |
553 | |
554 | while ((*to++ = *from++) != '\0') { |
555 | continue; |
556 | } |
557 | |
558 | return ret; |
559 | } |
560 | #endif |
561 | |
562 | /* |
563 | * Abstract: |
564 | * strncpy copies "count" characters from the "from" string to |
565 | * the "to" string. If "from" contains less than "count" characters |
566 | * "to" will be padded with null characters until exactly "count" |
567 | * characters have been written. The return value is a pointer |
568 | * to the "to" string. |
569 | */ |
570 | #ifndef __arch_strncpy |
571 | char * |
572 | strncpy_impl(char * dst, const char * src, size_t maxlen) |
573 | { |
574 | const size_t srclen = strnlen_impl(s: src, maxlen); |
575 | if (srclen < maxlen) { |
576 | memcpy_impl(dst, src, srclen); |
577 | memset_impl(dst + srclen, c: 0, maxlen - srclen); |
578 | } else { |
579 | memcpy_impl(dst, src, maxlen); |
580 | } |
581 | return dst; |
582 | } |
583 | #endif /* __arch_strncpy */ |
584 | |
585 | /* |
586 | * atoi: |
587 | * |
588 | * This function converts an ascii string into an integer. |
589 | * |
590 | * input : string |
591 | * output : a number |
592 | */ |
593 | |
594 | int |
595 | atoi(const char *cp) |
596 | { |
597 | int number; |
598 | |
599 | for (number = 0; ('0' <= *cp) && (*cp <= '9'); cp++) { |
600 | number = (number * 10) + (*cp - '0'); |
601 | } |
602 | |
603 | return number; |
604 | } |
605 | |
606 | /* |
607 | * convert an integer to an ASCII string. |
608 | * inputs: |
609 | * num integer to be converted |
610 | * str string pointer. |
611 | * |
612 | * outputs: |
613 | * pointer to string start. |
614 | */ |
615 | |
616 | char * |
617 | itoa(int num, char *str) |
618 | { |
619 | char digits[11]; |
620 | char *dp; |
621 | char *cp = str; |
622 | |
623 | if (num == 0) { |
624 | *cp++ = '0'; |
625 | } else { |
626 | dp = digits; |
627 | while (num) { |
628 | *dp++ = '0' + num % 10; |
629 | num /= 10; |
630 | } |
631 | while (dp != digits) { |
632 | *cp++ = *--dp; |
633 | } |
634 | } |
635 | *cp++ = '\0'; |
636 | |
637 | return str; |
638 | } |
639 | |
640 | #if CONFIG_VSPRINTF |
641 | /* |
642 | * Deprecation Warning: |
643 | * strcat() is being deprecated. Please use strlcat() instead. |
644 | */ |
645 | char * |
646 | strcat_impl(char *dest, const char *src) |
647 | { |
648 | char *old = dest; |
649 | |
650 | while (*dest) { |
651 | ++dest; |
652 | } |
653 | while ((*dest++ = *src++)) { |
654 | ; |
655 | } |
656 | return old; |
657 | } |
658 | #endif |
659 | |
660 | /* |
661 | * Appends src to string dst of size siz (unlike strncat, siz is the |
662 | * full size of dst, not space left). At most siz-1 characters |
663 | * will be copied. Always NUL terminates (unless siz <= strlen(dst)). |
664 | * Returns strlen(src) + MIN(siz, strlen(initial dst)). |
665 | * If retval >= siz, truncation occurred. |
666 | */ |
667 | #ifndef __arch_strlcat |
668 | size_t |
669 | strlcat_impl(char *dst, const char *src, size_t siz) |
670 | { |
671 | char *d = dst; |
672 | const char *s = src; |
673 | size_t n = siz; |
674 | size_t dlen; |
675 | |
676 | /* Find the end of dst and adjust bytes left but don't go past end */ |
677 | while (n-- != 0 && *d != '\0') { |
678 | d++; |
679 | } |
680 | dlen = (size_t)(d - dst); |
681 | n = siz - dlen; |
682 | |
683 | if (n == 0) { |
684 | return dlen + strlen_impl(s); |
685 | } |
686 | while (*s != '\0') { |
687 | if (n != 1) { |
688 | *d++ = *s; |
689 | n--; |
690 | } |
691 | s++; |
692 | } |
693 | *d = '\0'; |
694 | |
695 | return dlen + (size_t)(s - src); /* count does not include NUL */ |
696 | } |
697 | #endif /* __arch_strlcat */ |
698 | |
699 | /* |
700 | * Append src string to dst. The operation stops once *any* of the following |
701 | * conditions is met: |
702 | * * when `dst` is filled with `dstsz` characters; |
703 | * * when `srcsz` characters have been copied; |
704 | * * when a NUL character has been copied from `src` to `dst`. |
705 | * `dst` is always NUL-terminated, truncating `src` as needed. |
706 | * If `dstsz` is 0, the function returns NULL. Otherwise, it returns `dst`, |
707 | * regardless of whether there was free space in dst to append any characters. |
708 | * This function is most useful to concatenate a fixed-size string to another. |
709 | */ |
710 | #ifndef __arch_strbufcat |
711 | const char *__null_terminated |
712 | strbufcat_impl( |
713 | char *__counted_by(dstsz)dst, |
714 | size_t dstsz, |
715 | const char *__counted_by(srcsz)src, |
716 | size_t srcsz) |
717 | { |
718 | size_t len; |
719 | if (dstsz == 0) { |
720 | return NULL; |
721 | } |
722 | |
723 | len = strnlen_impl(s: dst, dstsz); |
724 | strbufcpy_impl(dst + len, dstsz - len, src, srcsz); |
725 | return dst; |
726 | } |
727 | #endif /* __arch_strbufcat */ |
728 | |
729 | /* |
730 | * Copy src to string dst of size siz. At most siz-1 characters |
731 | * will be copied. Always NUL terminates (unless siz == 0). |
732 | * Returns strlen(src); if retval >= siz, truncation occurred. |
733 | */ |
734 | #ifndef __arch_strlcpy |
735 | size_t |
736 | strlcpy_impl(char * dst, const char * src, size_t maxlen) |
737 | { |
738 | const size_t srclen = strlen_impl(src); |
739 | if (srclen + 1 < maxlen) { |
740 | memcpy_impl(dst, src, srclen + 1); |
741 | } else if (maxlen != 0) { |
742 | memcpy_impl(dst, src, maxlen - 1); |
743 | dst[maxlen - 1] = '\0'; |
744 | } |
745 | return srclen; |
746 | } |
747 | #endif /* __arch_strlcpy */ |
748 | |
749 | /* |
750 | * Copy src string to dst. The copy stops once *any* of the following conditions |
751 | * is met: |
752 | * * when `dstsz` characters have been copied; |
753 | * * when `srcsz` characters have been copied; |
754 | * * when a NUL character has been copied from `src` to `dst`. |
755 | * `dst` is always NUL-terminated, truncating `src` as needed. |
756 | * If `dstsz` is 0, the function returns NULL. Otherwise, it returns `dst`. |
757 | * This function is most useful to copy a fixed-size string from one buffer to |
758 | * another. |
759 | */ |
760 | #ifndef __arch_strbufcpy |
761 | const char *__null_terminated |
762 | strbufcpy_impl( |
763 | char *__counted_by(dstsz)dst, |
764 | size_t dstsz, |
765 | const char *__counted_by(srcsz)src, |
766 | size_t srcsz) |
767 | { |
768 | size_t copymax; |
769 | |
770 | if (dstsz == 0) { |
771 | return NULL; |
772 | } |
773 | |
774 | copymax = strnlen_impl(s: src, srcsz); |
775 | if (copymax < dstsz) { |
776 | memmove_impl(dst, src, copymax); |
777 | dst[copymax] = 0; |
778 | } else { |
779 | memmove_impl(dst, src, dstsz); |
780 | dst[dstsz - 1] = 0; |
781 | } |
782 | return __unsafe_forge_null_terminated(const char *__null_terminated, dst); |
783 | } |
784 | #endif /* __arch_strbufcpy */ |
785 | |
786 | #ifndef __arch_strncat |
787 | char * |
788 | strncat_impl(char *s1, const char *s2, size_t n) |
789 | { |
790 | if (n != 0) { |
791 | char *d = s1; |
792 | const char *s = s2; |
793 | |
794 | while (*d != 0) { |
795 | d++; |
796 | } |
797 | do { |
798 | if ((*d = *s++) == '\0') { |
799 | break; |
800 | } |
801 | d++; |
802 | } while (--n != 0); |
803 | *d = '\0'; |
804 | } |
805 | |
806 | return __CAST_AWAY_QUALIFIER(s1, const, char *); |
807 | } |
808 | #endif /* __arch_strncat */ |
809 | |
810 | #ifndef __arch_strnstr |
811 | char * |
812 | strnstr_impl(const char *s, const char *find, size_t slen) |
813 | { |
814 | char c, sc; |
815 | size_t len; |
816 | |
817 | if ((c = *find++) != '\0') { |
818 | len = strlen_impl(find); |
819 | do { |
820 | do { |
821 | if ((sc = *s++) == '\0' || slen-- < 1) { |
822 | return NULL; |
823 | } |
824 | } while (sc != c); |
825 | if (len > slen) { |
826 | return NULL; |
827 | } |
828 | } while (strncmp_impl(s, find, len) != 0); |
829 | s--; |
830 | } |
831 | |
832 | return __CAST_AWAY_QUALIFIER(s, const, char *); |
833 | } |
834 | #endif /* __arch_strnstr */ |
835 | |
836 | void * __memcpy_chk(void *dst, void const *src, size_t s, size_t chk_size); |
837 | void * __memmove_chk(void *dst, void const *src, size_t s, size_t chk_size); |
838 | void * __memset_chk(void *dst, int c, size_t s, size_t chk_size); |
839 | size_t __strlcpy_chk(char *dst, char const *src, size_t s, size_t chk_size); |
840 | size_t __strlcat_chk(char *dst, char const *src, size_t s, size_t chk_size); |
841 | char * __strncpy_chk(char *restrict dst, char *restrict src, size_t len, size_t chk_size); |
842 | char * __strncat_chk(char *restrict dst, const char *restrict src, size_t len, size_t chk_size); |
843 | char * __strcpy_chk(char *restrict dst, const char *restrict src, size_t chk_size); |
844 | char * __strcat_chk(char *restrict dst, const char *restrict src, size_t chk_size); |
845 | |
846 | void * |
847 | __memcpy_chk(void *dst, void const *src, size_t s, size_t chk_size) |
848 | { |
849 | if (__improbable(chk_size < s)) { |
850 | panic("__memcpy_chk object size check failed: dst %p, src %p, (%zu < %zu)" , dst, src, chk_size, s); |
851 | } |
852 | return memcpy_impl(dst, src, s); |
853 | } |
854 | |
855 | void * |
856 | __memmove_chk(void *dst, void const *src, size_t s, size_t chk_size) |
857 | { |
858 | if (__improbable(chk_size < s)) { |
859 | panic("__memmove_chk object size check failed: dst %p, src %p, (%zu < %zu)" , dst, src, chk_size, s); |
860 | } |
861 | return memmove_impl(dst, src, s); |
862 | } |
863 | |
864 | void * |
865 | __memset_chk(void *dst, int c, size_t s, size_t chk_size) |
866 | { |
867 | if (__improbable(chk_size < s)) { |
868 | panic("__memset_chk object size check failed: dst %p, c %c, (%zu < %zu)" , dst, c, chk_size, s); |
869 | } |
870 | return memset_impl(dst, c, s); |
871 | } |
872 | |
873 | size_t |
874 | __strlcat_chk(char *dst, char const *src, size_t s, size_t chk_size) |
875 | { |
876 | if (__improbable(chk_size < s)) { |
877 | panic("__strlcat_chk object size check failed: dst %p, src %p, (%zu < %zu)" , dst, src, chk_size, s); |
878 | } |
879 | return strlcat_impl(dst, src, siz: s); |
880 | } |
881 | |
882 | size_t |
883 | __strlcpy_chk(char *dst, char const *src, size_t s, size_t chk_size) |
884 | { |
885 | if (__improbable(chk_size < s)) { |
886 | panic("__strlcpy_chk object size check failed: dst %p, src %p, (%zu < %zu)" , dst, src, chk_size, s); |
887 | } |
888 | return strlcpy_impl(dst, src, maxlen: s); |
889 | } |
890 | |
891 | char * |
892 | __strncpy_chk(char *restrict dst, char *restrict src, |
893 | size_t len, size_t chk_size) |
894 | { |
895 | if (__improbable(chk_size < len)) { |
896 | panic("__strncpy_chk object size check failed: dst %p, src %p, (%zu < %zu)" , dst, src, chk_size, len); |
897 | } |
898 | return strncpy_impl(dst, src, maxlen: len); |
899 | } |
900 | |
901 | char * |
902 | __strncat_chk(char *restrict dst, const char *restrict src, |
903 | size_t len, size_t chk_size) |
904 | { |
905 | size_t len1 = strlen_impl(dst); |
906 | size_t len2 = strnlen_impl(s: src, len); |
907 | if (__improbable(chk_size < len1 + len2 + 1)) { |
908 | panic("__strncat_chk object size check failed: dst %p, src %p, (%zu < %zu + %zu + 1)" , dst, src, chk_size, len1, len2); |
909 | } |
910 | return strncat_impl(s1: dst, s2: src, n: len); |
911 | } |
912 | |
913 | char * |
914 | __strcpy_chk(char *restrict dst, const char *restrict src, size_t chk_size) |
915 | { |
916 | size_t len = strlen_impl(src); |
917 | if (__improbable(chk_size < len + 1)) { |
918 | panic("__strcpy_chk object size check failed: dst %p, src %p, (%zu < %zu + 1)" , dst, src, chk_size, len); |
919 | } |
920 | memcpy_impl(dst, src, len + 1); |
921 | return dst; |
922 | } |
923 | |
924 | char * |
925 | __strcat_chk(char *restrict dst, const char *restrict src, size_t chk_size) |
926 | { |
927 | size_t len1 = strlen_impl(dst); |
928 | size_t len2 = strlen_impl(src); |
929 | size_t required_len = len1 + len2 + 1; |
930 | if (__improbable(chk_size < required_len)) { |
931 | panic("__strcat_chk object size check failed: dst %p, src %p, (%zu < %zu + %zu + 1)" , dst, src, chk_size, len1, len2); |
932 | } |
933 | memcpy_impl(dst + len1, src, len2 + 1); |
934 | return dst; |
935 | } |
936 | |