FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
string.h
Go to the documentation of this file.
1 /*
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:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15 /*
16  Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
17 
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:
25 
26  The above copyright notice and this permission notice shall be
27  included in all copies or substantial portions of the Software.
28 
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.
36 */
37 
38 /** \file
39 
40  Optimized string handling code, including c11-compliant
41  "safe C library" variants.
42 */
43 
44 #ifndef included_clib_string_h
45 #define included_clib_string_h
46 
47 #include <vppinfra/clib.h> /* for CLIB_LINUX_KERNEL */
48 #include <vppinfra/vector.h>
49 
50 #ifdef CLIB_LINUX_KERNEL
51 #include <linux/string.h>
52 #endif
53 
54 #ifdef CLIB_UNIX
55 #include <string.h>
56 #endif
57 
58 #ifdef CLIB_STANDALONE
59 #include <vppinfra/standalone_string.h>
60 #endif
61 
62 #if _x86_64_
63 #include <x86intrin.h>
64 #endif
65 
66 /* Exchanges source and destination. */
67 void clib_memswap (void *_a, void *_b, uword bytes);
68 
69 /*
70  * the vector unit memcpy variants confuse coverity
71  * so don't let it anywhere near them.
72  */
73 #ifndef __COVERITY__
74 #if __AVX512F__
75 #include <vppinfra/memcpy_avx512.h>
76 #elif __AVX2__
77 #include <vppinfra/memcpy_avx2.h>
78 #elif __SSSE3__
79 #include <vppinfra/memcpy_sse3.h>
80 #else
81 #define clib_memcpy_fast(a,b,c) memcpy(a,b,c)
82 #endif
83 #else /* __COVERITY__ */
84 #define clib_memcpy_fast(a,b,c) memcpy(a,b,c)
85 #endif
86 
87 /* c-11 string manipulation variants */
88 
89 #ifndef EOK
90 #define EOK 0
91 #endif
92 #ifndef EINVAL
93 #define EINVAL 22
94 #endif
95 #ifndef ESRCH
96 #define ESRCH 3
97 #endif
98 #ifndef EOVERFLOW
99 #define EOVERFLOW 75
100 #endif
101 
102 /*
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.
110  */
111 #define CLIB_STRING_MACRO_MAX 4096
112 
113 typedef int errno_t;
114 typedef uword rsize_t;
115 
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);
119 
121 memcpy_s_inline (void *__restrict__ dest, rsize_t dmax,
122  const void *__restrict__ src, rsize_t n)
123 {
124  uword low, hi;
125  u8 bad;
126 
127  /*
128  * Optimize constant-number-of-bytes calls without asking
129  * "too many questions for someone from New Jersey"
130  */
131  if (__builtin_constant_p (n))
132  {
133  clib_memcpy_fast (dest, src, n);
134  return EOK;
135  }
136 
137  /*
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...
142  */
143  bad = (dest == 0) + (src == 0) + (n > dmax) + (dest == src) + (n == 0);
144  if (PREDICT_FALSE (bad != 0))
145  {
146  /* Not actually trying to copy anything is OK */
147  if (n == 0)
148  return EOK;
149  if (dest == NULL)
150  clib_c11_violation ("dest NULL");
151  if (src == NULL)
152  clib_c11_violation ("src NULL");
153  if (n > dmax)
154  clib_c11_violation ("n > dmax");
155  if (dest == src)
156  clib_c11_violation ("dest == src");
157  return EINVAL;
158  }
159 
160  /* Check for src/dst overlap, which is not allowed */
161  low = (uword) (src < dest ? src : dest);
162  hi = (uword) (src < dest ? dest : src);
163 
164  if (PREDICT_FALSE (low + (n - 1) >= hi))
165  {
166  clib_c11_violation ("src/dest overlap");
167  return EINVAL;
168  }
169 
170  clib_memcpy_fast (dest, src, n);
171  return EOK;
172 }
173 
174 /*
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
178  * argument...
179  */
180 #define clib_memcpy(d,s,n) memcpy_s_inline(d,n,s,n)
181 
182 errno_t memset_s (void *s, rsize_t smax, int c, rsize_t n);
183 
185 memset_s_inline (void *s, rsize_t smax, int c, rsize_t n)
186 {
187  u8 bad;
188 
189  bad = (s == 0) + (n > smax);
190 
191  if (PREDICT_FALSE (bad != 0))
192  {
193  if (s == 0)
194  clib_c11_violation ("s NULL");
195  if (n > smax)
196  clib_c11_violation ("n > smax");
197  return (EINVAL);
198  }
199  memset (s, c, n);
200  return (EOK);
201 }
202 
203 /*
204  * This macro is not [so much of] a crutch.
205  * It's super-typical to write:
206  *
207  * ep = pool_get (<pool>);
208  * clib_memset(ep, 0, sizeof (*ep));
209  *
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.
213  */
214 #define clib_memset(s,c,n) memset_s_inline(s,n,c,n)
215 
217 clib_memcpy_le (u8 * dst, u8 * src, u8 len, u8 max_len)
218 {
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
223  };
224  u8x32 lv = u8x32_splat (len);
225  u8x32 add = u8x32_splat (32);
226 
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);
231 
232  d0 = u8x32_blend (d0, s0, u8x32_is_greater (lv, mask));
233  u8x32_store_unaligned (d0, dst);
234 
235  if (max_len <= 32)
236  return;
237 
238  mask += add;
239  d1 = u8x32_blend (d1, s1, u8x32_is_greater (lv, mask));
240  u8x32_store_unaligned (d1, dst + 32);
241 
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);
247 
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);
256 
257  d0 = u8x16_blend (d0, s0, u8x16_is_greater (lv, mask));
258  u8x16_store_unaligned (d0, dst);
259 
260  if (max_len <= 16)
261  return;
262 
263  mask += add;
264  d1 = u8x16_blend (d1, s1, u8x16_is_greater (lv, mask));
265  u8x16_store_unaligned (d1, dst + 16);
266 
267  if (max_len <= 32)
268  return;
269 
270  mask += add;
271  d2 = u8x16_blend (d2, s2, u8x16_is_greater (lv, mask));
272  u8x16_store_unaligned (d2, dst + 32);
273 
274  mask += add;
275  d3 = u8x16_blend (d3, s3, u8x16_is_greater (lv, mask));
276  u8x16_store_unaligned (d3, dst + 48);
277 #else
278  memmove (dst, src, len);
279 #endif
280 }
281 
284 {
285  clib_memcpy_le (dst, src, len, 64);
286 }
287 
290 {
291  clib_memcpy_le (dst, src, len, 32);
292 }
293 
296 {
297  u64 *ptr = p;
298 #if defined(CLIB_HAVE_VEC512)
299  u64x8 v512 = u64x8_splat (val);
300  while (count >= 8)
301  {
302  u64x8_store_unaligned (v512, ptr);
303  ptr += 8;
304  count -= 8;
305  }
306  if (count == 0)
307  return;
308 #endif
309 #if defined(CLIB_HAVE_VEC256)
310  u64x4 v256 = u64x4_splat (val);
311  while (count >= 4)
312  {
313  u64x4_store_unaligned (v256, ptr);
314  ptr += 4;
315  count -= 4;
316  }
317  if (count == 0)
318  return;
319 #else
320  while (count >= 4)
321  {
322  ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
323  ptr += 4;
324  count -= 4;
325  }
326 #endif
327  while (count--)
328  ptr++[0] = val;
329 }
330 
333 {
334  u32 *ptr = p;
335 #if defined(CLIB_HAVE_VEC512)
336  u32x16 v512 = u32x16_splat (val);
337  while (count >= 16)
338  {
339  u32x16_store_unaligned (v512, ptr);
340  ptr += 16;
341  count -= 16;
342  }
343  if (count == 0)
344  return;
345 #endif
346 #if defined(CLIB_HAVE_VEC256)
347  u32x8 v256 = u32x8_splat (val);
348  while (count >= 8)
349  {
350  u32x8_store_unaligned (v256, ptr);
351  ptr += 8;
352  count -= 8;
353  }
354  if (count == 0)
355  return;
356 #endif
357 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
358  u32x4 v128 = u32x4_splat (val);
359  while (count >= 4)
360  {
361  u32x4_store_unaligned (v128, ptr);
362  ptr += 4;
363  count -= 4;
364  }
365 #else
366  while (count >= 4)
367  {
368  ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
369  ptr += 4;
370  count -= 4;
371  }
372 #endif
373  while (count--)
374  ptr++[0] = val;
375 }
376 
379 {
380  u16 *ptr = p;
381 #if defined(CLIB_HAVE_VEC512)
382  u16x32 v512 = u16x32_splat (val);
383  while (count >= 32)
384  {
385  u16x32_store_unaligned (v512, ptr);
386  ptr += 32;
387  count -= 32;
388  }
389  if (count == 0)
390  return;
391 #endif
392 #if defined(CLIB_HAVE_VEC256)
393  u16x16 v256 = u16x16_splat (val);
394  while (count >= 16)
395  {
396  u16x16_store_unaligned (v256, ptr);
397  ptr += 16;
398  count -= 16;
399  }
400  if (count == 0)
401  return;
402 #endif
403 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
404  u16x8 v128 = u16x8_splat (val);
405  while (count >= 8)
406  {
407  u16x8_store_unaligned (v128, ptr);
408  ptr += 8;
409  count -= 8;
410  }
411 #else
412  while (count >= 4)
413  {
414  ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
415  ptr += 4;
416  count -= 4;
417  }
418 #endif
419  while (count--)
420  ptr++[0] = val;
421 }
422 
424 clib_memset_u8 (void *p, u8 val, uword count)
425 {
426  u8 *ptr = p;
427 #if defined(CLIB_HAVE_VEC512)
428  u8x64 v512 = u8x64_splat (val);
429  while (count >= 64)
430  {
431  u8x64_store_unaligned (v512, ptr);
432  ptr += 64;
433  count -= 64;
434  }
435  if (count == 0)
436  return;
437 #endif
438 #if defined(CLIB_HAVE_VEC256)
439  u8x32 v256 = u8x32_splat (val);
440  while (count >= 32)
441  {
442  u8x32_store_unaligned (v256, ptr);
443  ptr += 32;
444  count -= 32;
445  }
446  if (count == 0)
447  return;
448 #endif
449 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
450  u8x16 v128 = u8x16_splat (val);
451  while (count >= 16)
452  {
453  u8x16_store_unaligned (v128, ptr);
454  ptr += 16;
455  count -= 16;
456  }
457 #else
458  while (count >= 4)
459  {
460  ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
461  ptr += 4;
462  count -= 4;
463  }
464 #endif
465  while (count--)
466  ptr++[0] = val;
467 }
468 
471 {
472  uword count;
473  u64 first;
474 
475  if (max_count == 1)
476  return 1;
477  if (data[0] != data[1])
478  return 1;
479 
480  count = 0;
481  first = data[0];
482 
483 #if defined(CLIB_HAVE_VEC256)
484  u64x4 splat = u64x4_splat (first);
485  while (1)
486  {
487  u64 bmp;
488  bmp = u8x32_msb_mask ((u8x32) (u64x4_load_unaligned (data) == splat));
489  if (bmp != 0xffffffff)
490  {
491  count += count_trailing_zeros (~bmp) / 8;
492  return clib_min (count, max_count);
493  }
494 
495  data += 4;
496  count += 4;
497 
498  if (count >= max_count)
499  return max_count;
500  }
501 #endif
502  count += 2;
503  data += 2;
504  while (count + 3 < max_count &&
505  ((data[0] ^ first) | (data[1] ^ first) |
506  (data[2] ^ first) | (data[3] ^ first)) == 0)
507  {
508  data += 4;
509  count += 4;
510  }
511  while (count < max_count && (data[0] == first))
512  {
513  data += 1;
514  count += 1;
515  }
516  return count;
517 }
518 
521 {
522  uword count;
523  u32 first;
524 
525  if (max_count == 1)
526  return 1;
527  if (data[0] != data[1])
528  return 1;
529 
530  count = 0;
531  first = data[0];
532 
533 #if defined(CLIB_HAVE_VEC256)
534  u32x8 splat = u32x8_splat (first);
535  while (1)
536  {
537  u64 bmp;
538  bmp = u8x32_msb_mask ((u8x32) (u32x8_load_unaligned (data) == splat));
539  if (bmp != 0xffffffff)
540  {
541  count += count_trailing_zeros (~bmp) / 4;
542  return clib_min (count, max_count);
543  }
544 
545  data += 8;
546  count += 8;
547 
548  if (count >= max_count)
549  return max_count;
550  }
551 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
552  u32x4 splat = u32x4_splat (first);
553  while (1)
554  {
555  u64 bmp;
556  bmp = u8x16_msb_mask ((u8x16) (u32x4_load_unaligned (data) == splat));
557  if (bmp != 0xffff)
558  {
559  count += count_trailing_zeros (~bmp) / 4;
560  return clib_min (count, max_count);
561  }
562 
563  data += 4;
564  count += 4;
565 
566  if (count >= max_count)
567  return max_count;
568  }
569 #endif
570  count += 2;
571  data += 2;
572  while (count + 3 < max_count &&
573  ((data[0] ^ first) | (data[1] ^ first) |
574  (data[2] ^ first) | (data[3] ^ first)) == 0)
575  {
576  data += 4;
577  count += 4;
578  }
579  while (count < max_count && (data[0] == first))
580  {
581  data += 1;
582  count += 1;
583  }
584  return count;
585 }
586 
589 {
590  uword count;
591  u16 first;
592 
593  if (max_count == 1)
594  return 1;
595  if (data[0] != data[1])
596  return 1;
597 
598  count = 0;
599  first = data[0];
600 
601 #if defined(CLIB_HAVE_VEC256)
602  u16x16 splat = u16x16_splat (first);
603  while (1)
604  {
605  u64 bmp;
606  bmp = u8x32_msb_mask ((u8x32) (u16x16_load_unaligned (data) == splat));
607  if (bmp != 0xffffffff)
608  {
609  count += count_trailing_zeros (~bmp) / 2;
610  return clib_min (count, max_count);
611  }
612 
613  data += 16;
614  count += 16;
615 
616  if (count >= max_count)
617  return max_count;
618  }
619 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
620  u16x8 splat = u16x8_splat (first);
621  while (1)
622  {
623  u64 bmp;
624  bmp = u8x16_msb_mask ((u8x16) (u16x8_load_unaligned (data) == splat));
625  if (bmp != 0xffff)
626  {
627  count += count_trailing_zeros (~bmp) / 2;
628  return clib_min (count, max_count);
629  }
630 
631  data += 8;
632  count += 8;
633 
634  if (count >= max_count)
635  return max_count;
636  }
637 #endif
638  count += 2;
639  data += 2;
640  while (count + 3 < max_count &&
641  ((data[0] ^ first) | (data[1] ^ first) |
642  (data[2] ^ first) | (data[3] ^ first)) == 0)
643  {
644  data += 4;
645  count += 4;
646  }
647  while (count < max_count && (data[0] == first))
648  {
649  data += 1;
650  count += 1;
651  }
652  return count;
653 }
654 
657 {
658  uword count;
659  u8 first;
660 
661  if (max_count == 1)
662  return 1;
663  if (data[0] != data[1])
664  return 1;
665 
666  count = 0;
667  first = data[0];
668 
669 #if defined(CLIB_HAVE_VEC256)
670  u8x32 splat = u8x32_splat (first);
671  while (1)
672  {
673  u64 bmp;
674  bmp = u8x32_msb_mask ((u8x32) (u8x32_load_unaligned (data) == splat));
675  if (bmp != 0xffffffff)
676  {
677  count += count_trailing_zeros (~bmp);
678  return clib_min (count, max_count);
679  }
680 
681  data += 32;
682  count += 32;
683 
684  if (count >= max_count)
685  return max_count;
686  }
687 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
688  u8x16 splat = u8x16_splat (first);
689  while (1)
690  {
691  u64 bmp;
692  bmp = u8x16_msb_mask ((u8x16) (u8x16_load_unaligned (data) == splat));
693  if (bmp != 0xffff)
694  {
695  count += count_trailing_zeros (~bmp);
696  return clib_min (count, max_count);
697  }
698 
699  data += 16;
700  count += 16;
701 
702  if (count >= max_count)
703  return max_count;
704  }
705 #endif
706  count += 2;
707  data += 2;
708  while (count + 3 < max_count &&
709  ((data[0] ^ first) | (data[1] ^ first) |
710  (data[2] ^ first) | (data[3] ^ first)) == 0)
711  {
712  data += 4;
713  count += 4;
714  }
715  while (count < max_count && (data[0] == first))
716  {
717  data += 1;
718  count += 1;
719  }
720  return count;
721 }
722 
723 /*
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.
736  */
737 #define clib_memcmp(s1,s2,m1) \
738  ({ int __diff = 0; \
739  memcmp_s_inline (s1, m1, s2, m1, &__diff); \
740  __diff; \
741  })
742 
743 errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
744  rsize_t s2max, int *diff);
745 
747 memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
748  int *diff)
749 {
750  u8 bad;
751 
752  bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
753  (s1max == 0);
754 
755  if (PREDICT_FALSE (bad != 0))
756  {
757  if (s1 == NULL)
758  clib_c11_violation ("s1 NULL");
759  if (s2 == NULL)
760  clib_c11_violation ("s2 NULL");
761  if (diff == NULL)
762  clib_c11_violation ("diff NULL");
763  if (s2max > s1max)
764  clib_c11_violation ("s2max > s1max");
765  if (s2max == 0)
766  clib_c11_violation ("s2max 0");
767  if (s1max == 0)
768  clib_c11_violation ("s1max 0");
769  return EINVAL;
770  }
771 
772  if (PREDICT_FALSE (s1 == s2))
773  {
774  *diff = 0;
775  return EOK;
776  }
777 
778  *diff = memcmp (s1, s2, s2max);
779  return EOK;
780 }
781 
782 /*
783  * This macro is to provide smooth mapping from strnlen to strnlen_s
784  */
785 #define clib_strnlen(s,m) strnlen_s_inline(s,m)
786 
787 size_t strnlen_s (const char *s, size_t maxsize);
788 
789 always_inline size_t
790 strnlen_s_inline (const char *s, size_t maxsize)
791 {
792  u8 bad;
793 
794  bad = (s == 0) + (maxsize == 0);
795  if (PREDICT_FALSE (bad != 0))
796  {
797  if (s == 0)
798  clib_c11_violation ("s NULL");
799  if (maxsize == 0)
800  clib_c11_violation ("maxsize 0");
801  return 0;
802  }
803  return strnlen (s, maxsize);
804 }
805 
806 /*
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.
825  */
826 #define clib_strcmp(s1,s2) \
827  ({ int __indicator = 0; \
828  strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator); \
829  __indicator; \
830  })
831 
832 errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
833  int *indicator);
834 
836 strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
837  int *indicator)
838 {
839  u8 bad;
840 
841  bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
842  (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
843 
844  if (PREDICT_FALSE (bad != 0))
845  {
846  if (indicator == NULL)
847  clib_c11_violation ("indicator NULL");
848  if (s1 == NULL)
849  clib_c11_violation ("s1 NULL");
850  if (s2 == NULL)
851  clib_c11_violation ("s2 NULL");
852  if (s1max == 0)
853  clib_c11_violation ("s1max 0");
854  if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
855  clib_c11_violation ("s1 unterminated");
856  return EINVAL;
857  }
858 
859  *indicator = strcmp (s1, s2);
860  return EOK;
861 }
862 
863 /*
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.
879  */
880 #define clib_strncmp(s1,s2,n) \
881  ({ int __indicator = 0; \
882  strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator); \
883  __indicator; \
884  })
885 
886 errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
887  int *indicator);
888 
890 strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
891  int *indicator)
892 {
893  u8 bad;
894  u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
895 
896  if (PREDICT_FALSE (s1_greater_s1max && indicator))
897  {
898  /*
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.
902  */
903  clib_c11_violation ("n exceeds s1 length");
904  *indicator = strncmp (s1, s2, n);
905  return EINVAL;
906  }
907 
908  bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
909  (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
910 
911  if (PREDICT_FALSE (bad != 0))
912  {
913  if (indicator == NULL)
914  clib_c11_violation ("indicator NULL");
915  if (s1 == NULL)
916  clib_c11_violation ("s1 NULL");
917  if (s2 == NULL)
918  clib_c11_violation ("s2 NULL");
919  if (s1max == 0)
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");
925  return EINVAL;
926  }
927 
928  *indicator = strncmp (s1, s2, n);
929  return EOK;
930 }
931 
932 /*
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.
937  */
938 #define clib_strcpy(d,s) strcpy_s_inline(d,CLIB_STRING_MACRO_MAX,s)
939 
940 errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
941  const char *__restrict__ src);
942 
944 strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
945  const char *__restrict__ src)
946 {
947  u8 bad;
948  uword low, hi;
949  size_t n;
950 
951  bad = (dest == 0) + (dmax == 0) + (src == 0);
952  if (PREDICT_FALSE (bad != 0))
953  {
954  if (dest == 0)
955  clib_c11_violation ("dest NULL");
956  if (src == 0)
957  clib_c11_violation ("src NULL");
958  if (dmax == 0)
959  clib_c11_violation ("dmax 0");
960  return EINVAL;
961  }
962 
963  n = clib_strnlen (src, dmax);
964  if (PREDICT_FALSE (n >= dmax))
965  {
966  clib_c11_violation ("not enough space for dest");
967  return (EINVAL);
968  }
969  /* Not actually trying to copy anything is OK */
970  if (PREDICT_FALSE (n == 0))
971  return EOK;
972 
973  /* Check for src/dst overlap, which is not allowed */
974  low = (uword) (src < dest ? src : dest);
975  hi = (uword) (src < dest ? dest : src);
976 
977  if (PREDICT_FALSE (low + (n - 1) >= hi))
978  {
979  clib_c11_violation ("src/dest overlap");
980  return EINVAL;
981  }
982 
983  clib_memcpy_fast (dest, src, n);
984  dest[n] = '\0';
985  return EOK;
986 }
987 
988 /*
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.
994  */
995 #define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
996 
997 errno_t
998 strncpy_s (char *__restrict__ dest, rsize_t dmax,
999  const char *__restrict__ src, rsize_t n);
1000 
1002 strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
1003  const char *__restrict__ src, rsize_t n)
1004 {
1005  u8 bad;
1006  uword low, hi;
1007  rsize_t m;
1008  errno_t status = EOK;
1009 
1010  bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
1011  if (PREDICT_FALSE (bad != 0))
1012  {
1013  /* Not actually trying to copy anything is OK */
1014  if (n == 0)
1015  return EOK;
1016  if (dest == 0)
1017  clib_c11_violation ("dest NULL");
1018  if (src == 0)
1019  clib_c11_violation ("src NULL");
1020  if (dmax == 0)
1021  clib_c11_violation ("dmax 0");
1022  return EINVAL;
1023  }
1024 
1025  if (PREDICT_FALSE (n >= dmax))
1026  {
1027  /* Relax and use strnlen of src */
1028  clib_c11_violation ("n >= dmax");
1029  m = clib_strnlen (src, dmax);
1030  if (m >= dmax)
1031  {
1032  /* Truncate, adjust copy length to fit dest */
1033  m = dmax - 1;
1034  status = EOVERFLOW;
1035  }
1036  }
1037  else
1038  /* cap the copy to strlen(src) in case n > strlen(src) */
1039  m = clib_strnlen (src, n);
1040 
1041  /* Check for src/dst overlap, which is not allowed */
1042  low = (uword) (src < dest ? src : dest);
1043  hi = (uword) (src < dest ? dest : src);
1044 
1045  /*
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.
1049  */
1050  if (PREDICT_FALSE (low + (m - 1) >= hi))
1051  {
1052  m = clib_strnlen (src, m);
1053 
1054  if (low + (m - 1) >= hi)
1055  {
1056  clib_c11_violation ("src/dest overlap");
1057  return EINVAL;
1058  }
1059  }
1060 
1061  clib_memcpy_fast (dest, src, m);
1062  dest[m] = '\0';
1063  return status;
1064 }
1065 
1066 /*
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.
1073  */
1074 #define clib_strcat(d,s) strcat_s_inline(d,CLIB_STRING_MACRO_MAX,s)
1075 
1076 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
1077  const char *__restrict__ src);
1078 
1080 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
1081  const char *__restrict__ src)
1082 {
1083  u8 bad;
1084  uword low, hi;
1085  size_t m, n, dest_size;
1086 
1087  bad = (dest == 0) + (dmax == 0) + (src == 0);
1088  if (PREDICT_FALSE (bad != 0))
1089  {
1090  if (dest == 0)
1091  clib_c11_violation ("dest NULL");
1092  if (src == 0)
1093  clib_c11_violation ("src NULL");
1094  if (dmax == 0)
1095  clib_c11_violation ("dmax 0");
1096  return EINVAL;
1097  }
1098 
1099  dest_size = clib_strnlen (dest, dmax);
1100  m = dmax - dest_size;
1101  n = clib_strnlen (src, m);
1102  if (PREDICT_FALSE (n >= m))
1103  {
1104  clib_c11_violation ("not enough space for dest");
1105  return EINVAL;
1106  }
1107 
1108  /* Not actually trying to concatenate anything is OK */
1109  if (PREDICT_FALSE (n == 0))
1110  return EOK;
1111 
1112  /* Check for src/dst overlap, which is not allowed */
1113  low = (uword) (src < dest ? src : dest);
1114  hi = (uword) (src < dest ? dest : src);
1115 
1116  if (PREDICT_FALSE (low + (n - 1) >= hi))
1117  {
1118  clib_c11_violation ("src/dest overlap");
1119  return EINVAL;
1120  }
1121 
1122  clib_memcpy_fast (dest + dest_size, src, n);
1123  dest[dest_size + n] = '\0';
1124  return EOK;
1125 }
1126 
1127 /*
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.
1134  */
1135 #define clib_strncat(d,s,n) strncat_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
1136 
1137 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
1138  const char *__restrict__ src, rsize_t n);
1139 
1141 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
1142  const char *__restrict__ src, rsize_t n)
1143 {
1144  u8 bad;
1145  uword low, hi;
1146  size_t m, dest_size, allowed_size;
1147  errno_t status = EOK;
1148 
1149  bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
1150  if (PREDICT_FALSE (bad != 0))
1151  {
1152  /* Not actually trying to concatenate anything is OK */
1153  if (n == 0)
1154  return EOK;
1155  if (dest == 0)
1156  clib_c11_violation ("dest NULL");
1157  if (src == 0)
1158  clib_c11_violation ("src NULL");
1159  if (dmax == 0)
1160  clib_c11_violation ("dmax 0");
1161  return EINVAL;
1162  }
1163 
1164  /* Check for src/dst overlap, which is not allowed */
1165  low = (uword) (src < dest ? src : dest);
1166  hi = (uword) (src < dest ? dest : src);
1167 
1168  if (PREDICT_FALSE (low + (n - 1) >= hi))
1169  {
1170  clib_c11_violation ("src/dest overlap");
1171  return EINVAL;
1172  }
1173 
1174  dest_size = clib_strnlen (dest, dmax);
1175  allowed_size = dmax - dest_size;
1176 
1177  if (PREDICT_FALSE (allowed_size == 0))
1178  {
1179  clib_c11_violation ("no space left in dest");
1180  return (EINVAL);
1181  }
1182 
1183  if (PREDICT_FALSE (n >= allowed_size))
1184  {
1185  /*
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
1189  */
1190  m = clib_strnlen (src, allowed_size);
1191  if (m >= allowed_size)
1192  {
1193  m = allowed_size - 1;
1194  status = EOVERFLOW;
1195  }
1196  }
1197  else
1198  m = clib_strnlen (src, n);
1199 
1200  clib_memcpy_fast (dest + dest_size, src, m);
1201  dest[dest_size + m] = '\0';
1202  return status;
1203 }
1204 
1205 /*
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
1212  * these problems.
1213  */
1214 #define clib_strtok(s1,s2,p) \
1215  ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX; \
1216  strtok_s_inline (s1, &__s1max, s2, p); \
1217  })
1218 
1219 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1220  const char *__restrict__ s2, char **__restrict__ ptr);
1221 
1222 always_inline char *
1223 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1224  const char *__restrict__ s2, char **__restrict__ ptr)
1225 {
1226 #define STRTOK_DELIM_MAX_LEN 16
1227  u8 bad;
1228  const char *pt;
1229  char *ptoken;
1230  uword dlen, slen;
1231 
1232  bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
1233  ((s1 == 0) && ptr && (*ptr == 0));
1234  if (PREDICT_FALSE (bad != 0))
1235  {
1236  if (s2 == NULL)
1237  clib_c11_violation ("s2 NULL");
1238  if (s1max == NULL)
1239  clib_c11_violation ("s1max is NULL");
1240  if (ptr == 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");
1245  return 0;
1246  }
1247 
1248  if (s1 == 0)
1249  s1 = *ptr;
1250 
1251  /*
1252  * scan s1 for a delimiter
1253  */
1254  dlen = *s1max;
1255  ptoken = 0;
1256  while (*s1 != '\0' && !ptoken)
1257  {
1258  if (PREDICT_FALSE (dlen == 0))
1259  {
1260  *ptr = 0;
1261  clib_c11_violation ("s1 unterminated");
1262  return 0;
1263  }
1264 
1265  /*
1266  * must scan the entire delimiter list
1267  * ISO should have included a delimiter string limit!!
1268  */
1269  slen = STRTOK_DELIM_MAX_LEN;
1270  pt = s2;
1271  while (*pt != '\0')
1272  {
1273  if (PREDICT_FALSE (slen == 0))
1274  {
1275  *ptr = 0;
1276  clib_c11_violation ("s2 unterminated");
1277  return 0;
1278  }
1279  slen--;
1280  if (*s1 == *pt)
1281  {
1282  ptoken = 0;
1283  break;
1284  }
1285  else
1286  {
1287  pt++;
1288  ptoken = s1;
1289  }
1290  }
1291  s1++;
1292  dlen--;
1293  }
1294 
1295  /*
1296  * if the beginning of a token was not found, then no
1297  * need to continue the scan.
1298  */
1299  if (ptoken == 0)
1300  {
1301  *s1max = dlen;
1302  return (ptoken);
1303  }
1304 
1305  /*
1306  * Now we need to locate the end of the token
1307  */
1308  while (*s1 != '\0')
1309  {
1310  if (dlen == 0)
1311  {
1312  *ptr = 0;
1313  clib_c11_violation ("s1 unterminated");
1314  return 0;
1315  }
1316 
1317  slen = STRTOK_DELIM_MAX_LEN;
1318  pt = s2;
1319  while (*pt != '\0')
1320  {
1321  if (slen == 0)
1322  {
1323  *ptr = 0;
1324  clib_c11_violation ("s2 unterminated");
1325  return 0;
1326  }
1327  slen--;
1328  if (*s1 == *pt)
1329  {
1330  /*
1331  * found a delimiter, set to null
1332  * and return context ptr to next char
1333  */
1334  *s1 = '\0';
1335  *ptr = (s1 + 1); /* return pointer for next scan */
1336  *s1max = dlen - 1; /* account for the nulled delimiter */
1337  return (ptoken);
1338  }
1339  else
1340  {
1341  /*
1342  * simply scanning through the delimiter string
1343  */
1344  pt++;
1345  }
1346  }
1347  s1++;
1348  dlen--;
1349  }
1350 
1351  *ptr = s1;
1352  *s1max = dlen;
1353  return (ptoken);
1354 }
1355 
1356 /*
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
1362  * does not.
1363  * Applications are encouraged to use the cool C11 strstr_s API to avoid
1364  * this problem.
1365  */
1366 #define clib_strstr(s1,s2) \
1367  ({ char * __substring = 0; \
1368  strstr_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, CLIB_STRING_MACRO_MAX, \
1369  &__substring); \
1370  __substring; \
1371  })
1372 
1373 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1374  char **substring);
1375 
1377 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1378  char **substring)
1379 {
1380  u8 bad;
1381  size_t s1_size, s2_size;
1382 
1383  bad =
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))
1388  {
1389  if (s1 == 0)
1390  clib_c11_violation ("s1 NULL");
1391  if (s2 == 0)
1392  clib_c11_violation ("s2 NULL");
1393  if (s1max == 0)
1394  clib_c11_violation ("s1max 0");
1395  if (s2max == 0)
1396  clib_c11_violation ("s2max 0");
1397  if (substring == 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");
1403  return EINVAL;
1404  }
1405 
1406  /*
1407  * s2 points to a string with zero length, or s2 equals s1, return s1
1408  */
1409  if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1410  {
1411  *substring = s1;
1412  return EOK;
1413  }
1414 
1415  /*
1416  * s2_size > s1_size, it won't find match.
1417  */
1418  s1_size = clib_strnlen (s1, s1max);
1419  s2_size = clib_strnlen (s2, s2max);
1420  if (PREDICT_FALSE (s2_size > s1_size))
1421  return ESRCH;
1422 
1423  *substring = strstr (s1, s2);
1424  if (*substring == 0)
1425  return ESRCH;
1426 
1427  return EOK;
1428 }
1429 
1430 #endif /* included_clib_string_h */
1431 
1432 /*
1433  * fd.io coding-style-patch-verification: ON
1434  *
1435  * Local Variables:
1436  * eval: (c-set-style "gnu")
1437  * End:
1438  */
errno_t strcat_s(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src)
append src string to dest string, including null
Definition: string.c:328
errno_t strcmp_s(const char *s1, rsize_t s1max, const char *s2, int *indicator)
compare string s2 to string s1, and their difference is returned in indicator
Definition: string.c:213
u8 count
Definition: dhcp.api:208
char * strtok_s(char *__restrict__ s1, rsize_t *__restrict__ s1max, const char *__restrict__ s2, char **__restrict__ ptr)
tokenize string s1 with delimiter specified in s2.
Definition: string.c:410
#define clib_min(x, y)
Definition: clib.h:295
static errno_t memcmp_s_inline(const void *s1, rsize_t s1max, const void *s2, rsize_t s2max, int *diff)
Definition: string.h:747
static errno_t strcmp_s_inline(const char *s1, rsize_t s1max, const char *s2, int *indicator)
Definition: string.h:836
Optimized string handling code, including c11-compliant "safe C library" variants.
unsigned long u64
Definition: types.h:89
u16x16 u64x4 static_always_inline u32 u8x32_msb_mask(u8x32 v)
Definition: vector_avx2.h:108
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
#define NULL
Definition: clib.h:58
size_t strnlen_s(const char *s, size_t maxsize)
compute the length in s, no more than maxsize
Definition: string.c:433
vl_api_address_t src
Definition: gre.api:60
static errno_t strcat_s_inline(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src)
Definition: string.h:1080
static errno_t strncpy_s_inline(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src, rsize_t n)
Definition: string.h:1002
static_always_inline u8x16 u8x16_blend(u8x16 v1, u8x16 v2, u8x16 mask)
Definition: vector_sse42.h:735
static errno_t strstr_s_inline(char *s1, rsize_t s1max, const char *s2, rsize_t s2max, char **substring)
Definition: string.h:1377
void clib_memswap(void *_a, void *_b, uword bytes)
Definition: string.c:49
unsigned char u8
Definition: types.h:56
#define count_trailing_zeros(x)
Definition: clib.h:139
errno_t memcmp_s(const void *s1, rsize_t s1max, const void *s2, rsize_t s2max, int *diff)
compare memory until they differ, and their difference is returned in diff
Definition: string.c:178
void clib_c11_violation(const char *s)
Definition: string.c:95
#define static_always_inline
Definition: clib.h:99
errno_t strcpy_s(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src)
copy src string to dest string
Definition: string.c:272
static errno_t memcpy_s_inline(void *__restrict__ dest, rsize_t dmax, const void *__restrict__ src, rsize_t n)
Definition: string.h:121
static errno_t memset_s_inline(void *s, rsize_t smax, int c, rsize_t n)
Definition: string.h:185
unsigned int u32
Definition: types.h:88
errno_t strstr_s(char *s1, rsize_t s1max, const char *s2, rsize_t s2max, char **substring)
locate the first occurrence of the substring s2 in s1
Definition: string.c:470
static heap_elt_t * first(heap_header_t *h)
Definition: heap.c:59
static errno_t strncat_s_inline(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src, rsize_t n)
Definition: string.h:1141
unsigned short u16
Definition: types.h:57
#define PREDICT_FALSE(x)
Definition: clib.h:111
#define always_inline
Definition: ipsec.h:28
static_always_inline u16 u8x16_msb_mask(u8x16 v)
Definition: vector_neon.h:132
static_always_inline uword clib_count_equal_u64(u64 *data, uword max_count)
Definition: string.h:470
vl_api_address_t dst
Definition: gre.api:61
#define STRTOK_DELIM_MAX_LEN
u8 len
Definition: ip_types.api:91
static_always_inline uword clib_count_equal_u16(u16 *data, uword max_count)
Definition: string.h:588
errno_t strncpy_s(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src, rsize_t n)
copy src string to dest string, no more than n characters
Definition: string.c:299
svmdb_client_t * c
vl_api_ip4_address_t low
Definition: arp.api:36
static_always_inline void clib_memcpy_le(u8 *dst, u8 *src, u8 len, u8 max_len)
Definition: string.h:217
errno_t memset_s(void *s, rsize_t smax, int c, rsize_t n)
set n bytes starting at s to the specified c value
Definition: string.c:145
errno_t strncat_s(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src, rsize_t n)
append src string to dest string, including null, no more than n characters
Definition: string.c:358
u8 data[128]
Definition: ipsec_types.api:87
static_always_inline u8x32 u8x32_is_greater(u8x32 v1, u8x32 v2)
Definition: vector_avx2.h:264
static errno_t strcpy_s_inline(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src)
Definition: string.h:944
static_always_inline u8x16 u8x16_is_greater(u8x16 v1, u8x16 v2)
Definition: vector_sse42.h:729
static_always_inline void clib_memset_u8(void *p, u8 val, uword count)
Definition: string.h:424
static char * strtok_s_inline(char *__restrict__ s1, rsize_t *__restrict__ s1max, const char *__restrict__ s2, char **__restrict__ ptr)
Definition: string.h:1223
vl_api_ip4_address_t hi
Definition: arp.api:37
static_always_inline void clib_memset_u16(void *p, u16 val, uword count)
Definition: string.h:378
static_always_inline void clib_memcpy_le64(u8 *dst, u8 *src, u8 len)
Definition: string.h:283
static_always_inline uword clib_count_equal_u8(u8 *data, uword max_count)
Definition: string.h:656
static errno_t strncmp_s_inline(const char *s1, rsize_t s1max, const char *s2, rsize_t n, int *indicator)
Definition: string.h:890
u64 uword
Definition: types.h:112
static_always_inline void clib_memset_u64(void *p, u64 val, uword count)
Definition: string.h:295
errno_t memcpy_s(void *__restrict__ dest, rsize_t dmax, const void *__restrict__ src, rsize_t n)
copy src to dest, at most n bytes, up to dmax
Definition: string.c:120
u64x4
Definition: vector_avx2.h:121
#define clib_strnlen(s, m)
Definition: string.h:785
static_always_inline uword clib_count_equal_u32(u32 *data, uword max_count)
Definition: string.h:520
unsigned long long u32x4
Definition: ixge.c:28
static size_t strnlen_s_inline(const char *s, size_t maxsize)
Definition: string.h:790
epu16_epi64 u16x16
Definition: vector_avx2.h:123
errno_t strncmp_s(const char *s1, rsize_t s1max, const char *s2, rsize_t n, int *indicator)
compare string s2 to string s1, no more than n characters, and their difference is returned in indica...
Definition: string.c:246
static_always_inline u8x32 u8x32_blend(u8x32 v1, u8x32 v2, u8x32 mask)
Definition: vector_avx2.h:270
uword rsize_t
Definition: string.h:114
static_always_inline void clib_memcpy_le32(u8 *dst, u8 *src, u8 len)
Definition: string.h:289
int errno_t
Definition: string.h:113
static_always_inline void clib_memset_u32(void *p, u32 val, uword count)
Definition: string.h:332