2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 Optimized string handling code, including c11-compliant
41 "safe C library" variants.
44 #ifndef included_clib_string_h
45 #define included_clib_string_h
47 #include <vppinfra/clib.h> /* for CLIB_LINUX_KERNEL */
48 #include <vppinfra/vector.h>
49 #include <vppinfra/error_bootstrap.h>
50 #include <vppinfra/memcpy_x86_64.h>
52 #ifdef CLIB_LINUX_KERNEL
53 #include <linux/string.h>
60 #ifdef CLIB_STANDALONE
61 #include <vppinfra/standalone_string.h>
65 #include <x86intrin.h>
68 /* Exchanges source and destination. */
69 void clib_memswap (void *_a, void *_b, uword bytes);
72 static_always_inline void *
73 clib_memcpy_fast (void *restrict dst, const void *restrict src, size_t n)
76 "memcpy(src, dst, n) with src == NULL or dst == NULL is undefined "
78 #if defined(__COVERITY__)
79 return memcpy (dst, src, n);
80 #elif defined(__x86_64__)
81 clib_memcpy_x86_64 (dst, src, n);
84 return memcpy (dst, src, n);
88 static_always_inline void *
89 clib_memmove (void *dst, const void *src, size_t n)
98 for (uword i = n - 1; (i + 1) > 0; i--)
101 for (uword i = 0; i < n; i++)
107 #include <vppinfra/memcpy.h>
109 /* c-11 string manipulation variants */
125 * In order to provide smooth mapping from unsafe string API to the clib string
126 * macro, we often have to improvise s1max and s2max due to the additional
127 * arguments are required for implementing the safe API. This macro is used
128 * to provide the s1max/s2max. It is not perfect because the actual
129 * s1max/s2max may be greater than 4k and the mapping from the unsafe API to
130 * the macro would cause a regression. However, it is not terribly likely.
131 * So I bet against the odds.
133 #define CLIB_STRING_MACRO_MAX 4096
136 typedef uword rsize_t;
138 void clib_c11_violation (const char *s);
139 errno_t memcpy_s (void *__restrict__ dest, rsize_t dmax,
140 const void *__restrict__ src, rsize_t n);
142 always_inline errno_t
143 memcpy_s_inline (void *__restrict__ dest, rsize_t dmax,
144 const void *__restrict__ src, rsize_t n)
150 * Optimize constant-number-of-bytes calls without asking
151 * "too many questions for someone from New Jersey"
153 if (COMPILE_TIME_CONST (n))
155 clib_memcpy_fast (dest, src, n);
160 * call bogus if: src or dst NULL, trying to copy
161 * more data than we have space in dst, or src == dst.
162 * n == 0 isn't really "bad", so check first in the
163 * "wall-of-shame" department...
165 bad = (dest == 0) + (src == 0) + (n > dmax) + (dest == src) + (n == 0);
166 if (PREDICT_FALSE (bad != 0))
168 /* Not actually trying to copy anything is OK */
172 clib_c11_violation ("dest NULL");
174 clib_c11_violation ("src NULL");
176 clib_c11_violation ("n > dmax");
178 clib_c11_violation ("dest == src");
182 /* Check for src/dst overlap, which is not allowed */
183 low = (uword) (src < dest ? src : dest);
184 hi = (uword) (src < dest ? dest : src);
186 if (PREDICT_FALSE (low + (n - 1) >= hi))
188 clib_c11_violation ("src/dest overlap");
192 clib_memcpy_fast (dest, src, n);
197 * Note: $$$ This macro is a crutch. Folks need to manually
198 * inspect every extant clib_memcpy(...) call and
199 * attempt to provide a real destination buffer size
202 #define clib_memcpy(d,s,n) memcpy_s_inline(d,n,s,n)
204 errno_t memset_s (void *s, rsize_t smax, int c, rsize_t n);
206 always_inline errno_t
207 memset_s_inline (void *s, rsize_t smax, int c, rsize_t n)
211 bad = (s == 0) + (n > smax);
213 if (PREDICT_FALSE (bad != 0))
216 clib_c11_violation ("s NULL");
218 clib_c11_violation ("n > smax");
226 * This macro is not [so much of] a crutch.
227 * It's super-typical to write:
229 * ep = pool_get (<pool>);
230 * clib_memset(ep, 0, sizeof (*ep));
232 * The compiler should delete the not-so useful
233 * (n > smax) test. TBH the NULL pointer check isn't
234 * so useful in this case, but so be it.
236 #define clib_memset(s,c,n) memset_s_inline(s,n,c,n)
238 static_always_inline void
239 clib_memcpy_le (u8 * dst, u8 * src, u8 len, u8 max_len)
241 #if defined (CLIB_HAVE_VEC256)
242 u8x32 s0, s1, d0, d1;
243 u8x32 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
244 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
246 u8x32 lv = u8x32_splat (len);
247 u8x32 add = u8x32_splat (32);
249 s0 = u8x32_load_unaligned (src);
250 s1 = u8x32_load_unaligned (src + 32);
251 d0 = u8x32_load_unaligned (dst);
252 d1 = u8x32_load_unaligned (dst + 32);
254 d0 = u8x32_blend (d0, s0, lv > mask);
255 u8x32_store_unaligned (d0, dst);
261 d1 = u8x32_blend (d1, s1, lv > mask);
262 u8x32_store_unaligned (d1, dst + 32);
264 #elif defined (CLIB_HAVE_VEC128)
265 u8x16 s0, s1, s2, s3, d0, d1, d2, d3;
266 u8x16 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
267 u8x16 lv = u8x16_splat (len);
268 u8x16 add = u8x16_splat (16);
270 s0 = u8x16_load_unaligned (src);
271 s1 = u8x16_load_unaligned (src + 16);
272 s2 = u8x16_load_unaligned (src + 32);
273 s3 = u8x16_load_unaligned (src + 48);
274 d0 = u8x16_load_unaligned (dst);
275 d1 = u8x16_load_unaligned (dst + 16);
276 d2 = u8x16_load_unaligned (dst + 32);
277 d3 = u8x16_load_unaligned (dst + 48);
279 d0 = u8x16_blend (d0, s0, lv > mask);
280 u8x16_store_unaligned (d0, dst);
286 d1 = u8x16_blend (d1, s1, lv > mask);
287 u8x16_store_unaligned (d1, dst + 16);
293 d2 = u8x16_blend (d2, s2, lv > mask);
294 u8x16_store_unaligned (d2, dst + 32);
297 d3 = u8x16_blend (d3, s3, lv > mask);
298 u8x16_store_unaligned (d3, dst + 48);
300 memmove (dst, src, len);
304 static_always_inline void
305 clib_memcpy_le64 (u8 * dst, u8 * src, u8 len)
307 clib_memcpy_le (dst, src, len, 64);
310 static_always_inline void
311 clib_memcpy_le32 (u8 * dst, u8 * src, u8 len)
313 clib_memcpy_le (dst, src, len, 32);
316 static_always_inline void
317 clib_memset_u64 (void *p, u64 val, uword count)
320 #if defined(CLIB_HAVE_VEC512)
321 u64x8 v512 = u64x8_splat (val);
324 u64x8_store_unaligned (v512, ptr);
331 #if defined(CLIB_HAVE_VEC256)
332 u64x4 v256 = u64x4_splat (val);
335 u64x4_store_unaligned (v256, ptr);
342 #if defined(CLIB_HAVE_VEC128)
343 u64x2 v = u64x2_splat (val);
347 #if defined(CLIB_HAVE_VEC128)
348 u64x2_store_unaligned (v, ptr);
349 u64x2_store_unaligned (v, ptr + 2);
351 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
361 static_always_inline void
362 clib_memset_u32 (void *p, u32 val, uword count)
365 #if defined(CLIB_HAVE_VEC512)
366 u32x16 v512 = u32x16_splat (val);
369 u32x16_store_unaligned (v512, ptr);
376 #if defined(CLIB_HAVE_VEC256)
377 u32x8 v256 = u32x8_splat (val);
380 u32x8_store_unaligned (v256, ptr);
387 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
388 u32x4 v128 = u32x4_splat (val);
391 u32x4_store_unaligned (v128, ptr);
398 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
407 static_always_inline void
408 clib_memset_u16 (void *p, u16 val, uword count)
411 #if defined(CLIB_HAVE_VEC512)
412 u16x32 v512 = u16x32_splat (val);
415 u16x32_store_unaligned (v512, ptr);
422 #if defined(CLIB_HAVE_VEC256)
423 u16x16 v256 = u16x16_splat (val);
426 u16x16_store_unaligned (v256, ptr);
433 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
434 u16x8 v128 = u16x8_splat (val);
437 u16x8_store_unaligned (v128, ptr);
444 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
453 static_always_inline void
454 clib_memset_u8 (void *p, u8 val, uword count)
457 #if defined(CLIB_HAVE_VEC512)
458 u8x64 v512 = u8x64_splat (val);
461 u8x64_store_unaligned (v512, ptr);
468 #if defined(CLIB_HAVE_VEC256)
469 u8x32 v256 = u8x32_splat (val);
472 u8x32_store_unaligned (v256, ptr);
479 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
480 u8x16 v128 = u8x16_splat (val);
483 u8x16_store_unaligned (v128, ptr);
490 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
501 * This macro is to provide smooth mapping from memcmp to memcmp_s.
502 * memcmp has fewer parameters and fewer returns than memcmp_s.
503 * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
504 * we return 0 and spit out a message in the console because there is
505 * no way to return the error code to the memcmp callers.
506 * This condition happens when s1 or s2 is null. Please note
507 * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
508 * anyway. So we are consistent in this case for the comparison return
509 * although we also spit out a C11 violation message in the console to
510 * warn that they pass null pointers for both s1 and s2.
511 * Applications are encouraged to use the cool C11 memcmp_s API to get the
512 * maximum benefit out of it.
514 #define clib_memcmp(s1,s2,m1) \
516 memcmp_s_inline (s1, m1, s2, m1, &__diff); \
520 errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
521 rsize_t s2max, int *diff);
523 always_inline errno_t
524 memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
529 bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
532 if (PREDICT_FALSE (bad != 0))
535 clib_c11_violation ("s1 NULL");
537 clib_c11_violation ("s2 NULL");
539 clib_c11_violation ("diff NULL");
541 clib_c11_violation ("s2max > s1max");
543 clib_c11_violation ("s2max 0");
545 clib_c11_violation ("s1max 0");
549 if (PREDICT_FALSE (s1 == s2))
555 *diff = memcmp (s1, s2, s2max);
560 * This macro is to provide smooth mapping from strnlen to strnlen_s
562 #define clib_strnlen(s,m) strnlen_s_inline(s,m)
564 size_t strnlen_s (const char *s, size_t maxsize);
567 strnlen_s_inline (const char *s, size_t maxsize)
571 bad = (s == 0) + (maxsize == 0);
572 if (PREDICT_FALSE (bad != 0))
575 clib_c11_violation ("s NULL");
577 clib_c11_violation ("maxsize 0");
580 return strnlen (s, maxsize);
584 * This macro is to provide smooth mapping from strcmp to strcmp_s.
585 * strcmp has fewer parameters and fewer returns than strcmp_s.
586 * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
587 * we return 0 and spit out a message in the console because
588 * there is no way to return the error to the strcmp callers.
589 * This condition happens when s1 or s2 is null. Please note in the extant
590 * strcmp call, they would end up crashing if one of them is null.
591 * So the new behavior is no crash, but an error is displayed in the
592 * console which I think is more user friendly. If both s1 and s2 are null,
593 * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
594 * to actually accessing the pointer contents. We are still consistent
595 * in this case for the comparison return although we also spit out a
596 * C11 violation message in the console to warn that they pass null pointers
597 * for both s1 and s2. The other problem is strcmp does not provide s1max,
598 * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
599 * If not, we may be accessing memory beyonf what is intended.
600 * Applications are encouraged to use the cool C11 strcmp_s API to get the
601 * maximum benefit out of it.
603 #define clib_strcmp(s1,s2) \
604 ({ int __indicator = 0; \
605 strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator); \
609 errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
612 always_inline errno_t
613 strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
618 bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
619 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
621 if (PREDICT_FALSE (bad != 0))
623 if (indicator == NULL)
624 clib_c11_violation ("indicator NULL");
626 clib_c11_violation ("s1 NULL");
628 clib_c11_violation ("s2 NULL");
630 clib_c11_violation ("s1max 0");
631 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
632 clib_c11_violation ("s1 unterminated");
636 *indicator = strcmp (s1, s2);
641 * This macro is to provide smooth mapping from strncmp to strncmp_s.
642 * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
643 * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
644 * we return 0 and spit out a message in the console because there is no
645 * means to return the error to the strncmp caller.
646 * This condition happens when s1 or s2 is null. In the extant strncmp call,
647 * they would end up crashing if one of them is null. So the new behavior is
648 * no crash, but error is displayed in the console which is more
649 * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
650 * strncmp did the pointers comparison prior to actually accessing the
651 * pointer contents. We are still consistent in this case for the comparison
652 * return although we also spit out a C11 violation message in the console to
653 * warn that they pass null pointers for both s1 and s2.
654 * Applications are encouraged to use the cool C11 strncmp_s API to get the
655 * maximum benefit out of it.
657 #define clib_strncmp(s1,s2,n) \
658 ({ int __indicator = 0; \
659 strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator); \
663 errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
666 always_inline errno_t
667 strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
671 u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
673 if (PREDICT_FALSE (s1_greater_s1max && indicator))
676 * strcmp allows n > s1max. If indicator is non null, we can still
677 * do the compare without any harm and return EINVAL as well as the
678 * result in indicator.
680 clib_c11_violation ("n exceeds s1 length");
681 *indicator = strncmp (s1, s2, n);
685 bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
686 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
688 if (PREDICT_FALSE (bad != 0))
690 if (indicator == NULL)
691 clib_c11_violation ("indicator NULL");
693 clib_c11_violation ("s1 NULL");
695 clib_c11_violation ("s2 NULL");
697 clib_c11_violation ("s1max 0");
698 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
699 clib_c11_violation ("s1 unterminated");
700 if (s1_greater_s1max)
701 clib_c11_violation ("n exceeds s1 length");
705 *indicator = strncmp (s1, s2, n);
709 errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
710 const char *__restrict__ src);
712 always_inline errno_t
713 strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
714 const char *__restrict__ src)
720 bad = (dest == 0) + (dmax == 0) + (src == 0);
721 if (PREDICT_FALSE (bad != 0))
724 clib_c11_violation ("dest NULL");
726 clib_c11_violation ("src NULL");
728 clib_c11_violation ("dmax 0");
732 n = clib_strnlen (src, dmax);
733 if (PREDICT_FALSE (n >= dmax))
735 clib_c11_violation ("not enough space for dest");
738 /* Not actually trying to copy anything is OK */
739 if (PREDICT_FALSE (n == 0))
742 /* Check for src/dst overlap, which is not allowed */
743 low = (uword) (src < dest ? src : dest);
744 hi = (uword) (src < dest ? dest : src);
746 if (PREDICT_FALSE (low + (n - 1) >= hi))
748 clib_c11_violation ("src/dest overlap");
752 clib_memcpy_fast (dest, src, n);
758 * This macro is provided for smooth migration from strncpy. It is not perfect
759 * because we don't know the size of the destination buffer to pass to
760 * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
761 * Applications are encouraged to move to the C11 strncpy_s API and provide
762 * the correct dmax for better error checking.
764 #define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
767 strncpy_s (char *__restrict__ dest, rsize_t dmax,
768 const char *__restrict__ src, rsize_t n);
770 always_inline errno_t
771 strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
772 const char *__restrict__ src, rsize_t n)
777 errno_t status = EOK;
779 bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
780 if (PREDICT_FALSE (bad != 0))
782 /* Not actually trying to copy anything is OK */
786 clib_c11_violation ("dest NULL");
788 clib_c11_violation ("src NULL");
790 clib_c11_violation ("dmax 0");
794 if (PREDICT_FALSE (n >= dmax))
796 /* Relax and use strnlen of src */
797 clib_c11_violation ("n >= dmax");
798 m = clib_strnlen (src, dmax);
801 /* Truncate, adjust copy length to fit dest */
807 /* cap the copy to strlen(src) in case n > strlen(src) */
808 m = clib_strnlen (src, n);
810 /* Check for src/dst overlap, which is not allowed */
811 low = (uword) (src < dest ? src : dest);
812 hi = (uword) (src < dest ? dest : src);
815 * This check may fail innocently if src + dmax >= dst, but
816 * src + strlen(src) < dst. If it fails, check more carefully before
817 * blowing the whistle.
819 if (PREDICT_FALSE (low + (m - 1) >= hi))
821 m = clib_strnlen (src, m);
823 if (low + (m - 1) >= hi)
825 clib_c11_violation ("src/dest overlap");
830 clib_memcpy_fast (dest, src, m);
835 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
836 const char *__restrict__ src);
838 always_inline errno_t
839 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
840 const char *__restrict__ src)
844 size_t m, n, dest_size;
846 bad = (dest == 0) + (dmax == 0) + (src == 0);
847 if (PREDICT_FALSE (bad != 0))
850 clib_c11_violation ("dest NULL");
852 clib_c11_violation ("src NULL");
854 clib_c11_violation ("dmax 0");
858 dest_size = clib_strnlen (dest, dmax);
859 m = dmax - dest_size;
860 n = clib_strnlen (src, m);
861 if (PREDICT_FALSE (n >= m))
863 clib_c11_violation ("not enough space for dest");
867 /* Not actually trying to concatenate anything is OK */
868 if (PREDICT_FALSE (n == 0))
871 /* Check for src/dst overlap, which is not allowed */
872 low = (uword) (src < dest ? src : dest);
873 hi = (uword) (src < dest ? dest : src);
875 if (PREDICT_FALSE (low + (n - 1) >= hi))
877 clib_c11_violation ("src/dest overlap");
881 clib_memcpy_fast (dest + dest_size, src, n);
882 dest[dest_size + n] = '\0';
886 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
887 const char *__restrict__ src, rsize_t n);
889 always_inline errno_t
890 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
891 const char *__restrict__ src, rsize_t n)
895 size_t m, dest_size, allowed_size;
896 errno_t status = EOK;
898 bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
899 if (PREDICT_FALSE (bad != 0))
901 /* Not actually trying to concatenate anything is OK */
905 clib_c11_violation ("dest NULL");
907 clib_c11_violation ("src NULL");
909 clib_c11_violation ("dmax 0");
913 /* Check for src/dst overlap, which is not allowed */
914 low = (uword) (src < dest ? src : dest);
915 hi = (uword) (src < dest ? dest : src);
917 if (PREDICT_FALSE (low + (n - 1) >= hi))
919 clib_c11_violation ("src/dest overlap");
923 dest_size = clib_strnlen (dest, dmax);
924 allowed_size = dmax - dest_size;
926 if (PREDICT_FALSE (allowed_size == 0))
928 clib_c11_violation ("no space left in dest");
932 if (PREDICT_FALSE (n >= allowed_size))
935 * unlike strcat_s, strncat_s will do the concatenation anyway when
936 * there is not enough space in dest. But it will do the truncation and
937 * null terminate dest
939 m = clib_strnlen (src, allowed_size);
940 if (m >= allowed_size)
942 m = allowed_size - 1;
947 m = clib_strnlen (src, n);
949 clib_memcpy_fast (dest + dest_size, src, m);
950 dest[dest_size + m] = '\0';
955 * This macro is to provide smooth mapping from strtok_r to strtok_s.
956 * To map strtok to this macro, the caller would have to supply an additional
957 * argument. strtokr_s requires s1max which the unsafe API does not have. So
958 * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
959 * this macro cannot catch unterminated s1 and s2.
960 * Applications are encouraged to use the cool C11 strtok_s API to avoid
963 #define clib_strtok(s1,s2,p) \
964 ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX; \
965 strtok_s_inline (s1, &__s1max, s2, p); \
968 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
969 const char *__restrict__ s2, char **__restrict__ ptr);
972 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
973 const char *__restrict__ s2, char **__restrict__ ptr)
975 #define STRTOK_DELIM_MAX_LEN 16
981 bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
982 ((s1 == 0) && ptr && (*ptr == 0));
983 if (PREDICT_FALSE (bad != 0))
986 clib_c11_violation ("s2 NULL");
988 clib_c11_violation ("s1max is NULL");
990 clib_c11_violation ("ptr is NULL");
991 /* s1 == 0 and *ptr == null is no good */
992 if ((s1 == 0) && ptr && (*ptr == 0))
993 clib_c11_violation ("s1 and ptr contents are NULL");
1001 * scan s1 for a delimiter
1005 while (*s1 != '\0' && !ptoken)
1007 if (PREDICT_FALSE (dlen == 0))
1010 clib_c11_violation ("s1 unterminated");
1015 * must scan the entire delimiter list
1016 * ISO should have included a delimiter string limit!!
1018 slen = STRTOK_DELIM_MAX_LEN;
1022 if (PREDICT_FALSE (slen == 0))
1025 clib_c11_violation ("s2 unterminated");
1045 * if the beginning of a token was not found, then no
1046 * need to continue the scan.
1055 * Now we need to locate the end of the token
1062 clib_c11_violation ("s1 unterminated");
1066 slen = STRTOK_DELIM_MAX_LEN;
1073 clib_c11_violation ("s2 unterminated");
1080 * found a delimiter, set to null
1081 * and return context ptr to next char
1084 *ptr = (s1 + 1); /* return pointer for next scan */
1085 *s1max = dlen - 1; /* account for the nulled delimiter */
1091 * simply scanning through the delimiter string
1105 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1108 always_inline errno_t
1109 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1113 size_t s1_size, s2_size;
1116 (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1117 (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1118 (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1119 if (PREDICT_FALSE (bad != 0))
1122 clib_c11_violation ("s1 NULL");
1124 clib_c11_violation ("s2 NULL");
1126 clib_c11_violation ("s1max 0");
1128 clib_c11_violation ("s2max 0");
1130 clib_c11_violation ("substring NULL");
1131 if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1132 clib_c11_violation ("s1 unterminated");
1133 if (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'))
1134 clib_c11_violation ("s2 unterminated");
1139 * s2 points to a string with zero length, or s2 equals s1, return s1
1141 if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1148 * s2_size > s1_size, it won't find match.
1150 s1_size = clib_strnlen (s1, s1max);
1151 s2_size = clib_strnlen (s2, s2max);
1152 if (PREDICT_FALSE (s2_size > s1_size))
1155 *substring = strstr (s1, s2);
1156 if (*substring == 0)
1162 #endif /* included_clib_string_h */
1165 * fd.io coding-style-patch-verification: ON
1168 * eval: (c-set-style "gnu")