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