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