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