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