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