crypto crypto-openssl: support hashing operations
[vpp.git] / src / plugins / unittest / string_test.c
1 /*
2  * Copyright (c) 2018 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 #include <vlib/vlib.h>
16 #include <vppinfra/string.h>
17
18 static int
19 test_memset_s (vlib_main_t * vm, unformat_input_t * input)
20 {
21   u8 dst[64];
22   int i;
23   errno_t err;
24
25   vlib_cli_output (vm, "Test memset_s...");
26
27   err = memset_s (dst, ARRAY_LEN (dst), 0xfe, ARRAY_LEN (dst));
28
29   if (err != EOK)
30     return -1;
31
32   for (i = 0; i < ARRAY_LEN (dst); i++)
33     if (dst[i] != 0xFE)
34       return -1;
35
36   err = memset_s (dst, ARRAY_LEN (dst), 0xfa, ARRAY_LEN (dst) + 1);
37
38   if (err == EOK)
39     return -1;
40
41   return 0;
42 }
43
44 static int
45 test_clib_memset (vlib_main_t * vm, unformat_input_t * input)
46 {
47   u8 dst[64];
48   int i;
49   errno_t err;
50
51   vlib_cli_output (vm, "Test clib_memset...");
52
53   err = clib_memset (dst, 0xfe, ARRAY_LEN (dst));
54
55   if (err != EOK)
56     return -1;
57
58   for (i = 0; i < ARRAY_LEN (dst); i++)
59     if (dst[i] != 0xFE)
60       return -1;
61
62   return 0;
63 }
64
65 static int
66 test_memcpy_s (vlib_main_t * vm, unformat_input_t * input)
67 {
68   char src[64], dst[64];
69   int i;
70   errno_t err;
71
72   vlib_cli_output (vm, "Test memcpy_s...");
73
74   for (i = 0; i < ARRAY_LEN (src); i++)
75     src[i] = i + 1;
76
77   /* Typical case */
78   err = memcpy_s (dst, sizeof (dst), src, sizeof (src));
79
80   if (err != EOK)
81     return -1;
82
83   /* This better not fail but check anyhow */
84   for (i = 0; i < ARRAY_LEN (dst); i++)
85     if (src[i] != dst[i])
86       return -1;
87
88   /*
89    * Size test: sizeof (src) > sizeof (dst)
90    * Skip this test when __builtin_constant_p (sizeof (src)) is true.
91    * This is because memcpy_s_inline skips all the errors checking when the
92    * the above buildin function returns true which may cause overrun problem
93    * for dst buffer if this test is executed.
94    */
95   if (__builtin_constant_p (sizeof (src)) == 0)
96     {
97       err = memcpy_s (dst + 1, sizeof (dst) - 1, src, sizeof (src));
98
99       if (err == EOK)
100         return -1;
101     }
102
103   /* overlap fail */
104   err = memcpy_s (dst, sizeof (dst), dst + 1, sizeof (dst) - 1);
105
106   if (err == EOK)
107     return -1;
108
109   /* Zero length copy */
110   err = memcpy_s (0, sizeof (dst), src, 0);
111
112   if (err != EOK)
113     return -1;
114
115   /* OK, seems to work */
116   return 0;
117 }
118
119 static int
120 test_clib_memcpy (vlib_main_t * vm, unformat_input_t * input)
121 {
122   char src[64], dst[64];
123   int i;
124   errno_t err;
125
126   vlib_cli_output (vm, "Test clib_memcpy...");
127
128   for (i = 0; i < ARRAY_LEN (src); i++)
129     src[i] = i + 1;
130
131   /* Typical case */
132   err = clib_memcpy (dst, src, sizeof (src));
133
134   if (err != EOK)
135     return -1;
136
137   /* This better not fail but check anyhow */
138   for (i = 0; i < ARRAY_LEN (dst); i++)
139     if (src[i] != dst[i])
140       return -1;
141   /* verify it against memcpy */
142   memcpy (dst, src, sizeof (src));
143
144   /* This better not fail but check anyhow */
145   for (i = 0; i < ARRAY_LEN (dst); i++)
146     if (src[i] != dst[i])
147       return -1;
148
149   /* Zero length copy */
150   err = clib_memcpy (0, src, 0);
151
152   if (err != EOK)
153     return -1;
154
155   /* OK, seems to work */
156   return 0;
157 }
158
159 static int
160 test_memcmp_s (vlib_main_t * vm, unformat_input_t * input)
161 {
162   char src[64], dst[64];
163   errno_t err;
164   int diff = 0;
165
166   vlib_cli_output (vm, "Test memcmp_s...");
167
168   /* Fill array with different values */
169   err = clib_memset (src, 0x1, ARRAY_LEN (src));
170   if (err != EOK)
171     return -1;
172   err = clib_memset (dst, 0x3, ARRAY_LEN (dst));
173   if (err != EOK)
174     return -1;
175
176   /* s1 > s2, > 0 is expected in diff */
177   err = memcmp_s (dst, ARRAY_LEN (dst), src, ARRAY_LEN (src), &diff);
178   if (err != EOK)
179     return -1;
180   if (!(diff > 0))
181     return -1;
182
183   /* s1 < s2, < 0 is expected in diff */
184   err = memcmp_s (src, ARRAY_LEN (src), dst, ARRAY_LEN (dst), &diff);
185   if (err != EOK)
186     return -1;
187   if (!(diff < 0))
188     return -1;
189
190   err = clib_memset (dst, 0x1, ARRAY_LEN (dst));
191   if (err != EOK)
192     return -1;
193
194   /* s1 == s2, 0 is expected in diff */
195   err = memcmp_s (src, ARRAY_LEN (src), dst, ARRAY_LEN (dst), &diff);
196   if (err != EOK)
197     return -1;
198   if (diff != 0)
199     return -1;
200
201   /* Try negative tests */
202   err = memcmp_s (0, 0, 0, 0, 0);
203   if (err != EINVAL)
204     return -1;
205
206   /* Try s2max > s1max */
207   err = memcmp_s (src, ARRAY_LEN (src) - 1, dst, ARRAY_LEN (dst), &diff);
208   if (err != EINVAL)
209     return -1;
210
211   /* OK, seems to work */
212   return 0;
213 }
214
215 static int
216 test_clib_memcmp (vlib_main_t * vm, unformat_input_t * input)
217 {
218   char src[64], dst[64];
219   errno_t err;
220   char *s;
221
222   vlib_cli_output (vm, "Test clib_memcmp...");
223
224   /* Fill array with different values */
225   err = clib_memset (src, 0x1, ARRAY_LEN (src));
226   if (err != EOK)
227     return -1;
228   err = clib_memset (dst, 0x3, ARRAY_LEN (dst));
229   if (err != EOK)
230     return -1;
231
232   /* s1 > s2, > 0 is expected in diff */
233   if (!(clib_memcmp (dst, src, ARRAY_LEN (src)) > 0))
234     return -1;
235   /* verify it against memcmp */
236   if (!(memcmp (dst, src, ARRAY_LEN (src)) > 0))
237     return -1;
238
239   /* s1 < s2, < 0 is expected in diff */
240   if (!(clib_memcmp (src, dst, ARRAY_LEN (dst)) < 0))
241     return -1;
242   /* verify it against memcmp */
243   if (!(memcmp (src, dst, ARRAY_LEN (dst)) < 0))
244     return -1;
245
246   err = clib_memset (dst, 0x1, ARRAY_LEN (dst));
247   if (err != EOK)
248     return -1;
249
250   /* s1 == s2, 0 is expected in diff */
251   if (clib_memcmp (src, dst, ARRAY_LEN (dst)) != 0)
252     return -1;
253   /* verify it against memcmp */
254   if (memcmp (src, dst, ARRAY_LEN (dst)) != 0)
255     return -1;
256
257   /* Try negative tests */
258   s = 0;
259   if (clib_memcmp (s, s, 0) != 0)
260     return -1;
261   /* verify it against memcmp */
262   if (memcmp (s, s, 0) != 0)
263     return -1;
264
265   /* OK, seems to work */
266   return 0;
267 }
268
269 static int
270 test_strcmp_s (vlib_main_t * vm, unformat_input_t * input)
271 {
272   char s1[] = "Simplicity is the ultimate sophistication";
273   uword s1len = sizeof (s1) - 1;        // excluding null
274   errno_t err;
275   int indicator = 0;
276
277   vlib_cli_output (vm, "Test strcmp_s...");
278
279   /* s1 == s2, 0 is expected */
280   err = strcmp_s (s1, s1len, "Simplicity is the ultimate sophistication",
281                   &indicator);
282   if (err != EOK)
283     return -1;
284   if (indicator != 0)
285     return -1;
286
287   /* s1 > s2, > 0 is expected */
288   err = strcmp_s (s1, s1len, "Simplicity is the ultimate", &indicator);
289   if (err != EOK)
290     return -1;
291   if (!(indicator > 0))
292     return -1;
293
294   /* s1 < s2, < 0 is expected */
295   err = strcmp_s (s1, s1len, "Simplicity is the ultimate sophistication!",
296                   &indicator);
297   if (err != EOK)
298     return -1;
299   if (!(indicator < 0))
300     return -1;
301
302   /* Try some negative tests */
303
304   /* Null pointers test */
305   err = strcmp_s (0, 0, 0, 0);
306   if (err != EINVAL)
307     return -1;
308
309   /* non-null terminated s1 */
310   s1[s1len] = 0x1;
311   err = strcmp_s (s1, s1len, "Simplicity is the ultimate sophistication",
312                   &indicator);
313   if (err != EINVAL)
314     return -1;
315
316   /* OK, seems to work */
317   return 0;
318 }
319
320 static int
321 test_clib_strcmp (vlib_main_t * vm, unformat_input_t * input)
322 {
323   char s1[] = "Simplicity is the ultimate sophistication";
324   int indicator;
325   char *s;
326
327   vlib_cli_output (vm, "Test clib_strcmp...");
328
329   /* s1 == s2, 0 is expected */
330   indicator = clib_strcmp (s1, "Simplicity is the ultimate sophistication");
331   if (indicator != 0)
332     return -1;
333   /* verify it against strcmp */
334   indicator = strcmp (s1, "Simplicity is the ultimate sophistication");
335   if (indicator != 0)
336     return -1;
337
338   /* s1 > s2, > 0 is expected */
339   indicator = clib_strcmp (s1, "Simplicity is the ultimate");
340   if (!(indicator > 0))
341     return -1;
342   /* verify it against strcmp */
343   indicator = strcmp (s1, "Simplicity is the ultimate");
344   if (!(indicator > 0))
345     return -1;
346
347   /* s1 < s2, < 0 is expected */
348   indicator = clib_strcmp (s1, "Simplicity is the ultimate sophistication!");
349   if (!(indicator < 0))
350     return -1;
351   /* verify it against strcmp */
352   indicator = strcmp (s1, "Simplicity is the ultimate sophistication!");
353   if (!(indicator < 0))
354     return -1;
355
356   /* Try some negative tests */
357
358   /* Null pointers comparison */
359   s = 0;
360   indicator = clib_strcmp (s, s);
361   if (indicator != 0)
362     return -1;
363
364   /* OK, seems to work */
365   return 0;
366 }
367
368 static int
369 test_strncmp_s (vlib_main_t * vm, unformat_input_t * input)
370 {
371   char s1[] = "Every moment is a fresh beginning";
372   uword s1len = sizeof (s1) - 1;        // excluding null
373   errno_t err;
374   int indicator = 0;
375
376   vlib_cli_output (vm, "Test strncmp_s...");
377
378   /* s1 == s2, 0 is expected */
379   err = strncmp_s (s1, s1len, "Every moment is a fresh beginning", s1len,
380                    &indicator);
381   if (err != EOK)
382     return -1;
383   if (indicator != 0)
384     return -1;
385
386   /* s1 > s2, 0 is expected since comparison is no more than n character */
387   err = strncmp_s (s1, s1len, "Every moment is a fresh begin",
388                    sizeof ("Every moment is a fresh begin") - 1, &indicator);
389   if (err != EOK)
390     return -1;
391   if (indicator != 0)
392     return -1;
393
394   /* s1 < s2, < 0 is expected */
395   err = strncmp_s (s1, s1len, "Every moment is fresh beginning",
396                    sizeof ("Every moment is fresh beginning") - 1,
397                    &indicator);
398   if (err != EOK)
399     return -1;
400   if (!(indicator < 0))
401     return -1;
402
403   /* s1 > s2, > 0 is expected */
404   err = strncmp_s ("Every moment is fresh beginning. ",
405                    sizeof ("Every moment is fresh beginning. ") - 1, s1,
406                    s1len, &indicator);
407   if (err != EOK)
408     return -1;
409   if (!(indicator > 0))
410     return -1;
411
412   /* Try some negative tests */
413
414   /* Null pointers */
415   err = strncmp_s (0, 0, 0, 0, 0);
416   if (err != EINVAL)
417     return -1;
418
419   /* n > s1max */
420   err = strncmp_s (s1, s1len, "Every moment is a fresh beginning", s1len + 1,
421                    &indicator);
422   if (err != EINVAL)
423     return -1;
424
425   /* unterminated s1 */
426   s1[s1len] = 0x1;
427   err = strncmp_s (s1, s1len, "Every moment is a fresh beginning",
428                    sizeof ("Every moment is a fresh beginning") - 1,
429                    &indicator);
430   if (err != EINVAL)
431     return -1;
432
433   /* OK, seems to work */
434   return 0;
435 }
436
437 static int
438 test_clib_strncmp (vlib_main_t * vm, unformat_input_t * input)
439 {
440   char s1[] = "Every moment is a fresh beginning";
441   uword s1len = sizeof (s1) - 1;        // excluding null
442   int indicator, v_indicator;
443
444   vlib_cli_output (vm, "Test clib_strncmp...");
445
446   /* s1 == s2, 0 is expected */
447   indicator = clib_strncmp (s1, "Every moment is a fresh beginning", s1len);
448   if (indicator != 0)
449     return -1;
450   /* verify it against strncmp */
451   v_indicator = strncmp (s1, "Every moment is a fresh beginning", s1len);
452   if (v_indicator != 0)
453     return -1;
454
455   /* s1 > s2, 0 is expected since comparison is no more than n character */
456   indicator = clib_strncmp (s1, "Every moment is a fresh begin",
457                             sizeof ("Every moment is a fresh begin") - 1);
458   if (indicator != 0)
459     return -1;
460   /* verify it against strncmp */
461   v_indicator = strncmp (s1, "Every moment is a fresh begin",
462                          sizeof ("Every moment is a fresh begin") - 1);
463   if (v_indicator != 0)
464     return -1;
465
466   /* s1 < s2, < 0 is expected */
467   indicator = clib_strncmp (s1, "Every moment is fresh beginning",
468                             sizeof ("Every moment is fresh beginning") - 1);
469   if (!(indicator < 0))
470     return -1;
471   /* verify it against strncmp */
472   v_indicator = strncmp (s1, "Every moment is fresh beginning",
473                          sizeof ("Every moment is fresh beginning") - 1);
474   if (!(v_indicator < 0))
475     return -1;
476   if (v_indicator != indicator)
477     return -1;
478
479   /* s1 > s2, > 0 is expected */
480   indicator = clib_strncmp ("Every moment is fresh beginning. ", s1, s1len);
481   if (!(indicator > 0))
482     return -1;
483   /* verify it against strncmp */
484   v_indicator = strncmp ("Every moment is fresh beginning. ", s1, s1len);
485   if (!(v_indicator > 0))
486     return -1;
487   if (v_indicator != indicator)
488     return -1;
489
490   /* Try some negative tests */
491
492   /* Null pointers */
493
494   /* make sure we don't crash */
495   indicator = clib_strncmp (0, 0, 0);
496   if (indicator != EOK)
497     return -1;
498
499   /* n > s1 len */
500   indicator =
501     clib_strncmp (s1, "Every moment is a fresh beginning", s1len + 1);
502   if (indicator != 0)
503     return -1;
504   /* verify it against strncmp */
505   v_indicator = strncmp (s1, "Every moment is a fresh beginning", s1len + 1);
506   if (v_indicator != 0)
507     return -1;
508
509   /* unterminated s1 */
510   s1[s1len] = 0x1;
511   CLIB_MEM_UNPOISON (s1, CLIB_STRING_MACRO_MAX);
512   indicator = clib_strncmp (s1, "Every moment is a fresh beginning",
513                             sizeof ("every moment is a fresh beginning") - 1);
514   if (indicator != 0)
515     return -1;
516   /* verify it against strncmp */
517   v_indicator = strncmp (s1, "Every moment is a fresh beginning",
518                          sizeof ("Every moment is a fresh beginning") - 1);
519   if (v_indicator != 0)
520     return -1;
521
522   /* OK, seems to work */
523   return 0;
524 }
525
526 static int
527 test_strcpy_s (vlib_main_t * vm, unformat_input_t * input)
528 {
529   char src[] = "To err is human.";
530   char dst[64];
531   int indicator;
532   size_t s1size = sizeof (dst); // including null
533   errno_t err;
534
535   vlib_cli_output (vm, "Test strcpy_s...");
536
537   err = strcpy_s (dst, s1size, src);
538   if (err != EOK)
539     return -1;
540
541   /* This better not fail but check anyhow */
542   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
543       EOK)
544     return -1;
545   if (indicator != 0)
546     return -1;
547
548   /* Negative tests */
549
550   err = strcpy_s (0, 0, 0);
551   if (err == EOK)
552     return -1;
553
554   /* Size fail */
555   err = strcpy_s (dst, 10, src);
556   if (err == EOK)
557     return -1;
558
559   /* overlap fail */
560 #if __GNUC__ < 8
561   /* GCC 8 flunks this one at compile time... */
562   err = strcpy_s (dst, s1size, dst);
563   if (err == EOK)
564     return -1;
565 #endif
566
567   /* overlap fail */
568   err = strcpy_s (dst, s1size, dst + 1);
569   if (err == EOK)
570     return -1;
571
572   /* OK, seems to work */
573   return 0;
574 }
575
576 static int
577 test_clib_strcpy (vlib_main_t * vm, unformat_input_t * input)
578 {
579   char src[] = "The journey of a one thousand miles begins with one step.";
580   char dst[100];
581   int indicator;
582   errno_t err;
583
584   vlib_cli_output (vm, "Test clib_strcpy...");
585
586   err = clib_strcpy (dst, src);
587   if (err != EOK)
588     return -1;
589
590   /* This better not fail but check anyhow */
591   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
592       EOK)
593     return -1;
594   if (indicator != 0)
595     return -1;
596
597   /* verify it against strcpy */
598   strcpy (dst, src);            //NOSONAR
599
600   /* This better not fail but check anyhow */
601   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
602       EOK)
603     return -1;
604   if (indicator != 0)
605     return -1;
606
607   /* Negative tests */
608
609   err = clib_strcpy (0, 0);
610   if (err == EOK)
611     return -1;
612
613   /* overlap fail */
614 #if __GNUC__ < 8
615   /* GCC 8 flunks this one at compile time... */
616   err = clib_strcpy (dst, dst);
617   if (err == EOK)
618     return -1;
619 #endif
620
621   /* overlap fail */
622   err = clib_strcpy (dst, dst + 1);
623   if (err == EOK)
624     return -1;
625
626   /* OK, seems to work */
627   return 0;
628 }
629
630 static int
631 test_strncpy_s (vlib_main_t * vm, unformat_input_t * input)
632 {
633   char src[] = "Those who dare to fail miserably can achieve greatly.";
634   char dst[100], old_dst[100];
635   int indicator, i;
636   size_t s1size = sizeof (dst); // including null
637   errno_t err;
638
639   vlib_cli_output (vm, "Test strncpy_s...");
640
641   /* dmax includes null, n excludes null */
642
643   /* n == string len of src */
644   err = strncpy_s (dst, s1size, src, clib_strnlen (src, sizeof (src)));
645   if (err != EOK)
646     return -1;
647   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
648       EOK)
649     return -1;
650   if (indicator != 0)
651     return -1;
652
653   /* limited copy -- strlen src > n, copy up to n */
654   err = strncpy_s (dst, s1size, "The price of greatness is responsibility.",
655                    10);
656   if (err != EOK)
657     return -1;
658   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
659                 &indicator) != EOK)
660     return -1;
661   if (indicator != 0)
662     return -1;
663
664   /* n > string len of src */
665   err = clib_memset (dst, 1, sizeof (dst));
666   if (err != EOK)
667     return -1;
668
669   err = strncpy_s (dst, s1size, src, clib_strnlen (src, sizeof (src)) + 10);
670   if (err != EOK)
671     return -1;
672   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
673       EOK)
674     return -1;
675   if (indicator != 0)
676     return -1;
677
678   /* Make sure bytes after strlen(dst) is untouched */
679   for (i = 1 + clib_strnlen (dst, sizeof (dst)); i < sizeof (dst); i++)
680     if (dst[i] != 1)
681       return -1;
682
683   /* truncation, n >= dmax */
684   err = strncpy_s (dst, clib_strnlen (src, sizeof (src)), src,
685                    clib_strnlen (src, sizeof (src)));
686   if (err != EOVERFLOW)
687     return -1;
688
689   /* Check dst content */
690   if (dst[strlen (dst)] != '\0')
691     return -1;
692   if (strncmp_s (dst, clib_strnlen (dst, sizeof (dst)), src,
693                  clib_strnlen (dst, sizeof (dst)), &indicator) != EOK)
694     return -1;
695   if (indicator != 0)
696     return -1;
697
698   /* zero length copy */
699   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
700   err = strncpy_s (dst, sizeof (dst), src, 0);
701   if (err != EOK)
702     return -1;
703   /* verify dst is untouched */
704   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), old_dst, &indicator) !=
705       EOK)
706     return -1;
707   if (indicator != 0)
708     return -1;
709
710   /* Negative tests */
711
712   err = strncpy_s (0, 0, 0, 1);
713   if (err == EOK)
714     return -1;
715
716   /* overlap fail */
717   err = strncpy_s (dst, s1size, dst + 1, s1size - 1);
718   if (err == EOK)
719     return -1;
720
721   /* overlap fail */
722 #if __GNUC__ < 8
723   /* GCC 8 flunks this one at compile time... */
724   err = strncpy_s (dst, s1size, dst, s1size);
725   if (err == EOK)
726     return -1;
727 #endif
728
729   /* OK, seems to work */
730   return 0;
731 }
732
733 static int
734 test_clib_strncpy (vlib_main_t * vm, unformat_input_t * input)
735 {
736   char src[] = "Those who dare to fail miserably can achieve greatly.";
737   char dst[100], old_dst[100];
738   int indicator;
739   size_t s1size = sizeof (dst); // including null
740   errno_t err;
741
742   vlib_cli_output (vm, "Test clib_strncpy...");
743
744   /* n == string len of src */
745   err = clib_strncpy (dst, src, clib_strnlen (src, sizeof (src)));
746   if (err != EOK)
747     return -1;
748
749   /* This better not fail but check anyhow */
750   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
751       EOK)
752     return -1;
753   if (indicator != 0)
754     return -1;
755
756   /* Verify it against strncpy */
757 #if __GNUC__ < 8
758   /* GCC 8 debian flunks this one at compile time */
759   strncpy (dst, src, strlen (src));
760
761   /* This better not fail but check anyhow */
762   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
763       EOK)
764     return -1;
765   if (indicator != 0)
766     return -1;
767 #endif
768
769   /* limited copy -- strlen src > n, copy up to n */
770   err = clib_strncpy (dst, "The price of greatness is responsibility.", 10);
771   if (err != EOK)
772     return -1;
773   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
774                 &indicator) != EOK)
775     return -1;
776   if (indicator != 0)
777     return -1;
778   /* verify it against strncpy */
779   memset_s (dst, sizeof (dst), 0, sizeof (dst));
780
781 #if __GNUC__ < 8
782   /* GCC 8 flunks this one at compile time... */
783   strncpy (dst, "The price of greatness is responsibility.", 10);
784   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
785                 &indicator) != EOK)
786     return -1;
787   if (indicator != 0)
788     return -1;
789 #endif
790
791   /* n > string len of src */
792   err = clib_strncpy (dst, src, clib_strnlen (src, sizeof (src)) + 10);
793   if (err != EOK)
794     return -1;
795   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
796       EOK)
797     return -1;
798   if (indicator != 0)
799     return -1;
800   /* Verify it against strncpy */
801 #if __GNUC__ < 8
802   /* GCC 8 debian flunks this one at compile time */
803   strncpy (dst, src, strlen (src));
804   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
805       EOK)
806     return -1;
807   if (indicator != 0)
808     return -1;
809 #endif
810
811   /* zero length copy */
812   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
813   err = clib_strncpy (dst, src, 0);
814   if (err != EOK)
815     return -1;
816   /* verify dst is untouched */
817   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), old_dst, &indicator) !=
818       EOK)
819     return -1;
820   if (indicator != 0)
821     return -1;
822
823   /* Negative tests */
824
825   err = clib_strncpy (0, 0, 1);
826   if (err == EOK)
827     return -1;
828
829   /* overlap fail */
830   err = clib_strncpy (dst, dst + 1, s1size);
831   if (err == EOK)
832     return -1;
833
834   /* overlap fail */
835 #if __GNUC__ < 8
836   /* GCC 8 flunks this one at compile time... */
837   err = clib_strncpy (dst, dst, s1size);
838   if (err == EOK)
839     return -1;
840 #endif
841
842   /* OK, seems to work */
843   return 0;
844 }
845
846 static int
847 test_strcat_s (vlib_main_t * vm, unformat_input_t * input)
848 {
849   char src[100], dst[100], old_dst[100];
850   size_t s1size = sizeof (dst); // including null
851   errno_t err;
852   int indicator;
853
854   vlib_cli_output (vm, "Test strcat_s...");
855
856   strcpy_s (dst, sizeof (dst), "Tough time never last ");
857   strcpy_s (src, sizeof (src), "but tough people do");
858   err = strcat_s (dst, s1size, src);
859   if (err != EOK)
860     return -1;
861   if (strcmp_s (dst, s1size - 1,
862                 "Tough time never last but tough people do",
863                 &indicator) != EOK)
864     return -1;
865   if (indicator != 0)
866     return -1;
867
868   /* empty string concatenation */
869   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
870   err = strcat_s (dst, s1size, "");
871   if (err != EOK)
872     return -1;
873   /* verify dst is untouched */
874   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
875     return -1;
876   if (indicator != 0)
877     return -1;
878
879   /* negative stuff */
880   err = strcat_s (0, 0, 0);
881   if (err != EINVAL)
882     return -1;
883
884   /* overlap fail */
885   err = strcat_s (dst, s1size, dst + 1);
886   if (err != EINVAL)
887     return -1;
888
889   /* overlap fail */
890 #if __GNUC__ < 8
891   /* GCC 8 flunks this one at compile time... */
892   err = strcat_s (dst, s1size, dst);
893   if (err != EINVAL)
894     return -1;
895 #endif
896
897   /* not enough space for dst */
898   err = strcat_s (dst, 10, src);
899   if (err != EINVAL)
900     return -1;
901
902   /* OK, seems to work */
903   return 0;
904 }
905
906 static int
907 test_clib_strcat (vlib_main_t * vm, unformat_input_t * input)
908 {
909   char src[100], dst[100], old_dst[100];
910   size_t s1size = sizeof (dst); // including null
911   errno_t err;
912   int indicator;
913
914   vlib_cli_output (vm, "Test clib_strcat...");
915
916   strcpy_s (dst, sizeof (dst), "Tough time never last ");
917   strcpy_s (src, sizeof (src), "but tough people do");
918   err = clib_strcat (dst, src);
919   if (err != EOK)
920     return -1;
921   if (strcmp_s (dst, s1size - 1,
922                 "Tough time never last but tough people do",
923                 &indicator) != EOK)
924     return -1;
925   if (indicator != 0)
926     return -1;
927   /* verify it against strcat */
928   strcpy_s (dst, sizeof (dst), "Tough time never last ");
929   strcpy_s (src, sizeof (src), "but tough people do");
930   strcat (dst, src);
931   if (strcmp_s (dst, s1size - 1,
932                 "Tough time never last but tough people do",
933                 &indicator) != EOK)
934     return -1;
935   if (indicator != 0)
936     return -1;
937
938   /* empty string concatenation */
939   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
940   err = clib_strcat (dst, "");
941   if (err != EOK)
942     return -1;
943   /* verify dst is untouched */
944   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
945     return -1;
946   if (indicator != 0)
947     return -1;
948
949   /* negative stuff */
950   err = clib_strcat (0, 0);
951   if (err != EINVAL)
952     return -1;
953
954   /* overlap fail */
955   err = clib_strcat (dst, dst + 1);
956   if (err != EINVAL)
957     return -1;
958
959   /* overlap fail */
960 #if __GNUC__ < 8
961   /* GCC 8 flunks this one at compile time... */
962   err = clib_strcat (dst, dst);
963   if (err != EINVAL)
964     return -1;
965 #endif
966
967   /* OK, seems to work */
968   return 0;
969 }
970
971 static int
972 test_strncat_s (vlib_main_t * vm, unformat_input_t * input)
973 {
974   char src[100], dst[100], old_dst[100];
975   size_t s1size = sizeof (dst); // including null
976   errno_t err;
977   char s1[] = "Two things are infinite: ";
978   char s2[] = "the universe and human stupidity; ";
979   char s3[] = "I am not sure about the universe.";
980   int indicator;
981
982   vlib_cli_output (vm, "Test strncat_s...");
983
984   strcpy_s (dst, sizeof (dst), s1);
985   strcpy_s (src, sizeof (src), s2);
986   err = strncat_s (dst, s1size, src, clib_strnlen (src, sizeof (src)));
987   if (err != EOK)
988     return -1;
989   if (strcmp_s (dst, s1size - 1,
990                 "Two things are infinite: the universe and human stupidity; ",
991                 &indicator) != EOK)
992     return -1;
993   if (indicator != 0)
994     return -1;
995
996   /* truncation, n >= dmax - strnlen_s (dst, dmax) */
997   err = strncat_s (dst, clib_strnlen (dst, sizeof (dst)) +
998                    clib_strnlen (s3, sizeof (s3)), s3,
999                    clib_strnlen (s3, sizeof (s3)));
1000   if (err != EOVERFLOW)
1001     return -1;
1002   /*
1003    * resulting string is dst + strlen (s3) - 1 characters + null.
1004    * notice the "." is missing at the end of the resulting string because
1005    * the space is needed to accommodate the null
1006    * Notice strcmp_s will check s1 or dst to make sure it is null terminated
1007    */
1008   if (strcmp_s (dst, s1size - 1,
1009                 "Two things are infinite: the universe and human stupidity; "
1010                 "I am not sure about the universe", &indicator) != EOK)
1011     return -1;
1012   if (indicator != 0)
1013     return -1;
1014
1015   /* n > strlen src */
1016   strcpy_s (dst, sizeof (dst), s1);
1017   err = strncat_s (dst, s1size, src, clib_strnlen (src, sizeof (src)) + 10);
1018   if (err != EOK)
1019     return -1;
1020   if (strcmp_s (dst, s1size - 1,
1021                 "Two things are infinite: the universe and human stupidity; ",
1022                 &indicator) != EOK)
1023     return -1;
1024   if (indicator != 0)
1025     return -1;
1026
1027   /* zero length strncat */
1028   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
1029   err = strncat_s (dst, sizeof (dst), src, 0);
1030   if (err != EOK)
1031     return -1;
1032   /* verify dst is untouched */
1033   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1034     return -1;
1035   if (indicator != 0)
1036     return -1;
1037
1038   /* empty string, wrong n concatenation */
1039   err = strncat_s (dst, sizeof (dst), "", 10);
1040   if (err != EOK)
1041     return -1;
1042   /* verify dst is untouched */
1043   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1044     return -1;
1045   if (indicator != 0)
1046     return -1;
1047
1048   /* limited concatenation, string > n, copy up to n */
1049   strcpy_s (dst, sizeof (dst), s1);
1050   err = strncat_s (dst, s1size, s2, 13);
1051   if (err != EOK)
1052     return -1;
1053   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1054                 &indicator) != EOK)
1055     return -1;
1056   if (indicator != 0)
1057     return -1;
1058   /* verify it against strncat */
1059 #if __GNUC__ < 8
1060   /* GCC 8 debian flunks this one at compile time */
1061   strcpy_s (dst, sizeof (dst), s1);
1062   strncat (dst, s2, 13);
1063   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1064                 &indicator) != EOK)
1065     return -1;
1066   if (indicator != 0)
1067     return -1;
1068 #endif
1069
1070   /* negative stuff */
1071   err = strncat_s (0, 0, 0, 1);
1072   if (err != EINVAL)
1073     return -1;
1074
1075   /* no room for dst -- dmax - strnlen_s (dst, dmax) == 0 */
1076   err = strncat_s (dst, clib_strnlen (dst, sizeof (dst)), s2,
1077                    clib_strnlen (s2, sizeof (s2)));
1078   if (err != EINVAL)
1079     return -1;
1080
1081   /* overlap fail */
1082   err = strncat_s (dst, s1size, dst + 1, clib_strnlen (dst + 1, s1size - 1));
1083   if (err != EINVAL)
1084     return -1;
1085
1086   /* overlap fail */
1087 #if __GNUC__ < 8
1088   /* GCC 8 flunks this one at compile time... */
1089   err = strncat_s (dst, s1size, dst, clib_strnlen (dst, sizeof (dst)));
1090   if (err != EINVAL)
1091     return -1;
1092 #endif
1093
1094   /* OK, seems to work */
1095   return 0;
1096 }
1097
1098 static int
1099 test_clib_strncat (vlib_main_t * vm, unformat_input_t * input)
1100 {
1101   char src[100], dst[100], old_dst[100];
1102   size_t s1size = sizeof (dst); // including null
1103   errno_t err;
1104   char s1[] = "Two things are infinite: ";
1105   char s2[] = "the universe and human stupidity; ";
1106   int indicator;
1107
1108   vlib_cli_output (vm, "Test clib_strncat...");
1109
1110   /* n == strlen src */
1111   strcpy_s (dst, sizeof (dst), s1);
1112   strcpy_s (src, sizeof (src), s2);
1113   err = clib_strncat (dst, src, clib_strnlen (src, sizeof (src)));
1114   if (err != EOK)
1115     return -1;
1116   if (strcmp_s (dst, s1size - 1,
1117                 "Two things are infinite: the universe and human stupidity; ",
1118                 &indicator) != EOK)
1119     return -1;
1120   if (indicator != 0)
1121     return -1;
1122   /* verify it against strncat */
1123   strcpy_s (dst, sizeof (dst), s1);
1124   strncat (dst, src, clib_strnlen (src, sizeof (src)));
1125   if (strcmp_s (dst, s1size - 1,
1126                 "Two things are infinite: the universe and human stupidity; ",
1127                 &indicator) != EOK)
1128     return -1;
1129   if (indicator != 0)
1130     return -1;
1131
1132   /* n > strlen src */
1133   strcpy_s (dst, sizeof (dst), s1);
1134   err = clib_strncat (dst, src, clib_strnlen (src, sizeof (src)) + 10);
1135   if (err != EOK)
1136     return -1;
1137   if (strcmp_s (dst, s1size - 1,
1138                 "Two things are infinite: the universe and human stupidity; ",
1139                 &indicator) != EOK)
1140     return -1;
1141   if (indicator != 0)
1142     return -1;
1143   /* verify it against strncat */
1144   strcpy_s (dst, sizeof (dst), s1);
1145   strncat (dst, src, clib_strnlen (src, sizeof (src)));
1146   if (strcmp_s (dst, s1size - 1,
1147                 "Two things are infinite: the universe and human stupidity; ",
1148                 &indicator) != EOK)
1149     return -1;
1150   if (indicator != 0)
1151     return -1;
1152
1153   /* zero length strncat */
1154   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
1155   err = clib_strncat (dst, src, 0);
1156   if (err != EOK)
1157     return -1;
1158   /* verify dst is untouched */
1159   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1160     return -1;
1161   if (indicator != 0)
1162     return -1;
1163
1164   /* empty string, wrong n concatenation */
1165   err = clib_strncat (dst, "", 10);
1166   if (err != EOK)
1167     return -1;
1168   /* verify dst is untouched */
1169   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1170     return -1;
1171   if (indicator != 0)
1172     return -1;
1173
1174   /* limited concatenation, string > n, copy up to n */
1175   strcpy_s (dst, sizeof (dst), s1);
1176   err = clib_strncat (dst, s2, 13);
1177   if (err != EOK)
1178     return -1;
1179   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1180                 &indicator) != EOK)
1181     return -1;
1182   if (indicator != 0)
1183     return -1;
1184   /* verify it against strncat */
1185 #if __GNUC__ < 8
1186   /* GCC 8 debian flunks this one at compile time */
1187   strcpy_s (dst, sizeof (dst), s1);
1188   strncat (dst, s2, 13);
1189   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1190                 &indicator) != EOK)
1191     return -1;
1192   if (indicator != 0)
1193     return -1;
1194 #endif
1195
1196   /* negative stuff */
1197   err = clib_strncat (0, 0, 1);
1198   if (err != EINVAL)
1199     return -1;
1200
1201   /* overlap fail */
1202   err = clib_strncat (dst, dst + 1, s1size - 1);
1203   if (err != EINVAL)
1204     return -1;
1205
1206   /* overlap fail */
1207 #if __GNUC__ < 8
1208   /* GCC 8 flunks this one at compile time... */
1209   err = clib_strncat (dst, dst, clib_strnlen (dst, sizeof (dst)));
1210   if (err != EINVAL)
1211     return -1;
1212 #endif
1213
1214   /* OK, seems to work */
1215   return 0;
1216 }
1217
1218 static int
1219 test_strtok_s (vlib_main_t * vm, unformat_input_t * input)
1220 {
1221   int indicator;
1222   char *tok, *ptr;
1223   char str2[20];
1224   char str1[40];
1225   uword len;
1226   char *p2str = 0;
1227   char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7;
1228
1229   vlib_cli_output (vm, "Test strtok_s...");
1230   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1231   len = strnlen_s (str1, sizeof (str1));
1232   tok1 = strtok_s (str1, &len, " ", &p2str);
1233   tok2 = strtok_s (0, &len, " ", &p2str);
1234   tok3 = strtok_s (0, &len, " ", &p2str);
1235   tok4 = strtok_s (0, &len, " ", &p2str);
1236   tok5 = strtok_s (0, &len, " ", &p2str);
1237   tok6 = strtok_s (0, &len, " ", &p2str);
1238   tok7 = strtok_s (0, &len, " ", &p2str);
1239   if ((tok1 == 0) ||
1240       strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
1241     return -1;
1242   if (indicator != 0)
1243     return -1;
1244   if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
1245     return -1;
1246   if (indicator != 0)
1247     return -1;
1248   if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
1249     return -1;
1250   if (indicator != 0)
1251     return -1;
1252   if ((tok4 == 0)
1253       || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
1254     return -1;
1255   if (indicator != 0)
1256     return -1;
1257   if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
1258     return -1;
1259   if (indicator != 0)
1260     return -1;
1261   if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
1262     return -1;
1263   if (indicator != 0)
1264     return -1;
1265   if (tok7 != 0)
1266     return -1;
1267
1268   /* delimiter not present in the string -- the whole string is returned */
1269   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1270   len = strnlen_s (str1, sizeof (str1) - 1);
1271   p2str = 0;
1272   tok1 = strtok_s (str1, &len, ",", &p2str);
1273   if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
1274     return -1;
1275   if (indicator != 0)
1276     return -1;
1277
1278   /* negative stuff */
1279   tok = strtok_s (0, 0, 0, 0);
1280   if (tok != 0)
1281     return -1;
1282
1283   /* s1 and ptr contents are null */
1284   ptr = 0;
1285   tok = strtok_s (0, 0, 0, &ptr);
1286   if (tok != 0)
1287     return -1;
1288
1289   /* unterminate s1 */
1290   p2str = 0;
1291   len = strnlen_s (str1, sizeof (str1) - 1);
1292   str1[strlen (str1)] = 0x2;
1293   tok = strtok_s (str1, &len, ",", &p2str);
1294   if (tok != 0)
1295     return -1;
1296
1297   /*
1298    * unterminated s2. This test case in not perfect because there is no
1299    * argument for s2max. But s2 len is limited to 16 characters. If the API
1300    * does not find the null character at s2[15], it declares the string s2
1301    * as unterminated.
1302    */
1303   memset_s (str2, sizeof (str2), 0xfa, sizeof (str2));
1304   tok = strtok_s (str1, &len, str2, &p2str);
1305   if (tok != 0)
1306     return -1;
1307
1308   /* OK, seems to work */
1309   return 0;
1310 }
1311
1312 static int
1313 test_clib_strtok (vlib_main_t * vm, unformat_input_t * input)
1314 {
1315   int indicator;
1316   char *s1 __attribute__ ((unused));
1317   char *tok __attribute__ ((unused));
1318   char *ptr __attribute__ ((unused));
1319   char str1[40];
1320   char *p2str;
1321   char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7;
1322
1323   vlib_cli_output (vm, "Test clib_strtok...");
1324   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1325   p2str = 0;
1326   tok1 = clib_strtok (str1, " ", &p2str);
1327   tok2 = clib_strtok (0, " ", &p2str);
1328   tok3 = clib_strtok (0, " ", &p2str);
1329   tok4 = clib_strtok (0, " ", &p2str);
1330   tok5 = clib_strtok (0, " ", &p2str);
1331   tok6 = clib_strtok (0, " ", &p2str);
1332   tok7 = clib_strtok (0, " ", &p2str);
1333   if ((tok1 == 0) ||
1334       strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
1335     return -1;
1336   if (indicator != 0)
1337     return -1;
1338   if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
1339     return -1;
1340   if (indicator != 0)
1341     return -1;
1342   if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
1343     return -1;
1344   if (indicator != 0)
1345     return -1;
1346   if ((tok4 == 0)
1347       || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
1348     return -1;
1349   if (indicator != 0)
1350     return -1;
1351   if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
1352     return -1;
1353   if (indicator != 0)
1354     return -1;
1355   if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
1356     return -1;
1357   if (indicator != 0)
1358     return -1;
1359   if (tok7 != 0)
1360     return -1;
1361   /* verify it againest strtok_r */
1362   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1363   p2str = 0;
1364   tok1 = strtok_r (str1, " ", &p2str);
1365   tok2 = strtok_r (0, " ", &p2str);
1366   tok3 = strtok_r (0, " ", &p2str);
1367   tok4 = strtok_r (0, " ", &p2str);
1368   tok5 = strtok_r (0, " ", &p2str);
1369   tok6 = strtok_r (0, " ", &p2str);
1370   tok7 = strtok_r (0, " ", &p2str);
1371   if ((tok1 == 0) ||
1372       strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
1373     return -1;
1374   if (indicator != 0)
1375     return -1;
1376   if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
1377     return -1;
1378   if (indicator != 0)
1379     return -1;
1380   if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
1381     return -1;
1382   if (indicator != 0)
1383     return -1;
1384   if ((tok4 == 0)
1385       || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
1386     return -1;
1387   if (indicator != 0)
1388     return -1;
1389   if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
1390     return -1;
1391   if (indicator != 0)
1392     return -1;
1393   if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
1394     return -1;
1395   if (indicator != 0)
1396     return -1;
1397   if (tok7 != 0)
1398     return -1;
1399
1400   /* delimiter not present in the string -- the whole string is returned */
1401   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1402   p2str = 0;
1403   tok1 = clib_strtok (str1, ",", &p2str);
1404   if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
1405     return -1;
1406   if (indicator != 0)
1407     return -1;
1408   /* verify it against strtok_r */
1409   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1410   p2str = 0;
1411   tok1 = strtok_r (str1, ",", &p2str);
1412   if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
1413     return -1;
1414   if (indicator != 0)
1415     return -1;
1416
1417   /* negative stuff */
1418   s1 = 0;
1419   ptr = 0;
1420 #if __GNUC__ < 8
1421   /* GCC 8 flunks this one at compile time... */
1422   tok = clib_strtok (s1, s1, (char **) 0);
1423   if (tok != 0)
1424     return -1;
1425
1426   /* s1 and ptr contents are null */
1427   tok = clib_strtok (s1, s1, &ptr);
1428   if (tok != 0)
1429     return -1;
1430 #endif
1431
1432   /* verify it against strtok_r */
1433   /* No can do. This causes a crash in strtok_r */
1434   // tok = strtok_r (s1, " ", &ptr);
1435   // if (tok != 0)
1436   //  return -1;
1437
1438   /*
1439    * Can't test unterminated string s1 and s2 becuase clib_strtok does not
1440    * supply s1 and s2 max
1441    */
1442
1443   /* OK, seems to work */
1444   return 0;
1445 }
1446
1447 static int
1448 test_strnlen_s (vlib_main_t * vm, unformat_input_t * input)
1449 {
1450   const char s1[] = "Truth is incontrovertible";
1451   size_t len;
1452
1453   vlib_cli_output (vm, "Test strnlen_s...");
1454
1455   len = strnlen_s (s1, sizeof (s1));
1456   if (len != sizeof (s1) - 1)
1457     return -1;
1458
1459   len = strnlen_s (s1, 5);
1460   if (len != 5)
1461     return -1;
1462
1463   /* negative stuff */
1464   len = strnlen_s (0, 0);
1465   if (len != 0)
1466     return -1;
1467
1468   /* OK, seems to work */
1469   return 0;
1470 }
1471
1472 static int
1473 test_clib_strnlen (vlib_main_t * vm, unformat_input_t * input)
1474 {
1475   const char s1[] = "Truth is incontrovertible";
1476   size_t len;
1477
1478   vlib_cli_output (vm, "Test clib_strnlen...");
1479
1480   len = clib_strnlen (s1, sizeof (s1));
1481   if (len != sizeof (s1) - 1)
1482     return -1;
1483
1484   len = clib_strnlen (s1, 5);
1485   if (len != 5)
1486     return -1;
1487
1488   /* negative stuff */
1489   len = clib_strnlen (0, 0);
1490   if (len != 0)
1491     return -1;
1492
1493   /* OK, seems to work */
1494   return 0;
1495 }
1496
1497 static int
1498 test_strstr_s (vlib_main_t * vm, unformat_input_t * input)
1499 {
1500   errno_t err;
1501   char *sub = 0;
1502   char s1[64];
1503   size_t s1len = sizeof (s1) - 1;       // excluding null
1504   int indicator;
1505
1506   vlib_cli_output (vm, "Test strstr_s...");
1507
1508   /* substring not present */
1509   strcpy_s (s1, s1len, "success is not final, failure is not fatal.");
1510   err = strstr_s (s1, s1len, "failures", sizeof ("failures"), &sub);;
1511   if (err != ESRCH)
1512     return -1;
1513
1514   /* substring present */
1515   err = strstr_s (s1, s1len, "failure", sizeof ("failure"), &sub);
1516   if (err != EOK)
1517     return -1;
1518
1519   if ((sub == 0) ||
1520       strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator)
1521       != EOK)
1522     return -1;
1523   if (indicator != 0)
1524     return -1;
1525
1526   /* negative stuff */
1527
1528   /* Null pointers test */
1529   err = strstr_s (0, 0, 0, 0, 0);
1530   if (err != EINVAL)
1531     return -1;
1532
1533   /* unterminated s1 and s2 */
1534   memset_s (s1, ARRAY_LEN (s1), 0xfe, ARRAY_LEN (s1));
1535   err = strstr_s (s1, s1len, s1, s1len, &sub);
1536   if (err != EINVAL)
1537     return -1;
1538
1539   /* OK, seems to work */
1540   return 0;
1541 }
1542
1543 static int
1544 test_clib_strstr (vlib_main_t * vm, unformat_input_t * input)
1545 {
1546   char *sub, *s;
1547   char s1[64];
1548   size_t s1len = sizeof (s1) - 1;       // excluding null
1549   int indicator;
1550
1551   vlib_cli_output (vm, "Test clib_strstr...");
1552
1553   /* substring not present */
1554   strcpy_s (s1, s1len, "success is not final, failure is not fatal.");
1555   sub = clib_strstr (s1, "failures");
1556   if (sub != 0)
1557     return -1;
1558   /* verify it against strstr */
1559   sub = strstr (s1, "failures");
1560   if (sub != 0)
1561     return -1;
1562
1563   /* substring present */
1564   sub = clib_strstr (s1, "failure");
1565   if (sub == 0)
1566     return -1;
1567   if (strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator) !=
1568       EOK)
1569     return -1;
1570   if (indicator != 0)
1571     return -1;
1572   /* verify it against strstr */
1573   sub = strstr (s1, "failure");
1574   if (sub == 0)
1575     return -1;
1576   if (strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator) !=
1577       EOK)
1578     return -1;
1579   if (indicator != 0)
1580     return -1;
1581
1582   /* negative stuff */
1583
1584   /* Null pointers test */
1585   s = 0;
1586   sub = clib_strstr (s, s);
1587   if (sub != 0)
1588     return -1;
1589   /*
1590    * Can't verify it against strstr for this test. Null pointers cause strstr
1591    * to crash. Go figure!
1592    */
1593
1594   /* unterminated s1 and s2 */
1595   memset_s (s1, ARRAY_LEN (s1), 0xfe, ARRAY_LEN (s1));
1596   CLIB_MEM_UNPOISON (s1, CLIB_STRING_MACRO_MAX);
1597   sub = clib_strstr (s1, s1);
1598   if (sub == 0)
1599     return -1;
1600   /*
1601    * Can't verify it against strstr for this test. Unterminated string causes
1602    * strstr to crash. Go figure!
1603    */
1604
1605   /* OK, seems to work */
1606   return 0;
1607 }
1608
1609 static int
1610 test_clib_count_equal (vlib_main_t * vm, unformat_input_t * input)
1611 {
1612   u64 s64[15];
1613   u32 s32[31];
1614   u16 s16[63];
1615   u8 s8[127];
1616   uword count;
1617
1618   vlib_cli_output (vm, "Test clib_count_equal_u64...");
1619   memset (s64, 0, sizeof (s64));
1620   count = clib_count_equal_u64 (s64, 0);
1621   if (0 != count)
1622     return -1;
1623   count = clib_count_equal_u64 (s64, 1);
1624   if (1 != count)
1625     return -1;
1626   count = clib_count_equal_u64 (s64, 3);
1627   if (3 != count)
1628     return -1;
1629   count = clib_count_equal_u64 (s64, 15);
1630   if (15 != count)
1631     return -1;
1632   s64[10] = 0xcafe;
1633   count = clib_count_equal_u64 (s64, 13);
1634   if (10 != count)
1635     return -1;
1636   s64[10] = 0;
1637
1638   vlib_cli_output (vm, "Test clib_count_equal_u32...");
1639   memset (s32, 0, sizeof (s32));
1640   count = clib_count_equal_u32 (s32, 0);
1641   if (0 != count)
1642     return -1;
1643   count = clib_count_equal_u32 (s32, 1);
1644   if (1 != count)
1645     return -1;
1646   count = clib_count_equal_u32 (s32, 3);
1647   if (3 != count)
1648     return -1;
1649   count = clib_count_equal_u32 (s32, 31);
1650   if (31 != count)
1651     return -1;
1652   s32[10] = 0xcafe;
1653   count = clib_count_equal_u32 (s32, 13);
1654   if (10 != count)
1655     return -1;
1656   s32[10] = 0;
1657
1658   vlib_cli_output (vm, "Test clib_count_equal_u16...");
1659   memset (s16, 0, sizeof (s16));
1660   count = clib_count_equal_u16 (s16, 0);
1661   if (0 != count)
1662     return -1;
1663   count = clib_count_equal_u16 (s16, 1);
1664   if (1 != count)
1665     return -1;
1666   count = clib_count_equal_u16 (s16, 3);
1667   if (3 != count)
1668     return -1;
1669   count = clib_count_equal_u16 (s16, 63);
1670   if (63 != count)
1671     return -1;
1672   s16[10] = 0xcafe;
1673   count = clib_count_equal_u16 (s16, 13);
1674   if (10 != count)
1675     return -1;
1676   s16[10] = 0;
1677
1678   vlib_cli_output (vm, "Test clib_count_equal_u8...");
1679   memset (s8, 0, sizeof (s8));
1680   count = clib_count_equal_u8 (s8, 0);
1681   if (0 != count)
1682     return -1;
1683   count = clib_count_equal_u8 (s8, 1);
1684   if (1 != count)
1685     return -1;
1686   count = clib_count_equal_u8 (s8, 3);
1687   if (3 != count)
1688     return -1;
1689   count = clib_count_equal_u8 (s8, 127);
1690   if (127 != count)
1691     return -1;
1692   s8[10] = 0xfe;
1693   count = clib_count_equal_u8 (s8, 13);
1694   if (10 != count)
1695     return -1;
1696   s8[10] = 0;
1697
1698   return 0;
1699 }
1700
1701
1702 #define foreach_string_test                               \
1703   _ (0, MEMCPY_S, "memcpy_s", memcpy_s)                   \
1704   _ (1, CLIB_MEMCPY, "clib_memcpy", clib_memcpy)          \
1705   _ (2, MEMSET_S , "memset_s", memset_s)                  \
1706   _ (3, CLIB_MEMSET , "clib_memset", clib_memset)         \
1707   _ (4, MEMCMP_S, "memcmp_s", memcmp_s)                   \
1708   _ (5, CLIB_MEMCMP, "clib_memcmp", clib_memcmp)          \
1709   _ (6, STRCMP_S, "strcmp_s", strcmp_s)                   \
1710   _ (7, CLIB_STRCMP, "clib_strcmp", clib_strcmp)          \
1711   _ (8, STRNCMP_S, "strncmp_s", strncmp_s)                \
1712   _ (9, CLIB_STRNCMP, "clib_strncmp", clib_strncmp)       \
1713   _ (10, STRCPY_S, "strcpy_s", strcpy_s)                  \
1714   _ (11, CLIB_STRCPY, "clib_strcpy", clib_strcpy)         \
1715   _ (12, STRNCPY_S, "strncpy_s", strncpy_s)               \
1716   _ (13, CLIB_STRNCPY, "clib_strncpy", clib_strncpy)      \
1717   _ (14, STRCAT_S, "strcat_s", strcat_s)                  \
1718   _ (15, CLIB_STRCAT, "clib_strcat", clib_strcat)         \
1719   _ (16, STRNCAT_S, "strncat_s", strncat_s)               \
1720   _ (17, CLIB_STRNCAT, "clib_strncat", clib_strncat)      \
1721   _ (18, STRTOK_S, "strtok_s", strtok_s)                  \
1722   _ (19, CLIB_STRTOK, "clib_strtok", clib_strtok)         \
1723   _ (20, STRNLEN_S, "strnlen_s", strnlen_s)               \
1724   _ (21, CLIB_STRNLEN, "clib_strnlen", clib_strnlen)      \
1725   _ (22, STRSTR_S, "strstr_s", strstr_s)                  \
1726   _ (23, CLIB_STRSTR, "clib_strstr", clib_strstr)         \
1727   _ (24, CLIB_COUNT_EQUAL, "clib_count_equal", clib_count_equal)
1728
1729 typedef enum
1730 {
1731 #define _(v,f,s,p) STRING_TEST_##f = v,
1732   foreach_string_test
1733 #undef _
1734 #define STRING_TEST_FIRST       STRING_TEST_MEMCPY_S
1735 #define STRING_TEST_LAST        STRING_TEST_CLIB_COUNT_EQUAL
1736 } string_test_t;
1737
1738 static uword
1739 unformat_string_test (unformat_input_t * input, va_list * args)
1740 {
1741   u8 *r = va_arg (*args, u8 *);
1742
1743   if (0)
1744     ;
1745 #define _(v,f,s,p) else if (unformat (input, s)) *r = STRING_TEST_##f;
1746   foreach_string_test
1747 #undef _
1748     else
1749     return 0;
1750
1751   return 1;
1752 }
1753
1754 typedef int (*string_test_func) (vlib_main_t * vm, unformat_input_t * input);
1755
1756 typedef struct
1757 {
1758   string_test_func test;
1759 } string_test_func_t;
1760
1761 static clib_error_t *
1762 string_test_command_fn (vlib_main_t * vm,
1763                         unformat_input_t * input,
1764                         vlib_cli_command_t * cmd_arg)
1765 {
1766   string_test_func_t string_func[] = {
1767 #define _(v,f,s,p) { test_##p },
1768     foreach_string_test
1769 #undef _
1770   };
1771   const char *string_table[] = {
1772 #define _(v,f,s,p) s,
1773     foreach_string_test
1774 #undef _
1775   };
1776   int res = 0, ok;
1777   i8 specific_test = ~0;
1778
1779   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1780     {
1781       if (unformat (input, "%U", unformat_string_test, &specific_test))
1782         break;
1783       else
1784         return clib_error_return (0, "unknown input `%U'",
1785                                   format_unformat_error, input);
1786     }
1787
1788   if (specific_test == ~0)
1789     {
1790       for (specific_test = STRING_TEST_FIRST;
1791            specific_test <= STRING_TEST_LAST; specific_test++)
1792         {
1793           ok = (string_func[specific_test]).test (vm, input);
1794           res += ok;
1795           if (ok != 0)
1796             vlib_cli_output (vm, "test_%s failed",
1797                              string_table[specific_test]);
1798         }
1799     }
1800   else
1801     res = (string_func[specific_test]).test (vm, input);
1802   if (res)
1803     vlib_cli_output (vm, "String unit test(s) failed...");
1804   else
1805     vlib_cli_output (vm, "String unit test(s) OK...");
1806   return 0;
1807 }
1808
1809 /* *INDENT-OFF* */
1810 VLIB_CLI_COMMAND (string_test_command, static) =
1811 {
1812   .path = "test string",
1813   .short_help = "test string [memcpy_s | clib_memcpy | memset_s | "
1814   "clib_memset | memcmp_s | clib_memcmp | strcmp_s | clib_strcmp | "
1815   "strncmp_s | clib_strncmp | strcpy_s | clib_strcpy | strncpy_s | "
1816   "clib_strncpy | strcat_s | clib_strcat | strncat_s | clib_strncat | "
1817   "strtok_s |  clib_strtok | strnlen_s | clib_strnlen | strstr_s | "
1818   "clib_strstr | clib_count_equal ]",
1819   .function = string_test_command_fn,
1820 };
1821 /* *INDENT-ON* */
1822
1823 /*
1824  * fd.io coding-style-patch-verification: ON
1825  *
1826  * Local Variables:
1827  * eval: (c-set-style "gnu")
1828  * End:
1829  */