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