blob: d5686704c224d988e15655ea8a082ccd33722ee3 [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 Marionfad3fb32017-12-14 09:30:11 +010074#if __AVX512F__
75#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
106 * to provide the s1max/s2max. It is not perfect becuase the actual
107 * 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 Marion04f3db32017-11-10 21:55:45 +0100216/*
217 * Copy 64 bytes of data to 4 destinations
218 * this function is typically used in quad-loop case when whole cacheline
219 * needs to be copied to 4 different places. First it reads whole cacheline
220 * to 1/2/4 SIMD registers and then it writes data to 4 destinations.
221 */
222
223static_always_inline void
224clib_memcpy64_x4 (void *d0, void *d1, void *d2, void *d3, void *s)
225{
Damjan Marionb2e1fe92017-11-22 12:41:32 +0100226#if defined (__AVX512F__)
227 __m512i r0 = _mm512_loadu_si512 (s);
Damjan Marion04f3db32017-11-10 21:55:45 +0100228
Damjan Marionb2e1fe92017-11-22 12:41:32 +0100229 _mm512_storeu_si512 (d0, r0);
230 _mm512_storeu_si512 (d1, r0);
231 _mm512_storeu_si512 (d2, r0);
232 _mm512_storeu_si512 (d3, r0);
Damjan Marion04f3db32017-11-10 21:55:45 +0100233
Damjan Marionb2e1fe92017-11-22 12:41:32 +0100234#elif defined (__AVX2__)
Sergio Gonzalez Monroy20ec7162017-12-08 11:25:13 +0000235 __m256i r0 = _mm256_loadu_si256 ((__m256i *) (s + 0 * 32));
236 __m256i r1 = _mm256_loadu_si256 ((__m256i *) (s + 1 * 32));
Damjan Marion04f3db32017-11-10 21:55:45 +0100237
Sergio Gonzalez Monroy20ec7162017-12-08 11:25:13 +0000238 _mm256_storeu_si256 ((__m256i *) (d0 + 0 * 32), r0);
239 _mm256_storeu_si256 ((__m256i *) (d0 + 1 * 32), r1);
Damjan Marion04f3db32017-11-10 21:55:45 +0100240
Sergio Gonzalez Monroy20ec7162017-12-08 11:25:13 +0000241 _mm256_storeu_si256 ((__m256i *) (d1 + 0 * 32), r0);
242 _mm256_storeu_si256 ((__m256i *) (d1 + 1 * 32), r1);
Damjan Marion04f3db32017-11-10 21:55:45 +0100243
Sergio Gonzalez Monroy20ec7162017-12-08 11:25:13 +0000244 _mm256_storeu_si256 ((__m256i *) (d2 + 0 * 32), r0);
245 _mm256_storeu_si256 ((__m256i *) (d2 + 1 * 32), r1);
Damjan Marion04f3db32017-11-10 21:55:45 +0100246
Sergio Gonzalez Monroy20ec7162017-12-08 11:25:13 +0000247 _mm256_storeu_si256 ((__m256i *) (d3 + 0 * 32), r0);
248 _mm256_storeu_si256 ((__m256i *) (d3 + 1 * 32), r1);
Damjan Marion04f3db32017-11-10 21:55:45 +0100249
Damjan Marionb2e1fe92017-11-22 12:41:32 +0100250#elif defined (__SSSE3__)
Sergio Gonzalez Monroy20ec7162017-12-08 11:25:13 +0000251 __m128i r0 = _mm_loadu_si128 ((__m128i *) (s + 0 * 16));
252 __m128i r1 = _mm_loadu_si128 ((__m128i *) (s + 1 * 16));
253 __m128i r2 = _mm_loadu_si128 ((__m128i *) (s + 2 * 16));
254 __m128i r3 = _mm_loadu_si128 ((__m128i *) (s + 3 * 16));
Damjan Marion04f3db32017-11-10 21:55:45 +0100255
Sergio Gonzalez Monroy20ec7162017-12-08 11:25:13 +0000256 _mm_storeu_si128 ((__m128i *) (d0 + 0 * 16), r0);
257 _mm_storeu_si128 ((__m128i *) (d0 + 1 * 16), r1);
258 _mm_storeu_si128 ((__m128i *) (d0 + 2 * 16), r2);
259 _mm_storeu_si128 ((__m128i *) (d0 + 3 * 16), r3);
Damjan Marion04f3db32017-11-10 21:55:45 +0100260
Sergio Gonzalez Monroy20ec7162017-12-08 11:25:13 +0000261 _mm_storeu_si128 ((__m128i *) (d1 + 0 * 16), r0);
262 _mm_storeu_si128 ((__m128i *) (d1 + 1 * 16), r1);
263 _mm_storeu_si128 ((__m128i *) (d1 + 2 * 16), r2);
264 _mm_storeu_si128 ((__m128i *) (d1 + 3 * 16), r3);
Damjan Marionb2e1fe92017-11-22 12:41:32 +0100265
Sergio Gonzalez Monroy20ec7162017-12-08 11:25:13 +0000266 _mm_storeu_si128 ((__m128i *) (d2 + 0 * 16), r0);
267 _mm_storeu_si128 ((__m128i *) (d2 + 1 * 16), r1);
268 _mm_storeu_si128 ((__m128i *) (d2 + 2 * 16), r2);
269 _mm_storeu_si128 ((__m128i *) (d2 + 3 * 16), r3);
Damjan Marionb2e1fe92017-11-22 12:41:32 +0100270
Sergio Gonzalez Monroy20ec7162017-12-08 11:25:13 +0000271 _mm_storeu_si128 ((__m128i *) (d3 + 0 * 16), r0);
272 _mm_storeu_si128 ((__m128i *) (d3 + 1 * 16), r1);
273 _mm_storeu_si128 ((__m128i *) (d3 + 2 * 16), r2);
274 _mm_storeu_si128 ((__m128i *) (d3 + 3 * 16), r3);
Damjan Marionb2e1fe92017-11-22 12:41:32 +0100275
Damjan Marion04f3db32017-11-10 21:55:45 +0100276#else
Dave Barach178cf492018-11-13 16:34:13 -0500277 clib_memcpy_fast (d0, s, 64);
278 clib_memcpy_fast (d1, s, 64);
279 clib_memcpy_fast (d2, s, 64);
280 clib_memcpy_fast (d3, s, 64);
Damjan Marion04f3db32017-11-10 21:55:45 +0100281#endif
282}
283
Damjan Marion14864772018-05-22 14:07:47 +0200284static_always_inline void
285clib_memset_u64 (void *p, u64 val, uword count)
286{
287 u64 *ptr = p;
288#if defined(CLIB_HAVE_VEC512)
289 u64x8 v512 = u64x8_splat (val);
290 while (count >= 8)
291 {
292 u64x8_store_unaligned (v512, ptr);
293 ptr += 8;
294 count -= 8;
295 }
296 if (count == 0)
297 return;
298#endif
299#if defined(CLIB_HAVE_VEC256)
300 u64x4 v256 = u64x4_splat (val);
301 while (count >= 4)
302 {
303 u64x4_store_unaligned (v256, ptr);
304 ptr += 4;
305 count -= 4;
306 }
307 if (count == 0)
308 return;
309#else
310 while (count >= 4)
311 {
312 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
313 ptr += 4;
314 count -= 4;
315 }
316#endif
317 while (count--)
318 ptr++[0] = val;
319}
320
321static_always_inline void
322clib_memset_u32 (void *p, u32 val, uword count)
323{
324 u32 *ptr = p;
325#if defined(CLIB_HAVE_VEC512)
326 u32x16 v512 = u32x16_splat (val);
327 while (count >= 16)
328 {
329 u32x16_store_unaligned (v512, ptr);
330 ptr += 16;
331 count -= 16;
332 }
333 if (count == 0)
334 return;
335#endif
336#if defined(CLIB_HAVE_VEC256)
337 u32x8 v256 = u32x8_splat (val);
338 while (count >= 8)
339 {
340 u32x8_store_unaligned (v256, ptr);
341 ptr += 8;
342 count -= 8;
343 }
344 if (count == 0)
345 return;
346#endif
347#if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
348 u32x4 v128 = u32x4_splat (val);
349 while (count >= 4)
350 {
351 u32x4_store_unaligned (v128, ptr);
352 ptr += 4;
353 count -= 4;
354 }
355#else
356 while (count >= 4)
357 {
358 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
359 ptr += 4;
360 count -= 4;
361 }
362#endif
363 while (count--)
364 ptr++[0] = val;
365}
366
367static_always_inline void
368clib_memset_u16 (void *p, u16 val, uword count)
369{
370 u16 *ptr = p;
371#if defined(CLIB_HAVE_VEC512)
372 u16x32 v512 = u16x32_splat (val);
373 while (count >= 32)
374 {
375 u16x32_store_unaligned (v512, ptr);
376 ptr += 32;
377 count -= 32;
378 }
379 if (count == 0)
380 return;
381#endif
382#if defined(CLIB_HAVE_VEC256)
383 u16x16 v256 = u16x16_splat (val);
384 while (count >= 16)
385 {
386 u16x16_store_unaligned (v256, ptr);
387 ptr += 16;
388 count -= 16;
389 }
390 if (count == 0)
391 return;
392#endif
393#if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
394 u16x8 v128 = u16x8_splat (val);
395 while (count >= 8)
396 {
397 u16x8_store_unaligned (v128, ptr);
398 ptr += 8;
399 count -= 8;
400 }
401#else
402 while (count >= 4)
403 {
404 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
405 ptr += 4;
406 count -= 4;
407 }
408#endif
409 while (count--)
410 ptr++[0] = val;
411}
412
413static_always_inline void
414clib_memset_u8 (void *p, u8 val, uword count)
415{
416 u8 *ptr = p;
417#if defined(CLIB_HAVE_VEC512)
418 u8x64 v512 = u8x64_splat (val);
419 while (count >= 64)
420 {
421 u8x64_store_unaligned (v512, ptr);
422 ptr += 64;
423 count -= 64;
424 }
425 if (count == 0)
426 return;
427#endif
428#if defined(CLIB_HAVE_VEC256)
429 u8x32 v256 = u8x32_splat (val);
430 while (count >= 32)
431 {
432 u8x32_store_unaligned (v256, ptr);
433 ptr += 32;
434 count -= 32;
435 }
436 if (count == 0)
437 return;
438#endif
439#if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
440 u8x16 v128 = u8x16_splat (val);
441 while (count >= 16)
442 {
443 u8x16_store_unaligned (v128, ptr);
444 ptr += 16;
445 count -= 16;
446 }
447#else
448 while (count >= 4)
449 {
450 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
451 ptr += 4;
452 count -= 4;
453 }
454#endif
455 while (count--)
456 ptr++[0] = val;
457}
458
459static_always_inline uword
460clib_count_equal_u64 (u64 * data, uword max_count)
461{
Neale Ranns2329e092018-10-03 14:13:27 -0400462 uword count;
463 u64 first;
Damjan Marion14864772018-05-22 14:07:47 +0200464
Neale Ranns2329e092018-10-03 14:13:27 -0400465 if (max_count == 1)
466 return 1;
Damjan Marion008eef32018-09-12 22:37:30 +0200467 if (data[0] != data[1])
468 return 1;
469
Neale Ranns2329e092018-10-03 14:13:27 -0400470 count = 0;
471 first = data[0];
472
Damjan Marion008eef32018-09-12 22:37:30 +0200473#if defined(CLIB_HAVE_VEC256)
474 u64x4 splat = u64x4_splat (first);
475 while (1)
Damjan Marion14864772018-05-22 14:07:47 +0200476 {
Damjan Marion008eef32018-09-12 22:37:30 +0200477 u64 bmp;
478 bmp = u8x32_msb_mask ((u8x32) (u64x4_load_unaligned (data) == splat));
479 if (bmp != 0xffffffff)
480 {
481 count += count_trailing_zeros (~bmp) / 8;
482 return clib_min (count, max_count);
483 }
484
485 data += 4;
486 count += 4;
487
Damjan Marion14864772018-05-22 14:07:47 +0200488 if (count >= max_count)
489 return max_count;
490 }
491#endif
Damjan Marion008eef32018-09-12 22:37:30 +0200492 count += 2;
493 data += 2;
Neale Ranns825fc482018-10-10 13:27:00 +0000494 while (count + 3 < max_count &&
Damjan Marion008eef32018-09-12 22:37:30 +0200495 ((data[0] ^ first) | (data[1] ^ first) |
496 (data[2] ^ first) | (data[3] ^ first)) == 0)
Damjan Marion14864772018-05-22 14:07:47 +0200497 {
498 data += 4;
499 count += 4;
Damjan Marion14864772018-05-22 14:07:47 +0200500 }
Damjan Marion14864772018-05-22 14:07:47 +0200501 while (count < max_count && (data[0] == first))
502 {
503 data += 1;
504 count += 1;
505 }
506 return count;
507}
508
509static_always_inline uword
510clib_count_equal_u32 (u32 * data, uword max_count)
511{
Neale Ranns2329e092018-10-03 14:13:27 -0400512 uword count;
513 u32 first;
Damjan Marion14864772018-05-22 14:07:47 +0200514
Neale Ranns2329e092018-10-03 14:13:27 -0400515 if (max_count == 1)
516 return 1;
Damjan Marion008eef32018-09-12 22:37:30 +0200517 if (data[0] != data[1])
518 return 1;
519
Neale Ranns2329e092018-10-03 14:13:27 -0400520 count = 0;
521 first = data[0];
522
Damjan Marion14864772018-05-22 14:07:47 +0200523#if defined(CLIB_HAVE_VEC256)
Damjan Marion008eef32018-09-12 22:37:30 +0200524 u32x8 splat = u32x8_splat (first);
525 while (1)
Damjan Marion14864772018-05-22 14:07:47 +0200526 {
Damjan Marion008eef32018-09-12 22:37:30 +0200527 u64 bmp;
528 bmp = u8x32_msb_mask ((u8x32) (u32x8_load_unaligned (data) == splat));
529 if (bmp != 0xffffffff)
530 {
531 count += count_trailing_zeros (~bmp) / 4;
532 return clib_min (count, max_count);
533 }
534
Damjan Marion14864772018-05-22 14:07:47 +0200535 data += 8;
536 count += 8;
Damjan Marion008eef32018-09-12 22:37:30 +0200537
538 if (count >= max_count)
539 return max_count;
540 }
541#elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
542 u32x4 splat = u32x4_splat (first);
543 while (1)
544 {
545 u64 bmp;
546 bmp = u8x16_msb_mask ((u8x16) (u32x4_load_unaligned (data) == splat));
547 if (bmp != 0xffff)
548 {
549 count += count_trailing_zeros (~bmp) / 4;
550 return clib_min (count, max_count);
551 }
552
553 data += 4;
554 count += 4;
555
Damjan Marion14864772018-05-22 14:07:47 +0200556 if (count >= max_count)
557 return max_count;
558 }
559#endif
Damjan Marion008eef32018-09-12 22:37:30 +0200560 count += 2;
561 data += 2;
Neale Ranns825fc482018-10-10 13:27:00 +0000562 while (count + 3 < max_count &&
Damjan Marion008eef32018-09-12 22:37:30 +0200563 ((data[0] ^ first) | (data[1] ^ first) |
564 (data[2] ^ first) | (data[3] ^ first)) == 0)
Damjan Marion14864772018-05-22 14:07:47 +0200565 {
566 data += 4;
567 count += 4;
Damjan Marion14864772018-05-22 14:07:47 +0200568 }
Damjan Marion14864772018-05-22 14:07:47 +0200569 while (count < max_count && (data[0] == first))
570 {
571 data += 1;
572 count += 1;
573 }
574 return count;
575}
576
577static_always_inline uword
578clib_count_equal_u16 (u16 * data, uword max_count)
579{
Neale Ranns2329e092018-10-03 14:13:27 -0400580 uword count;
581 u16 first;
Damjan Marion14864772018-05-22 14:07:47 +0200582
Neale Ranns2329e092018-10-03 14:13:27 -0400583 if (max_count == 1)
584 return 1;
Damjan Marion008eef32018-09-12 22:37:30 +0200585 if (data[0] != data[1])
586 return 1;
587
Neale Ranns2329e092018-10-03 14:13:27 -0400588 count = 0;
589 first = data[0];
590
Damjan Marion14864772018-05-22 14:07:47 +0200591#if defined(CLIB_HAVE_VEC256)
Damjan Marion008eef32018-09-12 22:37:30 +0200592 u16x16 splat = u16x16_splat (first);
593 while (1)
Damjan Marion14864772018-05-22 14:07:47 +0200594 {
Damjan Marion008eef32018-09-12 22:37:30 +0200595 u64 bmp;
596 bmp = u8x32_msb_mask ((u8x32) (u16x16_load_unaligned (data) == splat));
597 if (bmp != 0xffffffff)
598 {
599 count += count_trailing_zeros (~bmp) / 2;
600 return clib_min (count, max_count);
601 }
602
Damjan Marion14864772018-05-22 14:07:47 +0200603 data += 16;
604 count += 16;
Damjan Marion008eef32018-09-12 22:37:30 +0200605
606 if (count >= max_count)
607 return max_count;
Damjan Marion14864772018-05-22 14:07:47 +0200608 }
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);
611 while (1)
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;
618 return clib_min (count, max_count);
619 }
620
Damjan Marion14864772018-05-22 14:07:47 +0200621 data += 8;
622 count += 8;
Damjan Marion008eef32018-09-12 22:37:30 +0200623
624 if (count >= max_count)
625 return max_count;
Damjan Marion14864772018-05-22 14:07:47 +0200626 }
627#endif
Damjan Marion008eef32018-09-12 22:37:30 +0200628 count += 2;
629 data += 2;
Neale Ranns825fc482018-10-10 13:27:00 +0000630 while (count + 3 < max_count &&
Damjan Marion008eef32018-09-12 22:37:30 +0200631 ((data[0] ^ first) | (data[1] ^ first) |
632 (data[2] ^ first) | (data[3] ^ first)) == 0)
633 {
634 data += 4;
635 count += 4;
636 }
Damjan Marion14864772018-05-22 14:07:47 +0200637 while (count < max_count && (data[0] == first))
638 {
639 data += 1;
640 count += 1;
641 }
642 return count;
643}
644
Damjan Marion008eef32018-09-12 22:37:30 +0200645static_always_inline uword
646clib_count_equal_u8 (u8 * data, uword max_count)
Damjan Marion14864772018-05-22 14:07:47 +0200647{
Neale Ranns2329e092018-10-03 14:13:27 -0400648 uword count;
649 u8 first;
Damjan Marion14864772018-05-22 14:07:47 +0200650
Neale Ranns2329e092018-10-03 14:13:27 -0400651 if (max_count == 1)
652 return 1;
Damjan Marion008eef32018-09-12 22:37:30 +0200653 if (data[0] != data[1])
654 return 1;
655
Neale Ranns2329e092018-10-03 14:13:27 -0400656 count = 0;
657 first = data[0];
658
Damjan Marion14864772018-05-22 14:07:47 +0200659#if defined(CLIB_HAVE_VEC256)
Damjan Marion008eef32018-09-12 22:37:30 +0200660 u8x32 splat = u8x32_splat (first);
661 while (1)
Damjan Marion14864772018-05-22 14:07:47 +0200662 {
Damjan Marion008eef32018-09-12 22:37:30 +0200663 u64 bmp;
664 bmp = u8x32_msb_mask ((u8x32) (u8x32_load_unaligned (data) == splat));
665 if (bmp != 0xffffffff)
666 {
667 count += count_trailing_zeros (~bmp);
668 return clib_min (count, max_count);
669 }
670
Damjan Marion14864772018-05-22 14:07:47 +0200671 data += 32;
672 count += 32;
Damjan Marion008eef32018-09-12 22:37:30 +0200673
674 if (count >= max_count)
675 return max_count;
676 }
677#elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
678 u8x16 splat = u8x16_splat (first);
679 while (1)
680 {
681 u64 bmp;
682 bmp = u8x16_msb_mask ((u8x16) (u8x16_load_unaligned (data) == splat));
683 if (bmp != 0xffff)
684 {
685 count += count_trailing_zeros (~bmp);
686 return clib_min (count, max_count);
687 }
688
689 data += 16;
690 count += 16;
691
692 if (count >= max_count)
693 return max_count;
Damjan Marion14864772018-05-22 14:07:47 +0200694 }
695#endif
Damjan Marion008eef32018-09-12 22:37:30 +0200696 count += 2;
697 data += 2;
Neale Ranns825fc482018-10-10 13:27:00 +0000698 while (count + 3 < max_count &&
Damjan Marion008eef32018-09-12 22:37:30 +0200699 ((data[0] ^ first) | (data[1] ^ first) |
700 (data[2] ^ first) | (data[3] ^ first)) == 0)
Damjan Marion14864772018-05-22 14:07:47 +0200701 {
702 data += 4;
703 count += 4;
704 }
Damjan Marion14864772018-05-22 14:07:47 +0200705 while (count < max_count && (data[0] == first))
706 {
707 data += 1;
708 count += 1;
709 }
710 return count;
711}
712
Stevenb0598492018-10-24 21:15:45 -0700713/*
714 * This macro is to provide smooth mapping from memcmp to memcmp_s.
715 * memcmp has fewer parameters and fewer returns than memcmp_s.
716 * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
717 * we return 0 and spit out a message in the console because there is
718 * no way to return the error code to the memcmp callers.
719 * This condition happens when s1 or s2 is null. Please note
720 * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
721 * anyway. So we are consistent in this case for the comparison return
722 * although we also spit out a C11 violation message in the console to
723 * warn that they pass null pointers for both s1 and s2.
724 * Applications are encouraged to use the cool C11 memcmp_s API to get the
725 * maximum benefit out of it.
726 */
727#define clib_memcmp(s1,s2,m1) \
728 ({ int __diff = 0; \
729 memcmp_s_inline (s1, m1, s2, m1, &__diff); \
730 __diff; \
731 })
732
733errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
734 rsize_t s2max, int *diff);
735
736always_inline errno_t
737memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
738 int *diff)
739{
740 u8 bad;
741
742 bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
743 (s1max == 0);
744
745 if (PREDICT_FALSE (bad != 0))
746 {
747 if (s1 == NULL)
748 clib_c11_violation ("s1 NULL");
749 if (s2 == NULL)
750 clib_c11_violation ("s2 NULL");
751 if (diff == NULL)
752 clib_c11_violation ("diff NULL");
753 if (s2max > s1max)
754 clib_c11_violation ("s2max > s1max");
755 if (s2max == 0)
756 clib_c11_violation ("s2max 0");
757 if (s1max == 0)
758 clib_c11_violation ("s1max 0");
759 return EINVAL;
760 }
761
762 if (PREDICT_FALSE (s1 == s2))
763 {
764 *diff = 0;
765 return EOK;
766 }
767
768 *diff = memcmp (s1, s2, s2max);
769 return EOK;
770}
771
772/*
773 * This macro is to provide smooth mapping from strnlen to strnlen_s
774 */
775#define clib_strnlen(s,m) strnlen_s_inline(s,m)
776
777size_t strnlen_s (const char *s, size_t maxsize);
778
779always_inline size_t
780strnlen_s_inline (const char *s, size_t maxsize)
781{
782 u8 bad;
783
784 bad = (s == 0) + (maxsize == 0);
785 if (PREDICT_FALSE (bad != 0))
786 {
787 if (s == 0)
788 clib_c11_violation ("s NULL");
789 if (maxsize == 0)
790 clib_c11_violation ("maxsize 0");
791 return 0;
792 }
793 return strnlen (s, maxsize);
794}
795
796/*
797 * This macro is to provide smooth mapping from strcmp to strcmp_s.
798 * strcmp has fewer parameters and fewer returns than strcmp_s.
799 * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
800 * we return 0 and spit out a message in the console because
801 * there is no way to return the error to the strcmp callers.
802 * This condition happens when s1 or s2 is null. Please note in the extant
803 * strcmp call, they would end up crashing if one of them is null.
804 * So the new behavior is no crash, but an error is displayed in the
805 * console which I think is more user friendly. If both s1 and s2 are null,
806 * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
807 * to actually accessing the pointer contents. We are still consistent
808 * in this case for the comparison return although we also spit out a
809 * C11 violation message in the console to warn that they pass null pointers
810 * for both s1 and s2. The other problem is strcmp does not provide s1max,
811 * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
812 * If not, we may be accessing memory beyonf what is intended.
813 * Applications are encouraged to use the cool C11 strcmp_s API to get the
814 * maximum benefit out of it.
815 */
816#define clib_strcmp(s1,s2) \
817 ({ int __indicator = 0; \
818 strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator); \
819 __indicator; \
820 })
821
822errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
823 int *indicator);
824
825always_inline errno_t
826strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
827 int *indicator)
828{
829 u8 bad;
830
831 bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
832 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
833
834 if (PREDICT_FALSE (bad != 0))
835 {
836 if (indicator == NULL)
837 clib_c11_violation ("indicator NULL");
838 if (s1 == NULL)
839 clib_c11_violation ("s1 NULL");
840 if (s2 == NULL)
841 clib_c11_violation ("s2 NULL");
842 if (s1max == 0)
843 clib_c11_violation ("s1max 0");
844 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
845 clib_c11_violation ("s1 unterminated");
846 return EINVAL;
847 }
848
849 *indicator = strcmp (s1, s2);
850 return EOK;
851}
852
853/*
854 * This macro is to provide smooth mapping from strncmp to strncmp_s.
855 * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
856 * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
857 * we return 0 and spit out a message in the console because there is no
858 * means to return the error to the strncmp caller.
859 * This condition happens when s1 or s2 is null. In the extant strncmp call,
860 * they would end up crashing if one of them is null. So the new behavior is
861 * no crash, but error is displayed in the console which is more
862 * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
863 * strncmp did the pointers comparison prior to actually accessing the
864 * pointer contents. We are still consistent in this case for the comparison
865 * return although we also spit out a C11 violation message in the console to
866 * warn that they pass null pointers for both s1 and s2.
867 * Applications are encouraged to use the cool C11 strncmp_s API to get the
868 * maximum benefit out of it.
869 */
870#define clib_strncmp(s1,s2,n) \
871 ({ int __indicator = 0; \
872 strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator); \
873 __indicator; \
874 })
875
876errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
877 int *indicator);
878
879always_inline errno_t
880strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
881 int *indicator)
882{
883 u8 bad;
884 u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
885
886 if (PREDICT_FALSE (s1_greater_s1max && indicator))
887 {
888 /*
889 * strcmp allows n > s1max. If indicator is non null, we can still
890 * do the compare without any harm and return EINVAL as well as the
891 * result in indicator.
892 */
893 clib_c11_violation ("n exceeds s1 length");
894 *indicator = strncmp (s1, s2, n);
895 return EINVAL;
896 }
897
898 bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
899 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
900
901 if (PREDICT_FALSE (bad != 0))
902 {
903 if (indicator == NULL)
904 clib_c11_violation ("indicator NULL");
905 if (s1 == NULL)
906 clib_c11_violation ("s1 NULL");
907 if (s2 == NULL)
908 clib_c11_violation ("s2 NULL");
909 if (s1max == 0)
910 clib_c11_violation ("s1max 0");
911 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
912 clib_c11_violation ("s1 unterminated");
913 if (s1_greater_s1max)
914 clib_c11_violation ("n exceeds s1 length");
915 return EINVAL;
916 }
917
918 *indicator = strncmp (s1, s2, n);
919 return EOK;
920}
921
922/*
923 * This macro is provided for smooth migration from strcpy. It is not perfect
924 * because we don't know the size of the destination buffer to pass to strcpy_s.
925 * We improvise dmax with CLIB_STRING_MACRO_MAX.
926 * Applications are encouraged to move to the C11 strcpy_s API.
927 */
928#define clib_strcpy(d,s) strcpy_s_inline(d,CLIB_STRING_MACRO_MAX,s)
929
930errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
931 const char *__restrict__ src);
932
933always_inline errno_t
934strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
935 const char *__restrict__ src)
936{
937 u8 bad;
938 uword low, hi;
939 size_t n;
940
941 bad = (dest == 0) + (dmax == 0) + (src == 0);
942 if (PREDICT_FALSE (bad != 0))
943 {
944 if (dest == 0)
945 clib_c11_violation ("dest NULL");
946 if (src == 0)
947 clib_c11_violation ("src NULL");
948 if (dmax == 0)
949 clib_c11_violation ("dmax 0");
950 return EINVAL;
951 }
952
953 n = clib_strnlen (src, dmax);
954 if (PREDICT_FALSE (n >= dmax))
955 {
956 clib_c11_violation ("not enough space for dest");
957 return (EINVAL);
958 }
959 /* Not actually trying to copy anything is OK */
960 if (PREDICT_FALSE (n == 0))
961 return EOK;
962
963 /* Check for src/dst overlap, which is not allowed */
964 low = (uword) (src < dest ? src : dest);
965 hi = (uword) (src < dest ? dest : src);
966
967 if (PREDICT_FALSE (low + (n - 1) >= hi))
968 {
969 clib_c11_violation ("src/dest overlap");
970 return EINVAL;
971 }
972
973 clib_memcpy_fast (dest, src, n);
974 dest[n] = '\0';
975 return EOK;
976}
977
978/*
979 * This macro is provided for smooth migration from strncpy. It is not perfect
980 * because we don't know the size of the destination buffer to pass to
981 * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
982 * Applications are encouraged to move to the C11 strncpy_s API and provide
983 * the correct dmax for better error checking.
984 */
985#define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
986
987errno_t
988strncpy_s (char *__restrict__ dest, rsize_t dmax,
989 const char *__restrict__ src, rsize_t n);
990
991always_inline errno_t
992strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
993 const char *__restrict__ src, rsize_t n)
994{
995 u8 bad;
996 uword low, hi;
997 rsize_t m;
998 errno_t status = EOK;
999
1000 bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
1001 if (PREDICT_FALSE (bad != 0))
1002 {
1003 /* Not actually trying to copy anything is OK */
1004 if (n == 0)
1005 return EOK;
1006 if (dest == 0)
1007 clib_c11_violation ("dest NULL");
1008 if (src == 0)
1009 clib_c11_violation ("src NULL");
1010 if (dmax == 0)
1011 clib_c11_violation ("dmax 0");
1012 return EINVAL;
1013 }
1014
1015 if (PREDICT_FALSE (n >= dmax))
1016 {
1017 /* Relax and use strnlen of src */
1018 clib_c11_violation ("n >= dmax");
1019 m = clib_strnlen (src, dmax);
1020 if (m >= dmax)
1021 {
1022 /* Truncate, adjust copy length to fit dest */
1023 m = dmax - 1;
1024 status = EOVERFLOW;
1025 }
1026 }
1027 else
1028 m = n;
1029
1030 /* Check for src/dst overlap, which is not allowed */
1031 low = (uword) (src < dest ? src : dest);
1032 hi = (uword) (src < dest ? dest : src);
1033
Dave Barachd08ae852018-12-05 08:41:11 -05001034 /*
1035 * This check may fail innocently if src + dmax >= dst, but
1036 * src + strlen(src) < dst. If it fails, check more carefully before
1037 * blowing the whistle.
1038 */
Stevenb0598492018-10-24 21:15:45 -07001039 if (PREDICT_FALSE (low + (m - 1) >= hi))
1040 {
Dave Barachd08ae852018-12-05 08:41:11 -05001041 m = clib_strnlen (src, m);
1042
1043 if (low + (m - 1) >= hi)
1044 {
1045 clib_c11_violation ("src/dest overlap");
1046 return EINVAL;
1047 }
Stevenb0598492018-10-24 21:15:45 -07001048 }
1049
1050 clib_memcpy_fast (dest, src, m);
1051 dest[m] = '\0';
1052 return status;
1053}
1054
1055/*
1056 * This macro is to provide smooth migration from strcat to strcat_s.
1057 * Because there is no dmax in strcat, we improvise it with
1058 * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite dest
1059 * with too many bytes from src.
1060 * Applications are encouraged to use C11 API to provide the actual dmax
1061 * for proper checking and protection.
1062 */
1063#define clib_strcat(d,s) strcat_s_inline(d,CLIB_STRING_MACRO_MAX,s)
1064
1065errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
1066 const char *__restrict__ src);
1067
1068always_inline errno_t
1069strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
1070 const char *__restrict__ src)
1071{
1072 u8 bad;
1073 uword low, hi;
1074 size_t m, n, dest_size;
1075
1076 bad = (dest == 0) + (dmax == 0) + (src == 0);
1077 if (PREDICT_FALSE (bad != 0))
1078 {
1079 if (dest == 0)
1080 clib_c11_violation ("dest NULL");
1081 if (src == 0)
1082 clib_c11_violation ("src NULL");
1083 if (dmax == 0)
1084 clib_c11_violation ("dmax 0");
1085 return EINVAL;
1086 }
1087
1088 dest_size = clib_strnlen (dest, dmax);
1089 m = dmax - dest_size;
1090 n = clib_strnlen (src, m);
1091 if (PREDICT_FALSE (n >= m))
1092 {
1093 clib_c11_violation ("not enough space for dest");
1094 return EINVAL;
1095 }
1096
1097 /* Not actually trying to concatenate anything is OK */
1098 if (PREDICT_FALSE (n == 0))
1099 return EOK;
1100
1101 /* Check for src/dst overlap, which is not allowed */
1102 low = (uword) (src < dest ? src : dest);
1103 hi = (uword) (src < dest ? dest : src);
1104
1105 if (PREDICT_FALSE (low + (n - 1) >= hi))
1106 {
1107 clib_c11_violation ("src/dest overlap");
1108 return EINVAL;
1109 }
1110
1111 clib_memcpy_fast (dest + dest_size, src, n);
1112 dest[dest_size + n] = '\0';
1113 return EOK;
1114}
1115
1116/*
1117 * This macro is to provide smooth migration from strncat to strncat_s.
1118 * The unsafe strncat does not have s1max. We improvise it with
1119 * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite
1120 * dest with too many bytes from src.
1121 * Applications are encouraged to move to C11 strncat_s which requires dmax
1122 * from the caller and provides checking to safeguard the memory corruption.
1123 */
1124#define clib_strncat(d,s,n) strncat_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
1125
1126errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
1127 const char *__restrict__ src, rsize_t n);
1128
1129always_inline errno_t
1130strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
1131 const char *__restrict__ src, rsize_t n)
1132{
1133 u8 bad;
1134 uword low, hi;
1135 size_t m, dest_size, allowed_size;
1136 errno_t status = EOK;
1137
1138 bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
1139 if (PREDICT_FALSE (bad != 0))
1140 {
1141 /* Not actually trying to concatenate anything is OK */
1142 if (n == 0)
1143 return EOK;
1144 if (dest == 0)
1145 clib_c11_violation ("dest NULL");
1146 if (src == 0)
1147 clib_c11_violation ("src NULL");
1148 if (dmax == 0)
1149 clib_c11_violation ("dmax 0");
1150 return EINVAL;
1151 }
1152
1153 /* Check for src/dst overlap, which is not allowed */
1154 low = (uword) (src < dest ? src : dest);
1155 hi = (uword) (src < dest ? dest : src);
1156
1157 if (PREDICT_FALSE (low + (n - 1) >= hi))
1158 {
1159 clib_c11_violation ("src/dest overlap");
1160 return EINVAL;
1161 }
1162
1163 dest_size = clib_strnlen (dest, dmax);
1164 allowed_size = dmax - dest_size;
1165
1166 if (PREDICT_FALSE (allowed_size == 0))
1167 {
1168 clib_c11_violation ("no space left in dest");
1169 return (EINVAL);
1170 }
1171
1172 if (PREDICT_FALSE (n >= allowed_size))
1173 {
1174 /*
1175 * unlike strcat_s, strncat_s will do the concatenation anyway when
1176 * there is not enough space in dest. But it will do the truncation and
1177 * null terminate dest
1178 */
1179 m = clib_strnlen (src, allowed_size);
1180 if (m >= allowed_size)
1181 {
1182 m = allowed_size - 1;
1183 status = EOVERFLOW;
1184 }
1185 }
1186 else
1187 m = clib_strnlen (src, n);
1188
1189 clib_memcpy_fast (dest + dest_size, src, m);
1190 dest[dest_size + m] = '\0';
1191 return status;
1192}
1193
1194/*
1195 * This macro is to provide smooth mapping from strtok_r to strtok_s.
1196 * To map strtok to this macro, the caller would have to supply an additional
1197 * argument. strtokr_s requires s1max which the unsafe API does not have. So
1198 * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
1199 * this macro cannot catch unterminated s1 and s2.
1200 * Applications are encouraged to use the cool C11 strtok_s API to avoid
1201 * these problems.
1202 */
1203#define clib_strtok(s1,s2,p) \
1204 ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX; \
1205 strtok_s_inline (s1, &__s1max, s2, p); \
1206 })
1207
1208char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1209 const char *__restrict__ s2, char **__restrict__ ptr);
1210
1211always_inline char *
1212strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1213 const char *__restrict__ s2, char **__restrict__ ptr)
1214{
1215#define STRTOK_DELIM_MAX_LEN 16
1216 u8 bad;
1217 const char *pt;
1218 char *ptoken;
1219 uword dlen, slen;
1220
1221 bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
1222 ((s1 == 0) && ptr && (*ptr == 0));
1223 if (PREDICT_FALSE (bad != 0))
1224 {
1225 if (s2 == NULL)
1226 clib_c11_violation ("s2 NULL");
1227 if (s1max == NULL)
1228 clib_c11_violation ("s1max is NULL");
1229 if (ptr == NULL)
1230 clib_c11_violation ("ptr is NULL");
1231 /* s1 == 0 and *ptr == null is no good */
1232 if ((s1 == 0) && ptr && (*ptr == 0))
1233 clib_c11_violation ("s1 and ptr contents are NULL");
1234 return 0;
1235 }
1236
1237 if (s1 == 0)
1238 s1 = *ptr;
1239
1240 /*
1241 * scan s1 for a delimiter
1242 */
1243 dlen = *s1max;
1244 ptoken = 0;
1245 while (*s1 != '\0' && !ptoken)
1246 {
1247 if (PREDICT_FALSE (dlen == 0))
1248 {
1249 *ptr = 0;
1250 clib_c11_violation ("s1 unterminated");
1251 return 0;
1252 }
1253
1254 /*
1255 * must scan the entire delimiter list
1256 * ISO should have included a delimiter string limit!!
1257 */
1258 slen = STRTOK_DELIM_MAX_LEN;
1259 pt = s2;
1260 while (*pt != '\0')
1261 {
1262 if (PREDICT_FALSE (slen == 0))
1263 {
1264 *ptr = 0;
1265 clib_c11_violation ("s2 unterminated");
1266 return 0;
1267 }
1268 slen--;
1269 if (*s1 == *pt)
1270 {
1271 ptoken = 0;
1272 break;
1273 }
1274 else
1275 {
1276 pt++;
1277 ptoken = s1;
1278 }
1279 }
1280 s1++;
1281 dlen--;
1282 }
1283
1284 /*
1285 * if the beginning of a token was not found, then no
1286 * need to continue the scan.
1287 */
1288 if (ptoken == 0)
1289 {
1290 *s1max = dlen;
1291 return (ptoken);
1292 }
1293
1294 /*
1295 * Now we need to locate the end of the token
1296 */
1297 while (*s1 != '\0')
1298 {
1299 if (dlen == 0)
1300 {
1301 *ptr = 0;
1302 clib_c11_violation ("s1 unterminated");
1303 return 0;
1304 }
1305
1306 slen = STRTOK_DELIM_MAX_LEN;
1307 pt = s2;
1308 while (*pt != '\0')
1309 {
1310 if (slen == 0)
1311 {
1312 *ptr = 0;
1313 clib_c11_violation ("s2 unterminated");
1314 return 0;
1315 }
1316 slen--;
1317 if (*s1 == *pt)
1318 {
1319 /*
1320 * found a delimiter, set to null
1321 * and return context ptr to next char
1322 */
1323 *s1 = '\0';
1324 *ptr = (s1 + 1); /* return pointer for next scan */
1325 *s1max = dlen - 1; /* account for the nulled delimiter */
1326 return (ptoken);
1327 }
1328 else
1329 {
1330 /*
1331 * simply scanning through the delimiter string
1332 */
1333 pt++;
1334 }
1335 }
1336 s1++;
1337 dlen--;
1338 }
1339
1340 *ptr = s1;
1341 *s1max = dlen;
1342 return (ptoken);
1343}
1344
1345/*
1346 * This macro is to provide smooth mapping from strstr to strstr_s.
1347 * strstr_s requires s1max and s2max which the unsafe API does not have. So
1348 * we have to improvise them with CLIB_STRING_MACRO_MAX which may cause us
1349 * to access memory beyond it is intended if s1 or s2 is unterminated.
1350 * For the record, strstr crashes if s1 or s2 is unterminated. But this macro
1351 * does not.
1352 * Applications are encouraged to use the cool C11 strstr_s API to avoid
1353 * this problem.
1354 */
1355#define clib_strstr(s1,s2) \
1356 ({ char * __substring = 0; \
1357 strstr_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, CLIB_STRING_MACRO_MAX, \
1358 &__substring); \
1359 __substring; \
1360 })
1361
1362errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1363 char **substring);
1364
1365always_inline errno_t
1366strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1367 char **substring)
1368{
1369 u8 bad;
1370 size_t s1_size, s2_size;
1371
1372 bad =
1373 (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1374 (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1375 (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1376 if (PREDICT_FALSE (bad != 0))
1377 {
1378 if (s1 == 0)
1379 clib_c11_violation ("s1 NULL");
1380 if (s2 == 0)
1381 clib_c11_violation ("s2 NULL");
1382 if (s1max == 0)
1383 clib_c11_violation ("s1max 0");
1384 if (s2max == 0)
1385 clib_c11_violation ("s2max 0");
1386 if (substring == 0)
1387 clib_c11_violation ("substring NULL");
1388 if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1389 clib_c11_violation ("s1 unterminated");
1390 if (s2 && s2max && (s2[clib_strnlen (s2, s1max)] != '\0'))
1391 clib_c11_violation ("s2 unterminated");
1392 return EINVAL;
1393 }
1394
1395 /*
1396 * s2 points to a string with zero length, or s2 equals s1, return s1
1397 */
1398 if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1399 {
1400 *substring = s1;
1401 return EOK;
1402 }
1403
1404 /*
1405 * s2_size > s1_size, it won't find match.
1406 */
1407 s1_size = clib_strnlen (s1, s1max);
1408 s2_size = clib_strnlen (s2, s2max);
1409 if (PREDICT_FALSE (s2_size > s1_size))
1410 return ESRCH;
1411
1412 *substring = strstr (s1, s2);
1413 if (*substring == 0)
1414 return ESRCH;
1415
1416 return EOK;
1417}
1418
Ed Warnickecb9cada2015-12-08 15:45:58 -07001419#endif /* included_clib_string_h */
Dave Barachc3799992016-08-15 11:12:27 -04001420
1421/*
1422 * fd.io coding-style-patch-verification: ON
1423 *
1424 * Local Variables:
1425 * eval: (c-set-style "gnu")
1426 * End:
1427 */