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