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>
50 #ifdef CLIB_LINUX_KERNEL
51 #include <linux/string.h>
58 #ifdef CLIB_STANDALONE
59 #include <vppinfra/standalone_string.h>
63 #include <x86intrin.h>
66 /* Exchanges source and destination. */
67 void clib_memswap (void *_a, void *_b, uword bytes);
70 * the vector unit memcpy variants confuse coverity
71 * so don't let it anywhere near them.
75 #include <vppinfra/memcpy_avx512.h>
77 #include <vppinfra/memcpy_avx2.h>
79 #include <vppinfra/memcpy_sse3.h>
81 #define clib_memcpy_fast(a,b,c) memcpy(a,b,c)
83 #else /* __COVERITY__ */
84 #define clib_memcpy_fast(a,b,c) memcpy(a,b,c)
87 /* c-11 string manipulation variants */
103 * In order to provide smooth mapping from unsafe string API to the clib string
104 * macro, we often have to improvise s1max and s2max due to the additional
105 * arguments are required for implementing the safe API. This macro is used
106 * to provide the s1max/s2max. It is not perfect because the actual
107 * s1max/s2max may be greater than 4k and the mapping from the unsafe API to
108 * the macro would cause a regression. However, it is not terribly likely.
109 * So I bet against the odds.
111 #define CLIB_STRING_MACRO_MAX 4096
114 typedef uword rsize_t;
116 void clib_c11_violation (const char *s);
117 errno_t memcpy_s (void *__restrict__ dest, rsize_t dmax,
118 const void *__restrict__ src, rsize_t n);
120 always_inline errno_t
121 memcpy_s_inline (void *__restrict__ dest, rsize_t dmax,
122 const void *__restrict__ src, rsize_t n)
128 * Optimize constant-number-of-bytes calls without asking
129 * "too many questions for someone from New Jersey"
131 if (__builtin_constant_p (n))
133 clib_memcpy_fast (dest, src, n);
138 * call bogus if: src or dst NULL, trying to copy
139 * more data than we have space in dst, or src == dst.
140 * n == 0 isn't really "bad", so check first in the
141 * "wall-of-shame" department...
143 bad = (dest == 0) + (src == 0) + (n > dmax) + (dest == src) + (n == 0);
144 if (PREDICT_FALSE (bad != 0))
146 /* Not actually trying to copy anything is OK */
150 clib_c11_violation ("dest NULL");
152 clib_c11_violation ("src NULL");
154 clib_c11_violation ("n > dmax");
156 clib_c11_violation ("dest == src");
160 /* Check for src/dst overlap, which is not allowed */
161 low = (uword) (src < dest ? src : dest);
162 hi = (uword) (src < dest ? dest : src);
164 if (PREDICT_FALSE (low + (n - 1) >= hi))
166 clib_c11_violation ("src/dest overlap");
170 clib_memcpy_fast (dest, src, n);
175 * Note: $$$ This macro is a crutch. Folks need to manually
176 * inspect every extant clib_memcpy(...) call and
177 * attempt to provide a real destination buffer size
180 #define clib_memcpy(d,s,n) memcpy_s_inline(d,n,s,n)
182 errno_t memset_s (void *s, rsize_t smax, int c, rsize_t n);
184 always_inline errno_t
185 memset_s_inline (void *s, rsize_t smax, int c, rsize_t n)
189 bad = (s == 0) + (n > smax);
191 if (PREDICT_FALSE (bad != 0))
194 clib_c11_violation ("s NULL");
196 clib_c11_violation ("n > smax");
204 * This macro is not [so much of] a crutch.
205 * It's super-typical to write:
207 * ep = pool_get (<pool>);
208 * clib_memset(ep, 0, sizeof (*ep));
210 * The compiler should delete the not-so useful
211 * (n > smax) test. TBH the NULL pointer check isn't
212 * so useful in this case, but so be it.
214 #define clib_memset(s,c,n) memset_s_inline(s,n,c,n)
216 static_always_inline void
217 clib_memcpy_le (u8 * dst, u8 * src, u8 len, u8 max_len)
219 #if defined (CLIB_HAVE_VEC256)
220 u8x32 s0, s1, d0, d1;
221 u8x32 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
222 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
224 u8x32 lv = u8x32_splat (len);
225 u8x32 add = u8x32_splat (32);
227 s0 = u8x32_load_unaligned (src);
228 s1 = u8x32_load_unaligned (src + 32);
229 d0 = u8x32_load_unaligned (dst);
230 d1 = u8x32_load_unaligned (dst + 32);
232 d0 = u8x32_blend (d0, s0, u8x32_is_greater (lv, mask));
233 u8x32_store_unaligned (d0, dst);
239 d1 = u8x32_blend (d1, s1, u8x32_is_greater (lv, mask));
240 u8x32_store_unaligned (d1, dst + 32);
242 #elif defined (CLIB_HAVE_VEC128)
243 u8x16 s0, s1, s2, s3, d0, d1, d2, d3;
244 u8x16 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
245 u8x16 lv = u8x16_splat (len);
246 u8x16 add = u8x16_splat (16);
248 s0 = u8x16_load_unaligned (src);
249 s1 = u8x16_load_unaligned (src + 16);
250 s2 = u8x16_load_unaligned (src + 32);
251 s3 = u8x16_load_unaligned (src + 48);
252 d0 = u8x16_load_unaligned (dst);
253 d1 = u8x16_load_unaligned (dst + 16);
254 d2 = u8x16_load_unaligned (dst + 32);
255 d3 = u8x16_load_unaligned (dst + 48);
257 d0 = u8x16_blend (d0, s0, u8x16_is_greater (lv, mask));
258 u8x16_store_unaligned (d0, dst);
264 d1 = u8x16_blend (d1, s1, u8x16_is_greater (lv, mask));
265 u8x16_store_unaligned (d1, dst + 16);
271 d2 = u8x16_blend (d2, s2, u8x16_is_greater (lv, mask));
272 u8x16_store_unaligned (d2, dst + 32);
275 d3 = u8x16_blend (d3, s3, u8x16_is_greater (lv, mask));
276 u8x16_store_unaligned (d3, dst + 48);
278 memmove (dst, src, len);
282 static_always_inline void
283 clib_memcpy_le64 (u8 * dst, u8 * src, u8 len)
285 clib_memcpy_le (dst, src, len, 64);
288 static_always_inline void
289 clib_memcpy_le32 (u8 * dst, u8 * src, u8 len)
291 clib_memcpy_le (dst, src, len, 32);
294 static_always_inline void
295 clib_memset_u64 (void *p, u64 val, uword count)
298 #if defined(CLIB_HAVE_VEC512)
299 u64x8 v512 = u64x8_splat (val);
302 u64x8_store_unaligned (v512, ptr);
309 #if defined(CLIB_HAVE_VEC256)
310 u64x4 v256 = u64x4_splat (val);
313 u64x4_store_unaligned (v256, ptr);
322 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
331 static_always_inline void
332 clib_memset_u32 (void *p, u32 val, uword count)
335 #if defined(CLIB_HAVE_VEC512)
336 u32x16 v512 = u32x16_splat (val);
339 u32x16_store_unaligned (v512, ptr);
346 #if defined(CLIB_HAVE_VEC256)
347 u32x8 v256 = u32x8_splat (val);
350 u32x8_store_unaligned (v256, ptr);
357 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
358 u32x4 v128 = u32x4_splat (val);
361 u32x4_store_unaligned (v128, ptr);
368 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
377 static_always_inline void
378 clib_memset_u16 (void *p, u16 val, uword count)
381 #if defined(CLIB_HAVE_VEC512)
382 u16x32 v512 = u16x32_splat (val);
385 u16x32_store_unaligned (v512, ptr);
392 #if defined(CLIB_HAVE_VEC256)
393 u16x16 v256 = u16x16_splat (val);
396 u16x16_store_unaligned (v256, ptr);
403 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
404 u16x8 v128 = u16x8_splat (val);
407 u16x8_store_unaligned (v128, ptr);
414 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
423 static_always_inline void
424 clib_memset_u8 (void *p, u8 val, uword count)
427 #if defined(CLIB_HAVE_VEC512)
428 u8x64 v512 = u8x64_splat (val);
431 u8x64_store_unaligned (v512, ptr);
438 #if defined(CLIB_HAVE_VEC256)
439 u8x32 v256 = u8x32_splat (val);
442 u8x32_store_unaligned (v256, ptr);
449 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
450 u8x16 v128 = u8x16_splat (val);
453 u8x16_store_unaligned (v128, ptr);
460 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
469 static_always_inline uword
470 clib_count_equal_u64 (u64 * data, uword max_count)
477 if (data[0] != data[1])
483 #if defined(CLIB_HAVE_VEC256)
484 u64x4 splat = u64x4_splat (first);
488 bmp = u8x32_msb_mask ((u8x32) (u64x4_load_unaligned (data) == splat));
489 if (bmp != 0xffffffff)
491 count += count_trailing_zeros (~bmp) / 8;
492 return clib_min (count, max_count);
498 if (count >= max_count)
504 while (count + 3 < max_count &&
505 ((data[0] ^ first) | (data[1] ^ first) |
506 (data[2] ^ first) | (data[3] ^ first)) == 0)
511 while (count < max_count && (data[0] == first))
519 static_always_inline uword
520 clib_count_equal_u32 (u32 * data, uword max_count)
527 if (data[0] != data[1])
533 #if defined(CLIB_HAVE_VEC256)
534 u32x8 splat = u32x8_splat (first);
538 bmp = u8x32_msb_mask ((u8x32) (u32x8_load_unaligned (data) == splat));
539 if (bmp != 0xffffffff)
541 count += count_trailing_zeros (~bmp) / 4;
542 return clib_min (count, max_count);
548 if (count >= max_count)
551 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
552 u32x4 splat = u32x4_splat (first);
556 bmp = u8x16_msb_mask ((u8x16) (u32x4_load_unaligned (data) == splat));
559 count += count_trailing_zeros (~bmp) / 4;
560 return clib_min (count, max_count);
566 if (count >= max_count)
572 while (count + 3 < max_count &&
573 ((data[0] ^ first) | (data[1] ^ first) |
574 (data[2] ^ first) | (data[3] ^ first)) == 0)
579 while (count < max_count && (data[0] == first))
587 static_always_inline uword
588 clib_count_equal_u16 (u16 * data, uword max_count)
595 if (data[0] != data[1])
601 #if defined(CLIB_HAVE_VEC256)
602 u16x16 splat = u16x16_splat (first);
606 bmp = u8x32_msb_mask ((u8x32) (u16x16_load_unaligned (data) == splat));
607 if (bmp != 0xffffffff)
609 count += count_trailing_zeros (~bmp) / 2;
610 return clib_min (count, max_count);
616 if (count >= max_count)
619 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
620 u16x8 splat = u16x8_splat (first);
624 bmp = u8x16_msb_mask ((u8x16) (u16x8_load_unaligned (data) == splat));
627 count += count_trailing_zeros (~bmp) / 2;
628 return clib_min (count, max_count);
634 if (count >= max_count)
640 while (count + 3 < max_count &&
641 ((data[0] ^ first) | (data[1] ^ first) |
642 (data[2] ^ first) | (data[3] ^ first)) == 0)
647 while (count < max_count && (data[0] == first))
655 static_always_inline uword
656 clib_count_equal_u8 (u8 * data, uword max_count)
663 if (data[0] != data[1])
669 #if defined(CLIB_HAVE_VEC256)
670 u8x32 splat = u8x32_splat (first);
674 bmp = u8x32_msb_mask ((u8x32) (u8x32_load_unaligned (data) == splat));
675 if (bmp != 0xffffffff)
677 count += count_trailing_zeros (~bmp);
678 return clib_min (count, max_count);
684 if (count >= max_count)
687 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
688 u8x16 splat = u8x16_splat (first);
692 bmp = u8x16_msb_mask ((u8x16) (u8x16_load_unaligned (data) == splat));
695 count += count_trailing_zeros (~bmp);
696 return clib_min (count, max_count);
702 if (count >= max_count)
708 while (count + 3 < max_count &&
709 ((data[0] ^ first) | (data[1] ^ first) |
710 (data[2] ^ first) | (data[3] ^ first)) == 0)
715 while (count < max_count && (data[0] == first))
724 * This macro is to provide smooth mapping from memcmp to memcmp_s.
725 * memcmp has fewer parameters and fewer returns than memcmp_s.
726 * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
727 * we return 0 and spit out a message in the console because there is
728 * no way to return the error code to the memcmp callers.
729 * This condition happens when s1 or s2 is null. Please note
730 * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
731 * anyway. So we are consistent in this case for the comparison return
732 * although we also spit out a C11 violation message in the console to
733 * warn that they pass null pointers for both s1 and s2.
734 * Applications are encouraged to use the cool C11 memcmp_s API to get the
735 * maximum benefit out of it.
737 #define clib_memcmp(s1,s2,m1) \
739 memcmp_s_inline (s1, m1, s2, m1, &__diff); \
743 errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
744 rsize_t s2max, int *diff);
746 always_inline errno_t
747 memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
752 bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
755 if (PREDICT_FALSE (bad != 0))
758 clib_c11_violation ("s1 NULL");
760 clib_c11_violation ("s2 NULL");
762 clib_c11_violation ("diff NULL");
764 clib_c11_violation ("s2max > s1max");
766 clib_c11_violation ("s2max 0");
768 clib_c11_violation ("s1max 0");
772 if (PREDICT_FALSE (s1 == s2))
778 *diff = memcmp (s1, s2, s2max);
783 * This macro is to provide smooth mapping from strnlen to strnlen_s
785 #define clib_strnlen(s,m) strnlen_s_inline(s,m)
787 size_t strnlen_s (const char *s, size_t maxsize);
790 strnlen_s_inline (const char *s, size_t maxsize)
794 bad = (s == 0) + (maxsize == 0);
795 if (PREDICT_FALSE (bad != 0))
798 clib_c11_violation ("s NULL");
800 clib_c11_violation ("maxsize 0");
803 return strnlen (s, maxsize);
807 * This macro is to provide smooth mapping from strcmp to strcmp_s.
808 * strcmp has fewer parameters and fewer returns than strcmp_s.
809 * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
810 * we return 0 and spit out a message in the console because
811 * there is no way to return the error to the strcmp callers.
812 * This condition happens when s1 or s2 is null. Please note in the extant
813 * strcmp call, they would end up crashing if one of them is null.
814 * So the new behavior is no crash, but an error is displayed in the
815 * console which I think is more user friendly. If both s1 and s2 are null,
816 * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
817 * to actually accessing the pointer contents. We are still consistent
818 * in this case for the comparison return although we also spit out a
819 * C11 violation message in the console to warn that they pass null pointers
820 * for both s1 and s2. The other problem is strcmp does not provide s1max,
821 * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
822 * If not, we may be accessing memory beyonf what is intended.
823 * Applications are encouraged to use the cool C11 strcmp_s API to get the
824 * maximum benefit out of it.
826 #define clib_strcmp(s1,s2) \
827 ({ int __indicator = 0; \
828 strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator); \
832 errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
835 always_inline errno_t
836 strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
841 bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
842 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
844 if (PREDICT_FALSE (bad != 0))
846 if (indicator == NULL)
847 clib_c11_violation ("indicator NULL");
849 clib_c11_violation ("s1 NULL");
851 clib_c11_violation ("s2 NULL");
853 clib_c11_violation ("s1max 0");
854 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
855 clib_c11_violation ("s1 unterminated");
859 *indicator = strcmp (s1, s2);
864 * This macro is to provide smooth mapping from strncmp to strncmp_s.
865 * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
866 * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
867 * we return 0 and spit out a message in the console because there is no
868 * means to return the error to the strncmp caller.
869 * This condition happens when s1 or s2 is null. In the extant strncmp call,
870 * they would end up crashing if one of them is null. So the new behavior is
871 * no crash, but error is displayed in the console which is more
872 * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
873 * strncmp did the pointers comparison prior to actually accessing the
874 * pointer contents. We are still consistent in this case for the comparison
875 * return although we also spit out a C11 violation message in the console to
876 * warn that they pass null pointers for both s1 and s2.
877 * Applications are encouraged to use the cool C11 strncmp_s API to get the
878 * maximum benefit out of it.
880 #define clib_strncmp(s1,s2,n) \
881 ({ int __indicator = 0; \
882 strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator); \
886 errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
889 always_inline errno_t
890 strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
894 u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
896 if (PREDICT_FALSE (s1_greater_s1max && indicator))
899 * strcmp allows n > s1max. If indicator is non null, we can still
900 * do the compare without any harm and return EINVAL as well as the
901 * result in indicator.
903 clib_c11_violation ("n exceeds s1 length");
904 *indicator = strncmp (s1, s2, n);
908 bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
909 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
911 if (PREDICT_FALSE (bad != 0))
913 if (indicator == NULL)
914 clib_c11_violation ("indicator NULL");
916 clib_c11_violation ("s1 NULL");
918 clib_c11_violation ("s2 NULL");
920 clib_c11_violation ("s1max 0");
921 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
922 clib_c11_violation ("s1 unterminated");
923 if (s1_greater_s1max)
924 clib_c11_violation ("n exceeds s1 length");
928 *indicator = strncmp (s1, s2, n);
933 * This macro is provided for smooth migration from strcpy. It is not perfect
934 * because we don't know the size of the destination buffer to pass to strcpy_s.
935 * We improvise dmax with CLIB_STRING_MACRO_MAX.
936 * Applications are encouraged to move to the C11 strcpy_s API.
938 #define clib_strcpy(d,s) strcpy_s_inline(d,CLIB_STRING_MACRO_MAX,s)
940 errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
941 const char *__restrict__ src);
943 always_inline errno_t
944 strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
945 const char *__restrict__ src)
951 bad = (dest == 0) + (dmax == 0) + (src == 0);
952 if (PREDICT_FALSE (bad != 0))
955 clib_c11_violation ("dest NULL");
957 clib_c11_violation ("src NULL");
959 clib_c11_violation ("dmax 0");
963 n = clib_strnlen (src, dmax);
964 if (PREDICT_FALSE (n >= dmax))
966 clib_c11_violation ("not enough space for dest");
969 /* Not actually trying to copy anything is OK */
970 if (PREDICT_FALSE (n == 0))
973 /* Check for src/dst overlap, which is not allowed */
974 low = (uword) (src < dest ? src : dest);
975 hi = (uword) (src < dest ? dest : src);
977 if (PREDICT_FALSE (low + (n - 1) >= hi))
979 clib_c11_violation ("src/dest overlap");
983 clib_memcpy_fast (dest, src, n);
989 * This macro is provided for smooth migration from strncpy. It is not perfect
990 * because we don't know the size of the destination buffer to pass to
991 * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
992 * Applications are encouraged to move to the C11 strncpy_s API and provide
993 * the correct dmax for better error checking.
995 #define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
998 strncpy_s (char *__restrict__ dest, rsize_t dmax,
999 const char *__restrict__ src, rsize_t n);
1001 always_inline errno_t
1002 strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
1003 const char *__restrict__ src, rsize_t n)
1008 errno_t status = EOK;
1010 bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
1011 if (PREDICT_FALSE (bad != 0))
1013 /* Not actually trying to copy anything is OK */
1017 clib_c11_violation ("dest NULL");
1019 clib_c11_violation ("src NULL");
1021 clib_c11_violation ("dmax 0");
1025 if (PREDICT_FALSE (n >= dmax))
1027 /* Relax and use strnlen of src */
1028 clib_c11_violation ("n >= dmax");
1029 m = clib_strnlen (src, dmax);
1032 /* Truncate, adjust copy length to fit dest */
1038 /* cap the copy to strlen(src) in case n > strlen(src) */
1039 m = clib_strnlen (src, n);
1041 /* Check for src/dst overlap, which is not allowed */
1042 low = (uword) (src < dest ? src : dest);
1043 hi = (uword) (src < dest ? dest : src);
1046 * This check may fail innocently if src + dmax >= dst, but
1047 * src + strlen(src) < dst. If it fails, check more carefully before
1048 * blowing the whistle.
1050 if (PREDICT_FALSE (low + (m - 1) >= hi))
1052 m = clib_strnlen (src, m);
1054 if (low + (m - 1) >= hi)
1056 clib_c11_violation ("src/dest overlap");
1061 clib_memcpy_fast (dest, src, m);
1067 * This macro is to provide smooth migration from strcat to strcat_s.
1068 * Because there is no dmax in strcat, we improvise it with
1069 * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite dest
1070 * with too many bytes from src.
1071 * Applications are encouraged to use C11 API to provide the actual dmax
1072 * for proper checking and protection.
1074 #define clib_strcat(d,s) strcat_s_inline(d,CLIB_STRING_MACRO_MAX,s)
1076 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
1077 const char *__restrict__ src);
1079 always_inline errno_t
1080 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
1081 const char *__restrict__ src)
1085 size_t m, n, dest_size;
1087 bad = (dest == 0) + (dmax == 0) + (src == 0);
1088 if (PREDICT_FALSE (bad != 0))
1091 clib_c11_violation ("dest NULL");
1093 clib_c11_violation ("src NULL");
1095 clib_c11_violation ("dmax 0");
1099 dest_size = clib_strnlen (dest, dmax);
1100 m = dmax - dest_size;
1101 n = clib_strnlen (src, m);
1102 if (PREDICT_FALSE (n >= m))
1104 clib_c11_violation ("not enough space for dest");
1108 /* Not actually trying to concatenate anything is OK */
1109 if (PREDICT_FALSE (n == 0))
1112 /* Check for src/dst overlap, which is not allowed */
1113 low = (uword) (src < dest ? src : dest);
1114 hi = (uword) (src < dest ? dest : src);
1116 if (PREDICT_FALSE (low + (n - 1) >= hi))
1118 clib_c11_violation ("src/dest overlap");
1122 clib_memcpy_fast (dest + dest_size, src, n);
1123 dest[dest_size + n] = '\0';
1128 * This macro is to provide smooth migration from strncat to strncat_s.
1129 * The unsafe strncat does not have s1max. We improvise it with
1130 * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite
1131 * dest with too many bytes from src.
1132 * Applications are encouraged to move to C11 strncat_s which requires dmax
1133 * from the caller and provides checking to safeguard the memory corruption.
1135 #define clib_strncat(d,s,n) strncat_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
1137 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
1138 const char *__restrict__ src, rsize_t n);
1140 always_inline errno_t
1141 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
1142 const char *__restrict__ src, rsize_t n)
1146 size_t m, dest_size, allowed_size;
1147 errno_t status = EOK;
1149 bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
1150 if (PREDICT_FALSE (bad != 0))
1152 /* Not actually trying to concatenate anything is OK */
1156 clib_c11_violation ("dest NULL");
1158 clib_c11_violation ("src NULL");
1160 clib_c11_violation ("dmax 0");
1164 /* Check for src/dst overlap, which is not allowed */
1165 low = (uword) (src < dest ? src : dest);
1166 hi = (uword) (src < dest ? dest : src);
1168 if (PREDICT_FALSE (low + (n - 1) >= hi))
1170 clib_c11_violation ("src/dest overlap");
1174 dest_size = clib_strnlen (dest, dmax);
1175 allowed_size = dmax - dest_size;
1177 if (PREDICT_FALSE (allowed_size == 0))
1179 clib_c11_violation ("no space left in dest");
1183 if (PREDICT_FALSE (n >= allowed_size))
1186 * unlike strcat_s, strncat_s will do the concatenation anyway when
1187 * there is not enough space in dest. But it will do the truncation and
1188 * null terminate dest
1190 m = clib_strnlen (src, allowed_size);
1191 if (m >= allowed_size)
1193 m = allowed_size - 1;
1198 m = clib_strnlen (src, n);
1200 clib_memcpy_fast (dest + dest_size, src, m);
1201 dest[dest_size + m] = '\0';
1206 * This macro is to provide smooth mapping from strtok_r to strtok_s.
1207 * To map strtok to this macro, the caller would have to supply an additional
1208 * argument. strtokr_s requires s1max which the unsafe API does not have. So
1209 * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
1210 * this macro cannot catch unterminated s1 and s2.
1211 * Applications are encouraged to use the cool C11 strtok_s API to avoid
1214 #define clib_strtok(s1,s2,p) \
1215 ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX; \
1216 strtok_s_inline (s1, &__s1max, s2, p); \
1219 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1220 const char *__restrict__ s2, char **__restrict__ ptr);
1222 always_inline char *
1223 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1224 const char *__restrict__ s2, char **__restrict__ ptr)
1226 #define STRTOK_DELIM_MAX_LEN 16
1232 bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
1233 ((s1 == 0) && ptr && (*ptr == 0));
1234 if (PREDICT_FALSE (bad != 0))
1237 clib_c11_violation ("s2 NULL");
1239 clib_c11_violation ("s1max is NULL");
1241 clib_c11_violation ("ptr is NULL");
1242 /* s1 == 0 and *ptr == null is no good */
1243 if ((s1 == 0) && ptr && (*ptr == 0))
1244 clib_c11_violation ("s1 and ptr contents are NULL");
1252 * scan s1 for a delimiter
1256 while (*s1 != '\0' && !ptoken)
1258 if (PREDICT_FALSE (dlen == 0))
1261 clib_c11_violation ("s1 unterminated");
1266 * must scan the entire delimiter list
1267 * ISO should have included a delimiter string limit!!
1269 slen = STRTOK_DELIM_MAX_LEN;
1273 if (PREDICT_FALSE (slen == 0))
1276 clib_c11_violation ("s2 unterminated");
1296 * if the beginning of a token was not found, then no
1297 * need to continue the scan.
1306 * Now we need to locate the end of the token
1313 clib_c11_violation ("s1 unterminated");
1317 slen = STRTOK_DELIM_MAX_LEN;
1324 clib_c11_violation ("s2 unterminated");
1331 * found a delimiter, set to null
1332 * and return context ptr to next char
1335 *ptr = (s1 + 1); /* return pointer for next scan */
1336 *s1max = dlen - 1; /* account for the nulled delimiter */
1342 * simply scanning through the delimiter string
1357 * This macro is to provide smooth mapping from strstr to strstr_s.
1358 * strstr_s requires s1max and s2max which the unsafe API does not have. So
1359 * we have to improvise them with CLIB_STRING_MACRO_MAX which may cause us
1360 * to access memory beyond it is intended if s1 or s2 is unterminated.
1361 * For the record, strstr crashes if s1 or s2 is unterminated. But this macro
1363 * Applications are encouraged to use the cool C11 strstr_s API to avoid
1366 #define clib_strstr(s1,s2) \
1367 ({ char * __substring = 0; \
1368 strstr_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, CLIB_STRING_MACRO_MAX, \
1373 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1376 always_inline errno_t
1377 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1381 size_t s1_size, s2_size;
1384 (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1385 (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1386 (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1387 if (PREDICT_FALSE (bad != 0))
1390 clib_c11_violation ("s1 NULL");
1392 clib_c11_violation ("s2 NULL");
1394 clib_c11_violation ("s1max 0");
1396 clib_c11_violation ("s2max 0");
1398 clib_c11_violation ("substring NULL");
1399 if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1400 clib_c11_violation ("s1 unterminated");
1401 if (s2 && s2max && (s2[clib_strnlen (s2, s1max)] != '\0'))
1402 clib_c11_violation ("s2 unterminated");
1407 * s2 points to a string with zero length, or s2 equals s1, return s1
1409 if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1416 * s2_size > s1_size, it won't find match.
1418 s1_size = clib_strnlen (s1, s1max);
1419 s2_size = clib_strnlen (s2, s2max);
1420 if (PREDICT_FALSE (s2_size > s1_size))
1423 *substring = strstr (s1, s2);
1424 if (*substring == 0)
1430 #endif /* included_clib_string_h */
1433 * fd.io coding-style-patch-verification: ON
1436 * eval: (c-set-style "gnu")