vppinfra: move clib_count_equal_* code
[vpp.git] / src / vppinfra / string.h
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 #include <vppinfra/error_bootstrap.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
91 static_always_inline void *
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
137 always_inline errno_t
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
201 always_inline errno_t
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
233 static_always_inline void
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
299 static_always_inline void
300 clib_memcpy_le64 (u8 * dst, u8 * src, u8 len)
301 {
302   clib_memcpy_le (dst, src, len, 64);
303 }
304
305 static_always_inline void
306 clib_memcpy_le32 (u8 * dst, u8 * src, u8 len)
307 {
308   clib_memcpy_le (dst, src, len, 32);
309 }
310
311 static_always_inline void
312 clib_memset_u64 (void *p, u64 val, uword count)
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
348 static_always_inline void
349 clib_memset_u32 (void *p, u32 val, uword count)
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
394 static_always_inline void
395 clib_memset_u16 (void *p, u16 val, uword count)
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
440 static_always_inline void
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
486
487 /*
488  * This macro is to provide smooth mapping from memcmp to memcmp_s.
489  * memcmp has fewer parameters and fewer returns than memcmp_s.
490  * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
491  * we return 0 and spit out a message in the console because there is
492  * no way to return the error code to the memcmp callers.
493  * This condition happens when s1 or s2 is null. Please note
494  * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
495  * anyway. So we are consistent in this case for the comparison return
496  * although we also spit out a C11 violation message in the console to
497  * warn that they pass null pointers for both s1 and s2.
498  * Applications are encouraged to use the cool C11 memcmp_s API to get the
499  * maximum benefit out of it.
500  */
501 #define clib_memcmp(s1,s2,m1) \
502   ({ int __diff = 0;                                   \
503     memcmp_s_inline (s1, m1, s2, m1, &__diff);  \
504     __diff; \
505   })
506
507 errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
508                   rsize_t s2max, int *diff);
509
510 always_inline errno_t
511 memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
512                  int *diff)
513 {
514   u8 bad;
515
516   bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
517     (s1max == 0);
518
519   if (PREDICT_FALSE (bad != 0))
520     {
521       if (s1 == NULL)
522         clib_c11_violation ("s1 NULL");
523       if (s2 == NULL)
524         clib_c11_violation ("s2 NULL");
525       if (diff == NULL)
526         clib_c11_violation ("diff NULL");
527       if (s2max > s1max)
528         clib_c11_violation ("s2max > s1max");
529       if (s2max == 0)
530         clib_c11_violation ("s2max 0");
531       if (s1max == 0)
532         clib_c11_violation ("s1max 0");
533       return EINVAL;
534     }
535
536   if (PREDICT_FALSE (s1 == s2))
537     {
538       *diff = 0;
539       return EOK;
540     }
541
542   *diff = memcmp (s1, s2, s2max);
543   return EOK;
544 }
545
546 /*
547  * This macro is to provide smooth mapping from strnlen to strnlen_s
548  */
549 #define clib_strnlen(s,m) strnlen_s_inline(s,m)
550
551 size_t strnlen_s (const char *s, size_t maxsize);
552
553 always_inline size_t
554 strnlen_s_inline (const char *s, size_t maxsize)
555 {
556   u8 bad;
557
558   bad = (s == 0) + (maxsize == 0);
559   if (PREDICT_FALSE (bad != 0))
560     {
561       if (s == 0)
562         clib_c11_violation ("s NULL");
563       if (maxsize == 0)
564         clib_c11_violation ("maxsize 0");
565       return 0;
566     }
567   return strnlen (s, maxsize);
568 }
569
570 /*
571  * This macro is to provide smooth mapping from strcmp to strcmp_s.
572  * strcmp has fewer parameters and fewer returns than strcmp_s.
573  * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
574  * we return 0 and spit out a message in the console because
575  * there is no way to return the error to the strcmp callers.
576  * This condition happens when s1 or s2 is null. Please note in the extant
577  * strcmp call, they would end up crashing if one of them is null.
578  * So the new behavior is no crash, but an error is displayed in the
579  * console which I think is more user friendly. If both s1 and s2 are null,
580  * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
581  * to actually accessing the pointer contents. We are still consistent
582  * in this case for the comparison return although we also spit out a
583  * C11 violation message in the console to warn that they pass null pointers
584  * for both s1 and s2. The other problem is strcmp does not provide s1max,
585  * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
586  * If not, we may be accessing memory beyonf what is intended.
587  * Applications are encouraged to use the cool C11 strcmp_s API to get the
588  * maximum benefit out of it.
589  */
590 #define clib_strcmp(s1,s2) \
591   ({ int __indicator = 0; \
592     strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator);      \
593     __indicator;                        \
594   })
595
596 errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
597                   int *indicator);
598
599 always_inline errno_t
600 strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
601                  int *indicator)
602 {
603   u8 bad;
604
605   bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
606     (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
607
608   if (PREDICT_FALSE (bad != 0))
609     {
610       if (indicator == NULL)
611         clib_c11_violation ("indicator NULL");
612       if (s1 == NULL)
613         clib_c11_violation ("s1 NULL");
614       if (s2 == NULL)
615         clib_c11_violation ("s2 NULL");
616       if (s1max == 0)
617         clib_c11_violation ("s1max 0");
618       if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
619         clib_c11_violation ("s1 unterminated");
620       return EINVAL;
621     }
622
623   *indicator = strcmp (s1, s2);
624   return EOK;
625 }
626
627 /*
628  * This macro is to provide smooth mapping from strncmp to strncmp_s.
629  * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
630  * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
631  * we return 0 and spit out a message in the console because there is no
632  * means to return the error to the strncmp caller.
633  * This condition happens when s1 or s2 is null. In the extant strncmp call,
634  * they would end up crashing if one of them is null. So the new behavior is
635  * no crash, but error is displayed in the console which is more
636  * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
637  * strncmp did the pointers comparison prior to actually accessing the
638  * pointer contents. We are still consistent in this case for the comparison
639  * return although we also spit out a C11 violation message in the console to
640  * warn that they pass null pointers for both s1 and s2.
641  * Applications are encouraged to use the cool C11 strncmp_s API to get the
642  * maximum benefit out of it.
643  */
644 #define clib_strncmp(s1,s2,n) \
645   ({ int __indicator = 0; \
646     strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator);  \
647     __indicator;                        \
648   })
649
650 errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
651                    int *indicator);
652
653 always_inline errno_t
654 strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
655                   int *indicator)
656 {
657   u8 bad;
658   u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
659
660   if (PREDICT_FALSE (s1_greater_s1max && indicator))
661     {
662       /*
663        * strcmp allows n > s1max. If indicator is non null, we can still
664        * do the compare without any harm and return EINVAL as well as the
665        * result in indicator.
666        */
667       clib_c11_violation ("n exceeds s1 length");
668       *indicator = strncmp (s1, s2, n);
669       return EINVAL;
670     }
671
672   bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
673     (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
674
675   if (PREDICT_FALSE (bad != 0))
676     {
677       if (indicator == NULL)
678         clib_c11_violation ("indicator NULL");
679       if (s1 == NULL)
680         clib_c11_violation ("s1 NULL");
681       if (s2 == NULL)
682         clib_c11_violation ("s2 NULL");
683       if (s1max == 0)
684         clib_c11_violation ("s1max 0");
685       if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
686         clib_c11_violation ("s1 unterminated");
687       if (s1_greater_s1max)
688         clib_c11_violation ("n exceeds s1 length");
689       return EINVAL;
690     }
691
692   *indicator = strncmp (s1, s2, n);
693   return EOK;
694 }
695
696 errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
697                   const char *__restrict__ src);
698
699 always_inline errno_t
700 strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
701                  const char *__restrict__ src)
702 {
703   u8 bad;
704   uword low, hi;
705   size_t n;
706
707   bad = (dest == 0) + (dmax == 0) + (src == 0);
708   if (PREDICT_FALSE (bad != 0))
709     {
710       if (dest == 0)
711         clib_c11_violation ("dest NULL");
712       if (src == 0)
713         clib_c11_violation ("src NULL");
714       if (dmax == 0)
715         clib_c11_violation ("dmax 0");
716       return EINVAL;
717     }
718
719   n = clib_strnlen (src, dmax);
720   if (PREDICT_FALSE (n >= dmax))
721     {
722       clib_c11_violation ("not enough space for dest");
723       return (EINVAL);
724     }
725   /* Not actually trying to copy anything is OK */
726   if (PREDICT_FALSE (n == 0))
727     return EOK;
728
729   /* Check for src/dst overlap, which is not allowed */
730   low = (uword) (src < dest ? src : dest);
731   hi = (uword) (src < dest ? dest : src);
732
733   if (PREDICT_FALSE (low + (n - 1) >= hi))
734     {
735       clib_c11_violation ("src/dest overlap");
736       return EINVAL;
737     }
738
739   clib_memcpy_fast (dest, src, n);
740   dest[n] = '\0';
741   return EOK;
742 }
743
744 /*
745  * This macro is provided for smooth migration from strncpy. It is not perfect
746  * because we don't know the size of the destination buffer to pass to
747  * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
748  * Applications are encouraged to move to the C11 strncpy_s API and provide
749  * the correct dmax for better error checking.
750  */
751 #define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
752
753 errno_t
754 strncpy_s (char *__restrict__ dest, rsize_t dmax,
755            const char *__restrict__ src, rsize_t n);
756
757 always_inline errno_t
758 strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
759                   const char *__restrict__ src, rsize_t n)
760 {
761   u8 bad;
762   uword low, hi;
763   rsize_t m;
764   errno_t status = EOK;
765
766   bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
767   if (PREDICT_FALSE (bad != 0))
768     {
769       /* Not actually trying to copy anything is OK */
770       if (n == 0)
771         return EOK;
772       if (dest == 0)
773         clib_c11_violation ("dest NULL");
774       if (src == 0)
775         clib_c11_violation ("src NULL");
776       if (dmax == 0)
777         clib_c11_violation ("dmax 0");
778       return EINVAL;
779     }
780
781   if (PREDICT_FALSE (n >= dmax))
782     {
783       /* Relax and use strnlen of src */
784       clib_c11_violation ("n >= dmax");
785       m = clib_strnlen (src, dmax);
786       if (m >= dmax)
787         {
788           /* Truncate, adjust copy length to fit dest */
789           m = dmax - 1;
790           status = EOVERFLOW;
791         }
792     }
793   else
794     /* cap the copy to strlen(src) in case n > strlen(src) */
795     m = clib_strnlen (src, n);
796
797   /* Check for src/dst overlap, which is not allowed */
798   low = (uword) (src < dest ? src : dest);
799   hi = (uword) (src < dest ? dest : src);
800
801   /*
802    * This check may fail innocently if src + dmax >= dst, but
803    * src + strlen(src) < dst. If it fails, check more carefully before
804    * blowing the whistle.
805    */
806   if (PREDICT_FALSE (low + (m - 1) >= hi))
807     {
808       m = clib_strnlen (src, m);
809
810       if (low + (m - 1) >= hi)
811         {
812           clib_c11_violation ("src/dest overlap");
813           return EINVAL;
814         }
815     }
816
817   clib_memcpy_fast (dest, src, m);
818   dest[m] = '\0';
819   return status;
820 }
821
822 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
823                   const char *__restrict__ src);
824
825 always_inline errno_t
826 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
827                  const char *__restrict__ src)
828 {
829   u8 bad;
830   uword low, hi;
831   size_t m, n, dest_size;
832
833   bad = (dest == 0) + (dmax == 0) + (src == 0);
834   if (PREDICT_FALSE (bad != 0))
835     {
836       if (dest == 0)
837         clib_c11_violation ("dest NULL");
838       if (src == 0)
839         clib_c11_violation ("src NULL");
840       if (dmax == 0)
841         clib_c11_violation ("dmax 0");
842       return EINVAL;
843     }
844
845   dest_size = clib_strnlen (dest, dmax);
846   m = dmax - dest_size;
847   n = clib_strnlen (src, m);
848   if (PREDICT_FALSE (n >= m))
849     {
850       clib_c11_violation ("not enough space for dest");
851       return EINVAL;
852     }
853
854   /* Not actually trying to concatenate anything is OK */
855   if (PREDICT_FALSE (n == 0))
856     return EOK;
857
858   /* Check for src/dst overlap, which is not allowed */
859   low = (uword) (src < dest ? src : dest);
860   hi = (uword) (src < dest ? dest : src);
861
862   if (PREDICT_FALSE (low + (n - 1) >= hi))
863     {
864       clib_c11_violation ("src/dest overlap");
865       return EINVAL;
866     }
867
868   clib_memcpy_fast (dest + dest_size, src, n);
869   dest[dest_size + n] = '\0';
870   return EOK;
871 }
872
873 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
874                    const char *__restrict__ src, rsize_t n);
875
876 always_inline errno_t
877 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
878                   const char *__restrict__ src, rsize_t n)
879 {
880   u8 bad;
881   uword low, hi;
882   size_t m, dest_size, allowed_size;
883   errno_t status = EOK;
884
885   bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
886   if (PREDICT_FALSE (bad != 0))
887     {
888       /* Not actually trying to concatenate anything is OK */
889       if (n == 0)
890         return EOK;
891       if (dest == 0)
892         clib_c11_violation ("dest NULL");
893       if (src == 0)
894         clib_c11_violation ("src NULL");
895       if (dmax == 0)
896         clib_c11_violation ("dmax 0");
897       return EINVAL;
898     }
899
900   /* Check for src/dst overlap, which is not allowed */
901   low = (uword) (src < dest ? src : dest);
902   hi = (uword) (src < dest ? dest : src);
903
904   if (PREDICT_FALSE (low + (n - 1) >= hi))
905     {
906       clib_c11_violation ("src/dest overlap");
907       return EINVAL;
908     }
909
910   dest_size = clib_strnlen (dest, dmax);
911   allowed_size = dmax - dest_size;
912
913   if (PREDICT_FALSE (allowed_size == 0))
914     {
915       clib_c11_violation ("no space left in dest");
916       return (EINVAL);
917     }
918
919   if (PREDICT_FALSE (n >= allowed_size))
920     {
921       /*
922        * unlike strcat_s, strncat_s will do the concatenation anyway when
923        * there is not enough space in dest. But it will do the truncation and
924        * null terminate dest
925        */
926       m = clib_strnlen (src, allowed_size);
927       if (m >= allowed_size)
928         {
929           m = allowed_size - 1;
930           status = EOVERFLOW;
931         }
932     }
933   else
934     m = clib_strnlen (src, n);
935
936   clib_memcpy_fast (dest + dest_size, src, m);
937   dest[dest_size + m] = '\0';
938   return status;
939 }
940
941 /*
942  * This macro is to provide smooth mapping from strtok_r to strtok_s.
943  * To map strtok to this macro, the caller would have to supply an additional
944  * argument. strtokr_s requires s1max which the unsafe API does not have. So
945  * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
946  * this macro cannot catch unterminated s1 and s2.
947  * Applications are encouraged to use the cool C11 strtok_s API to avoid
948  * these problems.
949  */
950 #define clib_strtok(s1,s2,p)               \
951   ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX;   \
952     strtok_s_inline (s1, &__s1max, s2, p);              \
953   })
954
955 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
956                 const char *__restrict__ s2, char **__restrict__ ptr);
957
958 always_inline char *
959 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
960                  const char *__restrict__ s2, char **__restrict__ ptr)
961 {
962 #define STRTOK_DELIM_MAX_LEN 16
963   u8 bad;
964   const char *pt;
965   char *ptoken;
966   uword dlen, slen;
967
968   bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
969     ((s1 == 0) && ptr && (*ptr == 0));
970   if (PREDICT_FALSE (bad != 0))
971     {
972       if (s2 == NULL)
973         clib_c11_violation ("s2 NULL");
974       if (s1max == NULL)
975         clib_c11_violation ("s1max is NULL");
976       if (ptr == NULL)
977         clib_c11_violation ("ptr is NULL");
978       /* s1 == 0 and *ptr == null is no good */
979       if ((s1 == 0) && ptr && (*ptr == 0))
980         clib_c11_violation ("s1 and ptr contents are NULL");
981       return 0;
982     }
983
984   if (s1 == 0)
985     s1 = *ptr;
986
987   /*
988    * scan s1 for a delimiter
989    */
990   dlen = *s1max;
991   ptoken = 0;
992   while (*s1 != '\0' && !ptoken)
993     {
994       if (PREDICT_FALSE (dlen == 0))
995         {
996           *ptr = 0;
997           clib_c11_violation ("s1 unterminated");
998           return 0;
999         }
1000
1001       /*
1002        * must scan the entire delimiter list
1003        * ISO should have included a delimiter string limit!!
1004        */
1005       slen = STRTOK_DELIM_MAX_LEN;
1006       pt = s2;
1007       while (*pt != '\0')
1008         {
1009           if (PREDICT_FALSE (slen == 0))
1010             {
1011               *ptr = 0;
1012               clib_c11_violation ("s2 unterminated");
1013               return 0;
1014             }
1015           slen--;
1016           if (*s1 == *pt)
1017             {
1018               ptoken = 0;
1019               break;
1020             }
1021           else
1022             {
1023               pt++;
1024               ptoken = s1;
1025             }
1026         }
1027       s1++;
1028       dlen--;
1029     }
1030
1031   /*
1032    * if the beginning of a token was not found, then no
1033    * need to continue the scan.
1034    */
1035   if (ptoken == 0)
1036     {
1037       *s1max = dlen;
1038       return (ptoken);
1039     }
1040
1041   /*
1042    * Now we need to locate the end of the token
1043    */
1044   while (*s1 != '\0')
1045     {
1046       if (dlen == 0)
1047         {
1048           *ptr = 0;
1049           clib_c11_violation ("s1 unterminated");
1050           return 0;
1051         }
1052
1053       slen = STRTOK_DELIM_MAX_LEN;
1054       pt = s2;
1055       while (*pt != '\0')
1056         {
1057           if (slen == 0)
1058             {
1059               *ptr = 0;
1060               clib_c11_violation ("s2 unterminated");
1061               return 0;
1062             }
1063           slen--;
1064           if (*s1 == *pt)
1065             {
1066               /*
1067                * found a delimiter, set to null
1068                * and return context ptr to next char
1069                */
1070               *s1 = '\0';
1071               *ptr = (s1 + 1);  /* return pointer for next scan */
1072               *s1max = dlen - 1;        /* account for the nulled delimiter */
1073               return (ptoken);
1074             }
1075           else
1076             {
1077               /*
1078                * simply scanning through the delimiter string
1079                */
1080               pt++;
1081             }
1082         }
1083       s1++;
1084       dlen--;
1085     }
1086
1087   *ptr = s1;
1088   *s1max = dlen;
1089   return (ptoken);
1090 }
1091
1092 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1093                   char **substring);
1094
1095 always_inline errno_t
1096 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1097                  char **substring)
1098 {
1099   u8 bad;
1100   size_t s1_size, s2_size;
1101
1102   bad =
1103     (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1104     (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1105     (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1106   if (PREDICT_FALSE (bad != 0))
1107     {
1108       if (s1 == 0)
1109         clib_c11_violation ("s1 NULL");
1110       if (s2 == 0)
1111         clib_c11_violation ("s2 NULL");
1112       if (s1max == 0)
1113         clib_c11_violation ("s1max 0");
1114       if (s2max == 0)
1115         clib_c11_violation ("s2max 0");
1116       if (substring == 0)
1117         clib_c11_violation ("substring NULL");
1118       if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1119         clib_c11_violation ("s1 unterminated");
1120       if (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'))
1121         clib_c11_violation ("s2 unterminated");
1122       return EINVAL;
1123     }
1124
1125   /*
1126    * s2 points to a string with zero length, or s2 equals s1, return s1
1127    */
1128   if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1129     {
1130       *substring = s1;
1131       return EOK;
1132     }
1133
1134   /*
1135    * s2_size > s1_size, it won't find match.
1136    */
1137   s1_size = clib_strnlen (s1, s1max);
1138   s2_size = clib_strnlen (s2, s2max);
1139   if (PREDICT_FALSE (s2_size > s1_size))
1140     return ESRCH;
1141
1142   *substring = strstr (s1, s2);
1143   if (*substring == 0)
1144     return ESRCH;
1145
1146   return EOK;
1147 }
1148
1149 #endif /* included_clib_string_h */
1150
1151 /*
1152  * fd.io coding-style-patch-verification: ON
1153  *
1154  * Local Variables:
1155  * eval: (c-set-style "gnu")
1156  * End:
1157  */