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 /* c-11 string manipulation variants */
118 * In order to provide smooth mapping from unsafe string API to the clib string
119 * macro, we often have to improvise s1max and s2max due to the additional
120 * arguments are required for implementing the safe API. This macro is used
121 * to provide the s1max/s2max. It is not perfect because the actual
122 * s1max/s2max may be greater than 4k and the mapping from the unsafe API to
123 * the macro would cause a regression. However, it is not terribly likely.
124 * So I bet against the odds.
126 #define CLIB_STRING_MACRO_MAX 4096
129 typedef uword rsize_t;
131 void clib_c11_violation (const char *s);
132 errno_t memcpy_s (void *__restrict__ dest, rsize_t dmax,
133 const void *__restrict__ src, rsize_t n);
135 always_inline errno_t
136 memcpy_s_inline (void *__restrict__ dest, rsize_t dmax,
137 const void *__restrict__ src, rsize_t n)
143 * Optimize constant-number-of-bytes calls without asking
144 * "too many questions for someone from New Jersey"
146 if (__builtin_constant_p (n))
148 clib_memcpy_fast (dest, src, n);
153 * call bogus if: src or dst NULL, trying to copy
154 * more data than we have space in dst, or src == dst.
155 * n == 0 isn't really "bad", so check first in the
156 * "wall-of-shame" department...
158 bad = (dest == 0) + (src == 0) + (n > dmax) + (dest == src) + (n == 0);
159 if (PREDICT_FALSE (bad != 0))
161 /* Not actually trying to copy anything is OK */
165 clib_c11_violation ("dest NULL");
167 clib_c11_violation ("src NULL");
169 clib_c11_violation ("n > dmax");
171 clib_c11_violation ("dest == src");
175 /* Check for src/dst overlap, which is not allowed */
176 low = (uword) (src < dest ? src : dest);
177 hi = (uword) (src < dest ? dest : src);
179 if (PREDICT_FALSE (low + (n - 1) >= hi))
181 clib_c11_violation ("src/dest overlap");
185 clib_memcpy_fast (dest, src, n);
190 * Note: $$$ This macro is a crutch. Folks need to manually
191 * inspect every extant clib_memcpy(...) call and
192 * attempt to provide a real destination buffer size
195 #define clib_memcpy(d,s,n) memcpy_s_inline(d,n,s,n)
197 errno_t memset_s (void *s, rsize_t smax, int c, rsize_t n);
199 always_inline errno_t
200 memset_s_inline (void *s, rsize_t smax, int c, rsize_t n)
204 bad = (s == 0) + (n > smax);
206 if (PREDICT_FALSE (bad != 0))
209 clib_c11_violation ("s NULL");
211 clib_c11_violation ("n > smax");
219 * This macro is not [so much of] a crutch.
220 * It's super-typical to write:
222 * ep = pool_get (<pool>);
223 * clib_memset(ep, 0, sizeof (*ep));
225 * The compiler should delete the not-so useful
226 * (n > smax) test. TBH the NULL pointer check isn't
227 * so useful in this case, but so be it.
229 #define clib_memset(s,c,n) memset_s_inline(s,n,c,n)
231 static_always_inline void
232 clib_memcpy_le (u8 * dst, u8 * src, u8 len, u8 max_len)
234 #if defined (CLIB_HAVE_VEC256)
235 u8x32 s0, s1, d0, d1;
236 u8x32 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
237 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
239 u8x32 lv = u8x32_splat (len);
240 u8x32 add = u8x32_splat (32);
242 s0 = u8x32_load_unaligned (src);
243 s1 = u8x32_load_unaligned (src + 32);
244 d0 = u8x32_load_unaligned (dst);
245 d1 = u8x32_load_unaligned (dst + 32);
247 d0 = u8x32_blend (d0, s0, u8x32_is_greater (lv, mask));
248 u8x32_store_unaligned (d0, dst);
254 d1 = u8x32_blend (d1, s1, u8x32_is_greater (lv, mask));
255 u8x32_store_unaligned (d1, dst + 32);
257 #elif defined (CLIB_HAVE_VEC128)
258 u8x16 s0, s1, s2, s3, d0, d1, d2, d3;
259 u8x16 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
260 u8x16 lv = u8x16_splat (len);
261 u8x16 add = u8x16_splat (16);
263 s0 = u8x16_load_unaligned (src);
264 s1 = u8x16_load_unaligned (src + 16);
265 s2 = u8x16_load_unaligned (src + 32);
266 s3 = u8x16_load_unaligned (src + 48);
267 d0 = u8x16_load_unaligned (dst);
268 d1 = u8x16_load_unaligned (dst + 16);
269 d2 = u8x16_load_unaligned (dst + 32);
270 d3 = u8x16_load_unaligned (dst + 48);
272 d0 = u8x16_blend (d0, s0, u8x16_is_greater (lv, mask));
273 u8x16_store_unaligned (d0, dst);
279 d1 = u8x16_blend (d1, s1, u8x16_is_greater (lv, mask));
280 u8x16_store_unaligned (d1, dst + 16);
286 d2 = u8x16_blend (d2, s2, u8x16_is_greater (lv, mask));
287 u8x16_store_unaligned (d2, dst + 32);
290 d3 = u8x16_blend (d3, s3, u8x16_is_greater (lv, mask));
291 u8x16_store_unaligned (d3, dst + 48);
293 memmove (dst, src, len);
297 static_always_inline void
298 clib_memcpy_le64 (u8 * dst, u8 * src, u8 len)
300 clib_memcpy_le (dst, src, len, 64);
303 static_always_inline void
304 clib_memcpy_le32 (u8 * dst, u8 * src, u8 len)
306 clib_memcpy_le (dst, src, len, 32);
309 static_always_inline void
310 clib_memset_u64 (void *p, u64 val, uword count)
313 #if defined(CLIB_HAVE_VEC512)
314 u64x8 v512 = u64x8_splat (val);
317 u64x8_store_unaligned (v512, ptr);
324 #if defined(CLIB_HAVE_VEC256)
325 u64x4 v256 = u64x4_splat (val);
328 u64x4_store_unaligned (v256, ptr);
337 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
346 static_always_inline void
347 clib_memset_u32 (void *p, u32 val, uword count)
350 #if defined(CLIB_HAVE_VEC512)
351 u32x16 v512 = u32x16_splat (val);
354 u32x16_store_unaligned (v512, ptr);
361 #if defined(CLIB_HAVE_VEC256)
362 u32x8 v256 = u32x8_splat (val);
365 u32x8_store_unaligned (v256, ptr);
372 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
373 u32x4 v128 = u32x4_splat (val);
376 u32x4_store_unaligned (v128, ptr);
383 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
392 static_always_inline void
393 clib_memset_u16 (void *p, u16 val, uword count)
396 #if defined(CLIB_HAVE_VEC512)
397 u16x32 v512 = u16x32_splat (val);
400 u16x32_store_unaligned (v512, ptr);
407 #if defined(CLIB_HAVE_VEC256)
408 u16x16 v256 = u16x16_splat (val);
411 u16x16_store_unaligned (v256, ptr);
418 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
419 u16x8 v128 = u16x8_splat (val);
422 u16x8_store_unaligned (v128, ptr);
429 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
438 static_always_inline void
439 clib_memset_u8 (void *p, u8 val, uword count)
442 #if defined(CLIB_HAVE_VEC512)
443 u8x64 v512 = u8x64_splat (val);
446 u8x64_store_unaligned (v512, ptr);
453 #if defined(CLIB_HAVE_VEC256)
454 u8x32 v256 = u8x32_splat (val);
457 u8x32_store_unaligned (v256, ptr);
464 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
465 u8x16 v128 = u8x16_splat (val);
468 u8x16_store_unaligned (v128, ptr);
475 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
484 static_always_inline uword
485 clib_count_equal_u64 (u64 * data, uword max_count)
492 if (data[0] != data[1])
498 #if defined(CLIB_HAVE_VEC256)
499 u64x4 splat = u64x4_splat (first);
500 while (count + 3 < max_count)
503 bmp = u8x32_msb_mask ((u8x32) (u64x4_load_unaligned (data) == splat));
504 if (bmp != 0xffffffff)
506 count += count_trailing_zeros (~bmp) / 8;
516 while (count + 3 < max_count &&
517 ((data[0] ^ first) | (data[1] ^ first) |
518 (data[2] ^ first) | (data[3] ^ first)) == 0)
524 while (count < max_count && (data[0] == first))
532 static_always_inline uword
533 clib_count_equal_u32 (u32 * data, uword max_count)
540 if (data[0] != data[1])
546 #if defined(CLIB_HAVE_VEC256)
547 u32x8 splat = u32x8_splat (first);
548 while (count + 7 < max_count)
551 bmp = u8x32_msb_mask ((u8x32) (u32x8_load_unaligned (data) == splat));
552 if (bmp != 0xffffffff)
554 count += count_trailing_zeros (~bmp) / 4;
561 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
562 u32x4 splat = u32x4_splat (first);
563 while (count + 3 < max_count)
566 bmp = u8x16_msb_mask ((u8x16) (u32x4_load_unaligned (data) == splat));
569 count += count_trailing_zeros (~bmp) / 4;
579 while (count + 3 < max_count &&
580 ((data[0] ^ first) | (data[1] ^ first) |
581 (data[2] ^ first) | (data[3] ^ first)) == 0)
587 while (count < max_count && (data[0] == first))
595 static_always_inline uword
596 clib_count_equal_u16 (u16 * data, uword max_count)
603 if (data[0] != data[1])
609 #if defined(CLIB_HAVE_VEC256)
610 u16x16 splat = u16x16_splat (first);
611 while (count + 15 < max_count)
614 bmp = u8x32_msb_mask ((u8x32) (u16x16_load_unaligned (data) == splat));
615 if (bmp != 0xffffffff)
617 count += count_trailing_zeros (~bmp) / 2;
624 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
625 u16x8 splat = u16x8_splat (first);
626 while (count + 7 < max_count)
629 bmp = u8x16_msb_mask ((u8x16) (u16x8_load_unaligned (data) == splat));
632 count += count_trailing_zeros (~bmp) / 2;
642 while (count + 3 < max_count &&
643 ((data[0] ^ first) | (data[1] ^ first) |
644 (data[2] ^ first) | (data[3] ^ first)) == 0)
650 while (count < max_count && (data[0] == first))
658 static_always_inline uword
659 clib_count_equal_u8 (u8 * data, uword max_count)
666 if (data[0] != data[1])
672 #if defined(CLIB_HAVE_VEC256)
673 u8x32 splat = u8x32_splat (first);
674 while (count + 31 < max_count)
677 bmp = u8x32_msb_mask ((u8x32) (u8x32_load_unaligned (data) == splat));
678 if (bmp != 0xffffffff)
680 count += count_trailing_zeros (~bmp);
687 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
688 u8x16 splat = u8x16_splat (first);
689 while (count + 15 < max_count)
692 bmp = u8x16_msb_mask ((u8x16) (u8x16_load_unaligned (data) == splat));
695 count += count_trailing_zeros (~bmp);
705 while (count + 3 < max_count &&
706 ((data[0] ^ first) | (data[1] ^ first) |
707 (data[2] ^ first) | (data[3] ^ first)) == 0)
713 while (count < max_count && (data[0] == first))
722 * This macro is to provide smooth mapping from memcmp to memcmp_s.
723 * memcmp has fewer parameters and fewer returns than memcmp_s.
724 * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
725 * we return 0 and spit out a message in the console because there is
726 * no way to return the error code to the memcmp callers.
727 * This condition happens when s1 or s2 is null. Please note
728 * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
729 * anyway. So we are consistent in this case for the comparison return
730 * although we also spit out a C11 violation message in the console to
731 * warn that they pass null pointers for both s1 and s2.
732 * Applications are encouraged to use the cool C11 memcmp_s API to get the
733 * maximum benefit out of it.
735 #define clib_memcmp(s1,s2,m1) \
737 memcmp_s_inline (s1, m1, s2, m1, &__diff); \
741 errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
742 rsize_t s2max, int *diff);
744 always_inline errno_t
745 memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
750 bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
753 if (PREDICT_FALSE (bad != 0))
756 clib_c11_violation ("s1 NULL");
758 clib_c11_violation ("s2 NULL");
760 clib_c11_violation ("diff NULL");
762 clib_c11_violation ("s2max > s1max");
764 clib_c11_violation ("s2max 0");
766 clib_c11_violation ("s1max 0");
770 if (PREDICT_FALSE (s1 == s2))
776 *diff = memcmp (s1, s2, s2max);
781 * This macro is to provide smooth mapping from strnlen to strnlen_s
783 #define clib_strnlen(s,m) strnlen_s_inline(s,m)
785 size_t strnlen_s (const char *s, size_t maxsize);
788 strnlen_s_inline (const char *s, size_t maxsize)
792 bad = (s == 0) + (maxsize == 0);
793 if (PREDICT_FALSE (bad != 0))
796 clib_c11_violation ("s NULL");
798 clib_c11_violation ("maxsize 0");
801 return strnlen (s, maxsize);
805 * This macro is to provide smooth mapping from strcmp to strcmp_s.
806 * strcmp has fewer parameters and fewer returns than strcmp_s.
807 * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
808 * we return 0 and spit out a message in the console because
809 * there is no way to return the error to the strcmp callers.
810 * This condition happens when s1 or s2 is null. Please note in the extant
811 * strcmp call, they would end up crashing if one of them is null.
812 * So the new behavior is no crash, but an error is displayed in the
813 * console which I think is more user friendly. If both s1 and s2 are null,
814 * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
815 * to actually accessing the pointer contents. We are still consistent
816 * in this case for the comparison return although we also spit out a
817 * C11 violation message in the console to warn that they pass null pointers
818 * for both s1 and s2. The other problem is strcmp does not provide s1max,
819 * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
820 * If not, we may be accessing memory beyonf what is intended.
821 * Applications are encouraged to use the cool C11 strcmp_s API to get the
822 * maximum benefit out of it.
824 #define clib_strcmp(s1,s2) \
825 ({ int __indicator = 0; \
826 strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator); \
830 errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
833 always_inline errno_t
834 strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
839 bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
840 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
842 if (PREDICT_FALSE (bad != 0))
844 if (indicator == NULL)
845 clib_c11_violation ("indicator NULL");
847 clib_c11_violation ("s1 NULL");
849 clib_c11_violation ("s2 NULL");
851 clib_c11_violation ("s1max 0");
852 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
853 clib_c11_violation ("s1 unterminated");
857 *indicator = strcmp (s1, s2);
862 * This macro is to provide smooth mapping from strncmp to strncmp_s.
863 * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
864 * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
865 * we return 0 and spit out a message in the console because there is no
866 * means to return the error to the strncmp caller.
867 * This condition happens when s1 or s2 is null. In the extant strncmp call,
868 * they would end up crashing if one of them is null. So the new behavior is
869 * no crash, but error is displayed in the console which is more
870 * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
871 * strncmp did the pointers comparison prior to actually accessing the
872 * pointer contents. We are still consistent in this case for the comparison
873 * return although we also spit out a C11 violation message in the console to
874 * warn that they pass null pointers for both s1 and s2.
875 * Applications are encouraged to use the cool C11 strncmp_s API to get the
876 * maximum benefit out of it.
878 #define clib_strncmp(s1,s2,n) \
879 ({ int __indicator = 0; \
880 strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator); \
884 errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
887 always_inline errno_t
888 strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
892 u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
894 if (PREDICT_FALSE (s1_greater_s1max && indicator))
897 * strcmp allows n > s1max. If indicator is non null, we can still
898 * do the compare without any harm and return EINVAL as well as the
899 * result in indicator.
901 clib_c11_violation ("n exceeds s1 length");
902 *indicator = strncmp (s1, s2, n);
906 bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
907 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
909 if (PREDICT_FALSE (bad != 0))
911 if (indicator == NULL)
912 clib_c11_violation ("indicator NULL");
914 clib_c11_violation ("s1 NULL");
916 clib_c11_violation ("s2 NULL");
918 clib_c11_violation ("s1max 0");
919 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
920 clib_c11_violation ("s1 unterminated");
921 if (s1_greater_s1max)
922 clib_c11_violation ("n exceeds s1 length");
926 *indicator = strncmp (s1, s2, n);
931 * This macro is provided for smooth migration from strcpy. It is not perfect
932 * because we don't know the size of the destination buffer to pass to strcpy_s.
933 * We improvise dmax with CLIB_STRING_MACRO_MAX.
934 * Applications are encouraged to move to the C11 strcpy_s API.
936 #define clib_strcpy(d,s) strcpy_s_inline(d,CLIB_STRING_MACRO_MAX,s)
938 errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
939 const char *__restrict__ src);
941 always_inline errno_t
942 strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
943 const char *__restrict__ src)
949 bad = (dest == 0) + (dmax == 0) + (src == 0);
950 if (PREDICT_FALSE (bad != 0))
953 clib_c11_violation ("dest NULL");
955 clib_c11_violation ("src NULL");
957 clib_c11_violation ("dmax 0");
961 n = clib_strnlen (src, dmax);
962 if (PREDICT_FALSE (n >= dmax))
964 clib_c11_violation ("not enough space for dest");
967 /* Not actually trying to copy anything is OK */
968 if (PREDICT_FALSE (n == 0))
971 /* Check for src/dst overlap, which is not allowed */
972 low = (uword) (src < dest ? src : dest);
973 hi = (uword) (src < dest ? dest : src);
975 if (PREDICT_FALSE (low + (n - 1) >= hi))
977 clib_c11_violation ("src/dest overlap");
981 clib_memcpy_fast (dest, src, n);
987 * This macro is provided for smooth migration from strncpy. It is not perfect
988 * because we don't know the size of the destination buffer to pass to
989 * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
990 * Applications are encouraged to move to the C11 strncpy_s API and provide
991 * the correct dmax for better error checking.
993 #define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
996 strncpy_s (char *__restrict__ dest, rsize_t dmax,
997 const char *__restrict__ src, rsize_t n);
999 always_inline errno_t
1000 strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
1001 const char *__restrict__ src, rsize_t n)
1006 errno_t status = EOK;
1008 bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
1009 if (PREDICT_FALSE (bad != 0))
1011 /* Not actually trying to copy anything is OK */
1015 clib_c11_violation ("dest NULL");
1017 clib_c11_violation ("src NULL");
1019 clib_c11_violation ("dmax 0");
1023 if (PREDICT_FALSE (n >= dmax))
1025 /* Relax and use strnlen of src */
1026 clib_c11_violation ("n >= dmax");
1027 m = clib_strnlen (src, dmax);
1030 /* Truncate, adjust copy length to fit dest */
1036 /* cap the copy to strlen(src) in case n > strlen(src) */
1037 m = clib_strnlen (src, n);
1039 /* Check for src/dst overlap, which is not allowed */
1040 low = (uword) (src < dest ? src : dest);
1041 hi = (uword) (src < dest ? dest : src);
1044 * This check may fail innocently if src + dmax >= dst, but
1045 * src + strlen(src) < dst. If it fails, check more carefully before
1046 * blowing the whistle.
1048 if (PREDICT_FALSE (low + (m - 1) >= hi))
1050 m = clib_strnlen (src, m);
1052 if (low + (m - 1) >= hi)
1054 clib_c11_violation ("src/dest overlap");
1059 clib_memcpy_fast (dest, src, m);
1065 * This macro is to provide smooth migration from strcat to strcat_s.
1066 * Because there is no dmax in strcat, we improvise it with
1067 * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite dest
1068 * with too many bytes from src.
1069 * Applications are encouraged to use C11 API to provide the actual dmax
1070 * for proper checking and protection.
1072 #define clib_strcat(d,s) strcat_s_inline(d,CLIB_STRING_MACRO_MAX,s)
1074 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
1075 const char *__restrict__ src);
1077 always_inline errno_t
1078 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
1079 const char *__restrict__ src)
1083 size_t m, n, dest_size;
1085 bad = (dest == 0) + (dmax == 0) + (src == 0);
1086 if (PREDICT_FALSE (bad != 0))
1089 clib_c11_violation ("dest NULL");
1091 clib_c11_violation ("src NULL");
1093 clib_c11_violation ("dmax 0");
1097 dest_size = clib_strnlen (dest, dmax);
1098 m = dmax - dest_size;
1099 n = clib_strnlen (src, m);
1100 if (PREDICT_FALSE (n >= m))
1102 clib_c11_violation ("not enough space for dest");
1106 /* Not actually trying to concatenate anything is OK */
1107 if (PREDICT_FALSE (n == 0))
1110 /* Check for src/dst overlap, which is not allowed */
1111 low = (uword) (src < dest ? src : dest);
1112 hi = (uword) (src < dest ? dest : src);
1114 if (PREDICT_FALSE (low + (n - 1) >= hi))
1116 clib_c11_violation ("src/dest overlap");
1120 clib_memcpy_fast (dest + dest_size, src, n);
1121 dest[dest_size + n] = '\0';
1126 * This macro is to provide smooth migration from strncat to strncat_s.
1127 * The unsafe strncat does not have s1max. We improvise it with
1128 * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite
1129 * dest with too many bytes from src.
1130 * Applications are encouraged to move to C11 strncat_s which requires dmax
1131 * from the caller and provides checking to safeguard the memory corruption.
1133 #define clib_strncat(d,s,n) strncat_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
1135 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
1136 const char *__restrict__ src, rsize_t n);
1138 always_inline errno_t
1139 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
1140 const char *__restrict__ src, rsize_t n)
1144 size_t m, dest_size, allowed_size;
1145 errno_t status = EOK;
1147 bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
1148 if (PREDICT_FALSE (bad != 0))
1150 /* Not actually trying to concatenate anything is OK */
1154 clib_c11_violation ("dest NULL");
1156 clib_c11_violation ("src NULL");
1158 clib_c11_violation ("dmax 0");
1162 /* Check for src/dst overlap, which is not allowed */
1163 low = (uword) (src < dest ? src : dest);
1164 hi = (uword) (src < dest ? dest : src);
1166 if (PREDICT_FALSE (low + (n - 1) >= hi))
1168 clib_c11_violation ("src/dest overlap");
1172 dest_size = clib_strnlen (dest, dmax);
1173 allowed_size = dmax - dest_size;
1175 if (PREDICT_FALSE (allowed_size == 0))
1177 clib_c11_violation ("no space left in dest");
1181 if (PREDICT_FALSE (n >= allowed_size))
1184 * unlike strcat_s, strncat_s will do the concatenation anyway when
1185 * there is not enough space in dest. But it will do the truncation and
1186 * null terminate dest
1188 m = clib_strnlen (src, allowed_size);
1189 if (m >= allowed_size)
1191 m = allowed_size - 1;
1196 m = clib_strnlen (src, n);
1198 clib_memcpy_fast (dest + dest_size, src, m);
1199 dest[dest_size + m] = '\0';
1204 * This macro is to provide smooth mapping from strtok_r to strtok_s.
1205 * To map strtok to this macro, the caller would have to supply an additional
1206 * argument. strtokr_s requires s1max which the unsafe API does not have. So
1207 * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
1208 * this macro cannot catch unterminated s1 and s2.
1209 * Applications are encouraged to use the cool C11 strtok_s API to avoid
1212 #define clib_strtok(s1,s2,p) \
1213 ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX; \
1214 strtok_s_inline (s1, &__s1max, s2, p); \
1217 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1218 const char *__restrict__ s2, char **__restrict__ ptr);
1220 always_inline char *
1221 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1222 const char *__restrict__ s2, char **__restrict__ ptr)
1224 #define STRTOK_DELIM_MAX_LEN 16
1230 bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
1231 ((s1 == 0) && ptr && (*ptr == 0));
1232 if (PREDICT_FALSE (bad != 0))
1235 clib_c11_violation ("s2 NULL");
1237 clib_c11_violation ("s1max is NULL");
1239 clib_c11_violation ("ptr is NULL");
1240 /* s1 == 0 and *ptr == null is no good */
1241 if ((s1 == 0) && ptr && (*ptr == 0))
1242 clib_c11_violation ("s1 and ptr contents are NULL");
1250 * scan s1 for a delimiter
1254 while (*s1 != '\0' && !ptoken)
1256 if (PREDICT_FALSE (dlen == 0))
1259 clib_c11_violation ("s1 unterminated");
1264 * must scan the entire delimiter list
1265 * ISO should have included a delimiter string limit!!
1267 slen = STRTOK_DELIM_MAX_LEN;
1271 if (PREDICT_FALSE (slen == 0))
1274 clib_c11_violation ("s2 unterminated");
1294 * if the beginning of a token was not found, then no
1295 * need to continue the scan.
1304 * Now we need to locate the end of the token
1311 clib_c11_violation ("s1 unterminated");
1315 slen = STRTOK_DELIM_MAX_LEN;
1322 clib_c11_violation ("s2 unterminated");
1329 * found a delimiter, set to null
1330 * and return context ptr to next char
1333 *ptr = (s1 + 1); /* return pointer for next scan */
1334 *s1max = dlen - 1; /* account for the nulled delimiter */
1340 * simply scanning through the delimiter string
1355 * This macro is to provide smooth mapping from strstr to strstr_s.
1356 * strstr_s requires s1max and s2max which the unsafe API does not have. So
1357 * we have to improvise them with CLIB_STRING_MACRO_MAX which may cause us
1358 * to access memory beyond it is intended if s1 or s2 is unterminated.
1359 * For the record, strstr crashes if s1 or s2 is unterminated. But this macro
1361 * Applications are encouraged to use the cool C11 strstr_s API to avoid
1364 #define clib_strstr(s1,s2) \
1365 ({ char * __substring = 0; \
1366 strstr_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, CLIB_STRING_MACRO_MAX, \
1371 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1374 always_inline errno_t
1375 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1379 size_t s1_size, s2_size;
1382 (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1383 (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1384 (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1385 if (PREDICT_FALSE (bad != 0))
1388 clib_c11_violation ("s1 NULL");
1390 clib_c11_violation ("s2 NULL");
1392 clib_c11_violation ("s1max 0");
1394 clib_c11_violation ("s2max 0");
1396 clib_c11_violation ("substring NULL");
1397 if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1398 clib_c11_violation ("s1 unterminated");
1399 if (s2 && s2max && (s2[clib_strnlen (s2, s1max)] != '\0'))
1400 clib_c11_violation ("s2 unterminated");
1405 * s2 points to a string with zero length, or s2 equals s1, return s1
1407 if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1414 * s2_size > s1_size, it won't find match.
1416 s1_size = clib_strnlen (s1, s1max);
1417 s2_size = clib_strnlen (s2, s2max);
1418 if (PREDICT_FALSE (s2_size > s1_size))
1421 *substring = strstr (s1, s2);
1422 if (*substring == 0)
1428 #endif /* included_clib_string_h */
1431 * fd.io coding-style-patch-verification: ON
1434 * eval: (c-set-style "gnu")