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