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