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