FD.io VPP  v20.09-64-g4f7b92f0a
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 __AVX512BITALG__
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 max_count;
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 (count + 3 < max_count)
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 count;
493  }
494 
495  data += 4;
496  count += 4;
497  }
498 #else
499  count += 2;
500  data += 2;
501  while (count + 3 < max_count &&
502  ((data[0] ^ first) | (data[1] ^ first) |
503  (data[2] ^ first) | (data[3] ^ first)) == 0)
504  {
505  data += 4;
506  count += 4;
507  }
508 #endif
509  while (count < max_count && (data[0] == first))
510  {
511  data += 1;
512  count += 1;
513  }
514  return count;
515 }
516 
519 {
520  uword count;
521  u32 first;
522 
523  if (max_count <= 1)
524  return max_count;
525  if (data[0] != data[1])
526  return 1;
527 
528  count = 0;
529  first = data[0];
530 
531 #if defined(CLIB_HAVE_VEC256)
532  u32x8 splat = u32x8_splat (first);
533  while (count + 7 < max_count)
534  {
535  u64 bmp;
536  bmp = u8x32_msb_mask ((u8x32) (u32x8_load_unaligned (data) == splat));
537  if (bmp != 0xffffffff)
538  {
539  count += count_trailing_zeros (~bmp) / 4;
540  return count;
541  }
542 
543  data += 8;
544  count += 8;
545  }
546 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
547  u32x4 splat = u32x4_splat (first);
548  while (count + 3 < max_count)
549  {
550  u64 bmp;
551  bmp = u8x16_msb_mask ((u8x16) (u32x4_load_unaligned (data) == splat));
552  if (bmp != 0xffff)
553  {
554  count += count_trailing_zeros (~bmp) / 4;
555  return count;
556  }
557 
558  data += 4;
559  count += 4;
560  }
561 #else
562  count += 2;
563  data += 2;
564  while (count + 3 < max_count &&
565  ((data[0] ^ first) | (data[1] ^ first) |
566  (data[2] ^ first) | (data[3] ^ first)) == 0)
567  {
568  data += 4;
569  count += 4;
570  }
571 #endif
572  while (count < max_count && (data[0] == first))
573  {
574  data += 1;
575  count += 1;
576  }
577  return count;
578 }
579 
582 {
583  uword count;
584  u16 first;
585 
586  if (max_count <= 1)
587  return max_count;
588  if (data[0] != data[1])
589  return 1;
590 
591  count = 0;
592  first = data[0];
593 
594 #if defined(CLIB_HAVE_VEC256)
595  u16x16 splat = u16x16_splat (first);
596  while (count + 15 < max_count)
597  {
598  u64 bmp;
599  bmp = u8x32_msb_mask ((u8x32) (u16x16_load_unaligned (data) == splat));
600  if (bmp != 0xffffffff)
601  {
602  count += count_trailing_zeros (~bmp) / 2;
603  return count;
604  }
605 
606  data += 16;
607  count += 16;
608  }
609 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
610  u16x8 splat = u16x8_splat (first);
611  while (count + 7 < max_count)
612  {
613  u64 bmp;
614  bmp = u8x16_msb_mask ((u8x16) (u16x8_load_unaligned (data) == splat));
615  if (bmp != 0xffff)
616  {
617  count += count_trailing_zeros (~bmp) / 2;
618  return count;
619  }
620 
621  data += 8;
622  count += 8;
623  }
624 #else
625  count += 2;
626  data += 2;
627  while (count + 3 < max_count &&
628  ((data[0] ^ first) | (data[1] ^ first) |
629  (data[2] ^ first) | (data[3] ^ first)) == 0)
630  {
631  data += 4;
632  count += 4;
633  }
634 #endif
635  while (count < max_count && (data[0] == first))
636  {
637  data += 1;
638  count += 1;
639  }
640  return count;
641 }
642 
645 {
646  uword count;
647  u8 first;
648 
649  if (max_count <= 1)
650  return max_count;
651  if (data[0] != data[1])
652  return 1;
653 
654  count = 0;
655  first = data[0];
656 
657 #if defined(CLIB_HAVE_VEC256)
658  u8x32 splat = u8x32_splat (first);
659  while (count + 31 < max_count)
660  {
661  u64 bmp;
662  bmp = u8x32_msb_mask ((u8x32) (u8x32_load_unaligned (data) == splat));
663  if (bmp != 0xffffffff)
664  {
665  count += count_trailing_zeros (~bmp);
666  return max_count;
667  }
668 
669  data += 32;
670  count += 32;
671  }
672 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
673  u8x16 splat = u8x16_splat (first);
674  while (count + 15 < max_count)
675  {
676  u64 bmp;
677  bmp = u8x16_msb_mask ((u8x16) (u8x16_load_unaligned (data) == splat));
678  if (bmp != 0xffff)
679  {
680  count += count_trailing_zeros (~bmp);
681  return count;
682  }
683 
684  data += 16;
685  count += 16;
686  }
687 #else
688  count += 2;
689  data += 2;
690  while (count + 3 < max_count &&
691  ((data[0] ^ first) | (data[1] ^ first) |
692  (data[2] ^ first) | (data[3] ^ first)) == 0)
693  {
694  data += 4;
695  count += 4;
696  }
697 #endif
698  while (count < max_count && (data[0] == first))
699  {
700  data += 1;
701  count += 1;
702  }
703  return count;
704 }
705 
706 /*
707  * This macro is to provide smooth mapping from memcmp to memcmp_s.
708  * memcmp has fewer parameters and fewer returns than memcmp_s.
709  * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
710  * we return 0 and spit out a message in the console because there is
711  * no way to return the error code to the memcmp callers.
712  * This condition happens when s1 or s2 is null. Please note
713  * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
714  * anyway. So we are consistent in this case for the comparison return
715  * although we also spit out a C11 violation message in the console to
716  * warn that they pass null pointers for both s1 and s2.
717  * Applications are encouraged to use the cool C11 memcmp_s API to get the
718  * maximum benefit out of it.
719  */
720 #define clib_memcmp(s1,s2,m1) \
721  ({ int __diff = 0; \
722  memcmp_s_inline (s1, m1, s2, m1, &__diff); \
723  __diff; \
724  })
725 
726 errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
727  rsize_t s2max, int *diff);
728 
730 memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
731  int *diff)
732 {
733  u8 bad;
734 
735  bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
736  (s1max == 0);
737 
738  if (PREDICT_FALSE (bad != 0))
739  {
740  if (s1 == NULL)
741  clib_c11_violation ("s1 NULL");
742  if (s2 == NULL)
743  clib_c11_violation ("s2 NULL");
744  if (diff == NULL)
745  clib_c11_violation ("diff NULL");
746  if (s2max > s1max)
747  clib_c11_violation ("s2max > s1max");
748  if (s2max == 0)
749  clib_c11_violation ("s2max 0");
750  if (s1max == 0)
751  clib_c11_violation ("s1max 0");
752  return EINVAL;
753  }
754 
755  if (PREDICT_FALSE (s1 == s2))
756  {
757  *diff = 0;
758  return EOK;
759  }
760 
761  *diff = memcmp (s1, s2, s2max);
762  return EOK;
763 }
764 
765 /*
766  * This macro is to provide smooth mapping from strnlen to strnlen_s
767  */
768 #define clib_strnlen(s,m) strnlen_s_inline(s,m)
769 
770 size_t strnlen_s (const char *s, size_t maxsize);
771 
772 always_inline size_t
773 strnlen_s_inline (const char *s, size_t maxsize)
774 {
775  u8 bad;
776 
777  bad = (s == 0) + (maxsize == 0);
778  if (PREDICT_FALSE (bad != 0))
779  {
780  if (s == 0)
781  clib_c11_violation ("s NULL");
782  if (maxsize == 0)
783  clib_c11_violation ("maxsize 0");
784  return 0;
785  }
786  return strnlen (s, maxsize);
787 }
788 
789 /*
790  * This macro is to provide smooth mapping from strcmp to strcmp_s.
791  * strcmp has fewer parameters and fewer returns than strcmp_s.
792  * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
793  * we return 0 and spit out a message in the console because
794  * there is no way to return the error to the strcmp callers.
795  * This condition happens when s1 or s2 is null. Please note in the extant
796  * strcmp call, they would end up crashing if one of them is null.
797  * So the new behavior is no crash, but an error is displayed in the
798  * console which I think is more user friendly. If both s1 and s2 are null,
799  * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
800  * to actually accessing the pointer contents. We are still consistent
801  * in this case for the comparison return although we also spit out a
802  * C11 violation message in the console to warn that they pass null pointers
803  * for both s1 and s2. The other problem is strcmp does not provide s1max,
804  * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
805  * If not, we may be accessing memory beyonf what is intended.
806  * Applications are encouraged to use the cool C11 strcmp_s API to get the
807  * maximum benefit out of it.
808  */
809 #define clib_strcmp(s1,s2) \
810  ({ int __indicator = 0; \
811  strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator); \
812  __indicator; \
813  })
814 
815 errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
816  int *indicator);
817 
819 strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
820  int *indicator)
821 {
822  u8 bad;
823 
824  bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
825  (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
826 
827  if (PREDICT_FALSE (bad != 0))
828  {
829  if (indicator == NULL)
830  clib_c11_violation ("indicator NULL");
831  if (s1 == NULL)
832  clib_c11_violation ("s1 NULL");
833  if (s2 == NULL)
834  clib_c11_violation ("s2 NULL");
835  if (s1max == 0)
836  clib_c11_violation ("s1max 0");
837  if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
838  clib_c11_violation ("s1 unterminated");
839  return EINVAL;
840  }
841 
842  *indicator = strcmp (s1, s2);
843  return EOK;
844 }
845 
846 /*
847  * This macro is to provide smooth mapping from strncmp to strncmp_s.
848  * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
849  * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
850  * we return 0 and spit out a message in the console because there is no
851  * means to return the error to the strncmp caller.
852  * This condition happens when s1 or s2 is null. In the extant strncmp call,
853  * they would end up crashing if one of them is null. So the new behavior is
854  * no crash, but error is displayed in the console which is more
855  * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
856  * strncmp did the pointers comparison prior to actually accessing the
857  * pointer contents. We are still consistent in this case for the comparison
858  * return although we also spit out a C11 violation message in the console to
859  * warn that they pass null pointers for both s1 and s2.
860  * Applications are encouraged to use the cool C11 strncmp_s API to get the
861  * maximum benefit out of it.
862  */
863 #define clib_strncmp(s1,s2,n) \
864  ({ int __indicator = 0; \
865  strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator); \
866  __indicator; \
867  })
868 
869 errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
870  int *indicator);
871 
873 strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
874  int *indicator)
875 {
876  u8 bad;
877  u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
878 
879  if (PREDICT_FALSE (s1_greater_s1max && indicator))
880  {
881  /*
882  * strcmp allows n > s1max. If indicator is non null, we can still
883  * do the compare without any harm and return EINVAL as well as the
884  * result in indicator.
885  */
886  clib_c11_violation ("n exceeds s1 length");
887  *indicator = strncmp (s1, s2, n);
888  return EINVAL;
889  }
890 
891  bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
892  (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
893 
894  if (PREDICT_FALSE (bad != 0))
895  {
896  if (indicator == NULL)
897  clib_c11_violation ("indicator NULL");
898  if (s1 == NULL)
899  clib_c11_violation ("s1 NULL");
900  if (s2 == NULL)
901  clib_c11_violation ("s2 NULL");
902  if (s1max == 0)
903  clib_c11_violation ("s1max 0");
904  if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
905  clib_c11_violation ("s1 unterminated");
906  if (s1_greater_s1max)
907  clib_c11_violation ("n exceeds s1 length");
908  return EINVAL;
909  }
910 
911  *indicator = strncmp (s1, s2, n);
912  return EOK;
913 }
914 
915 /*
916  * This macro is provided for smooth migration from strcpy. It is not perfect
917  * because we don't know the size of the destination buffer to pass to strcpy_s.
918  * We improvise dmax with CLIB_STRING_MACRO_MAX.
919  * Applications are encouraged to move to the C11 strcpy_s API.
920  */
921 #define clib_strcpy(d,s) strcpy_s_inline(d,CLIB_STRING_MACRO_MAX,s)
922 
923 errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
924  const char *__restrict__ src);
925 
927 strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
928  const char *__restrict__ src)
929 {
930  u8 bad;
931  uword low, hi;
932  size_t n;
933 
934  bad = (dest == 0) + (dmax == 0) + (src == 0);
935  if (PREDICT_FALSE (bad != 0))
936  {
937  if (dest == 0)
938  clib_c11_violation ("dest NULL");
939  if (src == 0)
940  clib_c11_violation ("src NULL");
941  if (dmax == 0)
942  clib_c11_violation ("dmax 0");
943  return EINVAL;
944  }
945 
946  n = clib_strnlen (src, dmax);
947  if (PREDICT_FALSE (n >= dmax))
948  {
949  clib_c11_violation ("not enough space for dest");
950  return (EINVAL);
951  }
952  /* Not actually trying to copy anything is OK */
953  if (PREDICT_FALSE (n == 0))
954  return EOK;
955 
956  /* Check for src/dst overlap, which is not allowed */
957  low = (uword) (src < dest ? src : dest);
958  hi = (uword) (src < dest ? dest : src);
959 
960  if (PREDICT_FALSE (low + (n - 1) >= hi))
961  {
962  clib_c11_violation ("src/dest overlap");
963  return EINVAL;
964  }
965 
966  clib_memcpy_fast (dest, src, n);
967  dest[n] = '\0';
968  return EOK;
969 }
970 
971 /*
972  * This macro is provided for smooth migration from strncpy. It is not perfect
973  * because we don't know the size of the destination buffer to pass to
974  * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
975  * Applications are encouraged to move to the C11 strncpy_s API and provide
976  * the correct dmax for better error checking.
977  */
978 #define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
979 
980 errno_t
981 strncpy_s (char *__restrict__ dest, rsize_t dmax,
982  const char *__restrict__ src, rsize_t n);
983 
985 strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
986  const char *__restrict__ src, rsize_t n)
987 {
988  u8 bad;
989  uword low, hi;
990  rsize_t m;
991  errno_t status = EOK;
992 
993  bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
994  if (PREDICT_FALSE (bad != 0))
995  {
996  /* Not actually trying to copy anything is OK */
997  if (n == 0)
998  return EOK;
999  if (dest == 0)
1000  clib_c11_violation ("dest NULL");
1001  if (src == 0)
1002  clib_c11_violation ("src NULL");
1003  if (dmax == 0)
1004  clib_c11_violation ("dmax 0");
1005  return EINVAL;
1006  }
1007 
1008  if (PREDICT_FALSE (n >= dmax))
1009  {
1010  /* Relax and use strnlen of src */
1011  clib_c11_violation ("n >= dmax");
1012  m = clib_strnlen (src, dmax);
1013  if (m >= dmax)
1014  {
1015  /* Truncate, adjust copy length to fit dest */
1016  m = dmax - 1;
1017  status = EOVERFLOW;
1018  }
1019  }
1020  else
1021  /* cap the copy to strlen(src) in case n > strlen(src) */
1022  m = clib_strnlen (src, n);
1023 
1024  /* Check for src/dst overlap, which is not allowed */
1025  low = (uword) (src < dest ? src : dest);
1026  hi = (uword) (src < dest ? dest : src);
1027 
1028  /*
1029  * This check may fail innocently if src + dmax >= dst, but
1030  * src + strlen(src) < dst. If it fails, check more carefully before
1031  * blowing the whistle.
1032  */
1033  if (PREDICT_FALSE (low + (m - 1) >= hi))
1034  {
1035  m = clib_strnlen (src, m);
1036 
1037  if (low + (m - 1) >= hi)
1038  {
1039  clib_c11_violation ("src/dest overlap");
1040  return EINVAL;
1041  }
1042  }
1043 
1044  clib_memcpy_fast (dest, src, m);
1045  dest[m] = '\0';
1046  return status;
1047 }
1048 
1049 /*
1050  * This macro is to provide smooth migration from strcat to strcat_s.
1051  * Because there is no dmax in strcat, we improvise it with
1052  * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite dest
1053  * with too many bytes from src.
1054  * Applications are encouraged to use C11 API to provide the actual dmax
1055  * for proper checking and protection.
1056  */
1057 #define clib_strcat(d,s) strcat_s_inline(d,CLIB_STRING_MACRO_MAX,s)
1058 
1059 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
1060  const char *__restrict__ src);
1061 
1063 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
1064  const char *__restrict__ src)
1065 {
1066  u8 bad;
1067  uword low, hi;
1068  size_t m, n, dest_size;
1069 
1070  bad = (dest == 0) + (dmax == 0) + (src == 0);
1071  if (PREDICT_FALSE (bad != 0))
1072  {
1073  if (dest == 0)
1074  clib_c11_violation ("dest NULL");
1075  if (src == 0)
1076  clib_c11_violation ("src NULL");
1077  if (dmax == 0)
1078  clib_c11_violation ("dmax 0");
1079  return EINVAL;
1080  }
1081 
1082  dest_size = clib_strnlen (dest, dmax);
1083  m = dmax - dest_size;
1084  n = clib_strnlen (src, m);
1085  if (PREDICT_FALSE (n >= m))
1086  {
1087  clib_c11_violation ("not enough space for dest");
1088  return EINVAL;
1089  }
1090 
1091  /* Not actually trying to concatenate anything is OK */
1092  if (PREDICT_FALSE (n == 0))
1093  return EOK;
1094 
1095  /* Check for src/dst overlap, which is not allowed */
1096  low = (uword) (src < dest ? src : dest);
1097  hi = (uword) (src < dest ? dest : src);
1098 
1099  if (PREDICT_FALSE (low + (n - 1) >= hi))
1100  {
1101  clib_c11_violation ("src/dest overlap");
1102  return EINVAL;
1103  }
1104 
1105  clib_memcpy_fast (dest + dest_size, src, n);
1106  dest[dest_size + n] = '\0';
1107  return EOK;
1108 }
1109 
1110 /*
1111  * This macro is to provide smooth migration from strncat to strncat_s.
1112  * The unsafe strncat does not have s1max. We improvise it with
1113  * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite
1114  * dest with too many bytes from src.
1115  * Applications are encouraged to move to C11 strncat_s which requires dmax
1116  * from the caller and provides checking to safeguard the memory corruption.
1117  */
1118 #define clib_strncat(d,s,n) strncat_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
1119 
1120 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
1121  const char *__restrict__ src, rsize_t n);
1122 
1124 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
1125  const char *__restrict__ src, rsize_t n)
1126 {
1127  u8 bad;
1128  uword low, hi;
1129  size_t m, dest_size, allowed_size;
1130  errno_t status = EOK;
1131 
1132  bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
1133  if (PREDICT_FALSE (bad != 0))
1134  {
1135  /* Not actually trying to concatenate anything is OK */
1136  if (n == 0)
1137  return EOK;
1138  if (dest == 0)
1139  clib_c11_violation ("dest NULL");
1140  if (src == 0)
1141  clib_c11_violation ("src NULL");
1142  if (dmax == 0)
1143  clib_c11_violation ("dmax 0");
1144  return EINVAL;
1145  }
1146 
1147  /* Check for src/dst overlap, which is not allowed */
1148  low = (uword) (src < dest ? src : dest);
1149  hi = (uword) (src < dest ? dest : src);
1150 
1151  if (PREDICT_FALSE (low + (n - 1) >= hi))
1152  {
1153  clib_c11_violation ("src/dest overlap");
1154  return EINVAL;
1155  }
1156 
1157  dest_size = clib_strnlen (dest, dmax);
1158  allowed_size = dmax - dest_size;
1159 
1160  if (PREDICT_FALSE (allowed_size == 0))
1161  {
1162  clib_c11_violation ("no space left in dest");
1163  return (EINVAL);
1164  }
1165 
1166  if (PREDICT_FALSE (n >= allowed_size))
1167  {
1168  /*
1169  * unlike strcat_s, strncat_s will do the concatenation anyway when
1170  * there is not enough space in dest. But it will do the truncation and
1171  * null terminate dest
1172  */
1173  m = clib_strnlen (src, allowed_size);
1174  if (m >= allowed_size)
1175  {
1176  m = allowed_size - 1;
1177  status = EOVERFLOW;
1178  }
1179  }
1180  else
1181  m = clib_strnlen (src, n);
1182 
1183  clib_memcpy_fast (dest + dest_size, src, m);
1184  dest[dest_size + m] = '\0';
1185  return status;
1186 }
1187 
1188 /*
1189  * This macro is to provide smooth mapping from strtok_r to strtok_s.
1190  * To map strtok to this macro, the caller would have to supply an additional
1191  * argument. strtokr_s requires s1max which the unsafe API does not have. So
1192  * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
1193  * this macro cannot catch unterminated s1 and s2.
1194  * Applications are encouraged to use the cool C11 strtok_s API to avoid
1195  * these problems.
1196  */
1197 #define clib_strtok(s1,s2,p) \
1198  ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX; \
1199  strtok_s_inline (s1, &__s1max, s2, p); \
1200  })
1201 
1202 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1203  const char *__restrict__ s2, char **__restrict__ ptr);
1204 
1205 always_inline char *
1206 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1207  const char *__restrict__ s2, char **__restrict__ ptr)
1208 {
1209 #define STRTOK_DELIM_MAX_LEN 16
1210  u8 bad;
1211  const char *pt;
1212  char *ptoken;
1213  uword dlen, slen;
1214 
1215  bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
1216  ((s1 == 0) && ptr && (*ptr == 0));
1217  if (PREDICT_FALSE (bad != 0))
1218  {
1219  if (s2 == NULL)
1220  clib_c11_violation ("s2 NULL");
1221  if (s1max == NULL)
1222  clib_c11_violation ("s1max is NULL");
1223  if (ptr == NULL)
1224  clib_c11_violation ("ptr is NULL");
1225  /* s1 == 0 and *ptr == null is no good */
1226  if ((s1 == 0) && ptr && (*ptr == 0))
1227  clib_c11_violation ("s1 and ptr contents are NULL");
1228  return 0;
1229  }
1230 
1231  if (s1 == 0)
1232  s1 = *ptr;
1233 
1234  /*
1235  * scan s1 for a delimiter
1236  */
1237  dlen = *s1max;
1238  ptoken = 0;
1239  while (*s1 != '\0' && !ptoken)
1240  {
1241  if (PREDICT_FALSE (dlen == 0))
1242  {
1243  *ptr = 0;
1244  clib_c11_violation ("s1 unterminated");
1245  return 0;
1246  }
1247 
1248  /*
1249  * must scan the entire delimiter list
1250  * ISO should have included a delimiter string limit!!
1251  */
1252  slen = STRTOK_DELIM_MAX_LEN;
1253  pt = s2;
1254  while (*pt != '\0')
1255  {
1256  if (PREDICT_FALSE (slen == 0))
1257  {
1258  *ptr = 0;
1259  clib_c11_violation ("s2 unterminated");
1260  return 0;
1261  }
1262  slen--;
1263  if (*s1 == *pt)
1264  {
1265  ptoken = 0;
1266  break;
1267  }
1268  else
1269  {
1270  pt++;
1271  ptoken = s1;
1272  }
1273  }
1274  s1++;
1275  dlen--;
1276  }
1277 
1278  /*
1279  * if the beginning of a token was not found, then no
1280  * need to continue the scan.
1281  */
1282  if (ptoken == 0)
1283  {
1284  *s1max = dlen;
1285  return (ptoken);
1286  }
1287 
1288  /*
1289  * Now we need to locate the end of the token
1290  */
1291  while (*s1 != '\0')
1292  {
1293  if (dlen == 0)
1294  {
1295  *ptr = 0;
1296  clib_c11_violation ("s1 unterminated");
1297  return 0;
1298  }
1299 
1300  slen = STRTOK_DELIM_MAX_LEN;
1301  pt = s2;
1302  while (*pt != '\0')
1303  {
1304  if (slen == 0)
1305  {
1306  *ptr = 0;
1307  clib_c11_violation ("s2 unterminated");
1308  return 0;
1309  }
1310  slen--;
1311  if (*s1 == *pt)
1312  {
1313  /*
1314  * found a delimiter, set to null
1315  * and return context ptr to next char
1316  */
1317  *s1 = '\0';
1318  *ptr = (s1 + 1); /* return pointer for next scan */
1319  *s1max = dlen - 1; /* account for the nulled delimiter */
1320  return (ptoken);
1321  }
1322  else
1323  {
1324  /*
1325  * simply scanning through the delimiter string
1326  */
1327  pt++;
1328  }
1329  }
1330  s1++;
1331  dlen--;
1332  }
1333 
1334  *ptr = s1;
1335  *s1max = dlen;
1336  return (ptoken);
1337 }
1338 
1339 /*
1340  * This macro is to provide smooth mapping from strstr to strstr_s.
1341  * strstr_s requires s1max and s2max which the unsafe API does not have. So
1342  * we have to improvise them with CLIB_STRING_MACRO_MAX which may cause us
1343  * to access memory beyond it is intended if s1 or s2 is unterminated.
1344  * For the record, strstr crashes if s1 or s2 is unterminated. But this macro
1345  * does not.
1346  * Applications are encouraged to use the cool C11 strstr_s API to avoid
1347  * this problem.
1348  */
1349 #define clib_strstr(s1,s2) \
1350  ({ char * __substring = 0; \
1351  strstr_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, CLIB_STRING_MACRO_MAX, \
1352  &__substring); \
1353  __substring; \
1354  })
1355 
1356 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1357  char **substring);
1358 
1360 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1361  char **substring)
1362 {
1363  u8 bad;
1364  size_t s1_size, s2_size;
1365 
1366  bad =
1367  (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1368  (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1369  (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1370  if (PREDICT_FALSE (bad != 0))
1371  {
1372  if (s1 == 0)
1373  clib_c11_violation ("s1 NULL");
1374  if (s2 == 0)
1375  clib_c11_violation ("s2 NULL");
1376  if (s1max == 0)
1377  clib_c11_violation ("s1max 0");
1378  if (s2max == 0)
1379  clib_c11_violation ("s2max 0");
1380  if (substring == 0)
1381  clib_c11_violation ("substring NULL");
1382  if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1383  clib_c11_violation ("s1 unterminated");
1384  if (s2 && s2max && (s2[clib_strnlen (s2, s1max)] != '\0'))
1385  clib_c11_violation ("s2 unterminated");
1386  return EINVAL;
1387  }
1388 
1389  /*
1390  * s2 points to a string with zero length, or s2 equals s1, return s1
1391  */
1392  if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1393  {
1394  *substring = s1;
1395  return EOK;
1396  }
1397 
1398  /*
1399  * s2_size > s1_size, it won't find match.
1400  */
1401  s1_size = clib_strnlen (s1, s1max);
1402  s2_size = clib_strnlen (s2, s2max);
1403  if (PREDICT_FALSE (s2_size > s1_size))
1404  return ESRCH;
1405 
1406  *substring = strstr (s1, s2);
1407  if (*substring == 0)
1408  return ESRCH;
1409 
1410  return EOK;
1411 }
1412 
1413 #endif /* included_clib_string_h */
1414 
1415 /*
1416  * fd.io coding-style-patch-verification: ON
1417  *
1418  * Local Variables:
1419  * eval: (c-set-style "gnu")
1420  * End:
1421  */
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
static errno_t memcmp_s_inline(const void *s1, rsize_t s1max, const void *s2, rsize_t s2max, int *diff)
Definition: string.h:730
static errno_t strcmp_s_inline(const char *s1, rsize_t s1max, const char *s2, int *indicator)
Definition: string.h:819
Optimized string handling code, including c11-compliant "safe C library" variants.
#define EOVERFLOW
Definition: string.h:99
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 EINVAL
Definition: string.h:93
size_t strnlen_s(const char *s, size_t maxsize)
compute the length in s, no more than maxsize
Definition: string.c:433
#define ESRCH
Definition: string.h:96
vl_api_address_t src
Definition: gre.api:54
static errno_t strcat_s_inline(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src)
Definition: string.h:1063
static errno_t strncpy_s_inline(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src, rsize_t n)
Definition: string.h:985
static_always_inline u8x16 u8x16_blend(u8x16 v1, u8x16 v2, u8x16 mask)
Definition: vector_sse42.h:752
u16 mask
Definition: flow_types.api:52
static errno_t strstr_s_inline(char *s1, rsize_t s1max, const char *s2, rsize_t s2max, char **substring)
Definition: string.h:1360
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:156
u8 data[128]
Definition: ipsec_types.api:89
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:108
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:1124
unsigned short u16
Definition: types.h:57
#define PREDICT_FALSE(x)
Definition: clib.h:120
#define always_inline
Definition: ipsec.h:28
static_always_inline u16 u8x16_msb_mask(u8x16 v)
Definition: vector_neon.h:138
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:55
#define STRTOK_DELIM_MAX_LEN
u8 len
Definition: ip_types.api:92
static_always_inline uword clib_count_equal_u16(u16 *data, uword max_count)
Definition: string.h:581
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
static_always_inline u8x32 u8x32_is_greater(u8x32 v1, u8x32 v2)
Definition: vector_avx2.h:299
static errno_t strcpy_s_inline(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src)
Definition: string.h:927
static_always_inline u8x16 u8x16_is_greater(u8x16 v1, u8x16 v2)
Definition: vector_sse42.h:746
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:1206
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:644
static errno_t strncmp_s_inline(const char *s1, rsize_t s1max, const char *s2, rsize_t n, int *indicator)
Definition: string.h:873
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:768
static_always_inline uword clib_count_equal_u32(u32 *data, uword max_count)
Definition: string.h:518
unsigned long long u32x4
Definition: ixge.c:28
static size_t strnlen_s_inline(const char *s, size_t maxsize)
Definition: string.h:773
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:305
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