blob: d9cd8fe1af9d071016d92a5f5d72a361d3bc8868 [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
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
217clib_memset_u64 (void *p, u64 val, uword count)
218{
219 u64 *ptr = p;
220#if defined(CLIB_HAVE_VEC512)
221 u64x8 v512 = u64x8_splat (val);
222 while (count >= 8)
223 {
224 u64x8_store_unaligned (v512, ptr);
225 ptr += 8;
226 count -= 8;
227 }
228 if (count == 0)
229 return;
230#endif
231#if defined(CLIB_HAVE_VEC256)
232 u64x4 v256 = u64x4_splat (val);
233 while (count >= 4)
234 {
235 u64x4_store_unaligned (v256, ptr);
236 ptr += 4;
237 count -= 4;
238 }
239 if (count == 0)
240 return;
241#else
242 while (count >= 4)
243 {
244 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
245 ptr += 4;
246 count -= 4;
247 }
248#endif
249 while (count--)
250 ptr++[0] = val;
251}
252
253static_always_inline void
254clib_memset_u32 (void *p, u32 val, uword count)
255{
256 u32 *ptr = p;
257#if defined(CLIB_HAVE_VEC512)
258 u32x16 v512 = u32x16_splat (val);
259 while (count >= 16)
260 {
261 u32x16_store_unaligned (v512, ptr);
262 ptr += 16;
263 count -= 16;
264 }
265 if (count == 0)
266 return;
267#endif
268#if defined(CLIB_HAVE_VEC256)
269 u32x8 v256 = u32x8_splat (val);
270 while (count >= 8)
271 {
272 u32x8_store_unaligned (v256, ptr);
273 ptr += 8;
274 count -= 8;
275 }
276 if (count == 0)
277 return;
278#endif
279#if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
280 u32x4 v128 = u32x4_splat (val);
281 while (count >= 4)
282 {
283 u32x4_store_unaligned (v128, ptr);
284 ptr += 4;
285 count -= 4;
286 }
287#else
288 while (count >= 4)
289 {
290 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
291 ptr += 4;
292 count -= 4;
293 }
294#endif
295 while (count--)
296 ptr++[0] = val;
297}
298
299static_always_inline void
300clib_memset_u16 (void *p, u16 val, uword count)
301{
302 u16 *ptr = p;
303#if defined(CLIB_HAVE_VEC512)
304 u16x32 v512 = u16x32_splat (val);
305 while (count >= 32)
306 {
307 u16x32_store_unaligned (v512, ptr);
308 ptr += 32;
309 count -= 32;
310 }
311 if (count == 0)
312 return;
313#endif
314#if defined(CLIB_HAVE_VEC256)
315 u16x16 v256 = u16x16_splat (val);
316 while (count >= 16)
317 {
318 u16x16_store_unaligned (v256, ptr);
319 ptr += 16;
320 count -= 16;
321 }
322 if (count == 0)
323 return;
324#endif
325#if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
326 u16x8 v128 = u16x8_splat (val);
327 while (count >= 8)
328 {
329 u16x8_store_unaligned (v128, ptr);
330 ptr += 8;
331 count -= 8;
332 }
333#else
334 while (count >= 4)
335 {
336 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
337 ptr += 4;
338 count -= 4;
339 }
340#endif
341 while (count--)
342 ptr++[0] = val;
343}
344
345static_always_inline void
346clib_memset_u8 (void *p, u8 val, uword count)
347{
348 u8 *ptr = p;
349#if defined(CLIB_HAVE_VEC512)
350 u8x64 v512 = u8x64_splat (val);
351 while (count >= 64)
352 {
353 u8x64_store_unaligned (v512, ptr);
354 ptr += 64;
355 count -= 64;
356 }
357 if (count == 0)
358 return;
359#endif
360#if defined(CLIB_HAVE_VEC256)
361 u8x32 v256 = u8x32_splat (val);
362 while (count >= 32)
363 {
364 u8x32_store_unaligned (v256, ptr);
365 ptr += 32;
366 count -= 32;
367 }
368 if (count == 0)
369 return;
370#endif
371#if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
372 u8x16 v128 = u8x16_splat (val);
373 while (count >= 16)
374 {
375 u8x16_store_unaligned (v128, ptr);
376 ptr += 16;
377 count -= 16;
378 }
379#else
380 while (count >= 4)
381 {
382 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
383 ptr += 4;
384 count -= 4;
385 }
386#endif
387 while (count--)
388 ptr++[0] = val;
389}
390
391static_always_inline uword
392clib_count_equal_u64 (u64 * data, uword max_count)
393{
Neale Ranns2329e092018-10-03 14:13:27 -0400394 uword count;
395 u64 first;
Damjan Marion14864772018-05-22 14:07:47 +0200396
Neale Ranns2329e092018-10-03 14:13:27 -0400397 if (max_count == 1)
398 return 1;
Damjan Marion008eef32018-09-12 22:37:30 +0200399 if (data[0] != data[1])
400 return 1;
401
Neale Ranns2329e092018-10-03 14:13:27 -0400402 count = 0;
403 first = data[0];
404
Damjan Marion008eef32018-09-12 22:37:30 +0200405#if defined(CLIB_HAVE_VEC256)
406 u64x4 splat = u64x4_splat (first);
407 while (1)
Damjan Marion14864772018-05-22 14:07:47 +0200408 {
Damjan Marion008eef32018-09-12 22:37:30 +0200409 u64 bmp;
410 bmp = u8x32_msb_mask ((u8x32) (u64x4_load_unaligned (data) == splat));
411 if (bmp != 0xffffffff)
412 {
413 count += count_trailing_zeros (~bmp) / 8;
414 return clib_min (count, max_count);
415 }
416
417 data += 4;
418 count += 4;
419
Damjan Marion14864772018-05-22 14:07:47 +0200420 if (count >= max_count)
421 return max_count;
422 }
423#endif
Damjan Marion008eef32018-09-12 22:37:30 +0200424 count += 2;
425 data += 2;
Neale Ranns825fc482018-10-10 13:27:00 +0000426 while (count + 3 < max_count &&
Damjan Marion008eef32018-09-12 22:37:30 +0200427 ((data[0] ^ first) | (data[1] ^ first) |
428 (data[2] ^ first) | (data[3] ^ first)) == 0)
Damjan Marion14864772018-05-22 14:07:47 +0200429 {
430 data += 4;
431 count += 4;
Damjan Marion14864772018-05-22 14:07:47 +0200432 }
Damjan Marion14864772018-05-22 14:07:47 +0200433 while (count < max_count && (data[0] == first))
434 {
435 data += 1;
436 count += 1;
437 }
438 return count;
439}
440
441static_always_inline uword
442clib_count_equal_u32 (u32 * data, uword max_count)
443{
Neale Ranns2329e092018-10-03 14:13:27 -0400444 uword count;
445 u32 first;
Damjan Marion14864772018-05-22 14:07:47 +0200446
Neale Ranns2329e092018-10-03 14:13:27 -0400447 if (max_count == 1)
448 return 1;
Damjan Marion008eef32018-09-12 22:37:30 +0200449 if (data[0] != data[1])
450 return 1;
451
Neale Ranns2329e092018-10-03 14:13:27 -0400452 count = 0;
453 first = data[0];
454
Damjan Marion14864772018-05-22 14:07:47 +0200455#if defined(CLIB_HAVE_VEC256)
Damjan Marion008eef32018-09-12 22:37:30 +0200456 u32x8 splat = u32x8_splat (first);
457 while (1)
Damjan Marion14864772018-05-22 14:07:47 +0200458 {
Damjan Marion008eef32018-09-12 22:37:30 +0200459 u64 bmp;
460 bmp = u8x32_msb_mask ((u8x32) (u32x8_load_unaligned (data) == splat));
461 if (bmp != 0xffffffff)
462 {
463 count += count_trailing_zeros (~bmp) / 4;
464 return clib_min (count, max_count);
465 }
466
Damjan Marion14864772018-05-22 14:07:47 +0200467 data += 8;
468 count += 8;
Damjan Marion008eef32018-09-12 22:37:30 +0200469
470 if (count >= max_count)
471 return max_count;
472 }
473#elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
474 u32x4 splat = u32x4_splat (first);
475 while (1)
476 {
477 u64 bmp;
478 bmp = u8x16_msb_mask ((u8x16) (u32x4_load_unaligned (data) == splat));
479 if (bmp != 0xffff)
480 {
481 count += count_trailing_zeros (~bmp) / 4;
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_u16 (u16 * data, uword max_count)
511{
Neale Ranns2329e092018-10-03 14:13:27 -0400512 uword count;
513 u16 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 u16x16 splat = u16x16_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) (u16x16_load_unaligned (data) == splat));
529 if (bmp != 0xffffffff)
530 {
531 count += count_trailing_zeros (~bmp) / 2;
532 return clib_min (count, max_count);
533 }
534
Damjan Marion14864772018-05-22 14:07:47 +0200535 data += 16;
536 count += 16;
Damjan Marion008eef32018-09-12 22:37:30 +0200537
538 if (count >= max_count)
539 return max_count;
Damjan Marion14864772018-05-22 14:07:47 +0200540 }
Damjan Marion008eef32018-09-12 22:37:30 +0200541#elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
542 u16x8 splat = u16x8_splat (first);
543 while (1)
Damjan Marion14864772018-05-22 14:07:47 +0200544 {
Damjan Marion008eef32018-09-12 22:37:30 +0200545 u64 bmp;
546 bmp = u8x16_msb_mask ((u8x16) (u16x8_load_unaligned (data) == splat));
547 if (bmp != 0xffff)
548 {
549 count += count_trailing_zeros (~bmp) / 2;
550 return clib_min (count, max_count);
551 }
552
Damjan Marion14864772018-05-22 14:07:47 +0200553 data += 8;
554 count += 8;
Damjan Marion008eef32018-09-12 22:37:30 +0200555
556 if (count >= max_count)
557 return max_count;
Damjan Marion14864772018-05-22 14:07:47 +0200558 }
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)
565 {
566 data += 4;
567 count += 4;
568 }
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
Damjan Marion008eef32018-09-12 22:37:30 +0200577static_always_inline uword
578clib_count_equal_u8 (u8 * data, uword max_count)
Damjan Marion14864772018-05-22 14:07:47 +0200579{
Neale Ranns2329e092018-10-03 14:13:27 -0400580 uword count;
581 u8 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 u8x32 splat = u8x32_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) (u8x32_load_unaligned (data) == splat));
597 if (bmp != 0xffffffff)
598 {
599 count += count_trailing_zeros (~bmp);
600 return clib_min (count, max_count);
601 }
602
Damjan Marion14864772018-05-22 14:07:47 +0200603 data += 32;
604 count += 32;
Damjan Marion008eef32018-09-12 22:37:30 +0200605
606 if (count >= max_count)
607 return max_count;
608 }
609#elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_MSB_MASK)
610 u8x16 splat = u8x16_splat (first);
611 while (1)
612 {
613 u64 bmp;
614 bmp = u8x16_msb_mask ((u8x16) (u8x16_load_unaligned (data) == splat));
615 if (bmp != 0xffff)
616 {
617 count += count_trailing_zeros (~bmp);
618 return clib_min (count, max_count);
619 }
620
621 data += 16;
622 count += 16;
623
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)
Damjan Marion14864772018-05-22 14:07:47 +0200633 {
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
Stevenb0598492018-10-24 21:15:45 -0700645/*
646 * This macro is to provide smooth mapping from memcmp to memcmp_s.
647 * memcmp has fewer parameters and fewer returns than memcmp_s.
648 * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
649 * we return 0 and spit out a message in the console because there is
650 * no way to return the error code to the memcmp callers.
651 * This condition happens when s1 or s2 is null. Please note
652 * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
653 * anyway. So we are consistent in this case for the comparison return
654 * although we also spit out a C11 violation message in the console to
655 * warn that they pass null pointers for both s1 and s2.
656 * Applications are encouraged to use the cool C11 memcmp_s API to get the
657 * maximum benefit out of it.
658 */
659#define clib_memcmp(s1,s2,m1) \
660 ({ int __diff = 0; \
661 memcmp_s_inline (s1, m1, s2, m1, &__diff); \
662 __diff; \
663 })
664
665errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
666 rsize_t s2max, int *diff);
667
668always_inline errno_t
669memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
670 int *diff)
671{
672 u8 bad;
673
674 bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
675 (s1max == 0);
676
677 if (PREDICT_FALSE (bad != 0))
678 {
679 if (s1 == NULL)
680 clib_c11_violation ("s1 NULL");
681 if (s2 == NULL)
682 clib_c11_violation ("s2 NULL");
683 if (diff == NULL)
684 clib_c11_violation ("diff NULL");
685 if (s2max > s1max)
686 clib_c11_violation ("s2max > s1max");
687 if (s2max == 0)
688 clib_c11_violation ("s2max 0");
689 if (s1max == 0)
690 clib_c11_violation ("s1max 0");
691 return EINVAL;
692 }
693
694 if (PREDICT_FALSE (s1 == s2))
695 {
696 *diff = 0;
697 return EOK;
698 }
699
700 *diff = memcmp (s1, s2, s2max);
701 return EOK;
702}
703
704/*
705 * This macro is to provide smooth mapping from strnlen to strnlen_s
706 */
707#define clib_strnlen(s,m) strnlen_s_inline(s,m)
708
709size_t strnlen_s (const char *s, size_t maxsize);
710
711always_inline size_t
712strnlen_s_inline (const char *s, size_t maxsize)
713{
714 u8 bad;
715
716 bad = (s == 0) + (maxsize == 0);
717 if (PREDICT_FALSE (bad != 0))
718 {
719 if (s == 0)
720 clib_c11_violation ("s NULL");
721 if (maxsize == 0)
722 clib_c11_violation ("maxsize 0");
723 return 0;
724 }
725 return strnlen (s, maxsize);
726}
727
728/*
729 * This macro is to provide smooth mapping from strcmp to strcmp_s.
730 * strcmp has fewer parameters and fewer returns than strcmp_s.
731 * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
732 * we return 0 and spit out a message in the console because
733 * there is no way to return the error to the strcmp callers.
734 * This condition happens when s1 or s2 is null. Please note in the extant
735 * strcmp call, they would end up crashing if one of them is null.
736 * So the new behavior is no crash, but an error is displayed in the
737 * console which I think is more user friendly. If both s1 and s2 are null,
738 * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
739 * to actually accessing the pointer contents. We are still consistent
740 * in this case for the comparison return although we also spit out a
741 * C11 violation message in the console to warn that they pass null pointers
742 * for both s1 and s2. The other problem is strcmp does not provide s1max,
743 * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
744 * If not, we may be accessing memory beyonf what is intended.
745 * Applications are encouraged to use the cool C11 strcmp_s API to get the
746 * maximum benefit out of it.
747 */
748#define clib_strcmp(s1,s2) \
749 ({ int __indicator = 0; \
750 strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator); \
751 __indicator; \
752 })
753
754errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
755 int *indicator);
756
757always_inline errno_t
758strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
759 int *indicator)
760{
761 u8 bad;
762
763 bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
764 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
765
766 if (PREDICT_FALSE (bad != 0))
767 {
768 if (indicator == NULL)
769 clib_c11_violation ("indicator NULL");
770 if (s1 == NULL)
771 clib_c11_violation ("s1 NULL");
772 if (s2 == NULL)
773 clib_c11_violation ("s2 NULL");
774 if (s1max == 0)
775 clib_c11_violation ("s1max 0");
776 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
777 clib_c11_violation ("s1 unterminated");
778 return EINVAL;
779 }
780
781 *indicator = strcmp (s1, s2);
782 return EOK;
783}
784
785/*
786 * This macro is to provide smooth mapping from strncmp to strncmp_s.
787 * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
788 * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
789 * we return 0 and spit out a message in the console because there is no
790 * means to return the error to the strncmp caller.
791 * This condition happens when s1 or s2 is null. In the extant strncmp call,
792 * they would end up crashing if one of them is null. So the new behavior is
793 * no crash, but error is displayed in the console which is more
794 * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
795 * strncmp did the pointers comparison prior to actually accessing the
796 * pointer contents. We are still consistent in this case for the comparison
797 * return although we also spit out a C11 violation message in the console to
798 * warn that they pass null pointers for both s1 and s2.
799 * Applications are encouraged to use the cool C11 strncmp_s API to get the
800 * maximum benefit out of it.
801 */
802#define clib_strncmp(s1,s2,n) \
803 ({ int __indicator = 0; \
804 strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator); \
805 __indicator; \
806 })
807
808errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
809 int *indicator);
810
811always_inline errno_t
812strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
813 int *indicator)
814{
815 u8 bad;
816 u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
817
818 if (PREDICT_FALSE (s1_greater_s1max && indicator))
819 {
820 /*
821 * strcmp allows n > s1max. If indicator is non null, we can still
822 * do the compare without any harm and return EINVAL as well as the
823 * result in indicator.
824 */
825 clib_c11_violation ("n exceeds s1 length");
826 *indicator = strncmp (s1, s2, n);
827 return EINVAL;
828 }
829
830 bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
831 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
832
833 if (PREDICT_FALSE (bad != 0))
834 {
835 if (indicator == NULL)
836 clib_c11_violation ("indicator NULL");
837 if (s1 == NULL)
838 clib_c11_violation ("s1 NULL");
839 if (s2 == NULL)
840 clib_c11_violation ("s2 NULL");
841 if (s1max == 0)
842 clib_c11_violation ("s1max 0");
843 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
844 clib_c11_violation ("s1 unterminated");
845 if (s1_greater_s1max)
846 clib_c11_violation ("n exceeds s1 length");
847 return EINVAL;
848 }
849
850 *indicator = strncmp (s1, s2, n);
851 return EOK;
852}
853
854/*
855 * This macro is provided for smooth migration from strcpy. It is not perfect
856 * because we don't know the size of the destination buffer to pass to strcpy_s.
857 * We improvise dmax with CLIB_STRING_MACRO_MAX.
858 * Applications are encouraged to move to the C11 strcpy_s API.
859 */
860#define clib_strcpy(d,s) strcpy_s_inline(d,CLIB_STRING_MACRO_MAX,s)
861
862errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
863 const char *__restrict__ src);
864
865always_inline errno_t
866strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
867 const char *__restrict__ src)
868{
869 u8 bad;
870 uword low, hi;
871 size_t n;
872
873 bad = (dest == 0) + (dmax == 0) + (src == 0);
874 if (PREDICT_FALSE (bad != 0))
875 {
876 if (dest == 0)
877 clib_c11_violation ("dest NULL");
878 if (src == 0)
879 clib_c11_violation ("src NULL");
880 if (dmax == 0)
881 clib_c11_violation ("dmax 0");
882 return EINVAL;
883 }
884
885 n = clib_strnlen (src, dmax);
886 if (PREDICT_FALSE (n >= dmax))
887 {
888 clib_c11_violation ("not enough space for dest");
889 return (EINVAL);
890 }
891 /* Not actually trying to copy anything is OK */
892 if (PREDICT_FALSE (n == 0))
893 return EOK;
894
895 /* Check for src/dst overlap, which is not allowed */
896 low = (uword) (src < dest ? src : dest);
897 hi = (uword) (src < dest ? dest : src);
898
899 if (PREDICT_FALSE (low + (n - 1) >= hi))
900 {
901 clib_c11_violation ("src/dest overlap");
902 return EINVAL;
903 }
904
905 clib_memcpy_fast (dest, src, n);
906 dest[n] = '\0';
907 return EOK;
908}
909
910/*
911 * This macro is provided for smooth migration from strncpy. It is not perfect
912 * because we don't know the size of the destination buffer to pass to
913 * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
914 * Applications are encouraged to move to the C11 strncpy_s API and provide
915 * the correct dmax for better error checking.
916 */
917#define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
918
919errno_t
920strncpy_s (char *__restrict__ dest, rsize_t dmax,
921 const char *__restrict__ src, rsize_t n);
922
923always_inline errno_t
924strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
925 const char *__restrict__ src, rsize_t n)
926{
927 u8 bad;
928 uword low, hi;
929 rsize_t m;
930 errno_t status = EOK;
931
932 bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
933 if (PREDICT_FALSE (bad != 0))
934 {
935 /* Not actually trying to copy anything is OK */
936 if (n == 0)
937 return EOK;
938 if (dest == 0)
939 clib_c11_violation ("dest NULL");
940 if (src == 0)
941 clib_c11_violation ("src NULL");
942 if (dmax == 0)
943 clib_c11_violation ("dmax 0");
944 return EINVAL;
945 }
946
947 if (PREDICT_FALSE (n >= dmax))
948 {
949 /* Relax and use strnlen of src */
950 clib_c11_violation ("n >= dmax");
951 m = clib_strnlen (src, dmax);
952 if (m >= dmax)
953 {
954 /* Truncate, adjust copy length to fit dest */
955 m = dmax - 1;
956 status = EOVERFLOW;
957 }
958 }
959 else
Stevenf09179f2019-01-07 20:32:01 -0800960 /* cap the copy to strlen(src) in case n > strlen(src) */
961 m = clib_strnlen (src, n);
Stevenb0598492018-10-24 21:15:45 -0700962
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
Dave Barachd08ae852018-12-05 08:41:11 -0500967 /*
968 * This check may fail innocently if src + dmax >= dst, but
969 * src + strlen(src) < dst. If it fails, check more carefully before
970 * blowing the whistle.
971 */
Stevenb0598492018-10-24 21:15:45 -0700972 if (PREDICT_FALSE (low + (m - 1) >= hi))
973 {
Dave Barachd08ae852018-12-05 08:41:11 -0500974 m = clib_strnlen (src, m);
975
976 if (low + (m - 1) >= hi)
977 {
978 clib_c11_violation ("src/dest overlap");
979 return EINVAL;
980 }
Stevenb0598492018-10-24 21:15:45 -0700981 }
982
983 clib_memcpy_fast (dest, src, m);
984 dest[m] = '\0';
985 return status;
986}
987
988/*
989 * This macro is to provide smooth migration from strcat to strcat_s.
990 * Because there is no dmax in strcat, we improvise it with
991 * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite dest
992 * with too many bytes from src.
993 * Applications are encouraged to use C11 API to provide the actual dmax
994 * for proper checking and protection.
995 */
996#define clib_strcat(d,s) strcat_s_inline(d,CLIB_STRING_MACRO_MAX,s)
997
998errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
999 const char *__restrict__ src);
1000
1001always_inline errno_t
1002strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
1003 const char *__restrict__ src)
1004{
1005 u8 bad;
1006 uword low, hi;
1007 size_t m, n, dest_size;
1008
1009 bad = (dest == 0) + (dmax == 0) + (src == 0);
1010 if (PREDICT_FALSE (bad != 0))
1011 {
1012 if (dest == 0)
1013 clib_c11_violation ("dest NULL");
1014 if (src == 0)
1015 clib_c11_violation ("src NULL");
1016 if (dmax == 0)
1017 clib_c11_violation ("dmax 0");
1018 return EINVAL;
1019 }
1020
1021 dest_size = clib_strnlen (dest, dmax);
1022 m = dmax - dest_size;
1023 n = clib_strnlen (src, m);
1024 if (PREDICT_FALSE (n >= m))
1025 {
1026 clib_c11_violation ("not enough space for dest");
1027 return EINVAL;
1028 }
1029
1030 /* Not actually trying to concatenate anything is OK */
1031 if (PREDICT_FALSE (n == 0))
1032 return EOK;
1033
1034 /* Check for src/dst overlap, which is not allowed */
1035 low = (uword) (src < dest ? src : dest);
1036 hi = (uword) (src < dest ? dest : src);
1037
1038 if (PREDICT_FALSE (low + (n - 1) >= hi))
1039 {
1040 clib_c11_violation ("src/dest overlap");
1041 return EINVAL;
1042 }
1043
1044 clib_memcpy_fast (dest + dest_size, src, n);
1045 dest[dest_size + n] = '\0';
1046 return EOK;
1047}
1048
1049/*
1050 * This macro is to provide smooth migration from strncat to strncat_s.
1051 * The unsafe strncat does not have s1max. We improvise it with
1052 * CLIB_STRING_MACRO_MAX. Please note there may be a chance to overwrite
1053 * dest with too many bytes from src.
1054 * Applications are encouraged to move to C11 strncat_s which requires dmax
1055 * from the caller and provides checking to safeguard the memory corruption.
1056 */
1057#define clib_strncat(d,s,n) strncat_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
1058
1059errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
1060 const char *__restrict__ src, rsize_t n);
1061
1062always_inline errno_t
1063strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
1064 const char *__restrict__ src, rsize_t n)
1065{
1066 u8 bad;
1067 uword low, hi;
1068 size_t m, dest_size, allowed_size;
1069 errno_t status = EOK;
1070
1071 bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
1072 if (PREDICT_FALSE (bad != 0))
1073 {
1074 /* Not actually trying to concatenate anything is OK */
1075 if (n == 0)
1076 return EOK;
1077 if (dest == 0)
1078 clib_c11_violation ("dest NULL");
1079 if (src == 0)
1080 clib_c11_violation ("src NULL");
1081 if (dmax == 0)
1082 clib_c11_violation ("dmax 0");
1083 return EINVAL;
1084 }
1085
1086 /* Check for src/dst overlap, which is not allowed */
1087 low = (uword) (src < dest ? src : dest);
1088 hi = (uword) (src < dest ? dest : src);
1089
1090 if (PREDICT_FALSE (low + (n - 1) >= hi))
1091 {
1092 clib_c11_violation ("src/dest overlap");
1093 return EINVAL;
1094 }
1095
1096 dest_size = clib_strnlen (dest, dmax);
1097 allowed_size = dmax - dest_size;
1098
1099 if (PREDICT_FALSE (allowed_size == 0))
1100 {
1101 clib_c11_violation ("no space left in dest");
1102 return (EINVAL);
1103 }
1104
1105 if (PREDICT_FALSE (n >= allowed_size))
1106 {
1107 /*
1108 * unlike strcat_s, strncat_s will do the concatenation anyway when
1109 * there is not enough space in dest. But it will do the truncation and
1110 * null terminate dest
1111 */
1112 m = clib_strnlen (src, allowed_size);
1113 if (m >= allowed_size)
1114 {
1115 m = allowed_size - 1;
1116 status = EOVERFLOW;
1117 }
1118 }
1119 else
1120 m = clib_strnlen (src, n);
1121
1122 clib_memcpy_fast (dest + dest_size, src, m);
1123 dest[dest_size + m] = '\0';
1124 return status;
1125}
1126
1127/*
1128 * This macro is to provide smooth mapping from strtok_r to strtok_s.
1129 * To map strtok to this macro, the caller would have to supply an additional
1130 * argument. strtokr_s requires s1max which the unsafe API does not have. So
1131 * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
1132 * this macro cannot catch unterminated s1 and s2.
1133 * Applications are encouraged to use the cool C11 strtok_s API to avoid
1134 * these problems.
1135 */
1136#define clib_strtok(s1,s2,p) \
1137 ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX; \
1138 strtok_s_inline (s1, &__s1max, s2, p); \
1139 })
1140
1141char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1142 const char *__restrict__ s2, char **__restrict__ ptr);
1143
1144always_inline char *
1145strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
1146 const char *__restrict__ s2, char **__restrict__ ptr)
1147{
1148#define STRTOK_DELIM_MAX_LEN 16
1149 u8 bad;
1150 const char *pt;
1151 char *ptoken;
1152 uword dlen, slen;
1153
1154 bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
1155 ((s1 == 0) && ptr && (*ptr == 0));
1156 if (PREDICT_FALSE (bad != 0))
1157 {
1158 if (s2 == NULL)
1159 clib_c11_violation ("s2 NULL");
1160 if (s1max == NULL)
1161 clib_c11_violation ("s1max is NULL");
1162 if (ptr == NULL)
1163 clib_c11_violation ("ptr is NULL");
1164 /* s1 == 0 and *ptr == null is no good */
1165 if ((s1 == 0) && ptr && (*ptr == 0))
1166 clib_c11_violation ("s1 and ptr contents are NULL");
1167 return 0;
1168 }
1169
1170 if (s1 == 0)
1171 s1 = *ptr;
1172
1173 /*
1174 * scan s1 for a delimiter
1175 */
1176 dlen = *s1max;
1177 ptoken = 0;
1178 while (*s1 != '\0' && !ptoken)
1179 {
1180 if (PREDICT_FALSE (dlen == 0))
1181 {
1182 *ptr = 0;
1183 clib_c11_violation ("s1 unterminated");
1184 return 0;
1185 }
1186
1187 /*
1188 * must scan the entire delimiter list
1189 * ISO should have included a delimiter string limit!!
1190 */
1191 slen = STRTOK_DELIM_MAX_LEN;
1192 pt = s2;
1193 while (*pt != '\0')
1194 {
1195 if (PREDICT_FALSE (slen == 0))
1196 {
1197 *ptr = 0;
1198 clib_c11_violation ("s2 unterminated");
1199 return 0;
1200 }
1201 slen--;
1202 if (*s1 == *pt)
1203 {
1204 ptoken = 0;
1205 break;
1206 }
1207 else
1208 {
1209 pt++;
1210 ptoken = s1;
1211 }
1212 }
1213 s1++;
1214 dlen--;
1215 }
1216
1217 /*
1218 * if the beginning of a token was not found, then no
1219 * need to continue the scan.
1220 */
1221 if (ptoken == 0)
1222 {
1223 *s1max = dlen;
1224 return (ptoken);
1225 }
1226
1227 /*
1228 * Now we need to locate the end of the token
1229 */
1230 while (*s1 != '\0')
1231 {
1232 if (dlen == 0)
1233 {
1234 *ptr = 0;
1235 clib_c11_violation ("s1 unterminated");
1236 return 0;
1237 }
1238
1239 slen = STRTOK_DELIM_MAX_LEN;
1240 pt = s2;
1241 while (*pt != '\0')
1242 {
1243 if (slen == 0)
1244 {
1245 *ptr = 0;
1246 clib_c11_violation ("s2 unterminated");
1247 return 0;
1248 }
1249 slen--;
1250 if (*s1 == *pt)
1251 {
1252 /*
1253 * found a delimiter, set to null
1254 * and return context ptr to next char
1255 */
1256 *s1 = '\0';
1257 *ptr = (s1 + 1); /* return pointer for next scan */
1258 *s1max = dlen - 1; /* account for the nulled delimiter */
1259 return (ptoken);
1260 }
1261 else
1262 {
1263 /*
1264 * simply scanning through the delimiter string
1265 */
1266 pt++;
1267 }
1268 }
1269 s1++;
1270 dlen--;
1271 }
1272
1273 *ptr = s1;
1274 *s1max = dlen;
1275 return (ptoken);
1276}
1277
1278/*
1279 * This macro is to provide smooth mapping from strstr to strstr_s.
1280 * strstr_s requires s1max and s2max which the unsafe API does not have. So
1281 * we have to improvise them with CLIB_STRING_MACRO_MAX which may cause us
1282 * to access memory beyond it is intended if s1 or s2 is unterminated.
1283 * For the record, strstr crashes if s1 or s2 is unterminated. But this macro
1284 * does not.
1285 * Applications are encouraged to use the cool C11 strstr_s API to avoid
1286 * this problem.
1287 */
1288#define clib_strstr(s1,s2) \
1289 ({ char * __substring = 0; \
1290 strstr_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, CLIB_STRING_MACRO_MAX, \
1291 &__substring); \
1292 __substring; \
1293 })
1294
1295errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1296 char **substring);
1297
1298always_inline errno_t
1299strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1300 char **substring)
1301{
1302 u8 bad;
1303 size_t s1_size, s2_size;
1304
1305 bad =
1306 (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1307 (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1308 (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1309 if (PREDICT_FALSE (bad != 0))
1310 {
1311 if (s1 == 0)
1312 clib_c11_violation ("s1 NULL");
1313 if (s2 == 0)
1314 clib_c11_violation ("s2 NULL");
1315 if (s1max == 0)
1316 clib_c11_violation ("s1max 0");
1317 if (s2max == 0)
1318 clib_c11_violation ("s2max 0");
1319 if (substring == 0)
1320 clib_c11_violation ("substring NULL");
1321 if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1322 clib_c11_violation ("s1 unterminated");
1323 if (s2 && s2max && (s2[clib_strnlen (s2, s1max)] != '\0'))
1324 clib_c11_violation ("s2 unterminated");
1325 return EINVAL;
1326 }
1327
1328 /*
1329 * s2 points to a string with zero length, or s2 equals s1, return s1
1330 */
1331 if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1332 {
1333 *substring = s1;
1334 return EOK;
1335 }
1336
1337 /*
1338 * s2_size > s1_size, it won't find match.
1339 */
1340 s1_size = clib_strnlen (s1, s1max);
1341 s2_size = clib_strnlen (s2, s2max);
1342 if (PREDICT_FALSE (s2_size > s1_size))
1343 return ESRCH;
1344
1345 *substring = strstr (s1, s2);
1346 if (*substring == 0)
1347 return ESRCH;
1348
1349 return EOK;
1350}
1351
Ed Warnickecb9cada2015-12-08 15:45:58 -07001352#endif /* included_clib_string_h */
Dave Barachc3799992016-08-15 11:12:27 -04001353
1354/*
1355 * fd.io coding-style-patch-verification: ON
1356 *
1357 * Local Variables:
1358 * eval: (c-set-style "gnu")
1359 * End:
1360 */