FD.io VPP  v21.06-3-gbb25fbf28
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>
50 
51 #ifdef CLIB_LINUX_KERNEL
52 #include <linux/string.h>
53 #endif
54 
55 #ifdef CLIB_UNIX
56 #include <string.h>
57 #endif
58 
59 #ifdef CLIB_STANDALONE
60 #include <vppinfra/standalone_string.h>
61 #endif
62 
63 #if _x86_64_
64 #include <x86intrin.h>
65 #endif
66 
67 /* Exchanges source and destination. */
68 void clib_memswap (void *_a, void *_b, uword bytes);
69 
70 /*
71  * the vector unit memcpy variants confuse coverity
72  * so don't let it anywhere near them.
73  */
74 #ifndef __COVERITY__
75 #if __AVX512BITALG__
76 #include <vppinfra/memcpy_avx512.h>
77 #define clib_memcpy_fast_arch(a, b, c) clib_memcpy_fast_avx512 (a, b, c)
78 #elif __AVX2__
79 #include <vppinfra/memcpy_avx2.h>
80 #define clib_memcpy_fast_arch(a, b, c) clib_memcpy_fast_avx2 (a, b, c)
81 #elif __SSSE3__
82 #include <vppinfra/memcpy_sse3.h>
83 #define clib_memcpy_fast_arch(a, b, c) clib_memcpy_fast_sse3 (a, b, c)
84 #endif /* __AVX512BITALG__ */
85 #endif /* __COVERITY__ */
86 
87 #ifndef clib_memcpy_fast_arch
88 #define clib_memcpy_fast_arch(a, b, c) memcpy (a, b, c)
89 #endif /* clib_memcpy_fast_arch */
90 
92 clib_memcpy_fast (void *restrict dst, const void *restrict src, size_t n)
93 {
94  ASSERT (dst && src &&
95  "memcpy(src, dst, n) with src == NULL or dst == NULL is undefined "
96  "behaviour");
97  return clib_memcpy_fast_arch (dst, src, n);
98 }
99 
100 #undef clib_memcpy_fast_arch
101 
102 #include <vppinfra/memcpy.h>
103 
104 /* c-11 string manipulation variants */
105 
106 #ifndef EOK
107 #define EOK 0
108 #endif
109 #ifndef EINVAL
110 #define EINVAL 22
111 #endif
112 #ifndef ESRCH
113 #define ESRCH 3
114 #endif
115 #ifndef EOVERFLOW
116 #define EOVERFLOW 75
117 #endif
118 
119 /*
120  * In order to provide smooth mapping from unsafe string API to the clib string
121  * macro, we often have to improvise s1max and s2max due to the additional
122  * arguments are required for implementing the safe API. This macro is used
123  * to provide the s1max/s2max. It is not perfect because the actual
124  * s1max/s2max may be greater than 4k and the mapping from the unsafe API to
125  * the macro would cause a regression. However, it is not terribly likely.
126  * So I bet against the odds.
127  */
128 #define CLIB_STRING_MACRO_MAX 4096
129 
130 typedef int errno_t;
131 typedef uword rsize_t;
132 
133 void clib_c11_violation (const char *s);
134 errno_t memcpy_s (void *__restrict__ dest, rsize_t dmax,
135  const void *__restrict__ src, rsize_t n);
136 
138 memcpy_s_inline (void *__restrict__ dest, rsize_t dmax,
139  const void *__restrict__ src, rsize_t n)
140 {
141  uword low, hi;
142  u8 bad;
143 
144  /*
145  * Optimize constant-number-of-bytes calls without asking
146  * "too many questions for someone from New Jersey"
147  */
148  if (COMPILE_TIME_CONST (n))
149  {
150  clib_memcpy_fast (dest, src, n);
151  return EOK;
152  }
153 
154  /*
155  * call bogus if: src or dst NULL, trying to copy
156  * more data than we have space in dst, or src == dst.
157  * n == 0 isn't really "bad", so check first in the
158  * "wall-of-shame" department...
159  */
160  bad = (dest == 0) + (src == 0) + (n > dmax) + (dest == src) + (n == 0);
161  if (PREDICT_FALSE (bad != 0))
162  {
163  /* Not actually trying to copy anything is OK */
164  if (n == 0)
165  return EOK;
166  if (dest == NULL)
167  clib_c11_violation ("dest NULL");
168  if (src == NULL)
169  clib_c11_violation ("src NULL");
170  if (n > dmax)
171  clib_c11_violation ("n > dmax");
172  if (dest == src)
173  clib_c11_violation ("dest == src");
174  return EINVAL;
175  }
176 
177  /* Check for src/dst overlap, which is not allowed */
178  low = (uword) (src < dest ? src : dest);
179  hi = (uword) (src < dest ? dest : src);
180 
181  if (PREDICT_FALSE (low + (n - 1) >= hi))
182  {
183  clib_c11_violation ("src/dest overlap");
184  return EINVAL;
185  }
186 
187  clib_memcpy_fast (dest, src, n);
188  return EOK;
189 }
190 
191 /*
192  * Note: $$$ This macro is a crutch. Folks need to manually
193  * inspect every extant clib_memcpy(...) call and
194  * attempt to provide a real destination buffer size
195  * argument...
196  */
197 #define clib_memcpy(d,s,n) memcpy_s_inline(d,n,s,n)
198 
199 errno_t memset_s (void *s, rsize_t smax, int c, rsize_t n);
200 
202 memset_s_inline (void *s, rsize_t smax, int c, rsize_t n)
203 {
204  u8 bad;
205 
206  bad = (s == 0) + (n > smax);
207 
208  if (PREDICT_FALSE (bad != 0))
209  {
210  if (s == 0)
211  clib_c11_violation ("s NULL");
212  if (n > smax)
213  clib_c11_violation ("n > smax");
214  return (EINVAL);
215  }
216  memset (s, c, n);
217  return (EOK);
218 }
219 
220 /*
221  * This macro is not [so much of] a crutch.
222  * It's super-typical to write:
223  *
224  * ep = pool_get (<pool>);
225  * clib_memset(ep, 0, sizeof (*ep));
226  *
227  * The compiler should delete the not-so useful
228  * (n > smax) test. TBH the NULL pointer check isn't
229  * so useful in this case, but so be it.
230  */
231 #define clib_memset(s,c,n) memset_s_inline(s,n,c,n)
232 
234 clib_memcpy_le (u8 * dst, u8 * src, u8 len, u8 max_len)
235 {
236 #if defined (CLIB_HAVE_VEC256)
237  u8x32 s0, s1, d0, d1;
238  u8x32 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
239  18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
240  };
241  u8x32 lv = u8x32_splat (len);
242  u8x32 add = u8x32_splat (32);
243 
244  s0 = u8x32_load_unaligned (src);
245  s1 = u8x32_load_unaligned (src + 32);
246  d0 = u8x32_load_unaligned (dst);
247  d1 = u8x32_load_unaligned (dst + 32);
248 
249  d0 = u8x32_blend (d0, s0, u8x32_is_greater (lv, mask));
250  u8x32_store_unaligned (d0, dst);
251 
252  if (max_len <= 32)
253  return;
254 
255  mask += add;
256  d1 = u8x32_blend (d1, s1, u8x32_is_greater (lv, mask));
257  u8x32_store_unaligned (d1, dst + 32);
258 
259 #elif defined (CLIB_HAVE_VEC128)
260  u8x16 s0, s1, s2, s3, d0, d1, d2, d3;
261  u8x16 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
262  u8x16 lv = u8x16_splat (len);
263  u8x16 add = u8x16_splat (16);
264 
265  s0 = u8x16_load_unaligned (src);
266  s1 = u8x16_load_unaligned (src + 16);
267  s2 = u8x16_load_unaligned (src + 32);
268  s3 = u8x16_load_unaligned (src + 48);
269  d0 = u8x16_load_unaligned (dst);
270  d1 = u8x16_load_unaligned (dst + 16);
271  d2 = u8x16_load_unaligned (dst + 32);
272  d3 = u8x16_load_unaligned (dst + 48);
273 
274  d0 = u8x16_blend (d0, s0, u8x16_is_greater (lv, mask));
275  u8x16_store_unaligned (d0, dst);
276 
277  if (max_len <= 16)
278  return;
279 
280  mask += add;
281  d1 = u8x16_blend (d1, s1, u8x16_is_greater (lv, mask));
282  u8x16_store_unaligned (d1, dst + 16);
283 
284  if (max_len <= 32)
285  return;
286 
287  mask += add;
288  d2 = u8x16_blend (d2, s2, u8x16_is_greater (lv, mask));
289  u8x16_store_unaligned (d2, dst + 32);
290 
291  mask += add;
292  d3 = u8x16_blend (d3, s3, u8x16_is_greater (lv, mask));
293  u8x16_store_unaligned (d3, dst + 48);
294 #else
295  memmove (dst, src, len);
296 #endif
297 }
298 
301 {
302  clib_memcpy_le (dst, src, len, 64);
303 }
304 
307 {
308  clib_memcpy_le (dst, src, len, 32);
309 }
310 
313 {
314  u64 *ptr = p;
315 #if defined(CLIB_HAVE_VEC512)
316  u64x8 v512 = u64x8_splat (val);
317  while (count >= 8)
318  {
319  u64x8_store_unaligned (v512, ptr);
320  ptr += 8;
321  count -= 8;
322  }
323  if (count == 0)
324  return;
325 #endif
326 #if defined(CLIB_HAVE_VEC256)
327  u64x4 v256 = u64x4_splat (val);
328  while (count >= 4)
329  {
330  u64x4_store_unaligned (v256, ptr);
331  ptr += 4;
332  count -= 4;
333  }
334  if (count == 0)
335  return;
336 #else
337  while (count >= 4)
338  {
339  ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
340  ptr += 4;
341  count -= 4;
342  }
343 #endif
344  while (count--)
345  ptr++[0] = val;
346 }
347 
350 {
351  u32 *ptr = p;
352 #if defined(CLIB_HAVE_VEC512)
353  u32x16 v512 = u32x16_splat (val);
354  while (count >= 16)
355  {
356  u32x16_store_unaligned (v512, ptr);
357  ptr += 16;
358  count -= 16;
359  }
360  if (count == 0)
361  return;
362 #endif
363 #if defined(CLIB_HAVE_VEC256)
364  u32x8 v256 = u32x8_splat (val);
365  while (count >= 8)
366  {
367  u32x8_store_unaligned (v256, ptr);
368  ptr += 8;
369  count -= 8;
370  }
371  if (count == 0)
372  return;
373 #endif
374 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
375  u32x4 v128 = u32x4_splat (val);
376  while (count >= 4)
377  {
378  u32x4_store_unaligned (v128, ptr);
379  ptr += 4;
380  count -= 4;
381  }
382 #else
383  while (count >= 4)
384  {
385  ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
386  ptr += 4;
387  count -= 4;
388  }
389 #endif
390  while (count--)
391  ptr++[0] = val;
392 }
393 
396 {
397  u16 *ptr = p;
398 #if defined(CLIB_HAVE_VEC512)
399  u16x32 v512 = u16x32_splat (val);
400  while (count >= 32)
401  {
402  u16x32_store_unaligned (v512, ptr);
403  ptr += 32;
404  count -= 32;
405  }
406  if (count == 0)
407  return;
408 #endif
409 #if defined(CLIB_HAVE_VEC256)
410  u16x16 v256 = u16x16_splat (val);
411  while (count >= 16)
412  {
413  u16x16_store_unaligned (v256, ptr);
414  ptr += 16;
415  count -= 16;
416  }
417  if (count == 0)
418  return;
419 #endif
420 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
421  u16x8 v128 = u16x8_splat (val);
422  while (count >= 8)
423  {
424  u16x8_store_unaligned (v128, ptr);
425  ptr += 8;
426  count -= 8;
427  }
428 #else
429  while (count >= 4)
430  {
431  ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
432  ptr += 4;
433  count -= 4;
434  }
435 #endif
436  while (count--)
437  ptr++[0] = val;
438 }
439 
441 clib_memset_u8 (void *p, u8 val, uword count)
442 {
443  u8 *ptr = p;
444 #if defined(CLIB_HAVE_VEC512)
445  u8x64 v512 = u8x64_splat (val);
446  while (count >= 64)
447  {
448  u8x64_store_unaligned (v512, ptr);
449  ptr += 64;
450  count -= 64;
451  }
452  if (count == 0)
453  return;
454 #endif
455 #if defined(CLIB_HAVE_VEC256)
456  u8x32 v256 = u8x32_splat (val);
457  while (count >= 32)
458  {
459  u8x32_store_unaligned (v256, ptr);
460  ptr += 32;
461  count -= 32;
462  }
463  if (count == 0)
464  return;
465 #endif
466 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
467  u8x16 v128 = u8x16_splat (val);
468  while (count >= 16)
469  {
470  u8x16_store_unaligned (v128, ptr);
471  ptr += 16;
472  count -= 16;
473  }
474 #else
475  while (count >= 4)
476  {
477  ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
478  ptr += 4;
479  count -= 4;
480  }
481 #endif
482  while (count--)
483  ptr++[0] = val;
484 }
485 
488 {
489  uword count;
490  u64 first;
491 
492  if (max_count <= 1)
493  return max_count;
494  if (data[0] != data[1])
495  return 1;
496 
497  count = 0;
498  first = data[0];
499 
500 #if defined(CLIB_HAVE_VEC256)
501  u64x4 splat = u64x4_splat (first);
502  while (count + 3 < max_count)
503  {
504  u64 bmp;
505  bmp = u8x32_msb_mask ((u8x32) (u64x4_load_unaligned (data) == splat));
506  if (bmp != 0xffffffff)
507  {
508  count += count_trailing_zeros (~bmp) / 8;
509  return count;
510  }
511 
512  data += 4;
513  count += 4;
514  }
515 #else
516  count += 2;
517  data += 2;
518  while (count + 3 < max_count &&
519  ((data[0] ^ first) | (data[1] ^ first) |
520  (data[2] ^ first) | (data[3] ^ first)) == 0)
521  {
522  data += 4;
523  count += 4;
524  }
525 #endif
526  while (count < max_count && (data[0] == first))
527  {
528  data += 1;
529  count += 1;
530  }
531  return count;
532 }
533 
536 {
537  uword count;
538  u32 first;
539 
540  if (max_count <= 1)
541  return max_count;
542  if (data[0] != data[1])
543  return 1;
544 
545  count = 0;
546  first = data[0];
547 
548 #if defined(CLIB_HAVE_VEC256)
549  u32x8 splat = u32x8_splat (first);
550  while (count + 7 < max_count)
551  {
552  u64 bmp;
553  bmp = u8x32_msb_mask ((u8x32) (u32x8_load_unaligned (data) == splat));
554  if (bmp != 0xffffffff)
555  {
556  count += count_trailing_zeros (~bmp) / 4;
557  return count;
558  }
559 
560  data += 8;
561  count += 8;
562  }
563 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
564  u32x4 splat = u32x4_splat (first);
565  while (count + 3 < max_count)
566  {
567  u64 bmp;
568  bmp = u8x16_msb_mask ((u8x16) (u32x4_load_unaligned (data) == splat));
569  if (bmp != 0xffff)
570  {
571  count += count_trailing_zeros (~bmp) / 4;
572  return count;
573  }
574 
575  data += 4;
576  count += 4;
577  }
578 #else
579  count += 2;
580  data += 2;
581  while (count + 3 < max_count &&
582  ((data[0] ^ first) | (data[1] ^ first) |
583  (data[2] ^ first) | (data[3] ^ first)) == 0)
584  {
585  data += 4;
586  count += 4;
587  }
588 #endif
589  while (count < max_count && (data[0] == first))
590  {
591  data += 1;
592  count += 1;
593  }
594  return count;
595 }
596 
599 {
600  uword count;
601  u16 first;
602 
603  if (max_count <= 1)
604  return max_count;
605  if (data[0] != data[1])
606  return 1;
607 
608  count = 0;
609  first = data[0];
610 
611 #if defined(CLIB_HAVE_VEC256)
612  u16x16 splat = u16x16_splat (first);
613  while (count + 15 < max_count)
614  {
615  u64 bmp;
616  bmp = u8x32_msb_mask ((u8x32) (u16x16_load_unaligned (data) == splat));
617  if (bmp != 0xffffffff)
618  {
619  count += count_trailing_zeros (~bmp) / 2;
620  return count;
621  }
622 
623  data += 16;
624  count += 16;
625  }
626 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
627  u16x8 splat = u16x8_splat (first);
628  while (count + 7 < max_count)
629  {
630  u64 bmp;
631  bmp = u8x16_msb_mask ((u8x16) (u16x8_load_unaligned (data) == splat));
632  if (bmp != 0xffff)
633  {
634  count += count_trailing_zeros (~bmp) / 2;
635  return count;
636  }
637 
638  data += 8;
639  count += 8;
640  }
641 #else
642  count += 2;
643  data += 2;
644  while (count + 3 < max_count &&
645  ((data[0] ^ first) | (data[1] ^ first) |
646  (data[2] ^ first) | (data[3] ^ first)) == 0)
647  {
648  data += 4;
649  count += 4;
650  }
651 #endif
652  while (count < max_count && (data[0] == first))
653  {
654  data += 1;
655  count += 1;
656  }
657  return count;
658 }
659 
662 {
663  uword count;
664  u8 first;
665 
666  if (max_count <= 1)
667  return max_count;
668  if (data[0] != data[1])
669  return 1;
670 
671  count = 0;
672  first = data[0];
673 
674 #if defined(CLIB_HAVE_VEC256)
675  u8x32 splat = u8x32_splat (first);
676  while (count + 31 < max_count)
677  {
678  u64 bmp;
679  bmp = u8x32_msb_mask ((u8x32) (u8x32_load_unaligned (data) == splat));
680  if (bmp != 0xffffffff)
681  return max_count;
682 
683  data += 32;
684  count += 32;
685  }
686 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
687  u8x16 splat = u8x16_splat (first);
688  while (count + 15 < max_count)
689  {
690  u64 bmp;
691  bmp = u8x16_msb_mask ((u8x16) (u8x16_load_unaligned (data) == splat));
692  if (bmp != 0xffff)
693  {
694  count += count_trailing_zeros (~bmp);
695  return count;
696  }
697 
698  data += 16;
699  count += 16;
700  }
701 #else
702  count += 2;
703  data += 2;
704  while (count + 3 < max_count &&
705  ((data[0] ^ first) | (data[1] ^ first) |
706  (data[2] ^ first) | (data[3] ^ first)) == 0)
707  {
708  data += 4;
709  count += 4;
710  }
711 #endif
712  while (count < max_count && (data[0] == first))
713  {
714  data += 1;
715  count += 1;
716  }
717  return count;
718 }
719 
720 /*
721  * This macro is to provide smooth mapping from memcmp to memcmp_s.
722  * memcmp has fewer parameters and fewer returns than memcmp_s.
723  * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
724  * we return 0 and spit out a message in the console because there is
725  * no way to return the error code to the memcmp callers.
726  * This condition happens when s1 or s2 is null. Please note
727  * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
728  * anyway. So we are consistent in this case for the comparison return
729  * although we also spit out a C11 violation message in the console to
730  * warn that they pass null pointers for both s1 and s2.
731  * Applications are encouraged to use the cool C11 memcmp_s API to get the
732  * maximum benefit out of it.
733  */
734 #define clib_memcmp(s1,s2,m1) \
735  ({ int __diff = 0; \
736  memcmp_s_inline (s1, m1, s2, m1, &__diff); \
737  __diff; \
738  })
739 
740 errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
741  rsize_t s2max, int *diff);
742 
744 memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
745  int *diff)
746 {
747  u8 bad;
748 
749  bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
750  (s1max == 0);
751 
752  if (PREDICT_FALSE (bad != 0))
753  {
754  if (s1 == NULL)
755  clib_c11_violation ("s1 NULL");
756  if (s2 == NULL)
757  clib_c11_violation ("s2 NULL");
758  if (diff == NULL)
759  clib_c11_violation ("diff NULL");
760  if (s2max > s1max)
761  clib_c11_violation ("s2max > s1max");
762  if (s2max == 0)
763  clib_c11_violation ("s2max 0");
764  if (s1max == 0)
765  clib_c11_violation ("s1max 0");
766  return EINVAL;
767  }
768 
769  if (PREDICT_FALSE (s1 == s2))
770  {
771  *diff = 0;
772  return EOK;
773  }
774 
775  *diff = memcmp (s1, s2, s2max);
776  return EOK;
777 }
778 
779 /*
780  * This macro is to provide smooth mapping from strnlen to strnlen_s
781  */
782 #define clib_strnlen(s,m) strnlen_s_inline(s,m)
783 
784 size_t strnlen_s (const char *s, size_t maxsize);
785 
786 always_inline size_t
787 strnlen_s_inline (const char *s, size_t maxsize)
788 {
789  u8 bad;
790 
791  bad = (s == 0) + (maxsize == 0);
792  if (PREDICT_FALSE (bad != 0))
793  {
794  if (s == 0)
795  clib_c11_violation ("s NULL");
796  if (maxsize == 0)
797  clib_c11_violation ("maxsize 0");
798  return 0;
799  }
800  return strnlen (s, maxsize);
801 }
802 
803 /*
804  * This macro is to provide smooth mapping from strcmp to strcmp_s.
805  * strcmp has fewer parameters and fewer returns than strcmp_s.
806  * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
807  * we return 0 and spit out a message in the console because
808  * there is no way to return the error to the strcmp callers.
809  * This condition happens when s1 or s2 is null. Please note in the extant
810  * strcmp call, they would end up crashing if one of them is null.
811  * So the new behavior is no crash, but an error is displayed in the
812  * console which I think is more user friendly. If both s1 and s2 are null,
813  * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
814  * to actually accessing the pointer contents. We are still consistent
815  * in this case for the comparison return although we also spit out a
816  * C11 violation message in the console to warn that they pass null pointers
817  * for both s1 and s2. The other problem is strcmp does not provide s1max,
818  * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
819  * If not, we may be accessing memory beyonf what is intended.
820  * Applications are encouraged to use the cool C11 strcmp_s API to get the
821  * maximum benefit out of it.
822  */
823 #define clib_strcmp(s1,s2) \
824  ({ int __indicator = 0; \
825  strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator); \
826  __indicator; \
827  })
828 
829 errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
830  int *indicator);
831 
833 strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
834  int *indicator)
835 {
836  u8 bad;
837 
838  bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
839  (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
840 
841  if (PREDICT_FALSE (bad != 0))
842  {
843  if (indicator == NULL)
844  clib_c11_violation ("indicator NULL");
845  if (s1 == NULL)
846  clib_c11_violation ("s1 NULL");
847  if (s2 == NULL)
848  clib_c11_violation ("s2 NULL");
849  if (s1max == 0)
850  clib_c11_violation ("s1max 0");
851  if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
852  clib_c11_violation ("s1 unterminated");
853  return EINVAL;
854  }
855 
856  *indicator = strcmp (s1, s2);
857  return EOK;
858 }
859 
860 /*
861  * This macro is to provide smooth mapping from strncmp to strncmp_s.
862  * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
863  * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
864  * we return 0 and spit out a message in the console because there is no
865  * means to return the error to the strncmp caller.
866  * This condition happens when s1 or s2 is null. In the extant strncmp call,
867  * they would end up crashing if one of them is null. So the new behavior is
868  * no crash, but error is displayed in the console which is more
869  * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
870  * strncmp did the pointers comparison prior to actually accessing the
871  * pointer contents. We are still consistent in this case for the comparison
872  * return although we also spit out a C11 violation message in the console to
873  * warn that they pass null pointers for both s1 and s2.
874  * Applications are encouraged to use the cool C11 strncmp_s API to get the
875  * maximum benefit out of it.
876  */
877 #define clib_strncmp(s1,s2,n) \
878  ({ int __indicator = 0; \
879  strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator); \
880  __indicator; \
881  })
882 
883 errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
884  int *indicator);
885 
887 strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
888  int *indicator)
889 {
890  u8 bad;
891  u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
892 
893  if (PREDICT_FALSE (s1_greater_s1max && indicator))
894  {
895  /*
896  * strcmp allows n > s1max. If indicator is non null, we can still
897  * do the compare without any harm and return EINVAL as well as the
898  * result in indicator.
899  */
900  clib_c11_violation ("n exceeds s1 length");
901  *indicator = strncmp (s1, s2, n);
902  return EINVAL;
903  }
904 
905  bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
906  (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
907 
908  if (PREDICT_FALSE (bad != 0))
909  {
910  if (indicator == NULL)
911  clib_c11_violation ("indicator NULL");
912  if (s1 == NULL)
913  clib_c11_violation ("s1 NULL");
914  if (s2 == NULL)
915  clib_c11_violation ("s2 NULL");
916  if (s1max == 0)
917  clib_c11_violation ("s1max 0");
918  if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
919  clib_c11_violation ("s1 unterminated");
920  if (s1_greater_s1max)
921  clib_c11_violation ("n exceeds s1 length");
922  return EINVAL;
923  }
924 
925  *indicator = strncmp (s1, s2, n);
926  return EOK;
927 }
928 
929 /*
930  * This macro is provided for smooth migration from strcpy. It is not perfect
931  * because we don't know the size of the destination buffer to pass to strcpy_s.
932  * We improvise dmax with CLIB_STRING_MACRO_MAX.
933  * Applications are encouraged to move to the C11 strcpy_s API.
934  */
935 #define clib_strcpy(d,s) strcpy_s_inline(d,CLIB_STRING_MACRO_MAX,s)
936 
937 errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
938  const char *__restrict__ src);
939 
941 strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
942  const char *__restrict__ src)
943 {
944  u8 bad;
945  uword low, hi;
946  size_t n;
947 
948  bad = (dest == 0) + (dmax == 0) + (src == 0);
949  if (PREDICT_FALSE (bad != 0))
950  {
951  if (dest == 0)
952  clib_c11_violation ("dest NULL");
953  if (src == 0)
954  clib_c11_violation ("src NULL");
955  if (dmax == 0)
956  clib_c11_violation ("dmax 0");
957  return EINVAL;
958  }
959 
960  n = clib_strnlen (src, dmax);
961  if (PREDICT_FALSE (n >= dmax))
962  {
963  clib_c11_violation ("not enough space for dest");
964  return (EINVAL);
965  }
966  /* Not actually trying to copy anything is OK */
967  if (PREDICT_FALSE (n == 0))
968  return EOK;
969 
970  /* Check for src/dst overlap, which is not allowed */
971  low = (uword) (src < dest ? src : dest);
972  hi = (uword) (src < dest ? dest : src);
973 
974  if (PREDICT_FALSE (low + (n - 1) >= hi))
975  {
976  clib_c11_violation ("src/dest overlap");
977  return EINVAL;
978  }
979 
980  clib_memcpy_fast (dest, src, n);
981  dest[n] = '\0';
982  return EOK;
983 }
984 
985 /*
986  * This macro is provided for smooth migration from strncpy. It is not perfect
987  * because we don't know the size of the destination buffer to pass to
988  * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
989  * Applications are encouraged to move to the C11 strncpy_s API and provide
990  * the correct dmax for better error checking.
991  */
992 #define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
993 
994 errno_t
995 strncpy_s (char *__restrict__ dest, rsize_t dmax,
996  const char *__restrict__ src, rsize_t n);
997 
999 strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
1000  const char *__restrict__ src, rsize_t n)
1001 {
1002  u8 bad;
1003  uword low, hi;
1004  rsize_t m;
1005  errno_t status = EOK;
1006 
1007  bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
1008  if (PREDICT_FALSE (bad != 0))
1009  {
1010  /* Not actually trying to copy anything is OK */
1011  if (n == 0)
1012  return EOK;
1013  if (dest == 0)
1014  clib_c11_violation ("dest NULL");
1015  if (src == 0)
1016  clib_c11_violation ("src NULL");
1017  if (dmax == 0)
1018  clib_c11_violation ("dmax 0");
1019  return EINVAL;
1020  }
1021 
1022  if (PREDICT_FALSE (n >= dmax))
1023  {
1024  /* Relax and use strnlen of src */
1025  clib_c11_violation ("n >= dmax");
1026  m = clib_strnlen (src, dmax);
1027  if (m >= dmax)
1028  {
1029  /* Truncate, adjust copy length to fit dest */
1030  m = dmax - 1;
1031  status = EOVERFLOW;
1032  }
1033  }
1034  else
1035  /* cap the copy to strlen(src) in case n > strlen(src) */
1036  m = clib_strnlen (src, n);
1037 
1038  /* Check for src/dst overlap, which is not allowed */
1039  low = (uword) (src < dest ? src : dest);
1040  hi = (uword) (src < dest ? dest : src);
1041 
1042  /*
1043  * This check may fail innocently if src + dmax >= dst, but
1044  * src + strlen(src) < dst. If it fails, check more carefully before
1045  * blowing the whistle.
1046  */
1047  if (PREDICT_FALSE (low + (m - 1) >= hi))
1048  {
1049  m = clib_strnlen (src, m);
1050 
1051  if (low + (m - 1) >= hi)
1052  {
1053  clib_c11_violation ("src/dest overlap");
1054  return EINVAL;
1055  }
1056  }
1057 
1058  clib_memcpy_fast (dest, src, m);
1059  dest[m] = '\0';
1060  return status;
1061 }
1062 
1063 /*
1064  * This macro is to provide smooth migration from strcat to strcat_s.
1065  * Because there is no dmax in strcat, we improvise it with
1066  * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite dest
1067  * with too many bytes from src.
1068  * Applications are encouraged to use C11 API to provide the actual dmax
1069  * for proper checking and protection.
1070  */
1071 #define clib_strcat(d,s) strcat_s_inline(d,CLIB_STRING_MACRO_MAX,s)
1072 
1073 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
1074  const char *__restrict__ src);
1075 
1077 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
1078  const char *__restrict__ src)
1079 {
1080  u8 bad;
1081  uword low, hi;
1082  size_t m, n, dest_size;
1083 
1084  bad = (dest == 0) + (dmax == 0) + (src == 0);
1085  if (PREDICT_FALSE (bad != 0))
1086  {
1087  if (dest == 0)
1088  clib_c11_violation ("dest NULL");
1089  if (src == 0)
1090  clib_c11_violation ("src NULL");
1091  if (dmax == 0)
1092  clib_c11_violation ("dmax 0");
1093  return EINVAL;
1094  }
1095 
1096  dest_size = clib_strnlen (dest, dmax);
1097  m = dmax - dest_size;
1098  n = clib_strnlen (src, m);
1099  if (PREDICT_FALSE (n >= m))
1100  {
1101  clib_c11_violation ("not enough space for dest");
1102  return EINVAL;
1103  }
1104 
1105  /* Not actually trying to concatenate anything is OK */
1106  if (PREDICT_FALSE (n == 0))
1107  return EOK;
1108 
1109  /* Check for src/dst overlap, which is not allowed */
1110  low = (uword) (src < dest ? src : dest);
1111  hi = (uword) (src < dest ? dest : src);
1112 
1113  if (PREDICT_FALSE (low + (n - 1) >= hi))
1114  {
1115  clib_c11_violation ("src/dest overlap");
1116  return EINVAL;
1117  }
1118 
1119  clib_memcpy_fast (dest + dest_size, src, n);
1120  dest[dest_size + n] = '\0';
1121  return EOK;
1122 }
1123 
1124 /*
1125  * This macro is to provide smooth migration from strncat to strncat_s.
1126  * The unsafe strncat does not have s1max. We improvise it with
1127  * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite
1128  * dest with too many bytes from src.
1129  * Applications are encouraged to move to C11 strncat_s which requires dmax
1130  * from the caller and provides checking to safeguard the memory corruption.
1131  */
1132 #define clib_strncat(d,s,n) strncat_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
1133 
1134 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
1135  const char *__restrict__ src, rsize_t n);
1136 
1138 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
1139  const char *__restrict__ src, rsize_t n)
1140 {
1141  u8 bad;
1142  uword low, hi;
1143  size_t m, dest_size, allowed_size;
1144  errno_t status = EOK;
1145 
1146  bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
1147  if (PREDICT_FALSE (bad != 0))
1148  {
1149  /* Not actually trying to concatenate anything is OK */
1150  if (n == 0)
1151  return EOK;
1152  if (dest == 0)
1153  clib_c11_violation ("dest NULL");
1154  if (src == 0)
1155  clib_c11_violation ("src NULL");
1156  if (dmax == 0)
1157  clib_c11_violation ("dmax 0");
1158  return EINVAL;
1159  }
1160 
1161  /* Check for src/dst overlap, which is not allowed */
1162  low = (uword) (src < dest ? src : dest);
1163  hi = (uword) (src < dest ? dest : src);
1164 
1165  if (PREDICT_FALSE (low + (n - 1) >= hi))
1166  {
1167  clib_c11_violation ("src/dest overlap");
1168  return EINVAL;
1169  }
1170 
1171  dest_size = clib_strnlen (dest, dmax);
1172  allowed_size = dmax - dest_size;
1173 
1174  if (PREDICT_FALSE (allowed_size == 0))
1175  {
1176  clib_c11_violation ("no space left in dest");
1177  return (EINVAL);
1178  }
1179 
1180  if (PREDICT_FALSE (n >= allowed_size))
1181  {
1182  /*
1183  * unlike strcat_s, strncat_s will do the concatenation anyway when
1184  * there is not enough space in dest. But it will do the truncation and
1185  * null terminate dest
1186  */
1187  m = clib_strnlen (src, allowed_size);
1188  if (m >= allowed_size)
1189  {
1190  m = allowed_size - 1;
1191  status = EOVERFLOW;
1192  }
1193  }
1194  else
1195  m = clib_strnlen (src, n);
1196 
1197  clib_memcpy_fast (dest + dest_size, src, m);
1198  dest[dest_size + m] = '\0';
1199  return status;
1200 }
1201 
1202 /*
1203  * This macro is to provide smooth mapping from strtok_r to strtok_s.
1204  * To map strtok to this macro, the caller would have to supply an additional
1205  * argument. strtokr_s requires s1max which the unsafe API does not have. So
1206  * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
1207  * this macro cannot catch unterminated s1 and s2.
1208  * Applications are encouraged to use the cool C11 strtok_s API to avoid
1209  * these problems.
1210  */
1211 #define clib_strtok(s1,s2,p) \
1212  ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX; \
1213  strtok_s_inline (s1, &__s1max, s2, p); \
1214  })
1215 
1216 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1217  const char *__restrict__ s2, char **__restrict__ ptr);
1218 
1219 always_inline char *
1220 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1221  const char *__restrict__ s2, char **__restrict__ ptr)
1222 {
1223 #define STRTOK_DELIM_MAX_LEN 16
1224  u8 bad;
1225  const char *pt;
1226  char *ptoken;
1227  uword dlen, slen;
1228 
1229  bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
1230  ((s1 == 0) && ptr && (*ptr == 0));
1231  if (PREDICT_FALSE (bad != 0))
1232  {
1233  if (s2 == NULL)
1234  clib_c11_violation ("s2 NULL");
1235  if (s1max == NULL)
1236  clib_c11_violation ("s1max is NULL");
1237  if (ptr == NULL)
1238  clib_c11_violation ("ptr is NULL");
1239  /* s1 == 0 and *ptr == null is no good */
1240  if ((s1 == 0) && ptr && (*ptr == 0))
1241  clib_c11_violation ("s1 and ptr contents are NULL");
1242  return 0;
1243  }
1244 
1245  if (s1 == 0)
1246  s1 = *ptr;
1247 
1248  /*
1249  * scan s1 for a delimiter
1250  */
1251  dlen = *s1max;
1252  ptoken = 0;
1253  while (*s1 != '\0' && !ptoken)
1254  {
1255  if (PREDICT_FALSE (dlen == 0))
1256  {
1257  *ptr = 0;
1258  clib_c11_violation ("s1 unterminated");
1259  return 0;
1260  }
1261 
1262  /*
1263  * must scan the entire delimiter list
1264  * ISO should have included a delimiter string limit!!
1265  */
1266  slen = STRTOK_DELIM_MAX_LEN;
1267  pt = s2;
1268  while (*pt != '\0')
1269  {
1270  if (PREDICT_FALSE (slen == 0))
1271  {
1272  *ptr = 0;
1273  clib_c11_violation ("s2 unterminated");
1274  return 0;
1275  }
1276  slen--;
1277  if (*s1 == *pt)
1278  {
1279  ptoken = 0;
1280  break;
1281  }
1282  else
1283  {
1284  pt++;
1285  ptoken = s1;
1286  }
1287  }
1288  s1++;
1289  dlen--;
1290  }
1291 
1292  /*
1293  * if the beginning of a token was not found, then no
1294  * need to continue the scan.
1295  */
1296  if (ptoken == 0)
1297  {
1298  *s1max = dlen;
1299  return (ptoken);
1300  }
1301 
1302  /*
1303  * Now we need to locate the end of the token
1304  */
1305  while (*s1 != '\0')
1306  {
1307  if (dlen == 0)
1308  {
1309  *ptr = 0;
1310  clib_c11_violation ("s1 unterminated");
1311  return 0;
1312  }
1313 
1314  slen = STRTOK_DELIM_MAX_LEN;
1315  pt = s2;
1316  while (*pt != '\0')
1317  {
1318  if (slen == 0)
1319  {
1320  *ptr = 0;
1321  clib_c11_violation ("s2 unterminated");
1322  return 0;
1323  }
1324  slen--;
1325  if (*s1 == *pt)
1326  {
1327  /*
1328  * found a delimiter, set to null
1329  * and return context ptr to next char
1330  */
1331  *s1 = '\0';
1332  *ptr = (s1 + 1); /* return pointer for next scan */
1333  *s1max = dlen - 1; /* account for the nulled delimiter */
1334  return (ptoken);
1335  }
1336  else
1337  {
1338  /*
1339  * simply scanning through the delimiter string
1340  */
1341  pt++;
1342  }
1343  }
1344  s1++;
1345  dlen--;
1346  }
1347 
1348  *ptr = s1;
1349  *s1max = dlen;
1350  return (ptoken);
1351 }
1352 
1353 /*
1354  * This macro is to provide smooth mapping from strstr to strstr_s.
1355  * strstr_s requires s1max and s2max which the unsafe API does not have. So
1356  * we have to improvise them with CLIB_STRING_MACRO_MAX which may cause us
1357  * to access memory beyond it is intended if s1 or s2 is unterminated.
1358  * For the record, strstr crashes if s1 or s2 is unterminated. But this macro
1359  * does not.
1360  * Applications are encouraged to use the cool C11 strstr_s API to avoid
1361  * this problem.
1362  */
1363 #define clib_strstr(s1,s2) \
1364  ({ char * __substring = 0; \
1365  strstr_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, CLIB_STRING_MACRO_MAX, \
1366  &__substring); \
1367  __substring; \
1368  })
1369 
1370 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1371  char **substring);
1372 
1374 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1375  char **substring)
1376 {
1377  u8 bad;
1378  size_t s1_size, s2_size;
1379 
1380  bad =
1381  (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1382  (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1383  (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1384  if (PREDICT_FALSE (bad != 0))
1385  {
1386  if (s1 == 0)
1387  clib_c11_violation ("s1 NULL");
1388  if (s2 == 0)
1389  clib_c11_violation ("s2 NULL");
1390  if (s1max == 0)
1391  clib_c11_violation ("s1max 0");
1392  if (s2max == 0)
1393  clib_c11_violation ("s2max 0");
1394  if (substring == 0)
1395  clib_c11_violation ("substring NULL");
1396  if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1397  clib_c11_violation ("s1 unterminated");
1398  if (s2 && s2max && (s2[clib_strnlen (s2, s1max)] != '\0'))
1399  clib_c11_violation ("s2 unterminated");
1400  return EINVAL;
1401  }
1402 
1403  /*
1404  * s2 points to a string with zero length, or s2 equals s1, return s1
1405  */
1406  if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1407  {
1408  *substring = s1;
1409  return EOK;
1410  }
1411 
1412  /*
1413  * s2_size > s1_size, it won't find match.
1414  */
1415  s1_size = clib_strnlen (s1, s1max);
1416  s2_size = clib_strnlen (s2, s2max);
1417  if (PREDICT_FALSE (s2_size > s1_size))
1418  return ESRCH;
1419 
1420  *substring = strstr (s1, s2);
1421  if (*substring == 0)
1422  return ESRCH;
1423 
1424  return EOK;
1425 }
1426 
1427 #endif /* included_clib_string_h */
1428 
1429 /*
1430  * fd.io coding-style-patch-verification: ON
1431  *
1432  * Local Variables:
1433  * eval: (c-set-style "gnu")
1434  * End:
1435  */
strncpy_s
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
strcat_s_inline
static errno_t strcat_s_inline(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src)
Definition: string.h:1077
count_trailing_zeros
#define count_trailing_zeros(x)
Definition: clib.h:161
u8x32_is_greater
static_always_inline u8x32 u8x32_is_greater(u8x32 v1, u8x32 v2)
Definition: vector_avx2.h:312
memcpy_avx512.h
memcpy_s
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
strstr_s
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
clib_memset_u16
static_always_inline void clib_memset_u16(void *p, u16 val, uword count)
Definition: string.h:395
clib.h
u8x16_msb_mask
static_always_inline u16 u8x16_msb_mask(u8x16 v)
Definition: vector_neon.h:138
string.h
clib_count_equal_u64
static_always_inline uword clib_count_equal_u64(u64 *data, uword max_count)
Definition: string.h:487
strnlen_s_inline
static size_t strnlen_s_inline(const char *s, size_t maxsize)
Definition: string.h:787
strcmp_s
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
memcpy.h
strtok_s
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
u16
unsigned short u16
Definition: types.h:57
first
static heap_elt_t * first(heap_header_t *h)
Definition: heap.c:59
clib_memset_u64
static_always_inline void clib_memset_u64(void *p, u64 val, uword count)
Definition: string.h:312
error_bootstrap.h
clib_memcpy_le32
static_always_inline void clib_memcpy_le32(u8 *dst, u8 *src, u8 len)
Definition: string.h:306
hi
vl_api_ip4_address_t hi
Definition: arp.api:37
STRTOK_DELIM_MAX_LEN
#define STRTOK_DELIM_MAX_LEN
clib_memcpy_fast
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
u16x32
_mm512_packus_epi16 u16x32
Definition: vector_avx512.h:98
u8x32_blend
static_always_inline u8x32 u8x32_blend(u8x32 v1, u8x32 v2, u8x32 mask)
Definition: vector_avx2.h:318
rsize_t
uword rsize_t
Definition: string.h:131
u8x16
u8x16
Definition: vector_sse42.h:194
clib_memcpy_le
static_always_inline void clib_memcpy_le(u8 *dst, u8 *src, u8 len, u8 max_len)
Definition: string.h:234
u8x16_blend
static_always_inline u8x16 u8x16_blend(u8x16 v1, u8x16 v2, u8x16 mask)
Definition: vector_sse42.h:702
clib_memset_u32
static_always_inline void clib_memset_u32(void *p, u32 val, uword count)
Definition: string.h:349
count
u8 count
Definition: dhcp.api:208
strcpy_s_inline
static errno_t strcpy_s_inline(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src)
Definition: string.h:941
len
u8 len
Definition: ip_types.api:103
clib_memcpy_fast_arch
#define clib_memcpy_fast_arch(a, b, c)
Definition: string.h:88
memcmp_s
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
PREDICT_FALSE
#define PREDICT_FALSE(x)
Definition: clib.h:124
clib_memcpy_le64
static_always_inline void clib_memcpy_le64(u8 *dst, u8 *src, u8 len)
Definition: string.h:300
c
svmdb_client_t * c
Definition: vpp_get_metrics.c:48
COMPILE_TIME_CONST
#define COMPILE_TIME_CONST(x)
Definition: clib.h:126
static_always_inline
#define static_always_inline
Definition: clib.h:112
strcpy_s
errno_t strcpy_s(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src)
copy src string to dest string
Definition: string.c:272
strncmp_s_inline
static errno_t strncmp_s_inline(const char *s1, rsize_t s1max, const char *s2, rsize_t n, int *indicator)
Definition: string.h:887
uword
u64 uword
Definition: types.h:112
memset_s
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
memset_s_inline
static errno_t memset_s_inline(void *s, rsize_t smax, int c, rsize_t n)
Definition: string.h:202
u8x32_msb_mask
_mm256_packus_epi16 _mm256_packus_epi32 static_always_inline u32 u8x32_msb_mask(u8x32 v)
Definition: vector_avx2.h:123
low
vl_api_ip4_address_t low
Definition: arp.api:36
mask
vl_api_pnat_mask_t mask
Definition: pnat.api:45
strnlen_s
size_t strnlen_s(const char *s, size_t maxsize)
compute the length in s, no more than maxsize
Definition: string.c:433
src
vl_api_address_t src
Definition: gre.api:54
clib_count_equal_u32
static_always_inline uword clib_count_equal_u32(u32 *data, uword max_count)
Definition: string.h:535
clib_count_equal_u8
static_always_inline uword clib_count_equal_u8(u8 *data, uword max_count)
Definition: string.h:661
errno_t
int errno_t
Definition: string.h:130
strcat_s
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
memcpy_s_inline
static errno_t memcpy_s_inline(void *__restrict__ dest, rsize_t dmax, const void *__restrict__ src, rsize_t n)
Definition: string.h:138
u8x16_is_greater
static_always_inline u8x16 u8x16_is_greater(u8x16 v1, u8x16 v2)
Definition: vector_sse42.h:696
clib_memset_u8
static_always_inline void clib_memset_u8(void *p, u8 val, uword count)
Definition: string.h:441
strncmp_s
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
memcmp_s_inline
static errno_t memcmp_s_inline(const void *s1, rsize_t s1max, const void *s2, rsize_t s2max, int *diff)
Definition: string.h:744
data
u8 data[128]
Definition: ipsec_types.api:92
clib_strnlen
#define clib_strnlen(s, m)
Definition: string.h:782
clib_c11_violation
void clib_c11_violation(const char *s)
Definition: string.c:95
always_inline
#define always_inline
Definition: rdma_mlx5dv.h:23
u16x8
_mm_packus_epi16 u16x8
Definition: vector_sse42.h:196
u64
unsigned long u64
Definition: types.h:89
u8x32
u8x32
Definition: vector_avx2.h:116
ASSERT
#define ASSERT(truth)
Definition: error_bootstrap.h:69
strncat_s_inline
static errno_t strncat_s_inline(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src, rsize_t n)
Definition: string.h:1138
u32
unsigned int u32
Definition: types.h:88
dst
vl_api_ip4_address_t dst
Definition: pnat.api:41
vector.h
u32x4
unsigned long long u32x4
Definition: ixge.c:28
memcpy_sse3.h
memcpy_avx2.h
u8
unsigned char u8
Definition: types.h:56
clib_count_equal_u16
static_always_inline uword clib_count_equal_u16(u16 *data, uword max_count)
Definition: string.h:598
u64x8
__m512i u64x8
Definition: vector_avx512.h:306
clib_memswap
void clib_memswap(void *_a, void *_b, uword bytes)
Definition: string.c:49
u8x64
u8x64
Definition: vector_avx512.h:96
strtok_s_inline
static char * strtok_s_inline(char *__restrict__ s1, rsize_t *__restrict__ s1max, const char *__restrict__ s2, char **__restrict__ ptr)
Definition: string.h:1220
strcmp_s_inline
static errno_t strcmp_s_inline(const char *s1, rsize_t s1max, const char *s2, int *indicator)
Definition: string.h:833
strncpy_s_inline
static errno_t strncpy_s_inline(char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src, rsize_t n)
Definition: string.h:999
strncat_s
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
u16x16
_mm256_packus_epi16 u16x16
Definition: vector_avx2.h:118
u64x4
u64x4
Definition: vector_avx2.h:142
strstr_s_inline
static errno_t strstr_s_inline(char *s1, rsize_t s1max, const char *s2, rsize_t s2max, char **substring)
Definition: string.h:1374