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