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>
51 #ifdef CLIB_LINUX_KERNEL
52 #include <linux/string.h>
59 #ifdef CLIB_STANDALONE
60 #include <vppinfra/standalone_string.h>
64 #include <x86intrin.h>
67 /* Exchanges source and destination. */
68 void clib_memswap (void *_a, void *_b, uword bytes);
71 * the vector unit memcpy variants confuse coverity
72 * so don't let it anywhere near them.
76 #include <vppinfra/memcpy_avx512.h>
77 #define clib_memcpy_fast_arch(a, b, c) clib_memcpy_fast_avx512 (a, b, c)
79 #include <vppinfra/memcpy_avx2.h>
80 #define clib_memcpy_fast_arch(a, b, c) clib_memcpy_fast_avx2 (a, b, c)
82 #include <vppinfra/memcpy_sse3.h>
83 #define clib_memcpy_fast_arch(a, b, c) clib_memcpy_fast_sse3 (a, b, c)
84 #endif /* __AVX512BITALG__ */
85 #endif /* __COVERITY__ */
87 #ifndef clib_memcpy_fast_arch
88 #define clib_memcpy_fast_arch(a, b, c) memcpy (a, b, c)
89 #endif /* clib_memcpy_fast_arch */
91 static_always_inline void *
92 clib_memcpy_fast (void *restrict dst, const void *restrict src, size_t n)
95 "memcpy(src, dst, n) with src == NULL or dst == NULL is undefined "
97 return clib_memcpy_fast_arch (dst, src, n);
100 #undef clib_memcpy_fast_arch
102 #include <vppinfra/memcpy.h>
104 /* c-11 string manipulation variants */
120 * In order to provide smooth mapping from unsafe string API to the clib string
121 * macro, we often have to improvise s1max and s2max due to the additional
122 * arguments are required for implementing the safe API. This macro is used
123 * to provide the s1max/s2max. It is not perfect because the actual
124 * s1max/s2max may be greater than 4k and the mapping from the unsafe API to
125 * the macro would cause a regression. However, it is not terribly likely.
126 * So I bet against the odds.
128 #define CLIB_STRING_MACRO_MAX 4096
131 typedef uword rsize_t;
133 void clib_c11_violation (const char *s);
134 errno_t memcpy_s (void *__restrict__ dest, rsize_t dmax,
135 const void *__restrict__ src, rsize_t n);
137 always_inline errno_t
138 memcpy_s_inline (void *__restrict__ dest, rsize_t dmax,
139 const void *__restrict__ src, rsize_t n)
145 * Optimize constant-number-of-bytes calls without asking
146 * "too many questions for someone from New Jersey"
148 if (COMPILE_TIME_CONST (n))
150 clib_memcpy_fast (dest, src, n);
155 * call bogus if: src or dst NULL, trying to copy
156 * more data than we have space in dst, or src == dst.
157 * n == 0 isn't really "bad", so check first in the
158 * "wall-of-shame" department...
160 bad = (dest == 0) + (src == 0) + (n > dmax) + (dest == src) + (n == 0);
161 if (PREDICT_FALSE (bad != 0))
163 /* Not actually trying to copy anything is OK */
167 clib_c11_violation ("dest NULL");
169 clib_c11_violation ("src NULL");
171 clib_c11_violation ("n > dmax");
173 clib_c11_violation ("dest == src");
177 /* Check for src/dst overlap, which is not allowed */
178 low = (uword) (src < dest ? src : dest);
179 hi = (uword) (src < dest ? dest : src);
181 if (PREDICT_FALSE (low + (n - 1) >= hi))
183 clib_c11_violation ("src/dest overlap");
187 clib_memcpy_fast (dest, src, n);
192 * Note: $$$ This macro is a crutch. Folks need to manually
193 * inspect every extant clib_memcpy(...) call and
194 * attempt to provide a real destination buffer size
197 #define clib_memcpy(d,s,n) memcpy_s_inline(d,n,s,n)
199 errno_t memset_s (void *s, rsize_t smax, int c, rsize_t n);
201 always_inline errno_t
202 memset_s_inline (void *s, rsize_t smax, int c, rsize_t n)
206 bad = (s == 0) + (n > smax);
208 if (PREDICT_FALSE (bad != 0))
211 clib_c11_violation ("s NULL");
213 clib_c11_violation ("n > smax");
221 * This macro is not [so much of] a crutch.
222 * It's super-typical to write:
224 * ep = pool_get (<pool>);
225 * clib_memset(ep, 0, sizeof (*ep));
227 * The compiler should delete the not-so useful
228 * (n > smax) test. TBH the NULL pointer check isn't
229 * so useful in this case, but so be it.
231 #define clib_memset(s,c,n) memset_s_inline(s,n,c,n)
233 static_always_inline void
234 clib_memcpy_le (u8 * dst, u8 * src, u8 len, u8 max_len)
236 #if defined (CLIB_HAVE_VEC256)
237 u8x32 s0, s1, d0, d1;
238 u8x32 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
239 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
241 u8x32 lv = u8x32_splat (len);
242 u8x32 add = u8x32_splat (32);
244 s0 = u8x32_load_unaligned (src);
245 s1 = u8x32_load_unaligned (src + 32);
246 d0 = u8x32_load_unaligned (dst);
247 d1 = u8x32_load_unaligned (dst + 32);
249 d0 = u8x32_blend (d0, s0, u8x32_is_greater (lv, mask));
250 u8x32_store_unaligned (d0, dst);
256 d1 = u8x32_blend (d1, s1, u8x32_is_greater (lv, mask));
257 u8x32_store_unaligned (d1, dst + 32);
259 #elif defined (CLIB_HAVE_VEC128)
260 u8x16 s0, s1, s2, s3, d0, d1, d2, d3;
261 u8x16 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
262 u8x16 lv = u8x16_splat (len);
263 u8x16 add = u8x16_splat (16);
265 s0 = u8x16_load_unaligned (src);
266 s1 = u8x16_load_unaligned (src + 16);
267 s2 = u8x16_load_unaligned (src + 32);
268 s3 = u8x16_load_unaligned (src + 48);
269 d0 = u8x16_load_unaligned (dst);
270 d1 = u8x16_load_unaligned (dst + 16);
271 d2 = u8x16_load_unaligned (dst + 32);
272 d3 = u8x16_load_unaligned (dst + 48);
274 d0 = u8x16_blend (d0, s0, u8x16_is_greater (lv, mask));
275 u8x16_store_unaligned (d0, dst);
281 d1 = u8x16_blend (d1, s1, u8x16_is_greater (lv, mask));
282 u8x16_store_unaligned (d1, dst + 16);
288 d2 = u8x16_blend (d2, s2, u8x16_is_greater (lv, mask));
289 u8x16_store_unaligned (d2, dst + 32);
292 d3 = u8x16_blend (d3, s3, u8x16_is_greater (lv, mask));
293 u8x16_store_unaligned (d3, dst + 48);
295 memmove (dst, src, len);
299 static_always_inline void
300 clib_memcpy_le64 (u8 * dst, u8 * src, u8 len)
302 clib_memcpy_le (dst, src, len, 64);
305 static_always_inline void
306 clib_memcpy_le32 (u8 * dst, u8 * src, u8 len)
308 clib_memcpy_le (dst, src, len, 32);
311 static_always_inline void
312 clib_memset_u64 (void *p, u64 val, uword count)
315 #if defined(CLIB_HAVE_VEC512)
316 u64x8 v512 = u64x8_splat (val);
319 u64x8_store_unaligned (v512, ptr);
326 #if defined(CLIB_HAVE_VEC256)
327 u64x4 v256 = u64x4_splat (val);
330 u64x4_store_unaligned (v256, ptr);
339 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
348 static_always_inline void
349 clib_memset_u32 (void *p, u32 val, uword count)
352 #if defined(CLIB_HAVE_VEC512)
353 u32x16 v512 = u32x16_splat (val);
356 u32x16_store_unaligned (v512, ptr);
363 #if defined(CLIB_HAVE_VEC256)
364 u32x8 v256 = u32x8_splat (val);
367 u32x8_store_unaligned (v256, ptr);
374 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
375 u32x4 v128 = u32x4_splat (val);
378 u32x4_store_unaligned (v128, ptr);
385 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
394 static_always_inline void
395 clib_memset_u16 (void *p, u16 val, uword count)
398 #if defined(CLIB_HAVE_VEC512)
399 u16x32 v512 = u16x32_splat (val);
402 u16x32_store_unaligned (v512, ptr);
409 #if defined(CLIB_HAVE_VEC256)
410 u16x16 v256 = u16x16_splat (val);
413 u16x16_store_unaligned (v256, ptr);
420 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
421 u16x8 v128 = u16x8_splat (val);
424 u16x8_store_unaligned (v128, ptr);
431 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
440 static_always_inline void
441 clib_memset_u8 (void *p, u8 val, uword count)
444 #if defined(CLIB_HAVE_VEC512)
445 u8x64 v512 = u8x64_splat (val);
448 u8x64_store_unaligned (v512, ptr);
455 #if defined(CLIB_HAVE_VEC256)
456 u8x32 v256 = u8x32_splat (val);
459 u8x32_store_unaligned (v256, ptr);
466 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
467 u8x16 v128 = u8x16_splat (val);
470 u8x16_store_unaligned (v128, ptr);
477 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
486 static_always_inline uword
487 clib_count_equal_u64 (u64 * data, uword max_count)
494 if (data[0] != data[1])
500 #if defined(CLIB_HAVE_VEC256)
501 u64x4 splat = u64x4_splat (first);
502 while (count + 3 < max_count)
505 bmp = u8x32_msb_mask ((u8x32) (u64x4_load_unaligned (data) == splat));
506 if (bmp != 0xffffffff)
508 count += count_trailing_zeros (~bmp) / 8;
518 while (count + 3 < max_count &&
519 ((data[0] ^ first) | (data[1] ^ first) |
520 (data[2] ^ first) | (data[3] ^ first)) == 0)
526 while (count < max_count && (data[0] == first))
534 static_always_inline uword
535 clib_count_equal_u32 (u32 * data, uword max_count)
542 if (data[0] != data[1])
548 #if defined(CLIB_HAVE_VEC256)
549 u32x8 splat = u32x8_splat (first);
550 while (count + 7 < max_count)
553 bmp = u8x32_msb_mask ((u8x32) (u32x8_load_unaligned (data) == splat));
554 if (bmp != 0xffffffff)
556 count += count_trailing_zeros (~bmp) / 4;
563 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
564 u32x4 splat = u32x4_splat (first);
565 while (count + 3 < max_count)
568 bmp = u8x16_msb_mask ((u8x16) (u32x4_load_unaligned (data) == splat));
571 count += count_trailing_zeros (~bmp) / 4;
581 while (count + 3 < max_count &&
582 ((data[0] ^ first) | (data[1] ^ first) |
583 (data[2] ^ first) | (data[3] ^ first)) == 0)
589 while (count < max_count && (data[0] == first))
597 static_always_inline uword
598 clib_count_equal_u16 (u16 * data, uword max_count)
605 if (data[0] != data[1])
611 #if defined(CLIB_HAVE_VEC256)
612 u16x16 splat = u16x16_splat (first);
613 while (count + 15 < max_count)
616 bmp = u8x32_msb_mask ((u8x32) (u16x16_load_unaligned (data) == splat));
617 if (bmp != 0xffffffff)
619 count += count_trailing_zeros (~bmp) / 2;
626 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
627 u16x8 splat = u16x8_splat (first);
628 while (count + 7 < max_count)
631 bmp = u8x16_msb_mask ((u8x16) (u16x8_load_unaligned (data) == splat));
634 count += count_trailing_zeros (~bmp) / 2;
644 while (count + 3 < max_count &&
645 ((data[0] ^ first) | (data[1] ^ first) |
646 (data[2] ^ first) | (data[3] ^ first)) == 0)
652 while (count < max_count && (data[0] == first))
660 static_always_inline uword
661 clib_count_equal_u8 (u8 * data, uword max_count)
668 if (data[0] != data[1])
674 #if defined(CLIB_HAVE_VEC256)
675 u8x32 splat = u8x32_splat (first);
676 while (count + 31 < max_count)
679 bmp = u8x32_msb_mask ((u8x32) (u8x32_load_unaligned (data) == splat));
680 if (bmp != 0xffffffff)
686 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
687 u8x16 splat = u8x16_splat (first);
688 while (count + 15 < max_count)
691 bmp = u8x16_msb_mask ((u8x16) (u8x16_load_unaligned (data) == splat));
694 count += count_trailing_zeros (~bmp);
704 while (count + 3 < max_count &&
705 ((data[0] ^ first) | (data[1] ^ first) |
706 (data[2] ^ first) | (data[3] ^ first)) == 0)
712 while (count < max_count && (data[0] == first))
721 * This macro is to provide smooth mapping from memcmp to memcmp_s.
722 * memcmp has fewer parameters and fewer returns than memcmp_s.
723 * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
724 * we return 0 and spit out a message in the console because there is
725 * no way to return the error code to the memcmp callers.
726 * This condition happens when s1 or s2 is null. Please note
727 * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
728 * anyway. So we are consistent in this case for the comparison return
729 * although we also spit out a C11 violation message in the console to
730 * warn that they pass null pointers for both s1 and s2.
731 * Applications are encouraged to use the cool C11 memcmp_s API to get the
732 * maximum benefit out of it.
734 #define clib_memcmp(s1,s2,m1) \
736 memcmp_s_inline (s1, m1, s2, m1, &__diff); \
740 errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
741 rsize_t s2max, int *diff);
743 always_inline errno_t
744 memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
749 bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
752 if (PREDICT_FALSE (bad != 0))
755 clib_c11_violation ("s1 NULL");
757 clib_c11_violation ("s2 NULL");
759 clib_c11_violation ("diff NULL");
761 clib_c11_violation ("s2max > s1max");
763 clib_c11_violation ("s2max 0");
765 clib_c11_violation ("s1max 0");
769 if (PREDICT_FALSE (s1 == s2))
775 *diff = memcmp (s1, s2, s2max);
780 * This macro is to provide smooth mapping from strnlen to strnlen_s
782 #define clib_strnlen(s,m) strnlen_s_inline(s,m)
784 size_t strnlen_s (const char *s, size_t maxsize);
787 strnlen_s_inline (const char *s, size_t maxsize)
791 bad = (s == 0) + (maxsize == 0);
792 if (PREDICT_FALSE (bad != 0))
795 clib_c11_violation ("s NULL");
797 clib_c11_violation ("maxsize 0");
800 return strnlen (s, maxsize);
804 * This macro is to provide smooth mapping from strcmp to strcmp_s.
805 * strcmp has fewer parameters and fewer returns than strcmp_s.
806 * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
807 * we return 0 and spit out a message in the console because
808 * there is no way to return the error to the strcmp callers.
809 * This condition happens when s1 or s2 is null. Please note in the extant
810 * strcmp call, they would end up crashing if one of them is null.
811 * So the new behavior is no crash, but an error is displayed in the
812 * console which I think is more user friendly. If both s1 and s2 are null,
813 * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
814 * to actually accessing the pointer contents. We are still consistent
815 * in this case for the comparison return although we also spit out a
816 * C11 violation message in the console to warn that they pass null pointers
817 * for both s1 and s2. The other problem is strcmp does not provide s1max,
818 * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
819 * If not, we may be accessing memory beyonf what is intended.
820 * Applications are encouraged to use the cool C11 strcmp_s API to get the
821 * maximum benefit out of it.
823 #define clib_strcmp(s1,s2) \
824 ({ int __indicator = 0; \
825 strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator); \
829 errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
832 always_inline errno_t
833 strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
838 bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
839 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
841 if (PREDICT_FALSE (bad != 0))
843 if (indicator == NULL)
844 clib_c11_violation ("indicator NULL");
846 clib_c11_violation ("s1 NULL");
848 clib_c11_violation ("s2 NULL");
850 clib_c11_violation ("s1max 0");
851 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
852 clib_c11_violation ("s1 unterminated");
856 *indicator = strcmp (s1, s2);
861 * This macro is to provide smooth mapping from strncmp to strncmp_s.
862 * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
863 * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
864 * we return 0 and spit out a message in the console because there is no
865 * means to return the error to the strncmp caller.
866 * This condition happens when s1 or s2 is null. In the extant strncmp call,
867 * they would end up crashing if one of them is null. So the new behavior is
868 * no crash, but error is displayed in the console which is more
869 * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
870 * strncmp did the pointers comparison prior to actually accessing the
871 * pointer contents. We are still consistent in this case for the comparison
872 * return although we also spit out a C11 violation message in the console to
873 * warn that they pass null pointers for both s1 and s2.
874 * Applications are encouraged to use the cool C11 strncmp_s API to get the
875 * maximum benefit out of it.
877 #define clib_strncmp(s1,s2,n) \
878 ({ int __indicator = 0; \
879 strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator); \
883 errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
886 always_inline errno_t
887 strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
891 u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
893 if (PREDICT_FALSE (s1_greater_s1max && indicator))
896 * strcmp allows n > s1max. If indicator is non null, we can still
897 * do the compare without any harm and return EINVAL as well as the
898 * result in indicator.
900 clib_c11_violation ("n exceeds s1 length");
901 *indicator = strncmp (s1, s2, n);
905 bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
906 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
908 if (PREDICT_FALSE (bad != 0))
910 if (indicator == NULL)
911 clib_c11_violation ("indicator NULL");
913 clib_c11_violation ("s1 NULL");
915 clib_c11_violation ("s2 NULL");
917 clib_c11_violation ("s1max 0");
918 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
919 clib_c11_violation ("s1 unterminated");
920 if (s1_greater_s1max)
921 clib_c11_violation ("n exceeds s1 length");
925 *indicator = strncmp (s1, s2, n);
930 * This macro is provided for smooth migration from strcpy. It is not perfect
931 * because we don't know the size of the destination buffer to pass to strcpy_s.
932 * We improvise dmax with CLIB_STRING_MACRO_MAX.
933 * Applications are encouraged to move to the C11 strcpy_s API.
935 #define clib_strcpy(d,s) strcpy_s_inline(d,CLIB_STRING_MACRO_MAX,s)
937 errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
938 const char *__restrict__ src);
940 always_inline errno_t
941 strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
942 const char *__restrict__ src)
948 bad = (dest == 0) + (dmax == 0) + (src == 0);
949 if (PREDICT_FALSE (bad != 0))
952 clib_c11_violation ("dest NULL");
954 clib_c11_violation ("src NULL");
956 clib_c11_violation ("dmax 0");
960 n = clib_strnlen (src, dmax);
961 if (PREDICT_FALSE (n >= dmax))
963 clib_c11_violation ("not enough space for dest");
966 /* Not actually trying to copy anything is OK */
967 if (PREDICT_FALSE (n == 0))
970 /* Check for src/dst overlap, which is not allowed */
971 low = (uword) (src < dest ? src : dest);
972 hi = (uword) (src < dest ? dest : src);
974 if (PREDICT_FALSE (low + (n - 1) >= hi))
976 clib_c11_violation ("src/dest overlap");
980 clib_memcpy_fast (dest, src, n);
986 * This macro is provided for smooth migration from strncpy. It is not perfect
987 * because we don't know the size of the destination buffer to pass to
988 * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
989 * Applications are encouraged to move to the C11 strncpy_s API and provide
990 * the correct dmax for better error checking.
992 #define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
995 strncpy_s (char *__restrict__ dest, rsize_t dmax,
996 const char *__restrict__ src, rsize_t n);
998 always_inline errno_t
999 strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
1000 const char *__restrict__ src, rsize_t n)
1005 errno_t status = EOK;
1007 bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
1008 if (PREDICT_FALSE (bad != 0))
1010 /* Not actually trying to copy anything is OK */
1014 clib_c11_violation ("dest NULL");
1016 clib_c11_violation ("src NULL");
1018 clib_c11_violation ("dmax 0");
1022 if (PREDICT_FALSE (n >= dmax))
1024 /* Relax and use strnlen of src */
1025 clib_c11_violation ("n >= dmax");
1026 m = clib_strnlen (src, dmax);
1029 /* Truncate, adjust copy length to fit dest */
1035 /* cap the copy to strlen(src) in case n > strlen(src) */
1036 m = clib_strnlen (src, n);
1038 /* Check for src/dst overlap, which is not allowed */
1039 low = (uword) (src < dest ? src : dest);
1040 hi = (uword) (src < dest ? dest : src);
1043 * This check may fail innocently if src + dmax >= dst, but
1044 * src + strlen(src) < dst. If it fails, check more carefully before
1045 * blowing the whistle.
1047 if (PREDICT_FALSE (low + (m - 1) >= hi))
1049 m = clib_strnlen (src, m);
1051 if (low + (m - 1) >= hi)
1053 clib_c11_violation ("src/dest overlap");
1058 clib_memcpy_fast (dest, src, m);
1064 * This macro is to provide smooth migration from strcat to strcat_s.
1065 * Because there is no dmax in strcat, we improvise it with
1066 * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite dest
1067 * with too many bytes from src.
1068 * Applications are encouraged to use C11 API to provide the actual dmax
1069 * for proper checking and protection.
1071 #define clib_strcat(d,s) strcat_s_inline(d,CLIB_STRING_MACRO_MAX,s)
1073 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
1074 const char *__restrict__ src);
1076 always_inline errno_t
1077 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
1078 const char *__restrict__ src)
1082 size_t m, n, dest_size;
1084 bad = (dest == 0) + (dmax == 0) + (src == 0);
1085 if (PREDICT_FALSE (bad != 0))
1088 clib_c11_violation ("dest NULL");
1090 clib_c11_violation ("src NULL");
1092 clib_c11_violation ("dmax 0");
1096 dest_size = clib_strnlen (dest, dmax);
1097 m = dmax - dest_size;
1098 n = clib_strnlen (src, m);
1099 if (PREDICT_FALSE (n >= m))
1101 clib_c11_violation ("not enough space for dest");
1105 /* Not actually trying to concatenate anything is OK */
1106 if (PREDICT_FALSE (n == 0))
1109 /* Check for src/dst overlap, which is not allowed */
1110 low = (uword) (src < dest ? src : dest);
1111 hi = (uword) (src < dest ? dest : src);
1113 if (PREDICT_FALSE (low + (n - 1) >= hi))
1115 clib_c11_violation ("src/dest overlap");
1119 clib_memcpy_fast (dest + dest_size, src, n);
1120 dest[dest_size + n] = '\0';
1125 * This macro is to provide smooth migration from strncat to strncat_s.
1126 * The unsafe strncat does not have s1max. We improvise it with
1127 * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite
1128 * dest with too many bytes from src.
1129 * Applications are encouraged to move to C11 strncat_s which requires dmax
1130 * from the caller and provides checking to safeguard the memory corruption.
1132 #define clib_strncat(d,s,n) strncat_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
1134 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
1135 const char *__restrict__ src, rsize_t n);
1137 always_inline errno_t
1138 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
1139 const char *__restrict__ src, rsize_t n)
1143 size_t m, dest_size, allowed_size;
1144 errno_t status = EOK;
1146 bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
1147 if (PREDICT_FALSE (bad != 0))
1149 /* Not actually trying to concatenate anything is OK */
1153 clib_c11_violation ("dest NULL");
1155 clib_c11_violation ("src NULL");
1157 clib_c11_violation ("dmax 0");
1161 /* Check for src/dst overlap, which is not allowed */
1162 low = (uword) (src < dest ? src : dest);
1163 hi = (uword) (src < dest ? dest : src);
1165 if (PREDICT_FALSE (low + (n - 1) >= hi))
1167 clib_c11_violation ("src/dest overlap");
1171 dest_size = clib_strnlen (dest, dmax);
1172 allowed_size = dmax - dest_size;
1174 if (PREDICT_FALSE (allowed_size == 0))
1176 clib_c11_violation ("no space left in dest");
1180 if (PREDICT_FALSE (n >= allowed_size))
1183 * unlike strcat_s, strncat_s will do the concatenation anyway when
1184 * there is not enough space in dest. But it will do the truncation and
1185 * null terminate dest
1187 m = clib_strnlen (src, allowed_size);
1188 if (m >= allowed_size)
1190 m = allowed_size - 1;
1195 m = clib_strnlen (src, n);
1197 clib_memcpy_fast (dest + dest_size, src, m);
1198 dest[dest_size + m] = '\0';
1203 * This macro is to provide smooth mapping from strtok_r to strtok_s.
1204 * To map strtok to this macro, the caller would have to supply an additional
1205 * argument. strtokr_s requires s1max which the unsafe API does not have. So
1206 * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
1207 * this macro cannot catch unterminated s1 and s2.
1208 * Applications are encouraged to use the cool C11 strtok_s API to avoid
1211 #define clib_strtok(s1,s2,p) \
1212 ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX; \
1213 strtok_s_inline (s1, &__s1max, s2, p); \
1216 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1217 const char *__restrict__ s2, char **__restrict__ ptr);
1219 always_inline char *
1220 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1221 const char *__restrict__ s2, char **__restrict__ ptr)
1223 #define STRTOK_DELIM_MAX_LEN 16
1229 bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
1230 ((s1 == 0) && ptr && (*ptr == 0));
1231 if (PREDICT_FALSE (bad != 0))
1234 clib_c11_violation ("s2 NULL");
1236 clib_c11_violation ("s1max is NULL");
1238 clib_c11_violation ("ptr is NULL");
1239 /* s1 == 0 and *ptr == null is no good */
1240 if ((s1 == 0) && ptr && (*ptr == 0))
1241 clib_c11_violation ("s1 and ptr contents are NULL");
1249 * scan s1 for a delimiter
1253 while (*s1 != '\0' && !ptoken)
1255 if (PREDICT_FALSE (dlen == 0))
1258 clib_c11_violation ("s1 unterminated");
1263 * must scan the entire delimiter list
1264 * ISO should have included a delimiter string limit!!
1266 slen = STRTOK_DELIM_MAX_LEN;
1270 if (PREDICT_FALSE (slen == 0))
1273 clib_c11_violation ("s2 unterminated");
1293 * if the beginning of a token was not found, then no
1294 * need to continue the scan.
1303 * Now we need to locate the end of the token
1310 clib_c11_violation ("s1 unterminated");
1314 slen = STRTOK_DELIM_MAX_LEN;
1321 clib_c11_violation ("s2 unterminated");
1328 * found a delimiter, set to null
1329 * and return context ptr to next char
1332 *ptr = (s1 + 1); /* return pointer for next scan */
1333 *s1max = dlen - 1; /* account for the nulled delimiter */
1339 * simply scanning through the delimiter string
1354 * This macro is to provide smooth mapping from strstr to strstr_s.
1355 * strstr_s requires s1max and s2max which the unsafe API does not have. So
1356 * we have to improvise them with CLIB_STRING_MACRO_MAX which may cause us
1357 * to access memory beyond it is intended if s1 or s2 is unterminated.
1358 * For the record, strstr crashes if s1 or s2 is unterminated. But this macro
1360 * Applications are encouraged to use the cool C11 strstr_s API to avoid
1363 #define clib_strstr(s1,s2) \
1364 ({ char * __substring = 0; \
1365 strstr_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, CLIB_STRING_MACRO_MAX, \
1370 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1373 always_inline errno_t
1374 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1378 size_t s1_size, s2_size;
1381 (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1382 (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1383 (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1384 if (PREDICT_FALSE (bad != 0))
1387 clib_c11_violation ("s1 NULL");
1389 clib_c11_violation ("s2 NULL");
1391 clib_c11_violation ("s1max 0");
1393 clib_c11_violation ("s2max 0");
1395 clib_c11_violation ("substring NULL");
1396 if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1397 clib_c11_violation ("s1 unterminated");
1398 if (s2 && s2max && (s2[clib_strnlen (s2, s1max)] != '\0'))
1399 clib_c11_violation ("s2 unterminated");
1404 * s2 points to a string with zero length, or s2 equals s1, return s1
1406 if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1413 * s2_size > s1_size, it won't find match.
1415 s1_size = clib_strnlen (s1, s1max);
1416 s2_size = clib_strnlen (s2, s2max);
1417 if (PREDICT_FALSE (s2_size > s1_size))
1420 *substring = strstr (s1, s2);
1421 if (*substring == 0)
1427 #endif /* included_clib_string_h */
1430 * fd.io coding-style-patch-verification: ON
1433 * eval: (c-set-style "gnu")