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