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