vppinfra: fix clib_count_equal_u8/16/32/64 overflow
[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 max_count;
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 (count + 3 < max_count)
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 count;
493         }
494
495       data += 4;
496       count += 4;
497     }
498 #else
499   count += 2;
500   data += 2;
501   while (count + 3 < max_count &&
502          ((data[0] ^ first) | (data[1] ^ first) |
503           (data[2] ^ first) | (data[3] ^ first)) == 0)
504     {
505       data += 4;
506       count += 4;
507     }
508 #endif
509   while (count < max_count && (data[0] == first))
510     {
511       data += 1;
512       count += 1;
513     }
514   return count;
515 }
516
517 static_always_inline uword
518 clib_count_equal_u32 (u32 * data, uword max_count)
519 {
520   uword count;
521   u32 first;
522
523   if (max_count <= 1)
524     return max_count;
525   if (data[0] != data[1])
526     return 1;
527
528   count = 0;
529   first = data[0];
530
531 #if defined(CLIB_HAVE_VEC256)
532   u32x8 splat = u32x8_splat (first);
533   while (count + 7 < max_count)
534     {
535       u64 bmp;
536       bmp = u8x32_msb_mask ((u8x32) (u32x8_load_unaligned (data) == splat));
537       if (bmp != 0xffffffff)
538         {
539           count += count_trailing_zeros (~bmp) / 4;
540           return count;
541         }
542
543       data += 8;
544       count += 8;
545     }
546 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
547   u32x4 splat = u32x4_splat (first);
548   while (count + 3 < max_count)
549     {
550       u64 bmp;
551       bmp = u8x16_msb_mask ((u8x16) (u32x4_load_unaligned (data) == splat));
552       if (bmp != 0xffff)
553         {
554           count += count_trailing_zeros (~bmp) / 4;
555           return count;
556         }
557
558       data += 4;
559       count += 4;
560     }
561 #else
562   count += 2;
563   data += 2;
564   while (count + 3 < max_count &&
565          ((data[0] ^ first) | (data[1] ^ first) |
566           (data[2] ^ first) | (data[3] ^ first)) == 0)
567     {
568       data += 4;
569       count += 4;
570     }
571 #endif
572   while (count < max_count && (data[0] == first))
573     {
574       data += 1;
575       count += 1;
576     }
577   return count;
578 }
579
580 static_always_inline uword
581 clib_count_equal_u16 (u16 * data, uword max_count)
582 {
583   uword count;
584   u16 first;
585
586   if (max_count <= 1)
587     return max_count;
588   if (data[0] != data[1])
589     return 1;
590
591   count = 0;
592   first = data[0];
593
594 #if defined(CLIB_HAVE_VEC256)
595   u16x16 splat = u16x16_splat (first);
596   while (count + 15 < max_count)
597     {
598       u64 bmp;
599       bmp = u8x32_msb_mask ((u8x32) (u16x16_load_unaligned (data) == splat));
600       if (bmp != 0xffffffff)
601         {
602           count += count_trailing_zeros (~bmp) / 2;
603           return count;
604         }
605
606       data += 16;
607       count += 16;
608     }
609 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
610   u16x8 splat = u16x8_splat (first);
611   while (count + 7 < max_count)
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 count;
619         }
620
621       data += 8;
622       count += 8;
623     }
624 #else
625   count += 2;
626   data += 2;
627   while (count + 3 < max_count &&
628          ((data[0] ^ first) | (data[1] ^ first) |
629           (data[2] ^ first) | (data[3] ^ first)) == 0)
630     {
631       data += 4;
632       count += 4;
633     }
634 #endif
635   while (count < max_count && (data[0] == first))
636     {
637       data += 1;
638       count += 1;
639     }
640   return count;
641 }
642
643 static_always_inline uword
644 clib_count_equal_u8 (u8 * data, uword max_count)
645 {
646   uword count;
647   u8 first;
648
649   if (max_count <= 1)
650     return max_count;
651   if (data[0] != data[1])
652     return 1;
653
654   count = 0;
655   first = data[0];
656
657 #if defined(CLIB_HAVE_VEC256)
658   u8x32 splat = u8x32_splat (first);
659   while (count + 31 < max_count)
660     {
661       u64 bmp;
662       bmp = u8x32_msb_mask ((u8x32) (u8x32_load_unaligned (data) == splat));
663       if (bmp != 0xffffffff)
664         {
665           count += count_trailing_zeros (~bmp);
666           return max_count;
667         }
668
669       data += 32;
670       count += 32;
671     }
672 #elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
673   u8x16 splat = u8x16_splat (first);
674   while (count + 15 < max_count)
675     {
676       u64 bmp;
677       bmp = u8x16_msb_mask ((u8x16) (u8x16_load_unaligned (data) == splat));
678       if (bmp != 0xffff)
679         {
680           count += count_trailing_zeros (~bmp);
681           return count;
682         }
683
684       data += 16;
685       count += 16;
686     }
687 #else
688   count += 2;
689   data += 2;
690   while (count + 3 < max_count &&
691          ((data[0] ^ first) | (data[1] ^ first) |
692           (data[2] ^ first) | (data[3] ^ first)) == 0)
693     {
694       data += 4;
695       count += 4;
696     }
697 #endif
698   while (count < max_count && (data[0] == first))
699     {
700       data += 1;
701       count += 1;
702     }
703   return count;
704 }
705
706 /*
707  * This macro is to provide smooth mapping from memcmp to memcmp_s.
708  * memcmp has fewer parameters and fewer returns than memcmp_s.
709  * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
710  * we return 0 and spit out a message in the console because there is
711  * no way to return the error code to the memcmp callers.
712  * This condition happens when s1 or s2 is null. Please note
713  * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
714  * anyway. So we are consistent in this case for the comparison return
715  * although we also spit out a C11 violation message in the console to
716  * warn that they pass null pointers for both s1 and s2.
717  * Applications are encouraged to use the cool C11 memcmp_s API to get the
718  * maximum benefit out of it.
719  */
720 #define clib_memcmp(s1,s2,m1) \
721   ({ int __diff = 0;                                   \
722     memcmp_s_inline (s1, m1, s2, m1, &__diff);  \
723     __diff; \
724   })
725
726 errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
727                   rsize_t s2max, int *diff);
728
729 always_inline errno_t
730 memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
731                  int *diff)
732 {
733   u8 bad;
734
735   bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
736     (s1max == 0);
737
738   if (PREDICT_FALSE (bad != 0))
739     {
740       if (s1 == NULL)
741         clib_c11_violation ("s1 NULL");
742       if (s2 == NULL)
743         clib_c11_violation ("s2 NULL");
744       if (diff == NULL)
745         clib_c11_violation ("diff NULL");
746       if (s2max > s1max)
747         clib_c11_violation ("s2max > s1max");
748       if (s2max == 0)
749         clib_c11_violation ("s2max 0");
750       if (s1max == 0)
751         clib_c11_violation ("s1max 0");
752       return EINVAL;
753     }
754
755   if (PREDICT_FALSE (s1 == s2))
756     {
757       *diff = 0;
758       return EOK;
759     }
760
761   *diff = memcmp (s1, s2, s2max);
762   return EOK;
763 }
764
765 /*
766  * This macro is to provide smooth mapping from strnlen to strnlen_s
767  */
768 #define clib_strnlen(s,m) strnlen_s_inline(s,m)
769
770 size_t strnlen_s (const char *s, size_t maxsize);
771
772 always_inline size_t
773 strnlen_s_inline (const char *s, size_t maxsize)
774 {
775   u8 bad;
776
777   bad = (s == 0) + (maxsize == 0);
778   if (PREDICT_FALSE (bad != 0))
779     {
780       if (s == 0)
781         clib_c11_violation ("s NULL");
782       if (maxsize == 0)
783         clib_c11_violation ("maxsize 0");
784       return 0;
785     }
786   return strnlen (s, maxsize);
787 }
788
789 /*
790  * This macro is to provide smooth mapping from strcmp to strcmp_s.
791  * strcmp has fewer parameters and fewer returns than strcmp_s.
792  * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
793  * we return 0 and spit out a message in the console because
794  * there is no way to return the error to the strcmp callers.
795  * This condition happens when s1 or s2 is null. Please note in the extant
796  * strcmp call, they would end up crashing if one of them is null.
797  * So the new behavior is no crash, but an error is displayed in the
798  * console which I think is more user friendly. If both s1 and s2 are null,
799  * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
800  * to actually accessing the pointer contents. We are still consistent
801  * in this case for the comparison return although we also spit out a
802  * C11 violation message in the console to warn that they pass null pointers
803  * for both s1 and s2. The other problem is strcmp does not provide s1max,
804  * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
805  * If not, we may be accessing memory beyonf what is intended.
806  * Applications are encouraged to use the cool C11 strcmp_s API to get the
807  * maximum benefit out of it.
808  */
809 #define clib_strcmp(s1,s2) \
810   ({ int __indicator = 0; \
811     strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator);      \
812     __indicator;                        \
813   })
814
815 errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
816                   int *indicator);
817
818 always_inline errno_t
819 strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
820                  int *indicator)
821 {
822   u8 bad;
823
824   bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
825     (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
826
827   if (PREDICT_FALSE (bad != 0))
828     {
829       if (indicator == NULL)
830         clib_c11_violation ("indicator NULL");
831       if (s1 == NULL)
832         clib_c11_violation ("s1 NULL");
833       if (s2 == NULL)
834         clib_c11_violation ("s2 NULL");
835       if (s1max == 0)
836         clib_c11_violation ("s1max 0");
837       if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
838         clib_c11_violation ("s1 unterminated");
839       return EINVAL;
840     }
841
842   *indicator = strcmp (s1, s2);
843   return EOK;
844 }
845
846 /*
847  * This macro is to provide smooth mapping from strncmp to strncmp_s.
848  * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
849  * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
850  * we return 0 and spit out a message in the console because there is no
851  * means to return the error to the strncmp caller.
852  * This condition happens when s1 or s2 is null. In the extant strncmp call,
853  * they would end up crashing if one of them is null. So the new behavior is
854  * no crash, but error is displayed in the console which is more
855  * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
856  * strncmp did the pointers comparison prior to actually accessing the
857  * pointer contents. We are still consistent in this case for the comparison
858  * return although we also spit out a C11 violation message in the console to
859  * warn that they pass null pointers for both s1 and s2.
860  * Applications are encouraged to use the cool C11 strncmp_s API to get the
861  * maximum benefit out of it.
862  */
863 #define clib_strncmp(s1,s2,n) \
864   ({ int __indicator = 0; \
865     strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator);  \
866     __indicator;                        \
867   })
868
869 errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
870                    int *indicator);
871
872 always_inline errno_t
873 strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
874                   int *indicator)
875 {
876   u8 bad;
877   u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
878
879   if (PREDICT_FALSE (s1_greater_s1max && indicator))
880     {
881       /*
882        * strcmp allows n > s1max. If indicator is non null, we can still
883        * do the compare without any harm and return EINVAL as well as the
884        * result in indicator.
885        */
886       clib_c11_violation ("n exceeds s1 length");
887       *indicator = strncmp (s1, s2, n);
888       return EINVAL;
889     }
890
891   bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
892     (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
893
894   if (PREDICT_FALSE (bad != 0))
895     {
896       if (indicator == NULL)
897         clib_c11_violation ("indicator NULL");
898       if (s1 == NULL)
899         clib_c11_violation ("s1 NULL");
900       if (s2 == NULL)
901         clib_c11_violation ("s2 NULL");
902       if (s1max == 0)
903         clib_c11_violation ("s1max 0");
904       if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
905         clib_c11_violation ("s1 unterminated");
906       if (s1_greater_s1max)
907         clib_c11_violation ("n exceeds s1 length");
908       return EINVAL;
909     }
910
911   *indicator = strncmp (s1, s2, n);
912   return EOK;
913 }
914
915 /*
916  * This macro is provided for smooth migration from strcpy. It is not perfect
917  * because we don't know the size of the destination buffer to pass to strcpy_s.
918  * We improvise dmax with CLIB_STRING_MACRO_MAX.
919  * Applications are encouraged to move to the C11 strcpy_s API.
920  */
921 #define clib_strcpy(d,s) strcpy_s_inline(d,CLIB_STRING_MACRO_MAX,s)
922
923 errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
924                   const char *__restrict__ src);
925
926 always_inline errno_t
927 strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
928                  const char *__restrict__ src)
929 {
930   u8 bad;
931   uword low, hi;
932   size_t n;
933
934   bad = (dest == 0) + (dmax == 0) + (src == 0);
935   if (PREDICT_FALSE (bad != 0))
936     {
937       if (dest == 0)
938         clib_c11_violation ("dest NULL");
939       if (src == 0)
940         clib_c11_violation ("src NULL");
941       if (dmax == 0)
942         clib_c11_violation ("dmax 0");
943       return EINVAL;
944     }
945
946   n = clib_strnlen (src, dmax);
947   if (PREDICT_FALSE (n >= dmax))
948     {
949       clib_c11_violation ("not enough space for dest");
950       return (EINVAL);
951     }
952   /* Not actually trying to copy anything is OK */
953   if (PREDICT_FALSE (n == 0))
954     return EOK;
955
956   /* Check for src/dst overlap, which is not allowed */
957   low = (uword) (src < dest ? src : dest);
958   hi = (uword) (src < dest ? dest : src);
959
960   if (PREDICT_FALSE (low + (n - 1) >= hi))
961     {
962       clib_c11_violation ("src/dest overlap");
963       return EINVAL;
964     }
965
966   clib_memcpy_fast (dest, src, n);
967   dest[n] = '\0';
968   return EOK;
969 }
970
971 /*
972  * This macro is provided for smooth migration from strncpy. It is not perfect
973  * because we don't know the size of the destination buffer to pass to
974  * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
975  * Applications are encouraged to move to the C11 strncpy_s API and provide
976  * the correct dmax for better error checking.
977  */
978 #define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
979
980 errno_t
981 strncpy_s (char *__restrict__ dest, rsize_t dmax,
982            const char *__restrict__ src, rsize_t n);
983
984 always_inline errno_t
985 strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
986                   const char *__restrict__ src, rsize_t n)
987 {
988   u8 bad;
989   uword low, hi;
990   rsize_t m;
991   errno_t status = EOK;
992
993   bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
994   if (PREDICT_FALSE (bad != 0))
995     {
996       /* Not actually trying to copy anything is OK */
997       if (n == 0)
998         return EOK;
999       if (dest == 0)
1000         clib_c11_violation ("dest NULL");
1001       if (src == 0)
1002         clib_c11_violation ("src NULL");
1003       if (dmax == 0)
1004         clib_c11_violation ("dmax 0");
1005       return EINVAL;
1006     }
1007
1008   if (PREDICT_FALSE (n >= dmax))
1009     {
1010       /* Relax and use strnlen of src */
1011       clib_c11_violation ("n >= dmax");
1012       m = clib_strnlen (src, dmax);
1013       if (m >= dmax)
1014         {
1015           /* Truncate, adjust copy length to fit dest */
1016           m = dmax - 1;
1017           status = EOVERFLOW;
1018         }
1019     }
1020   else
1021     /* cap the copy to strlen(src) in case n > strlen(src) */
1022     m = clib_strnlen (src, n);
1023
1024   /* Check for src/dst overlap, which is not allowed */
1025   low = (uword) (src < dest ? src : dest);
1026   hi = (uword) (src < dest ? dest : src);
1027
1028   /*
1029    * This check may fail innocently if src + dmax >= dst, but
1030    * src + strlen(src) < dst. If it fails, check more carefully before
1031    * blowing the whistle.
1032    */
1033   if (PREDICT_FALSE (low + (m - 1) >= hi))
1034     {
1035       m = clib_strnlen (src, m);
1036
1037       if (low + (m - 1) >= hi)
1038         {
1039           clib_c11_violation ("src/dest overlap");
1040           return EINVAL;
1041         }
1042     }
1043
1044   clib_memcpy_fast (dest, src, m);
1045   dest[m] = '\0';
1046   return status;
1047 }
1048
1049 /*
1050  * This macro is to provide smooth migration from strcat to strcat_s.
1051  * Because there is no dmax in strcat, we improvise it with
1052  * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite dest
1053  * with too many bytes from src.
1054  * Applications are encouraged to use C11 API to provide the actual dmax
1055  * for proper checking and protection.
1056  */
1057 #define clib_strcat(d,s) strcat_s_inline(d,CLIB_STRING_MACRO_MAX,s)
1058
1059 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
1060                   const char *__restrict__ src);
1061
1062 always_inline errno_t
1063 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
1064                  const char *__restrict__ src)
1065 {
1066   u8 bad;
1067   uword low, hi;
1068   size_t m, n, dest_size;
1069
1070   bad = (dest == 0) + (dmax == 0) + (src == 0);
1071   if (PREDICT_FALSE (bad != 0))
1072     {
1073       if (dest == 0)
1074         clib_c11_violation ("dest NULL");
1075       if (src == 0)
1076         clib_c11_violation ("src NULL");
1077       if (dmax == 0)
1078         clib_c11_violation ("dmax 0");
1079       return EINVAL;
1080     }
1081
1082   dest_size = clib_strnlen (dest, dmax);
1083   m = dmax - dest_size;
1084   n = clib_strnlen (src, m);
1085   if (PREDICT_FALSE (n >= m))
1086     {
1087       clib_c11_violation ("not enough space for dest");
1088       return EINVAL;
1089     }
1090
1091   /* Not actually trying to concatenate anything is OK */
1092   if (PREDICT_FALSE (n == 0))
1093     return EOK;
1094
1095   /* Check for src/dst overlap, which is not allowed */
1096   low = (uword) (src < dest ? src : dest);
1097   hi = (uword) (src < dest ? dest : src);
1098
1099   if (PREDICT_FALSE (low + (n - 1) >= hi))
1100     {
1101       clib_c11_violation ("src/dest overlap");
1102       return EINVAL;
1103     }
1104
1105   clib_memcpy_fast (dest + dest_size, src, n);
1106   dest[dest_size + n] = '\0';
1107   return EOK;
1108 }
1109
1110 /*
1111  * This macro is to provide smooth migration from strncat to strncat_s.
1112  * The unsafe strncat does not have s1max. We improvise it with
1113  * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite
1114  * dest with too many bytes from src.
1115  * Applications are encouraged to move to C11 strncat_s which requires dmax
1116  * from the caller and provides checking to safeguard the memory corruption.
1117  */
1118 #define clib_strncat(d,s,n) strncat_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
1119
1120 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
1121                    const char *__restrict__ src, rsize_t n);
1122
1123 always_inline errno_t
1124 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
1125                   const char *__restrict__ src, rsize_t n)
1126 {
1127   u8 bad;
1128   uword low, hi;
1129   size_t m, dest_size, allowed_size;
1130   errno_t status = EOK;
1131
1132   bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
1133   if (PREDICT_FALSE (bad != 0))
1134     {
1135       /* Not actually trying to concatenate anything is OK */
1136       if (n == 0)
1137         return EOK;
1138       if (dest == 0)
1139         clib_c11_violation ("dest NULL");
1140       if (src == 0)
1141         clib_c11_violation ("src NULL");
1142       if (dmax == 0)
1143         clib_c11_violation ("dmax 0");
1144       return EINVAL;
1145     }
1146
1147   /* Check for src/dst overlap, which is not allowed */
1148   low = (uword) (src < dest ? src : dest);
1149   hi = (uword) (src < dest ? dest : src);
1150
1151   if (PREDICT_FALSE (low + (n - 1) >= hi))
1152     {
1153       clib_c11_violation ("src/dest overlap");
1154       return EINVAL;
1155     }
1156
1157   dest_size = clib_strnlen (dest, dmax);
1158   allowed_size = dmax - dest_size;
1159
1160   if (PREDICT_FALSE (allowed_size == 0))
1161     {
1162       clib_c11_violation ("no space left in dest");
1163       return (EINVAL);
1164     }
1165
1166   if (PREDICT_FALSE (n >= allowed_size))
1167     {
1168       /*
1169        * unlike strcat_s, strncat_s will do the concatenation anyway when
1170        * there is not enough space in dest. But it will do the truncation and
1171        * null terminate dest
1172        */
1173       m = clib_strnlen (src, allowed_size);
1174       if (m >= allowed_size)
1175         {
1176           m = allowed_size - 1;
1177           status = EOVERFLOW;
1178         }
1179     }
1180   else
1181     m = clib_strnlen (src, n);
1182
1183   clib_memcpy_fast (dest + dest_size, src, m);
1184   dest[dest_size + m] = '\0';
1185   return status;
1186 }
1187
1188 /*
1189  * This macro is to provide smooth mapping from strtok_r to strtok_s.
1190  * To map strtok to this macro, the caller would have to supply an additional
1191  * argument. strtokr_s requires s1max which the unsafe API does not have. So
1192  * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
1193  * this macro cannot catch unterminated s1 and s2.
1194  * Applications are encouraged to use the cool C11 strtok_s API to avoid
1195  * these problems.
1196  */
1197 #define clib_strtok(s1,s2,p)               \
1198   ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX;   \
1199     strtok_s_inline (s1, &__s1max, s2, p);              \
1200   })
1201
1202 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1203                 const char *__restrict__ s2, char **__restrict__ ptr);
1204
1205 always_inline char *
1206 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1207                  const char *__restrict__ s2, char **__restrict__ ptr)
1208 {
1209 #define STRTOK_DELIM_MAX_LEN 16
1210   u8 bad;
1211   const char *pt;
1212   char *ptoken;
1213   uword dlen, slen;
1214
1215   bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
1216     ((s1 == 0) && ptr && (*ptr == 0));
1217   if (PREDICT_FALSE (bad != 0))
1218     {
1219       if (s2 == NULL)
1220         clib_c11_violation ("s2 NULL");
1221       if (s1max == NULL)
1222         clib_c11_violation ("s1max is NULL");
1223       if (ptr == NULL)
1224         clib_c11_violation ("ptr is NULL");
1225       /* s1 == 0 and *ptr == null is no good */
1226       if ((s1 == 0) && ptr && (*ptr == 0))
1227         clib_c11_violation ("s1 and ptr contents are NULL");
1228       return 0;
1229     }
1230
1231   if (s1 == 0)
1232     s1 = *ptr;
1233
1234   /*
1235    * scan s1 for a delimiter
1236    */
1237   dlen = *s1max;
1238   ptoken = 0;
1239   while (*s1 != '\0' && !ptoken)
1240     {
1241       if (PREDICT_FALSE (dlen == 0))
1242         {
1243           *ptr = 0;
1244           clib_c11_violation ("s1 unterminated");
1245           return 0;
1246         }
1247
1248       /*
1249        * must scan the entire delimiter list
1250        * ISO should have included a delimiter string limit!!
1251        */
1252       slen = STRTOK_DELIM_MAX_LEN;
1253       pt = s2;
1254       while (*pt != '\0')
1255         {
1256           if (PREDICT_FALSE (slen == 0))
1257             {
1258               *ptr = 0;
1259               clib_c11_violation ("s2 unterminated");
1260               return 0;
1261             }
1262           slen--;
1263           if (*s1 == *pt)
1264             {
1265               ptoken = 0;
1266               break;
1267             }
1268           else
1269             {
1270               pt++;
1271               ptoken = s1;
1272             }
1273         }
1274       s1++;
1275       dlen--;
1276     }
1277
1278   /*
1279    * if the beginning of a token was not found, then no
1280    * need to continue the scan.
1281    */
1282   if (ptoken == 0)
1283     {
1284       *s1max = dlen;
1285       return (ptoken);
1286     }
1287
1288   /*
1289    * Now we need to locate the end of the token
1290    */
1291   while (*s1 != '\0')
1292     {
1293       if (dlen == 0)
1294         {
1295           *ptr = 0;
1296           clib_c11_violation ("s1 unterminated");
1297           return 0;
1298         }
1299
1300       slen = STRTOK_DELIM_MAX_LEN;
1301       pt = s2;
1302       while (*pt != '\0')
1303         {
1304           if (slen == 0)
1305             {
1306               *ptr = 0;
1307               clib_c11_violation ("s2 unterminated");
1308               return 0;
1309             }
1310           slen--;
1311           if (*s1 == *pt)
1312             {
1313               /*
1314                * found a delimiter, set to null
1315                * and return context ptr to next char
1316                */
1317               *s1 = '\0';
1318               *ptr = (s1 + 1);  /* return pointer for next scan */
1319               *s1max = dlen - 1;        /* account for the nulled delimiter */
1320               return (ptoken);
1321             }
1322           else
1323             {
1324               /*
1325                * simply scanning through the delimiter string
1326                */
1327               pt++;
1328             }
1329         }
1330       s1++;
1331       dlen--;
1332     }
1333
1334   *ptr = s1;
1335   *s1max = dlen;
1336   return (ptoken);
1337 }
1338
1339 /*
1340  * This macro is to provide smooth mapping from strstr to strstr_s.
1341  * strstr_s requires s1max and s2max which the unsafe API does not have. So
1342  * we have to improvise them with CLIB_STRING_MACRO_MAX which may cause us
1343  * to access memory beyond it is intended if s1 or s2 is unterminated.
1344  * For the record, strstr crashes if s1 or s2 is unterminated. But this macro
1345  * does not.
1346  * Applications are encouraged to use the cool C11 strstr_s API to avoid
1347  * this problem.
1348  */
1349 #define clib_strstr(s1,s2) \
1350   ({ char * __substring = 0; \
1351     strstr_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, CLIB_STRING_MACRO_MAX, \
1352                      &__substring);              \
1353     __substring;                                 \
1354   })
1355
1356 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1357                   char **substring);
1358
1359 always_inline errno_t
1360 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1361                  char **substring)
1362 {
1363   u8 bad;
1364   size_t s1_size, s2_size;
1365
1366   bad =
1367     (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1368     (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1369     (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1370   if (PREDICT_FALSE (bad != 0))
1371     {
1372       if (s1 == 0)
1373         clib_c11_violation ("s1 NULL");
1374       if (s2 == 0)
1375         clib_c11_violation ("s2 NULL");
1376       if (s1max == 0)
1377         clib_c11_violation ("s1max 0");
1378       if (s2max == 0)
1379         clib_c11_violation ("s2max 0");
1380       if (substring == 0)
1381         clib_c11_violation ("substring NULL");
1382       if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1383         clib_c11_violation ("s1 unterminated");
1384       if (s2 && s2max && (s2[clib_strnlen (s2, s1max)] != '\0'))
1385         clib_c11_violation ("s2 unterminated");
1386       return EINVAL;
1387     }
1388
1389   /*
1390    * s2 points to a string with zero length, or s2 equals s1, return s1
1391    */
1392   if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1393     {
1394       *substring = s1;
1395       return EOK;
1396     }
1397
1398   /*
1399    * s2_size > s1_size, it won't find match.
1400    */
1401   s1_size = clib_strnlen (s1, s1max);
1402   s2_size = clib_strnlen (s2, s2max);
1403   if (PREDICT_FALSE (s2_size > s1_size))
1404     return ESRCH;
1405
1406   *substring = strstr (s1, s2);
1407   if (*substring == 0)
1408     return ESRCH;
1409
1410   return EOK;
1411 }
1412
1413 #endif /* included_clib_string_h */
1414
1415 /*
1416  * fd.io coding-style-patch-verification: ON
1417  *
1418  * Local Variables:
1419  * eval: (c-set-style "gnu")
1420  * End:
1421  */