vppinfra: c11 safe string functions
[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
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 becuase 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
120 always_inline errno_t
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
184 always_inline errno_t
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
223 static_always_inline void
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
284 static_always_inline void
285 clib_memset_u64 (void *p, u64 val, uword count)
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
321 static_always_inline void
322 clib_memset_u32 (void *p, u32 val, uword count)
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
367 static_always_inline void
368 clib_memset_u16 (void *p, u16 val, uword count)
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
413 static_always_inline void
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
459 static_always_inline uword
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
509 static_always_inline uword
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
577 static_always_inline uword
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
645 static_always_inline uword
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
736 always_inline errno_t
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
825 always_inline errno_t
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
879 always_inline errno_t
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
933 always_inline errno_t
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
991 always_inline errno_t
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     m = n;
1029
1030   /* Check for src/dst overlap, which is not allowed */
1031   low = (uword) (src < dest ? src : dest);
1032   hi = (uword) (src < dest ? dest : src);
1033
1034   if (PREDICT_FALSE (low + (m - 1) >= hi))
1035     {
1036       clib_c11_violation ("src/dest overlap");
1037       return EINVAL;
1038     }
1039
1040   clib_memcpy_fast (dest, src, m);
1041   dest[m] = '\0';
1042   return status;
1043 }
1044
1045 /*
1046  * This macro is to provide smooth migration from strcat to strcat_s.
1047  * Because there is no dmax in strcat, we improvise it with
1048  * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite dest
1049  * with too many bytes from src.
1050  * Applications are encouraged to use C11 API to provide the actual dmax
1051  * for proper checking and protection.
1052  */
1053 #define clib_strcat(d,s) strcat_s_inline(d,CLIB_STRING_MACRO_MAX,s)
1054
1055 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
1056                   const char *__restrict__ src);
1057
1058 always_inline errno_t
1059 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
1060                  const char *__restrict__ src)
1061 {
1062   u8 bad;
1063   uword low, hi;
1064   size_t m, n, dest_size;
1065
1066   bad = (dest == 0) + (dmax == 0) + (src == 0);
1067   if (PREDICT_FALSE (bad != 0))
1068     {
1069       if (dest == 0)
1070         clib_c11_violation ("dest NULL");
1071       if (src == 0)
1072         clib_c11_violation ("src NULL");
1073       if (dmax == 0)
1074         clib_c11_violation ("dmax 0");
1075       return EINVAL;
1076     }
1077
1078   dest_size = clib_strnlen (dest, dmax);
1079   m = dmax - dest_size;
1080   n = clib_strnlen (src, m);
1081   if (PREDICT_FALSE (n >= m))
1082     {
1083       clib_c11_violation ("not enough space for dest");
1084       return EINVAL;
1085     }
1086
1087   /* Not actually trying to concatenate anything is OK */
1088   if (PREDICT_FALSE (n == 0))
1089     return EOK;
1090
1091   /* Check for src/dst overlap, which is not allowed */
1092   low = (uword) (src < dest ? src : dest);
1093   hi = (uword) (src < dest ? dest : src);
1094
1095   if (PREDICT_FALSE (low + (n - 1) >= hi))
1096     {
1097       clib_c11_violation ("src/dest overlap");
1098       return EINVAL;
1099     }
1100
1101   clib_memcpy_fast (dest + dest_size, src, n);
1102   dest[dest_size + n] = '\0';
1103   return EOK;
1104 }
1105
1106 /*
1107  * This macro is to provide smooth migration from strncat to strncat_s.
1108  * The unsafe strncat does not have s1max. We improvise it with
1109  * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite
1110  * dest with too many bytes from src.
1111  * Applications are encouraged to move to C11 strncat_s which requires dmax
1112  * from the caller and provides checking to safeguard the memory corruption.
1113  */
1114 #define clib_strncat(d,s,n) strncat_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
1115
1116 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
1117                    const char *__restrict__ src, rsize_t n);
1118
1119 always_inline errno_t
1120 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
1121                   const char *__restrict__ src, rsize_t n)
1122 {
1123   u8 bad;
1124   uword low, hi;
1125   size_t m, dest_size, allowed_size;
1126   errno_t status = EOK;
1127
1128   bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
1129   if (PREDICT_FALSE (bad != 0))
1130     {
1131       /* Not actually trying to concatenate anything is OK */
1132       if (n == 0)
1133         return EOK;
1134       if (dest == 0)
1135         clib_c11_violation ("dest NULL");
1136       if (src == 0)
1137         clib_c11_violation ("src NULL");
1138       if (dmax == 0)
1139         clib_c11_violation ("dmax 0");
1140       return EINVAL;
1141     }
1142
1143   /* Check for src/dst overlap, which is not allowed */
1144   low = (uword) (src < dest ? src : dest);
1145   hi = (uword) (src < dest ? dest : src);
1146
1147   if (PREDICT_FALSE (low + (n - 1) >= hi))
1148     {
1149       clib_c11_violation ("src/dest overlap");
1150       return EINVAL;
1151     }
1152
1153   dest_size = clib_strnlen (dest, dmax);
1154   allowed_size = dmax - dest_size;
1155
1156   if (PREDICT_FALSE (allowed_size == 0))
1157     {
1158       clib_c11_violation ("no space left in dest");
1159       return (EINVAL);
1160     }
1161
1162   if (PREDICT_FALSE (n >= allowed_size))
1163     {
1164       /*
1165        * unlike strcat_s, strncat_s will do the concatenation anyway when
1166        * there is not enough space in dest. But it will do the truncation and
1167        * null terminate dest
1168        */
1169       m = clib_strnlen (src, allowed_size);
1170       if (m >= allowed_size)
1171         {
1172           m = allowed_size - 1;
1173           status = EOVERFLOW;
1174         }
1175     }
1176   else
1177     m = clib_strnlen (src, n);
1178
1179   clib_memcpy_fast (dest + dest_size, src, m);
1180   dest[dest_size + m] = '\0';
1181   return status;
1182 }
1183
1184 /*
1185  * This macro is to provide smooth mapping from strtok_r to strtok_s.
1186  * To map strtok to this macro, the caller would have to supply an additional
1187  * argument. strtokr_s requires s1max which the unsafe API does not have. So
1188  * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
1189  * this macro cannot catch unterminated s1 and s2.
1190  * Applications are encouraged to use the cool C11 strtok_s API to avoid
1191  * these problems.
1192  */
1193 #define clib_strtok(s1,s2,p)               \
1194   ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX;   \
1195     strtok_s_inline (s1, &__s1max, s2, p);              \
1196   })
1197
1198 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1199                 const char *__restrict__ s2, char **__restrict__ ptr);
1200
1201 always_inline char *
1202 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1203                  const char *__restrict__ s2, char **__restrict__ ptr)
1204 {
1205 #define STRTOK_DELIM_MAX_LEN 16
1206   u8 bad;
1207   const char *pt;
1208   char *ptoken;
1209   uword dlen, slen;
1210
1211   bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
1212     ((s1 == 0) && ptr && (*ptr == 0));
1213   if (PREDICT_FALSE (bad != 0))
1214     {
1215       if (s2 == NULL)
1216         clib_c11_violation ("s2 NULL");
1217       if (s1max == NULL)
1218         clib_c11_violation ("s1max is NULL");
1219       if (ptr == NULL)
1220         clib_c11_violation ("ptr is NULL");
1221       /* s1 == 0 and *ptr == null is no good */
1222       if ((s1 == 0) && ptr && (*ptr == 0))
1223         clib_c11_violation ("s1 and ptr contents are NULL");
1224       return 0;
1225     }
1226
1227   if (s1 == 0)
1228     s1 = *ptr;
1229
1230   /*
1231    * scan s1 for a delimiter
1232    */
1233   dlen = *s1max;
1234   ptoken = 0;
1235   while (*s1 != '\0' && !ptoken)
1236     {
1237       if (PREDICT_FALSE (dlen == 0))
1238         {
1239           *ptr = 0;
1240           clib_c11_violation ("s1 unterminated");
1241           return 0;
1242         }
1243
1244       /*
1245        * must scan the entire delimiter list
1246        * ISO should have included a delimiter string limit!!
1247        */
1248       slen = STRTOK_DELIM_MAX_LEN;
1249       pt = s2;
1250       while (*pt != '\0')
1251         {
1252           if (PREDICT_FALSE (slen == 0))
1253             {
1254               *ptr = 0;
1255               clib_c11_violation ("s2 unterminated");
1256               return 0;
1257             }
1258           slen--;
1259           if (*s1 == *pt)
1260             {
1261               ptoken = 0;
1262               break;
1263             }
1264           else
1265             {
1266               pt++;
1267               ptoken = s1;
1268             }
1269         }
1270       s1++;
1271       dlen--;
1272     }
1273
1274   /*
1275    * if the beginning of a token was not found, then no
1276    * need to continue the scan.
1277    */
1278   if (ptoken == 0)
1279     {
1280       *s1max = dlen;
1281       return (ptoken);
1282     }
1283
1284   /*
1285    * Now we need to locate the end of the token
1286    */
1287   while (*s1 != '\0')
1288     {
1289       if (dlen == 0)
1290         {
1291           *ptr = 0;
1292           clib_c11_violation ("s1 unterminated");
1293           return 0;
1294         }
1295
1296       slen = STRTOK_DELIM_MAX_LEN;
1297       pt = s2;
1298       while (*pt != '\0')
1299         {
1300           if (slen == 0)
1301             {
1302               *ptr = 0;
1303               clib_c11_violation ("s2 unterminated");
1304               return 0;
1305             }
1306           slen--;
1307           if (*s1 == *pt)
1308             {
1309               /*
1310                * found a delimiter, set to null
1311                * and return context ptr to next char
1312                */
1313               *s1 = '\0';
1314               *ptr = (s1 + 1);  /* return pointer for next scan */
1315               *s1max = dlen - 1;        /* account for the nulled delimiter */
1316               return (ptoken);
1317             }
1318           else
1319             {
1320               /*
1321                * simply scanning through the delimiter string
1322                */
1323               pt++;
1324             }
1325         }
1326       s1++;
1327       dlen--;
1328     }
1329
1330   *ptr = s1;
1331   *s1max = dlen;
1332   return (ptoken);
1333 }
1334
1335 /*
1336  * This macro is to provide smooth mapping from strstr to strstr_s.
1337  * strstr_s requires s1max and s2max which the unsafe API does not have. So
1338  * we have to improvise them with CLIB_STRING_MACRO_MAX which may cause us
1339  * to access memory beyond it is intended if s1 or s2 is unterminated.
1340  * For the record, strstr crashes if s1 or s2 is unterminated. But this macro
1341  * does not.
1342  * Applications are encouraged to use the cool C11 strstr_s API to avoid
1343  * this problem.
1344  */
1345 #define clib_strstr(s1,s2) \
1346   ({ char * __substring = 0; \
1347     strstr_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, CLIB_STRING_MACRO_MAX, \
1348                      &__substring);              \
1349     __substring;                                 \
1350   })
1351
1352 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1353                   char **substring);
1354
1355 always_inline errno_t
1356 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1357                  char **substring)
1358 {
1359   u8 bad;
1360   size_t s1_size, s2_size;
1361
1362   bad =
1363     (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1364     (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1365     (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1366   if (PREDICT_FALSE (bad != 0))
1367     {
1368       if (s1 == 0)
1369         clib_c11_violation ("s1 NULL");
1370       if (s2 == 0)
1371         clib_c11_violation ("s2 NULL");
1372       if (s1max == 0)
1373         clib_c11_violation ("s1max 0");
1374       if (s2max == 0)
1375         clib_c11_violation ("s2max 0");
1376       if (substring == 0)
1377         clib_c11_violation ("substring NULL");
1378       if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1379         clib_c11_violation ("s1 unterminated");
1380       if (s2 && s2max && (s2[clib_strnlen (s2, s1max)] != '\0'))
1381         clib_c11_violation ("s2 unterminated");
1382       return EINVAL;
1383     }
1384
1385   /*
1386    * s2 points to a string with zero length, or s2 equals s1, return s1
1387    */
1388   if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1389     {
1390       *substring = s1;
1391       return EOK;
1392     }
1393
1394   /*
1395    * s2_size > s1_size, it won't find match.
1396    */
1397   s1_size = clib_strnlen (s1, s1max);
1398   s2_size = clib_strnlen (s2, s2max);
1399   if (PREDICT_FALSE (s2_size > s1_size))
1400     return ESRCH;
1401
1402   *substring = strstr (s1, s2);
1403   if (*substring == 0)
1404     return ESRCH;
1405
1406   return EOK;
1407 }
1408
1409 #endif /* included_clib_string_h */
1410
1411 /*
1412  * fd.io coding-style-patch-verification: ON
1413  *
1414  * Local Variables:
1415  * eval: (c-set-style "gnu")
1416  * End:
1417  */