ipsec: support per next-header next-nodes
[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 #include <vppinfra/error_bootstrap.h>
50 #include <vppinfra/memcpy_x86_64.h>
51
52 #ifdef CLIB_LINUX_KERNEL
53 #include <linux/string.h>
54 #endif
55
56 #ifdef CLIB_UNIX
57 #include <string.h>
58 #endif
59
60 #ifdef CLIB_STANDALONE
61 #include <vppinfra/standalone_string.h>
62 #endif
63
64 #if _x86_64_
65 #include <x86intrin.h>
66 #endif
67
68 /* Exchanges source and destination. */
69 void clib_memswap (void *_a, void *_b, uword bytes);
70
71
72 static_always_inline void *
73 clib_memcpy_fast (void *restrict dst, const void *restrict src, size_t n)
74 {
75   ASSERT (dst && src &&
76           "memcpy(src, dst, n) with src == NULL or dst == NULL is undefined "
77           "behaviour");
78 #if defined(__COVERITY__)
79   return memcpy (dst, src, n);
80 #elif defined(__x86_64__)
81   clib_memcpy_x86_64 (dst, src, n);
82   return dst;
83 #else
84   return memcpy (dst, src, n);
85 #endif
86 }
87
88 static_always_inline void *
89 clib_memmove (void *dst, const void *src, size_t n)
90 {
91   u8 *d = (u8 *) dst;
92   u8 *s = (u8 *) src;
93
94   if (s == d)
95     return d;
96
97   if (d > s)
98     for (uword i = n - 1; (i + 1) > 0; i--)
99       d[i] = s[i];
100   else
101     for (uword i = 0; i < n; i++)
102       d[i] = s[i];
103
104   return d;
105 }
106
107 #include <vppinfra/memcpy.h>
108
109 /* c-11 string manipulation variants */
110
111 #ifndef EOK
112 #define EOK 0
113 #endif
114 #ifndef EINVAL
115 #define EINVAL 22
116 #endif
117 #ifndef ESRCH
118 #define ESRCH 3
119 #endif
120 #ifndef EOVERFLOW
121 #define EOVERFLOW 75
122 #endif
123
124 /*
125  * In order to provide smooth mapping from unsafe string API to the clib string
126  * macro, we often have to improvise s1max and s2max due to the additional
127  * arguments are required for implementing the safe API. This macro is used
128  * to provide the s1max/s2max. It is not perfect because the actual
129  * s1max/s2max may be greater than 4k and the mapping from the unsafe API to
130  * the macro would cause a regression. However, it is not terribly likely.
131  * So I bet against the odds.
132  */
133 #define CLIB_STRING_MACRO_MAX 4096
134
135 typedef int errno_t;
136 typedef uword rsize_t;
137
138 void clib_c11_violation (const char *s);
139 errno_t memcpy_s (void *__restrict__ dest, rsize_t dmax,
140                   const void *__restrict__ src, rsize_t n);
141
142 always_inline errno_t
143 memcpy_s_inline (void *__restrict__ dest, rsize_t dmax,
144                  const void *__restrict__ src, rsize_t n)
145 {
146   uword low, hi;
147   u8 bad;
148
149   /*
150    * Optimize constant-number-of-bytes calls without asking
151    * "too many questions for someone from New Jersey"
152    */
153   if (COMPILE_TIME_CONST (n))
154     {
155       clib_memcpy_fast (dest, src, n);
156       return EOK;
157     }
158
159   /*
160    * call bogus if: src or dst NULL, trying to copy
161    * more data than we have space in dst, or src == dst.
162    * n == 0 isn't really "bad", so check first in the
163    * "wall-of-shame" department...
164    */
165   bad = (dest == 0) + (src == 0) + (n > dmax) + (dest == src) + (n == 0);
166   if (PREDICT_FALSE (bad != 0))
167     {
168       /* Not actually trying to copy anything is OK */
169       if (n == 0)
170         return EOK;
171       if (dest == NULL)
172         clib_c11_violation ("dest NULL");
173       if (src == NULL)
174         clib_c11_violation ("src NULL");
175       if (n > dmax)
176         clib_c11_violation ("n > dmax");
177       if (dest == src)
178         clib_c11_violation ("dest == src");
179       return EINVAL;
180     }
181
182   /* Check for src/dst overlap, which is not allowed */
183   low = (uword) (src < dest ? src : dest);
184   hi = (uword) (src < dest ? dest : src);
185
186   if (PREDICT_FALSE (low + (n - 1) >= hi))
187     {
188       clib_c11_violation ("src/dest overlap");
189       return EINVAL;
190     }
191
192   clib_memcpy_fast (dest, src, n);
193   return EOK;
194 }
195
196 /*
197  * Note: $$$ This macro is a crutch. Folks need to manually
198  * inspect every extant clib_memcpy(...) call and
199  * attempt to provide a real destination buffer size
200  * argument...
201  */
202 #define clib_memcpy(d,s,n) memcpy_s_inline(d,n,s,n)
203
204 errno_t memset_s (void *s, rsize_t smax, int c, rsize_t n);
205
206 always_inline errno_t
207 memset_s_inline (void *s, rsize_t smax, int c, rsize_t n)
208 {
209   u8 bad;
210
211   bad = (s == 0) + (n > smax);
212
213   if (PREDICT_FALSE (bad != 0))
214     {
215       if (s == 0)
216         clib_c11_violation ("s NULL");
217       if (n > smax)
218         clib_c11_violation ("n > smax");
219       return (EINVAL);
220     }
221   memset (s, c, n);
222   return (EOK);
223 }
224
225 /*
226  * This macro is not [so much of] a crutch.
227  * It's super-typical to write:
228  *
229  *   ep = pool_get (<pool>);
230  *   clib_memset(ep, 0, sizeof (*ep));
231  *
232  * The compiler should delete the not-so useful
233  * (n > smax) test. TBH the NULL pointer check isn't
234  * so useful in this case, but so be it.
235  */
236 #define clib_memset(s,c,n) memset_s_inline(s,n,c,n)
237
238 static_always_inline void
239 clib_memcpy_le (u8 * dst, u8 * src, u8 len, u8 max_len)
240 {
241 #if defined (CLIB_HAVE_VEC256)
242   u8x32 s0, s1, d0, d1;
243   u8x32 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
244     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
245   };
246   u8x32 lv = u8x32_splat (len);
247   u8x32 add = u8x32_splat (32);
248
249   s0 = u8x32_load_unaligned (src);
250   s1 = u8x32_load_unaligned (src + 32);
251   d0 = u8x32_load_unaligned (dst);
252   d1 = u8x32_load_unaligned (dst + 32);
253
254   d0 = u8x32_blend (d0, s0, lv > mask);
255   u8x32_store_unaligned (d0, dst);
256
257   if (max_len <= 32)
258     return;
259
260   mask += add;
261   d1 = u8x32_blend (d1, s1, lv > mask);
262   u8x32_store_unaligned (d1, dst + 32);
263
264 #elif defined (CLIB_HAVE_VEC128)
265   u8x16 s0, s1, s2, s3, d0, d1, d2, d3;
266   u8x16 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
267   u8x16 lv = u8x16_splat (len);
268   u8x16 add = u8x16_splat (16);
269
270   s0 = u8x16_load_unaligned (src);
271   s1 = u8x16_load_unaligned (src + 16);
272   s2 = u8x16_load_unaligned (src + 32);
273   s3 = u8x16_load_unaligned (src + 48);
274   d0 = u8x16_load_unaligned (dst);
275   d1 = u8x16_load_unaligned (dst + 16);
276   d2 = u8x16_load_unaligned (dst + 32);
277   d3 = u8x16_load_unaligned (dst + 48);
278
279   d0 = u8x16_blend (d0, s0, lv > mask);
280   u8x16_store_unaligned (d0, dst);
281
282   if (max_len <= 16)
283     return;
284
285   mask += add;
286   d1 = u8x16_blend (d1, s1, lv > mask);
287   u8x16_store_unaligned (d1, dst + 16);
288
289   if (max_len <= 32)
290     return;
291
292   mask += add;
293   d2 = u8x16_blend (d2, s2, lv > mask);
294   u8x16_store_unaligned (d2, dst + 32);
295
296   mask += add;
297   d3 = u8x16_blend (d3, s3, lv > mask);
298   u8x16_store_unaligned (d3, dst + 48);
299 #else
300   memmove (dst, src, len);
301 #endif
302 }
303
304 static_always_inline void
305 clib_memcpy_le64 (u8 * dst, u8 * src, u8 len)
306 {
307   clib_memcpy_le (dst, src, len, 64);
308 }
309
310 static_always_inline void
311 clib_memcpy_le32 (u8 * dst, u8 * src, u8 len)
312 {
313   clib_memcpy_le (dst, src, len, 32);
314 }
315
316 static_always_inline void
317 clib_memset_u64 (void *p, u64 val, uword count)
318 {
319   u64 *ptr = p;
320 #if defined(CLIB_HAVE_VEC512)
321   u64x8 v512 = u64x8_splat (val);
322   while (count >= 8)
323     {
324       u64x8_store_unaligned (v512, ptr);
325       ptr += 8;
326       count -= 8;
327     }
328   if (count == 0)
329     return;
330 #endif
331 #if defined(CLIB_HAVE_VEC256)
332   u64x4 v256 = u64x4_splat (val);
333   while (count >= 4)
334     {
335       u64x4_store_unaligned (v256, ptr);
336       ptr += 4;
337       count -= 4;
338     }
339   if (count == 0)
340     return;
341 #else
342 #if defined(CLIB_HAVE_VEC128)
343   u64x2 v = u64x2_splat (val);
344 #endif
345   while (count >= 4)
346     {
347 #if defined(CLIB_HAVE_VEC128)
348       u64x2_store_unaligned (v, ptr);
349       u64x2_store_unaligned (v, ptr + 2);
350 #else
351       ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
352 #endif
353       ptr += 4;
354       count -= 4;
355     }
356 #endif
357   while (count--)
358     ptr++[0] = val;
359 }
360
361 static_always_inline void
362 clib_memset_u32 (void *p, u32 val, uword count)
363 {
364   u32 *ptr = p;
365 #if defined(CLIB_HAVE_VEC512)
366   u32x16 v512 = u32x16_splat (val);
367   while (count >= 16)
368     {
369       u32x16_store_unaligned (v512, ptr);
370       ptr += 16;
371       count -= 16;
372     }
373   if (count == 0)
374     return;
375 #endif
376 #if defined(CLIB_HAVE_VEC256)
377   u32x8 v256 = u32x8_splat (val);
378   while (count >= 8)
379     {
380       u32x8_store_unaligned (v256, ptr);
381       ptr += 8;
382       count -= 8;
383     }
384   if (count == 0)
385     return;
386 #endif
387 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
388   u32x4 v128 = u32x4_splat (val);
389   while (count >= 4)
390     {
391       u32x4_store_unaligned (v128, ptr);
392       ptr += 4;
393       count -= 4;
394     }
395 #else
396   while (count >= 4)
397     {
398       ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
399       ptr += 4;
400       count -= 4;
401     }
402 #endif
403   while (count--)
404     ptr++[0] = val;
405 }
406
407 static_always_inline void
408 clib_memset_u16 (void *p, u16 val, uword count)
409 {
410   u16 *ptr = p;
411 #if defined(CLIB_HAVE_VEC512)
412   u16x32 v512 = u16x32_splat (val);
413   while (count >= 32)
414     {
415       u16x32_store_unaligned (v512, ptr);
416       ptr += 32;
417       count -= 32;
418     }
419   if (count == 0)
420     return;
421 #endif
422 #if defined(CLIB_HAVE_VEC256)
423   u16x16 v256 = u16x16_splat (val);
424   while (count >= 16)
425     {
426       u16x16_store_unaligned (v256, ptr);
427       ptr += 16;
428       count -= 16;
429     }
430   if (count == 0)
431     return;
432 #endif
433 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
434   u16x8 v128 = u16x8_splat (val);
435   while (count >= 8)
436     {
437       u16x8_store_unaligned (v128, ptr);
438       ptr += 8;
439       count -= 8;
440     }
441 #else
442   while (count >= 4)
443     {
444       ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
445       ptr += 4;
446       count -= 4;
447     }
448 #endif
449   while (count--)
450     ptr++[0] = val;
451 }
452
453 static_always_inline void
454 clib_memset_u8 (void *p, u8 val, uword count)
455 {
456   u8 *ptr = p;
457 #if defined(CLIB_HAVE_VEC512)
458   u8x64 v512 = u8x64_splat (val);
459   while (count >= 64)
460     {
461       u8x64_store_unaligned (v512, ptr);
462       ptr += 64;
463       count -= 64;
464     }
465   if (count == 0)
466     return;
467 #endif
468 #if defined(CLIB_HAVE_VEC256)
469   u8x32 v256 = u8x32_splat (val);
470   while (count >= 32)
471     {
472       u8x32_store_unaligned (v256, ptr);
473       ptr += 32;
474       count -= 32;
475     }
476   if (count == 0)
477     return;
478 #endif
479 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
480   u8x16 v128 = u8x16_splat (val);
481   while (count >= 16)
482     {
483       u8x16_store_unaligned (v128, ptr);
484       ptr += 16;
485       count -= 16;
486     }
487 #else
488   while (count >= 4)
489     {
490       ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
491       ptr += 4;
492       count -= 4;
493     }
494 #endif
495   while (count--)
496     ptr++[0] = val;
497 }
498
499
500 /*
501  * This macro is to provide smooth mapping from memcmp to memcmp_s.
502  * memcmp has fewer parameters and fewer returns than memcmp_s.
503  * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
504  * we return 0 and spit out a message in the console because there is
505  * no way to return the error code to the memcmp callers.
506  * This condition happens when s1 or s2 is null. Please note
507  * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
508  * anyway. So we are consistent in this case for the comparison return
509  * although we also spit out a C11 violation message in the console to
510  * warn that they pass null pointers for both s1 and s2.
511  * Applications are encouraged to use the cool C11 memcmp_s API to get the
512  * maximum benefit out of it.
513  */
514 #define clib_memcmp(s1,s2,m1) \
515   ({ int __diff = 0;                                   \
516     memcmp_s_inline (s1, m1, s2, m1, &__diff);  \
517     __diff; \
518   })
519
520 errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
521                   rsize_t s2max, int *diff);
522
523 always_inline errno_t
524 memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
525                  int *diff)
526 {
527   u8 bad;
528
529   bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
530     (s1max == 0);
531
532   if (PREDICT_FALSE (bad != 0))
533     {
534       if (s1 == NULL)
535         clib_c11_violation ("s1 NULL");
536       if (s2 == NULL)
537         clib_c11_violation ("s2 NULL");
538       if (diff == NULL)
539         clib_c11_violation ("diff NULL");
540       if (s2max > s1max)
541         clib_c11_violation ("s2max > s1max");
542       if (s2max == 0)
543         clib_c11_violation ("s2max 0");
544       if (s1max == 0)
545         clib_c11_violation ("s1max 0");
546       return EINVAL;
547     }
548
549   if (PREDICT_FALSE (s1 == s2))
550     {
551       *diff = 0;
552       return EOK;
553     }
554
555   *diff = memcmp (s1, s2, s2max);
556   return EOK;
557 }
558
559 /*
560  * This macro is to provide smooth mapping from strnlen to strnlen_s
561  */
562 #define clib_strnlen(s,m) strnlen_s_inline(s,m)
563
564 size_t strnlen_s (const char *s, size_t maxsize);
565
566 always_inline size_t
567 strnlen_s_inline (const char *s, size_t maxsize)
568 {
569   u8 bad;
570
571   bad = (s == 0) + (maxsize == 0);
572   if (PREDICT_FALSE (bad != 0))
573     {
574       if (s == 0)
575         clib_c11_violation ("s NULL");
576       if (maxsize == 0)
577         clib_c11_violation ("maxsize 0");
578       return 0;
579     }
580   return strnlen (s, maxsize);
581 }
582
583 /*
584  * This macro is to provide smooth mapping from strcmp to strcmp_s.
585  * strcmp has fewer parameters and fewer returns than strcmp_s.
586  * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
587  * we return 0 and spit out a message in the console because
588  * there is no way to return the error to the strcmp callers.
589  * This condition happens when s1 or s2 is null. Please note in the extant
590  * strcmp call, they would end up crashing if one of them is null.
591  * So the new behavior is no crash, but an error is displayed in the
592  * console which I think is more user friendly. If both s1 and s2 are null,
593  * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
594  * to actually accessing the pointer contents. We are still consistent
595  * in this case for the comparison return although we also spit out a
596  * C11 violation message in the console to warn that they pass null pointers
597  * for both s1 and s2. The other problem is strcmp does not provide s1max,
598  * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
599  * If not, we may be accessing memory beyonf what is intended.
600  * Applications are encouraged to use the cool C11 strcmp_s API to get the
601  * maximum benefit out of it.
602  */
603 #define clib_strcmp(s1,s2) \
604   ({ int __indicator = 0; \
605     strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator);      \
606     __indicator;                        \
607   })
608
609 errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
610                   int *indicator);
611
612 always_inline errno_t
613 strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
614                  int *indicator)
615 {
616   u8 bad;
617
618   bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
619     (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
620
621   if (PREDICT_FALSE (bad != 0))
622     {
623       if (indicator == NULL)
624         clib_c11_violation ("indicator NULL");
625       if (s1 == NULL)
626         clib_c11_violation ("s1 NULL");
627       if (s2 == NULL)
628         clib_c11_violation ("s2 NULL");
629       if (s1max == 0)
630         clib_c11_violation ("s1max 0");
631       if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
632         clib_c11_violation ("s1 unterminated");
633       return EINVAL;
634     }
635
636   *indicator = strcmp (s1, s2);
637   return EOK;
638 }
639
640 /*
641  * This macro is to provide smooth mapping from strncmp to strncmp_s.
642  * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
643  * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
644  * we return 0 and spit out a message in the console because there is no
645  * means to return the error to the strncmp caller.
646  * This condition happens when s1 or s2 is null. In the extant strncmp call,
647  * they would end up crashing if one of them is null. So the new behavior is
648  * no crash, but error is displayed in the console which is more
649  * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
650  * strncmp did the pointers comparison prior to actually accessing the
651  * pointer contents. We are still consistent in this case for the comparison
652  * return although we also spit out a C11 violation message in the console to
653  * warn that they pass null pointers for both s1 and s2.
654  * Applications are encouraged to use the cool C11 strncmp_s API to get the
655  * maximum benefit out of it.
656  */
657 #define clib_strncmp(s1,s2,n) \
658   ({ int __indicator = 0; \
659     strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator);  \
660     __indicator;                        \
661   })
662
663 errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
664                    int *indicator);
665
666 always_inline errno_t
667 strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
668                   int *indicator)
669 {
670   u8 bad;
671   u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
672
673   if (PREDICT_FALSE (s1_greater_s1max && indicator))
674     {
675       /*
676        * strcmp allows n > s1max. If indicator is non null, we can still
677        * do the compare without any harm and return EINVAL as well as the
678        * result in indicator.
679        */
680       clib_c11_violation ("n exceeds s1 length");
681       *indicator = strncmp (s1, s2, n);
682       return EINVAL;
683     }
684
685   bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
686     (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
687
688   if (PREDICT_FALSE (bad != 0))
689     {
690       if (indicator == NULL)
691         clib_c11_violation ("indicator NULL");
692       if (s1 == NULL)
693         clib_c11_violation ("s1 NULL");
694       if (s2 == NULL)
695         clib_c11_violation ("s2 NULL");
696       if (s1max == 0)
697         clib_c11_violation ("s1max 0");
698       if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
699         clib_c11_violation ("s1 unterminated");
700       if (s1_greater_s1max)
701         clib_c11_violation ("n exceeds s1 length");
702       return EINVAL;
703     }
704
705   *indicator = strncmp (s1, s2, n);
706   return EOK;
707 }
708
709 errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
710                   const char *__restrict__ src);
711
712 always_inline errno_t
713 strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
714                  const char *__restrict__ src)
715 {
716   u8 bad;
717   uword low, hi;
718   size_t n;
719
720   bad = (dest == 0) + (dmax == 0) + (src == 0);
721   if (PREDICT_FALSE (bad != 0))
722     {
723       if (dest == 0)
724         clib_c11_violation ("dest NULL");
725       if (src == 0)
726         clib_c11_violation ("src NULL");
727       if (dmax == 0)
728         clib_c11_violation ("dmax 0");
729       return EINVAL;
730     }
731
732   n = clib_strnlen (src, dmax);
733   if (PREDICT_FALSE (n >= dmax))
734     {
735       clib_c11_violation ("not enough space for dest");
736       return (EINVAL);
737     }
738   /* Not actually trying to copy anything is OK */
739   if (PREDICT_FALSE (n == 0))
740     return EOK;
741
742   /* Check for src/dst overlap, which is not allowed */
743   low = (uword) (src < dest ? src : dest);
744   hi = (uword) (src < dest ? dest : src);
745
746   if (PREDICT_FALSE (low + (n - 1) >= hi))
747     {
748       clib_c11_violation ("src/dest overlap");
749       return EINVAL;
750     }
751
752   clib_memcpy_fast (dest, src, n);
753   dest[n] = '\0';
754   return EOK;
755 }
756
757 /*
758  * This macro is provided for smooth migration from strncpy. It is not perfect
759  * because we don't know the size of the destination buffer to pass to
760  * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
761  * Applications are encouraged to move to the C11 strncpy_s API and provide
762  * the correct dmax for better error checking.
763  */
764 #define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
765
766 errno_t
767 strncpy_s (char *__restrict__ dest, rsize_t dmax,
768            const char *__restrict__ src, rsize_t n);
769
770 always_inline errno_t
771 strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
772                   const char *__restrict__ src, rsize_t n)
773 {
774   u8 bad;
775   uword low, hi;
776   rsize_t m;
777   errno_t status = EOK;
778
779   bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
780   if (PREDICT_FALSE (bad != 0))
781     {
782       /* Not actually trying to copy anything is OK */
783       if (n == 0)
784         return EOK;
785       if (dest == 0)
786         clib_c11_violation ("dest NULL");
787       if (src == 0)
788         clib_c11_violation ("src NULL");
789       if (dmax == 0)
790         clib_c11_violation ("dmax 0");
791       return EINVAL;
792     }
793
794   if (PREDICT_FALSE (n >= dmax))
795     {
796       /* Relax and use strnlen of src */
797       clib_c11_violation ("n >= dmax");
798       m = clib_strnlen (src, dmax);
799       if (m >= dmax)
800         {
801           /* Truncate, adjust copy length to fit dest */
802           m = dmax - 1;
803           status = EOVERFLOW;
804         }
805     }
806   else
807     /* cap the copy to strlen(src) in case n > strlen(src) */
808     m = clib_strnlen (src, n);
809
810   /* Check for src/dst overlap, which is not allowed */
811   low = (uword) (src < dest ? src : dest);
812   hi = (uword) (src < dest ? dest : src);
813
814   /*
815    * This check may fail innocently if src + dmax >= dst, but
816    * src + strlen(src) < dst. If it fails, check more carefully before
817    * blowing the whistle.
818    */
819   if (PREDICT_FALSE (low + (m - 1) >= hi))
820     {
821       m = clib_strnlen (src, m);
822
823       if (low + (m - 1) >= hi)
824         {
825           clib_c11_violation ("src/dest overlap");
826           return EINVAL;
827         }
828     }
829
830   clib_memcpy_fast (dest, src, m);
831   dest[m] = '\0';
832   return status;
833 }
834
835 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
836                   const char *__restrict__ src);
837
838 always_inline errno_t
839 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
840                  const char *__restrict__ src)
841 {
842   u8 bad;
843   uword low, hi;
844   size_t m, n, dest_size;
845
846   bad = (dest == 0) + (dmax == 0) + (src == 0);
847   if (PREDICT_FALSE (bad != 0))
848     {
849       if (dest == 0)
850         clib_c11_violation ("dest NULL");
851       if (src == 0)
852         clib_c11_violation ("src NULL");
853       if (dmax == 0)
854         clib_c11_violation ("dmax 0");
855       return EINVAL;
856     }
857
858   dest_size = clib_strnlen (dest, dmax);
859   m = dmax - dest_size;
860   n = clib_strnlen (src, m);
861   if (PREDICT_FALSE (n >= m))
862     {
863       clib_c11_violation ("not enough space for dest");
864       return EINVAL;
865     }
866
867   /* Not actually trying to concatenate anything is OK */
868   if (PREDICT_FALSE (n == 0))
869     return EOK;
870
871   /* Check for src/dst overlap, which is not allowed */
872   low = (uword) (src < dest ? src : dest);
873   hi = (uword) (src < dest ? dest : src);
874
875   if (PREDICT_FALSE (low + (n - 1) >= hi))
876     {
877       clib_c11_violation ("src/dest overlap");
878       return EINVAL;
879     }
880
881   clib_memcpy_fast (dest + dest_size, src, n);
882   dest[dest_size + n] = '\0';
883   return EOK;
884 }
885
886 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
887                    const char *__restrict__ src, rsize_t n);
888
889 always_inline errno_t
890 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
891                   const char *__restrict__ src, rsize_t n)
892 {
893   u8 bad;
894   uword low, hi;
895   size_t m, dest_size, allowed_size;
896   errno_t status = EOK;
897
898   bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
899   if (PREDICT_FALSE (bad != 0))
900     {
901       /* Not actually trying to concatenate anything is OK */
902       if (n == 0)
903         return EOK;
904       if (dest == 0)
905         clib_c11_violation ("dest NULL");
906       if (src == 0)
907         clib_c11_violation ("src NULL");
908       if (dmax == 0)
909         clib_c11_violation ("dmax 0");
910       return EINVAL;
911     }
912
913   /* Check for src/dst overlap, which is not allowed */
914   low = (uword) (src < dest ? src : dest);
915   hi = (uword) (src < dest ? dest : src);
916
917   if (PREDICT_FALSE (low + (n - 1) >= hi))
918     {
919       clib_c11_violation ("src/dest overlap");
920       return EINVAL;
921     }
922
923   dest_size = clib_strnlen (dest, dmax);
924   allowed_size = dmax - dest_size;
925
926   if (PREDICT_FALSE (allowed_size == 0))
927     {
928       clib_c11_violation ("no space left in dest");
929       return (EINVAL);
930     }
931
932   if (PREDICT_FALSE (n >= allowed_size))
933     {
934       /*
935        * unlike strcat_s, strncat_s will do the concatenation anyway when
936        * there is not enough space in dest. But it will do the truncation and
937        * null terminate dest
938        */
939       m = clib_strnlen (src, allowed_size);
940       if (m >= allowed_size)
941         {
942           m = allowed_size - 1;
943           status = EOVERFLOW;
944         }
945     }
946   else
947     m = clib_strnlen (src, n);
948
949   clib_memcpy_fast (dest + dest_size, src, m);
950   dest[dest_size + m] = '\0';
951   return status;
952 }
953
954 /*
955  * This macro is to provide smooth mapping from strtok_r to strtok_s.
956  * To map strtok to this macro, the caller would have to supply an additional
957  * argument. strtokr_s requires s1max which the unsafe API does not have. So
958  * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
959  * this macro cannot catch unterminated s1 and s2.
960  * Applications are encouraged to use the cool C11 strtok_s API to avoid
961  * these problems.
962  */
963 #define clib_strtok(s1,s2,p)               \
964   ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX;   \
965     strtok_s_inline (s1, &__s1max, s2, p);              \
966   })
967
968 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
969                 const char *__restrict__ s2, char **__restrict__ ptr);
970
971 always_inline char *
972 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
973                  const char *__restrict__ s2, char **__restrict__ ptr)
974 {
975 #define STRTOK_DELIM_MAX_LEN 16
976   u8 bad;
977   const char *pt;
978   char *ptoken;
979   uword dlen, slen;
980
981   bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
982     ((s1 == 0) && ptr && (*ptr == 0));
983   if (PREDICT_FALSE (bad != 0))
984     {
985       if (s2 == NULL)
986         clib_c11_violation ("s2 NULL");
987       if (s1max == NULL)
988         clib_c11_violation ("s1max is NULL");
989       if (ptr == NULL)
990         clib_c11_violation ("ptr is NULL");
991       /* s1 == 0 and *ptr == null is no good */
992       if ((s1 == 0) && ptr && (*ptr == 0))
993         clib_c11_violation ("s1 and ptr contents are NULL");
994       return 0;
995     }
996
997   if (s1 == 0)
998     s1 = *ptr;
999
1000   /*
1001    * scan s1 for a delimiter
1002    */
1003   dlen = *s1max;
1004   ptoken = 0;
1005   while (*s1 != '\0' && !ptoken)
1006     {
1007       if (PREDICT_FALSE (dlen == 0))
1008         {
1009           *ptr = 0;
1010           clib_c11_violation ("s1 unterminated");
1011           return 0;
1012         }
1013
1014       /*
1015        * must scan the entire delimiter list
1016        * ISO should have included a delimiter string limit!!
1017        */
1018       slen = STRTOK_DELIM_MAX_LEN;
1019       pt = s2;
1020       while (*pt != '\0')
1021         {
1022           if (PREDICT_FALSE (slen == 0))
1023             {
1024               *ptr = 0;
1025               clib_c11_violation ("s2 unterminated");
1026               return 0;
1027             }
1028           slen--;
1029           if (*s1 == *pt)
1030             {
1031               ptoken = 0;
1032               break;
1033             }
1034           else
1035             {
1036               pt++;
1037               ptoken = s1;
1038             }
1039         }
1040       s1++;
1041       dlen--;
1042     }
1043
1044   /*
1045    * if the beginning of a token was not found, then no
1046    * need to continue the scan.
1047    */
1048   if (ptoken == 0)
1049     {
1050       *s1max = dlen;
1051       return (ptoken);
1052     }
1053
1054   /*
1055    * Now we need to locate the end of the token
1056    */
1057   while (*s1 != '\0')
1058     {
1059       if (dlen == 0)
1060         {
1061           *ptr = 0;
1062           clib_c11_violation ("s1 unterminated");
1063           return 0;
1064         }
1065
1066       slen = STRTOK_DELIM_MAX_LEN;
1067       pt = s2;
1068       while (*pt != '\0')
1069         {
1070           if (slen == 0)
1071             {
1072               *ptr = 0;
1073               clib_c11_violation ("s2 unterminated");
1074               return 0;
1075             }
1076           slen--;
1077           if (*s1 == *pt)
1078             {
1079               /*
1080                * found a delimiter, set to null
1081                * and return context ptr to next char
1082                */
1083               *s1 = '\0';
1084               *ptr = (s1 + 1);  /* return pointer for next scan */
1085               *s1max = dlen - 1;        /* account for the nulled delimiter */
1086               return (ptoken);
1087             }
1088           else
1089             {
1090               /*
1091                * simply scanning through the delimiter string
1092                */
1093               pt++;
1094             }
1095         }
1096       s1++;
1097       dlen--;
1098     }
1099
1100   *ptr = s1;
1101   *s1max = dlen;
1102   return (ptoken);
1103 }
1104
1105 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1106                   char **substring);
1107
1108 always_inline errno_t
1109 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1110                  char **substring)
1111 {
1112   u8 bad;
1113   size_t s1_size, s2_size;
1114
1115   bad =
1116     (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1117     (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1118     (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1119   if (PREDICT_FALSE (bad != 0))
1120     {
1121       if (s1 == 0)
1122         clib_c11_violation ("s1 NULL");
1123       if (s2 == 0)
1124         clib_c11_violation ("s2 NULL");
1125       if (s1max == 0)
1126         clib_c11_violation ("s1max 0");
1127       if (s2max == 0)
1128         clib_c11_violation ("s2max 0");
1129       if (substring == 0)
1130         clib_c11_violation ("substring NULL");
1131       if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1132         clib_c11_violation ("s1 unterminated");
1133       if (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'))
1134         clib_c11_violation ("s2 unterminated");
1135       return EINVAL;
1136     }
1137
1138   /*
1139    * s2 points to a string with zero length, or s2 equals s1, return s1
1140    */
1141   if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1142     {
1143       *substring = s1;
1144       return EOK;
1145     }
1146
1147   /*
1148    * s2_size > s1_size, it won't find match.
1149    */
1150   s1_size = clib_strnlen (s1, s1max);
1151   s2_size = clib_strnlen (s2, s2max);
1152   if (PREDICT_FALSE (s2_size > s1_size))
1153     return ESRCH;
1154
1155   *substring = strstr (s1, s2);
1156   if (*substring == 0)
1157     return ESRCH;
1158
1159   return EOK;
1160 }
1161
1162 #endif /* included_clib_string_h */
1163
1164 /*
1165  * fd.io coding-style-patch-verification: ON
1166  *
1167  * Local Variables:
1168  * eval: (c-set-style "gnu")
1169  * End:
1170  */