unittest: Skip string test case for sizeof (src) > sizeof (dst)
[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   indicator = clib_strncmp (s1, "Every moment is a fresh beginning",
512                             sizeof ("every moment is a fresh beginning") - 1);
513   if (indicator != 0)
514     return -1;
515   /* verify it against strncmp */
516   v_indicator = strncmp (s1, "Every moment is a fresh beginning",
517                          sizeof ("Every moment is a fresh beginning") - 1);
518   if (v_indicator != 0)
519     return -1;
520
521   /* OK, seems to work */
522   return 0;
523 }
524
525 static int
526 test_strcpy_s (vlib_main_t * vm, unformat_input_t * input)
527 {
528   char src[] = "To err is human.";
529   char dst[64];
530   int indicator;
531   size_t s1size = sizeof (dst); // including null
532   errno_t err;
533
534   vlib_cli_output (vm, "Test strcpy_s...");
535
536   err = strcpy_s (dst, s1size, src);
537   if (err != EOK)
538     return -1;
539
540   /* This better not fail but check anyhow */
541   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
542       EOK)
543     return -1;
544   if (indicator != 0)
545     return -1;
546
547   /* Negative tests */
548
549   err = strcpy_s (0, 0, 0);
550   if (err == EOK)
551     return -1;
552
553   /* Size fail */
554   err = strcpy_s (dst, 10, src);
555   if (err == EOK)
556     return -1;
557
558   /* overlap fail */
559 #if __GNUC__ < 8
560   /* GCC 8 flunks this one at compile time... */
561   err = strcpy_s (dst, s1size, dst);
562   if (err == EOK)
563     return -1;
564 #endif
565
566   /* overlap fail */
567   err = strcpy_s (dst, s1size, dst + 1);
568   if (err == EOK)
569     return -1;
570
571   /* OK, seems to work */
572   return 0;
573 }
574
575 static int
576 test_clib_strcpy (vlib_main_t * vm, unformat_input_t * input)
577 {
578   char src[] = "The journey of a one thousand miles begins with one step.";
579   char dst[100];
580   int indicator;
581   errno_t err;
582
583   vlib_cli_output (vm, "Test clib_strcpy...");
584
585   err = clib_strcpy (dst, src);
586   if (err != EOK)
587     return -1;
588
589   /* This better not fail but check anyhow */
590   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
591       EOK)
592     return -1;
593   if (indicator != 0)
594     return -1;
595
596   /* verify it against strcpy */
597   strcpy (dst, src);
598
599   /* This better not fail but check anyhow */
600   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
601       EOK)
602     return -1;
603   if (indicator != 0)
604     return -1;
605
606   /* Negative tests */
607
608   err = clib_strcpy (0, 0);
609   if (err == EOK)
610     return -1;
611
612   /* overlap fail */
613 #if __GNUC__ < 8
614   /* GCC 8 flunks this one at compile time... */
615   err = clib_strcpy (dst, dst);
616   if (err == EOK)
617     return -1;
618 #endif
619
620   /* overlap fail */
621   err = clib_strcpy (dst, dst + 1);
622   if (err == EOK)
623     return -1;
624
625   /* OK, seems to work */
626   return 0;
627 }
628
629 static int
630 test_strncpy_s (vlib_main_t * vm, unformat_input_t * input)
631 {
632   char src[] = "Those who dare to fail miserably can achieve greatly.";
633   char dst[100], old_dst[100];
634   int indicator, i;
635   size_t s1size = sizeof (dst); // including null
636   errno_t err;
637
638   vlib_cli_output (vm, "Test strncpy_s...");
639
640   /* dmax includes null, n excludes null */
641
642   /* n == string len of src */
643   err = strncpy_s (dst, s1size, src, clib_strnlen (src, sizeof (src)));
644   if (err != EOK)
645     return -1;
646   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
647       EOK)
648     return -1;
649   if (indicator != 0)
650     return -1;
651
652   /* limited copy -- strlen src > n, copy up to n */
653   err = strncpy_s (dst, s1size, "The price of greatness is responsibility.",
654                    10);
655   if (err != EOK)
656     return -1;
657   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
658                 &indicator) != EOK)
659     return -1;
660   if (indicator != 0)
661     return -1;
662
663   /* n > string len of src */
664   err = clib_memset (dst, 1, sizeof (dst));
665   if (err != EOK)
666     return -1;
667
668   err = strncpy_s (dst, s1size, src, clib_strnlen (src, sizeof (src)) + 10);
669   if (err != EOK)
670     return -1;
671   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
672       EOK)
673     return -1;
674   if (indicator != 0)
675     return -1;
676
677   /* Make sure bytes after strlen(dst) is untouched */
678   for (i = 1 + clib_strnlen (dst, sizeof (dst)); i < sizeof (dst); i++)
679     if (dst[i] != 1)
680       return -1;
681
682   /* truncation, n >= dmax */
683   err = strncpy_s (dst, clib_strnlen (src, sizeof (src)), src,
684                    clib_strnlen (src, sizeof (src)));
685   if (err != EOVERFLOW)
686     return -1;
687
688   /* Check dst content */
689   if (dst[strlen (dst)] != '\0')
690     return -1;
691   if (strncmp_s (dst, clib_strnlen (dst, sizeof (dst)), src,
692                  clib_strnlen (dst, sizeof (dst)), &indicator) != EOK)
693     return -1;
694   if (indicator != 0)
695     return -1;
696
697   /* zero length copy */
698   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
699   err = strncpy_s (dst, sizeof (dst), src, 0);
700   if (err != EOK)
701     return -1;
702   /* verify dst is untouched */
703   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), old_dst, &indicator) !=
704       EOK)
705     return -1;
706   if (indicator != 0)
707     return -1;
708
709   /* Negative tests */
710
711   err = strncpy_s (0, 0, 0, 1);
712   if (err == EOK)
713     return -1;
714
715   /* overlap fail */
716   err = strncpy_s (dst, s1size, dst + 1, s1size - 1);
717   if (err == EOK)
718     return -1;
719
720   /* overlap fail */
721 #if __GNUC__ < 8
722   /* GCC 8 flunks this one at compile time... */
723   err = strncpy_s (dst, s1size, dst, s1size);
724   if (err == EOK)
725     return -1;
726 #endif
727
728   /* OK, seems to work */
729   return 0;
730 }
731
732 static int
733 test_clib_strncpy (vlib_main_t * vm, unformat_input_t * input)
734 {
735   char src[] = "Those who dare to fail miserably can achieve greatly.";
736   char dst[100], old_dst[100];
737   int indicator;
738   size_t s1size = sizeof (dst); // including null
739   errno_t err;
740
741   vlib_cli_output (vm, "Test clib_strncpy...");
742
743   /* n == string len of src */
744   err = clib_strncpy (dst, src, clib_strnlen (src, sizeof (src)));
745   if (err != EOK)
746     return -1;
747
748   /* This better not fail but check anyhow */
749   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
750       EOK)
751     return -1;
752   if (indicator != 0)
753     return -1;
754
755   /* Verify it against strncpy */
756 #if __GNUC__ < 8
757   /* GCC 8 debian flunks this one at compile time */
758   strncpy (dst, src, strlen (src));
759
760   /* This better not fail but check anyhow */
761   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
762       EOK)
763     return -1;
764   if (indicator != 0)
765     return -1;
766 #endif
767
768   /* limited copy -- strlen src > n, copy up to n */
769   err = clib_strncpy (dst, "The price of greatness is responsibility.", 10);
770   if (err != EOK)
771     return -1;
772   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
773                 &indicator) != EOK)
774     return -1;
775   if (indicator != 0)
776     return -1;
777   /* verify it against strncpy */
778   memset_s (dst, sizeof (dst), 0, sizeof (dst));
779
780 #if __GNUC__ < 8
781   /* GCC 8 flunks this one at compile time... */
782   strncpy (dst, "The price of greatness is responsibility.", 10);
783   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
784                 &indicator) != EOK)
785     return -1;
786   if (indicator != 0)
787     return -1;
788 #endif
789
790   /* n > string len of src */
791   err = clib_strncpy (dst, src, clib_strnlen (src, sizeof (src)) + 10);
792   if (err != EOK)
793     return -1;
794   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
795       EOK)
796     return -1;
797   if (indicator != 0)
798     return -1;
799   /* Verify it against strncpy */
800 #if __GNUC__ < 8
801   /* GCC 8 debian flunks this one at compile time */
802   strncpy (dst, src, strlen (src));
803   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
804       EOK)
805     return -1;
806   if (indicator != 0)
807     return -1;
808 #endif
809
810   /* zero length copy */
811   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
812   err = clib_strncpy (dst, src, 0);
813   if (err != EOK)
814     return -1;
815   /* verify dst is untouched */
816   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), old_dst, &indicator) !=
817       EOK)
818     return -1;
819   if (indicator != 0)
820     return -1;
821
822   /* Negative tests */
823
824   err = clib_strncpy (0, 0, 1);
825   if (err == EOK)
826     return -1;
827
828   /* overlap fail */
829   err = clib_strncpy (dst, dst + 1, s1size);
830   if (err == EOK)
831     return -1;
832
833   /* overlap fail */
834 #if __GNUC__ < 8
835   /* GCC 8 flunks this one at compile time... */
836   err = clib_strncpy (dst, dst, s1size);
837   if (err == EOK)
838     return -1;
839 #endif
840
841   /* OK, seems to work */
842   return 0;
843 }
844
845 static int
846 test_strcat_s (vlib_main_t * vm, unformat_input_t * input)
847 {
848   char src[100], dst[100], old_dst[100];
849   size_t s1size = sizeof (dst); // including null
850   errno_t err;
851   int indicator;
852
853   vlib_cli_output (vm, "Test strcat_s...");
854
855   strcpy_s (dst, sizeof (dst), "Tough time never last ");
856   strcpy_s (src, sizeof (src), "but tough people do");
857   err = strcat_s (dst, s1size, src);
858   if (err != EOK)
859     return -1;
860   if (strcmp_s (dst, s1size - 1,
861                 "Tough time never last but tough people do",
862                 &indicator) != EOK)
863     return -1;
864   if (indicator != 0)
865     return -1;
866
867   /* empty string concatenation */
868   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
869   err = strcat_s (dst, s1size, "");
870   if (err != EOK)
871     return -1;
872   /* verify dst is untouched */
873   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
874     return -1;
875   if (indicator != 0)
876     return -1;
877
878   /* negative stuff */
879   err = strcat_s (0, 0, 0);
880   if (err != EINVAL)
881     return -1;
882
883   /* overlap fail */
884   err = strcat_s (dst, s1size, dst + 1);
885   if (err != EINVAL)
886     return -1;
887
888   /* overlap fail */
889 #if __GNUC__ < 8
890   /* GCC 8 flunks this one at compile time... */
891   err = strcat_s (dst, s1size, dst);
892   if (err != EINVAL)
893     return -1;
894 #endif
895
896   /* not enough space for dst */
897   err = strcat_s (dst, 10, src);
898   if (err != EINVAL)
899     return -1;
900
901   /* OK, seems to work */
902   return 0;
903 }
904
905 static int
906 test_clib_strcat (vlib_main_t * vm, unformat_input_t * input)
907 {
908   char src[100], dst[100], old_dst[100];
909   size_t s1size = sizeof (dst); // including null
910   errno_t err;
911   int indicator;
912
913   vlib_cli_output (vm, "Test clib_strcat...");
914
915   strcpy_s (dst, sizeof (dst), "Tough time never last ");
916   strcpy_s (src, sizeof (src), "but tough people do");
917   err = clib_strcat (dst, src);
918   if (err != EOK)
919     return -1;
920   if (strcmp_s (dst, s1size - 1,
921                 "Tough time never last but tough people do",
922                 &indicator) != EOK)
923     return -1;
924   if (indicator != 0)
925     return -1;
926   /* verify it against strcat */
927   strcpy_s (dst, sizeof (dst), "Tough time never last ");
928   strcpy_s (src, sizeof (src), "but tough people do");
929   strcat (dst, src);
930   if (strcmp_s (dst, s1size - 1,
931                 "Tough time never last but tough people do",
932                 &indicator) != EOK)
933     return -1;
934   if (indicator != 0)
935     return -1;
936
937   /* empty string concatenation */
938   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
939   err = clib_strcat (dst, "");
940   if (err != EOK)
941     return -1;
942   /* verify dst is untouched */
943   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
944     return -1;
945   if (indicator != 0)
946     return -1;
947
948   /* negative stuff */
949   err = clib_strcat (0, 0);
950   if (err != EINVAL)
951     return -1;
952
953   /* overlap fail */
954   err = clib_strcat (dst, dst + 1);
955   if (err != EINVAL)
956     return -1;
957
958   /* overlap fail */
959 #if __GNUC__ < 8
960   /* GCC 8 flunks this one at compile time... */
961   err = clib_strcat (dst, dst);
962   if (err != EINVAL)
963     return -1;
964 #endif
965
966   /* OK, seems to work */
967   return 0;
968 }
969
970 static int
971 test_strncat_s (vlib_main_t * vm, unformat_input_t * input)
972 {
973   char src[100], dst[100], old_dst[100];
974   size_t s1size = sizeof (dst); // including null
975   errno_t err;
976   char s1[] = "Two things are infinite: ";
977   char s2[] = "the universe and human stupidity; ";
978   char s3[] = "I am not sure about the universe.";
979   int indicator;
980
981   vlib_cli_output (vm, "Test strncat_s...");
982
983   strcpy_s (dst, sizeof (dst), s1);
984   strcpy_s (src, sizeof (src), s2);
985   err = strncat_s (dst, s1size, src, clib_strnlen (src, sizeof (src)));
986   if (err != EOK)
987     return -1;
988   if (strcmp_s (dst, s1size - 1,
989                 "Two things are infinite: the universe and human stupidity; ",
990                 &indicator) != EOK)
991     return -1;
992   if (indicator != 0)
993     return -1;
994
995   /* truncation, n >= dmax - strnlen_s (dst, dmax) */
996   err = strncat_s (dst, clib_strnlen (dst, sizeof (dst)) +
997                    clib_strnlen (s3, sizeof (s3)), s3,
998                    clib_strnlen (s3, sizeof (s3)));
999   if (err != EOVERFLOW)
1000     return -1;
1001   /*
1002    * resulting string is dst + strlen (s3) - 1 characters + null.
1003    * notice the "." is missing at the end of the resulting string because
1004    * the space is needed to accommodate the null
1005    * Notice strcmp_s will check s1 or dst to make sure it is null terminated
1006    */
1007   if (strcmp_s (dst, s1size - 1,
1008                 "Two things are infinite: the universe and human stupidity; "
1009                 "I am not sure about the universe", &indicator) != EOK)
1010     return -1;
1011   if (indicator != 0)
1012     return -1;
1013
1014   /* n > strlen src */
1015   strcpy_s (dst, sizeof (dst), s1);
1016   err = strncat_s (dst, s1size, src, clib_strnlen (src, sizeof (src)) + 10);
1017   if (err != EOK)
1018     return -1;
1019   if (strcmp_s (dst, s1size - 1,
1020                 "Two things are infinite: the universe and human stupidity; ",
1021                 &indicator) != EOK)
1022     return -1;
1023   if (indicator != 0)
1024     return -1;
1025
1026   /* zero length strncat */
1027   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
1028   err = strncat_s (dst, sizeof (dst), src, 0);
1029   if (err != EOK)
1030     return -1;
1031   /* verify dst is untouched */
1032   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1033     return -1;
1034   if (indicator != 0)
1035     return -1;
1036
1037   /* empty string, wrong n concatenation */
1038   err = strncat_s (dst, sizeof (dst), "", 10);
1039   if (err != EOK)
1040     return -1;
1041   /* verify dst is untouched */
1042   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1043     return -1;
1044   if (indicator != 0)
1045     return -1;
1046
1047   /* limited concatenation, string > n, copy up to n */
1048   strcpy_s (dst, sizeof (dst), s1);
1049   err = strncat_s (dst, s1size, s2, 13);
1050   if (err != EOK)
1051     return -1;
1052   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1053                 &indicator) != EOK)
1054     return -1;
1055   if (indicator != 0)
1056     return -1;
1057   /* verify it against strncat */
1058 #if __GNUC__ < 8
1059   /* GCC 8 debian flunks this one at compile time */
1060   strcpy_s (dst, sizeof (dst), s1);
1061   strncat (dst, s2, 13);
1062   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1063                 &indicator) != EOK)
1064     return -1;
1065   if (indicator != 0)
1066     return -1;
1067 #endif
1068
1069   /* negative stuff */
1070   err = strncat_s (0, 0, 0, 1);
1071   if (err != EINVAL)
1072     return -1;
1073
1074   /* no room for dst -- dmax - strnlen_s (dst, dmax) == 0 */
1075   err = strncat_s (dst, clib_strnlen (dst, sizeof (dst)), s2,
1076                    clib_strnlen (s2, sizeof (s2)));
1077   if (err != EINVAL)
1078     return -1;
1079
1080   /* overlap fail */
1081   err = strncat_s (dst, s1size, dst + 1, clib_strnlen (dst + 1, s1size - 1));
1082   if (err != EINVAL)
1083     return -1;
1084
1085   /* overlap fail */
1086 #if __GNUC__ < 8
1087   /* GCC 8 flunks this one at compile time... */
1088   err = strncat_s (dst, s1size, dst, clib_strnlen (dst, sizeof (dst)));
1089   if (err != EINVAL)
1090     return -1;
1091 #endif
1092
1093   /* OK, seems to work */
1094   return 0;
1095 }
1096
1097 static int
1098 test_clib_strncat (vlib_main_t * vm, unformat_input_t * input)
1099 {
1100   char src[100], dst[100], old_dst[100];
1101   size_t s1size = sizeof (dst); // including null
1102   errno_t err;
1103   char s1[] = "Two things are infinite: ";
1104   char s2[] = "the universe and human stupidity; ";
1105   int indicator;
1106
1107   vlib_cli_output (vm, "Test clib_strncat...");
1108
1109   /* n == strlen src */
1110   strcpy_s (dst, sizeof (dst), s1);
1111   strcpy_s (src, sizeof (src), s2);
1112   err = clib_strncat (dst, src, clib_strnlen (src, sizeof (src)));
1113   if (err != EOK)
1114     return -1;
1115   if (strcmp_s (dst, s1size - 1,
1116                 "Two things are infinite: the universe and human stupidity; ",
1117                 &indicator) != EOK)
1118     return -1;
1119   if (indicator != 0)
1120     return -1;
1121   /* verify it against strncat */
1122   strcpy_s (dst, sizeof (dst), s1);
1123   strncat (dst, src, clib_strnlen (src, sizeof (src)));
1124   if (strcmp_s (dst, s1size - 1,
1125                 "Two things are infinite: the universe and human stupidity; ",
1126                 &indicator) != EOK)
1127     return -1;
1128   if (indicator != 0)
1129     return -1;
1130
1131   /* n > strlen src */
1132   strcpy_s (dst, sizeof (dst), s1);
1133   err = clib_strncat (dst, src, clib_strnlen (src, sizeof (src)) + 10);
1134   if (err != EOK)
1135     return -1;
1136   if (strcmp_s (dst, s1size - 1,
1137                 "Two things are infinite: the universe and human stupidity; ",
1138                 &indicator) != EOK)
1139     return -1;
1140   if (indicator != 0)
1141     return -1;
1142   /* verify it against strncat */
1143   strcpy_s (dst, sizeof (dst), s1);
1144   strncat (dst, src, clib_strnlen (src, sizeof (src)));
1145   if (strcmp_s (dst, s1size - 1,
1146                 "Two things are infinite: the universe and human stupidity; ",
1147                 &indicator) != EOK)
1148     return -1;
1149   if (indicator != 0)
1150     return -1;
1151
1152   /* zero length strncat */
1153   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
1154   err = clib_strncat (dst, src, 0);
1155   if (err != EOK)
1156     return -1;
1157   /* verify dst is untouched */
1158   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1159     return -1;
1160   if (indicator != 0)
1161     return -1;
1162
1163   /* empty string, wrong n concatenation */
1164   err = clib_strncat (dst, "", 10);
1165   if (err != EOK)
1166     return -1;
1167   /* verify dst is untouched */
1168   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1169     return -1;
1170   if (indicator != 0)
1171     return -1;
1172
1173   /* limited concatenation, string > n, copy up to n */
1174   strcpy_s (dst, sizeof (dst), s1);
1175   err = clib_strncat (dst, s2, 13);
1176   if (err != EOK)
1177     return -1;
1178   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1179                 &indicator) != EOK)
1180     return -1;
1181   if (indicator != 0)
1182     return -1;
1183   /* verify it against strncat */
1184 #if __GNUC__ < 8
1185   /* GCC 8 debian flunks this one at compile time */
1186   strcpy_s (dst, sizeof (dst), s1);
1187   strncat (dst, s2, 13);
1188   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1189                 &indicator) != EOK)
1190     return -1;
1191   if (indicator != 0)
1192     return -1;
1193 #endif
1194
1195   /* negative stuff */
1196   err = clib_strncat (0, 0, 1);
1197   if (err != EINVAL)
1198     return -1;
1199
1200   /* overlap fail */
1201   err = clib_strncat (dst, dst + 1, s1size - 1);
1202   if (err != EINVAL)
1203     return -1;
1204
1205   /* overlap fail */
1206 #if __GNUC__ < 8
1207   /* GCC 8 flunks this one at compile time... */
1208   err = clib_strncat (dst, dst, clib_strnlen (dst, sizeof (dst)));
1209   if (err != EINVAL)
1210     return -1;
1211 #endif
1212
1213   /* OK, seems to work */
1214   return 0;
1215 }
1216
1217 static int
1218 test_strtok_s (vlib_main_t * vm, unformat_input_t * input)
1219 {
1220   int indicator;
1221   char *tok, *ptr;
1222   char str2[20];
1223   char str1[40];
1224   uword len;
1225   char *p2str = 0;
1226   char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7;
1227
1228   vlib_cli_output (vm, "Test strtok_s...");
1229   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1230   len = strnlen_s (str1, sizeof (str1));
1231   tok1 = strtok_s (str1, &len, " ", &p2str);
1232   tok2 = strtok_s (0, &len, " ", &p2str);
1233   tok3 = strtok_s (0, &len, " ", &p2str);
1234   tok4 = strtok_s (0, &len, " ", &p2str);
1235   tok5 = strtok_s (0, &len, " ", &p2str);
1236   tok6 = strtok_s (0, &len, " ", &p2str);
1237   tok7 = strtok_s (0, &len, " ", &p2str);
1238   if ((tok1 == 0) ||
1239       strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
1240     return -1;
1241   if (indicator != 0)
1242     return -1;
1243   if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
1244     return -1;
1245   if (indicator != 0)
1246     return -1;
1247   if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
1248     return -1;
1249   if (indicator != 0)
1250     return -1;
1251   if ((tok4 == 0)
1252       || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
1253     return -1;
1254   if (indicator != 0)
1255     return -1;
1256   if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
1257     return -1;
1258   if (indicator != 0)
1259     return -1;
1260   if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
1261     return -1;
1262   if (indicator != 0)
1263     return -1;
1264   if (tok7 != 0)
1265     return -1;
1266
1267   /* delimiter not present in the string -- the whole string is returned */
1268   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1269   len = strnlen_s (str1, sizeof (str1) - 1);
1270   p2str = 0;
1271   tok1 = strtok_s (str1, &len, ",", &p2str);
1272   if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
1273     return -1;
1274   if (indicator != 0)
1275     return -1;
1276
1277   /* negative stuff */
1278   tok = strtok_s (0, 0, 0, 0);
1279   if (tok != 0)
1280     return -1;
1281
1282   /* s1 and ptr contents are null */
1283   ptr = 0;
1284   tok = strtok_s (0, 0, 0, &ptr);
1285   if (tok != 0)
1286     return -1;
1287
1288   /* unterminate s1 */
1289   p2str = 0;
1290   len = strnlen_s (str1, sizeof (str1) - 1);
1291   str1[strlen (str1)] = 0x2;
1292   tok = strtok_s (str1, &len, ",", &p2str);
1293   if (tok != 0)
1294     return -1;
1295
1296   /*
1297    * unterminated s2. This test case in not perfect because there is no
1298    * argument for s2max. But s2 len is limited to 16 characters. If the API
1299    * does not find the null character at s2[15], it declares the string s2
1300    * as unterminated.
1301    */
1302   memset_s (str2, sizeof (str2), 0xfa, sizeof (str2));
1303   tok = strtok_s (str1, &len, str2, &p2str);
1304   if (tok != 0)
1305     return -1;
1306
1307   /* OK, seems to work */
1308   return 0;
1309 }
1310
1311 static int
1312 test_clib_strtok (vlib_main_t * vm, unformat_input_t * input)
1313 {
1314   int indicator;
1315   char *s1 __attribute__ ((unused));
1316   char *tok __attribute__ ((unused));
1317   char *ptr __attribute__ ((unused));
1318   char str1[40];
1319   char *p2str;
1320   char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7;
1321
1322   vlib_cli_output (vm, "Test clib_strtok...");
1323   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1324   p2str = 0;
1325   tok1 = clib_strtok (str1, " ", &p2str);
1326   tok2 = clib_strtok (0, " ", &p2str);
1327   tok3 = clib_strtok (0, " ", &p2str);
1328   tok4 = clib_strtok (0, " ", &p2str);
1329   tok5 = clib_strtok (0, " ", &p2str);
1330   tok6 = clib_strtok (0, " ", &p2str);
1331   tok7 = clib_strtok (0, " ", &p2str);
1332   if ((tok1 == 0) ||
1333       strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
1334     return -1;
1335   if (indicator != 0)
1336     return -1;
1337   if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
1338     return -1;
1339   if (indicator != 0)
1340     return -1;
1341   if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
1342     return -1;
1343   if (indicator != 0)
1344     return -1;
1345   if ((tok4 == 0)
1346       || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
1347     return -1;
1348   if (indicator != 0)
1349     return -1;
1350   if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
1351     return -1;
1352   if (indicator != 0)
1353     return -1;
1354   if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
1355     return -1;
1356   if (indicator != 0)
1357     return -1;
1358   if (tok7 != 0)
1359     return -1;
1360   /* verify it againest strtok_r */
1361   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1362   p2str = 0;
1363   tok1 = strtok_r (str1, " ", &p2str);
1364   tok2 = strtok_r (0, " ", &p2str);
1365   tok3 = strtok_r (0, " ", &p2str);
1366   tok4 = strtok_r (0, " ", &p2str);
1367   tok5 = strtok_r (0, " ", &p2str);
1368   tok6 = strtok_r (0, " ", &p2str);
1369   tok7 = strtok_r (0, " ", &p2str);
1370   if ((tok1 == 0) ||
1371       strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
1372     return -1;
1373   if (indicator != 0)
1374     return -1;
1375   if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
1376     return -1;
1377   if (indicator != 0)
1378     return -1;
1379   if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
1380     return -1;
1381   if (indicator != 0)
1382     return -1;
1383   if ((tok4 == 0)
1384       || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
1385     return -1;
1386   if (indicator != 0)
1387     return -1;
1388   if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
1389     return -1;
1390   if (indicator != 0)
1391     return -1;
1392   if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
1393     return -1;
1394   if (indicator != 0)
1395     return -1;
1396   if (tok7 != 0)
1397     return -1;
1398
1399   /* delimiter not present in the string -- the whole string is returned */
1400   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1401   p2str = 0;
1402   tok1 = clib_strtok (str1, ",", &p2str);
1403   if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
1404     return -1;
1405   if (indicator != 0)
1406     return -1;
1407   /* verify it against strtok_r */
1408   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1409   p2str = 0;
1410   tok1 = strtok_r (str1, ",", &p2str);
1411   if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
1412     return -1;
1413   if (indicator != 0)
1414     return -1;
1415
1416   /* negative stuff */
1417   s1 = 0;
1418   ptr = 0;
1419 #if __GNUC__ < 8
1420   /* GCC 8 flunks this one at compile time... */
1421   tok = clib_strtok (s1, s1, (char **) 0);
1422   if (tok != 0)
1423     return -1;
1424
1425   /* s1 and ptr contents are null */
1426   tok = clib_strtok (s1, s1, &ptr);
1427   if (tok != 0)
1428     return -1;
1429 #endif
1430
1431   /* verify it against strtok_r */
1432   /* No can do. This causes a crash in strtok_r */
1433   // tok = strtok_r (s1, " ", &ptr);
1434   // if (tok != 0)
1435   //  return -1;
1436
1437   /*
1438    * Can't test unterminated string s1 and s2 becuase clib_strtok does not
1439    * supply s1 and s2 max
1440    */
1441
1442   /* OK, seems to work */
1443   return 0;
1444 }
1445
1446 static int
1447 test_strnlen_s (vlib_main_t * vm, unformat_input_t * input)
1448 {
1449   const char s1[] = "Truth is incontrovertible";
1450   size_t len;
1451
1452   vlib_cli_output (vm, "Test strnlen_s...");
1453
1454   len = strnlen_s (s1, sizeof (s1));
1455   if (len != sizeof (s1) - 1)
1456     return -1;
1457
1458   len = strnlen_s (s1, 5);
1459   if (len != 5)
1460     return -1;
1461
1462   /* negative stuff */
1463   len = strnlen_s (0, 0);
1464   if (len != 0)
1465     return -1;
1466
1467   /* OK, seems to work */
1468   return 0;
1469 }
1470
1471 static int
1472 test_clib_strnlen (vlib_main_t * vm, unformat_input_t * input)
1473 {
1474   const char s1[] = "Truth is incontrovertible";
1475   size_t len;
1476
1477   vlib_cli_output (vm, "Test clib_strnlen...");
1478
1479   len = clib_strnlen (s1, sizeof (s1));
1480   if (len != sizeof (s1) - 1)
1481     return -1;
1482
1483   len = clib_strnlen (s1, 5);
1484   if (len != 5)
1485     return -1;
1486
1487   /* negative stuff */
1488   len = clib_strnlen (0, 0);
1489   if (len != 0)
1490     return -1;
1491
1492   /* OK, seems to work */
1493   return 0;
1494 }
1495
1496 static int
1497 test_strstr_s (vlib_main_t * vm, unformat_input_t * input)
1498 {
1499   errno_t err;
1500   char *sub = 0;
1501   char s1[64];
1502   size_t s1len = sizeof (s1) - 1;       // excluding null
1503   int indicator;
1504
1505   vlib_cli_output (vm, "Test strstr_s...");
1506
1507   /* substring not present */
1508   strcpy_s (s1, s1len, "success is not final, failure is not fatal.");
1509   err = strstr_s (s1, s1len, "failures", sizeof ("failures"), &sub);;
1510   if (err != ESRCH)
1511     return -1;
1512
1513   /* substring present */
1514   err = strstr_s (s1, s1len, "failure", sizeof ("failure"), &sub);
1515   if (err != EOK)
1516     return -1;
1517
1518   if ((sub == 0) ||
1519       strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator)
1520       != EOK)
1521     return -1;
1522   if (indicator != 0)
1523     return -1;
1524
1525   /* negative stuff */
1526
1527   /* Null pointers test */
1528   err = strstr_s (0, 0, 0, 0, 0);
1529   if (err != EINVAL)
1530     return -1;
1531
1532   /* unterminated s1 and s2 */
1533   memset_s (s1, ARRAY_LEN (s1), 0xfe, ARRAY_LEN (s1));
1534   err = strstr_s (s1, s1len, s1, s1len, &sub);
1535   if (err != EINVAL)
1536     return -1;
1537
1538   /* OK, seems to work */
1539   return 0;
1540 }
1541
1542 static int
1543 test_clib_strstr (vlib_main_t * vm, unformat_input_t * input)
1544 {
1545   char *sub, *s;
1546   char s1[64];
1547   size_t s1len = sizeof (s1) - 1;       // excluding null
1548   int indicator;
1549
1550   vlib_cli_output (vm, "Test clib_strstr...");
1551
1552   /* substring not present */
1553   strcpy_s (s1, s1len, "success is not final, failure is not fatal.");
1554   sub = clib_strstr (s1, "failures");
1555   if (sub != 0)
1556     return -1;
1557   /* verify it against strstr */
1558   sub = strstr (s1, "failures");
1559   if (sub != 0)
1560     return -1;
1561
1562   /* substring present */
1563   sub = clib_strstr (s1, "failure");
1564   if (sub == 0)
1565     return -1;
1566   if (strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator) !=
1567       EOK)
1568     return -1;
1569   if (indicator != 0)
1570     return -1;
1571   /* verify it against strstr */
1572   sub = strstr (s1, "failure");
1573   if (sub == 0)
1574     return -1;
1575   if (strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator) !=
1576       EOK)
1577     return -1;
1578   if (indicator != 0)
1579     return -1;
1580
1581   /* negative stuff */
1582
1583   /* Null pointers test */
1584   s = 0;
1585   sub = clib_strstr (s, s);
1586   if (sub != 0)
1587     return -1;
1588   /*
1589    * Can't verify it against strstr for this test. Null pointers cause strstr
1590    * to crash. Go figure!
1591    */
1592
1593   /* unterminated s1 and s2 */
1594   memset_s (s1, ARRAY_LEN (s1), 0xfe, ARRAY_LEN (s1));
1595   sub = clib_strstr (s1, s1);
1596   if (sub == 0)
1597     return -1;
1598   /*
1599    * Can't verify it against strstr for this test. Unterminated string causes
1600    * strstr to crash. Go figure!
1601    */
1602
1603   /* OK, seems to work */
1604   return 0;
1605 }
1606
1607 #define foreach_string_test                               \
1608   _ (0, MEMCPY_S, "memcpy_s", memcpy_s)                   \
1609   _ (1, CLIB_MEMCPY, "clib_memcpy", clib_memcpy)          \
1610   _ (2, MEMSET_S , "memset_s", memset_s)                  \
1611   _ (3, CLIB_MEMSET , "clib_memset", clib_memset)         \
1612   _ (4, MEMCMP_S, "memcmp_s", memcmp_s)                   \
1613   _ (5, CLIB_MEMCMP, "clib_memcmp", clib_memcmp)          \
1614   _ (6, STRCMP_S, "strcmp_s", strcmp_s)                   \
1615   _ (7, CLIB_STRCMP, "clib_strcmp", clib_strcmp)          \
1616   _ (8, STRNCMP_S, "strncmp_s", strncmp_s)                \
1617   _ (9, CLIB_STRNCMP, "clib_strncmp", clib_strncmp)       \
1618   _ (10, STRCPY_S, "strcpy_s", strcpy_s)                  \
1619   _ (11, CLIB_STRCPY, "clib_strcpy", clib_strcpy)         \
1620   _ (12, STRNCPY_S, "strncpy_s", strncpy_s)               \
1621   _ (13, CLIB_STRNCPY, "clib_strncpy", clib_strncpy)      \
1622   _ (14, STRCAT_S, "strcat_s", strcat_s)                  \
1623   _ (15, CLIB_STRCAT, "clib_strcat", clib_strcat)         \
1624   _ (16, STRNCAT_S, "strncat_s", strncat_s)               \
1625   _ (17, CLIB_STRNCAT, "clib_strncat", clib_strncat)      \
1626   _ (18, STRTOK_S, "strtok_s", strtok_s)                  \
1627   _ (19, CLIB_STRTOK, "clib_strtok", clib_strtok)         \
1628   _ (20, STRNLEN_S, "strnlen_s", strnlen_s)               \
1629   _ (21, CLIB_STRNLEN, "clib_strnlen", clib_strnlen)      \
1630   _ (22, STRSTR_S, "strstr_s", strstr_s)                  \
1631   _ (23, CLIB_STRSTR, "clib_strstr", clib_strstr)
1632
1633 typedef enum
1634 {
1635 #define _(v,f,s,p) STRING_TEST_##f = v,
1636   foreach_string_test
1637 #undef _
1638 } string_test_t;
1639
1640 static uword
1641 unformat_string_test (unformat_input_t * input, va_list * args)
1642 {
1643   u8 *r = va_arg (*args, u8 *);
1644
1645   if (0)
1646     ;
1647 #define _(v,f,s,p) else if (unformat (input, s)) *r = STRING_TEST_##f;
1648   foreach_string_test
1649 #undef _
1650     else
1651     return 0;
1652
1653   return 1;
1654 }
1655
1656 typedef int (*string_test_func) (vlib_main_t * vm, unformat_input_t * input);
1657
1658 typedef struct
1659 {
1660   string_test_func test;
1661 } string_test_func_t;
1662
1663 static clib_error_t *
1664 string_test_command_fn (vlib_main_t * vm,
1665                         unformat_input_t * input,
1666                         vlib_cli_command_t * cmd_arg)
1667 {
1668   string_test_func_t string_func[] = {
1669 #define _(v,f,s,p) { test_##p },
1670     foreach_string_test
1671 #undef _
1672   };
1673   const char *string_table[] = {
1674 #define _(v,f,s,p) s,
1675     foreach_string_test
1676 #undef _
1677   };
1678   int res = 0, ok;
1679   i8 specific_test = ~0;
1680
1681   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1682     {
1683       if (unformat (input, "%U", unformat_string_test, &specific_test))
1684         break;
1685       else
1686         return clib_error_return (0, "unknown input `%U'",
1687                                   format_unformat_error, input);
1688     }
1689
1690   if (specific_test == ~0)
1691     {
1692       for (specific_test = STRING_TEST_MEMCPY_S;
1693            specific_test <= STRING_TEST_CLIB_STRSTR; specific_test++)
1694         {
1695           ok = (string_func[specific_test]).test (vm, input);
1696           res += ok;
1697           if (ok != 0)
1698             vlib_cli_output (vm, "test_%s failed",
1699                              string_table[specific_test]);
1700         }
1701     }
1702   else
1703     res = (string_func[specific_test]).test (vm, input);
1704   if (res)
1705     vlib_cli_output (vm, "String unit test(s) failed...");
1706   else
1707     vlib_cli_output (vm, "String unit test(s) OK...");
1708   return 0;
1709 }
1710
1711 /* *INDENT-OFF* */
1712 VLIB_CLI_COMMAND (string_test_command, static) =
1713 {
1714   .path = "test string",
1715   .short_help = "test string [memcpy_s | clib_memcpy | memset_s | "
1716   "clib_memset | memcmp_s | clib_memcmp | strcmp_s | clib_strcmp | "
1717   "strncmp_s | clib_strncmp | strcpy_s | clib_strcpy | strncpy_s | "
1718   "clib_strncpy | strcat_s | clib_strcat | strncat_s | clib_strncat | "
1719   "strtok_s |  clib_strtok | strnlen_s | clib_strnlen | strstr_s | "
1720   "clib_strstr]",
1721   .function = string_test_command_fn,
1722 };
1723 /* *INDENT-ON* */
1724
1725 /*
1726  * fd.io coding-style-patch-verification: ON
1727  *
1728  * Local Variables:
1729  * eval: (c-set-style "gnu")
1730  * End:
1731  */