summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorSteven <sluong@cisco.com>2018-10-24 21:15:45 -0700
committerDave Barach <dave@barachs.net>2018-12-02 08:47:46 -0500
commitb0598497afde60146fe8480331c9f96e7a79475a (patch)
treea3d9f454195cb9317fceb29efe62f5b62de89dea /src/plugins
parente7f61d1db511b9b09c7771c5851eaaf95a2fc7fe (diff)
vppinfra: c11 safe string functions
Add memcmp_s, strcmp_s, strncmp_s, strcpy_s, strncpy_s, strcat_s, strncat_s, strtok_s, strnlen_s, and strstr_s C11 safe string API. For migrating extant unsafe API, add also the corresponding macro version of each safe API, clib_memcmp, clib_strcmp, etc. In general, the benefits of the safe string APIs are to provide null pointer checks, add additional argument to specify the string length of the passed string rather than relying on the null terminated character, and src/dest overlap checking for the the string copy operations. The macro version of the API takes the same number of arguments as the unsafe API to provide easy migration. However, it does not usually provide the full aformentioned benefits. In some cases, it is necessary to move to the safe API rather than using the macro in order to avoid some unpredictable problems such as accessing memory beyond what it is intended due to the lack of the passed string length. dbarach: add a "make test" vector, and a doxygen file header cookie. Change-Id: I5cd79b8928dcf76a79bf3f0b8cbc1a8f24942f4c Signed-off-by: Steven <sluong@cisco.com> Signed-off-by: Dave Barach <dave@barachs.net>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/unittest/string_test.c1584
1 files changed, 1559 insertions, 25 deletions
diff --git a/src/plugins/unittest/string_test.c b/src/plugins/unittest/string_test.c
index a5caa9094f0..2beee139ec9 100644
--- a/src/plugins/unittest/string_test.c
+++ b/src/plugins/unittest/string_test.c
@@ -16,7 +16,7 @@
#include <vppinfra/string.h>
static int
-test_clib_memset (vlib_main_t * vm, unformat_input_t * input)
+test_memset_s (vlib_main_t * vm, unformat_input_t * input)
{
u8 dst[64];
int i;
@@ -42,7 +42,28 @@ test_clib_memset (vlib_main_t * vm, unformat_input_t * input)
}
static int
-test_memcpy (vlib_main_t * vm, unformat_input_t * input)
+test_clib_memset (vlib_main_t * vm, unformat_input_t * input)
+{
+ u8 dst[64];
+ int i;
+ errno_t err;
+
+ vlib_cli_output (vm, "Test clib_memset...");
+
+ err = clib_memset (dst, 0xfe, ARRAY_LEN (dst));
+
+ if (err != EOK)
+ return -1;
+
+ for (i = 0; i < ARRAY_LEN (dst); i++)
+ if (dst[i] != 0xFE)
+ return -1;
+
+ return 0;
+}
+
+static int
+test_memcpy_s (vlib_main_t * vm, unformat_input_t * input)
{
char src[64], dst[64];
int i;
@@ -86,40 +107,1548 @@ test_memcpy (vlib_main_t * vm, unformat_input_t * input)
return 0;
}
+static int
+test_clib_memcpy (vlib_main_t * vm, unformat_input_t * input)
+{
+ char src[64], dst[64];
+ int i;
+ errno_t err;
+
+ vlib_cli_output (vm, "Test clib_memcpy...");
+
+ for (i = 0; i < ARRAY_LEN (src); i++)
+ src[i] = i + 1;
+
+ /* Typical case */
+ err = clib_memcpy (dst, src, sizeof (src));
+
+ if (err != EOK)
+ return -1;
+
+ /* This better not fail but check anyhow */
+ for (i = 0; i < ARRAY_LEN (dst); i++)
+ if (src[i] != dst[i])
+ return -1;
+ /* verify it against memcpy */
+ memcpy (dst, src, sizeof (src));
+
+ /* This better not fail but check anyhow */
+ for (i = 0; i < ARRAY_LEN (dst); i++)
+ if (src[i] != dst[i])
+ return -1;
+
+ /* Zero length copy */
+ err = clib_memcpy (0, src, 0);
+
+ if (err != EOK)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_memcmp_s (vlib_main_t * vm, unformat_input_t * input)
+{
+ char src[64], dst[64];
+ errno_t err;
+ int diff = 0;
+
+ vlib_cli_output (vm, "Test memcmp_s...");
+
+ /* Fill array with different values */
+ err = clib_memset (src, 0x1, ARRAY_LEN (src));
+ if (err != EOK)
+ return -1;
+ err = clib_memset (dst, 0x3, ARRAY_LEN (dst));
+ if (err != EOK)
+ return -1;
+
+ /* s1 > s2, > 0 is expected in diff */
+ err = memcmp_s (dst, ARRAY_LEN (dst), src, ARRAY_LEN (src), &diff);
+ if (err != EOK)
+ return -1;
+ if (!(diff > 0))
+ return -1;
+
+ /* s1 < s2, < 0 is expected in diff */
+ err = memcmp_s (src, ARRAY_LEN (src), dst, ARRAY_LEN (dst), &diff);
+ if (err != EOK)
+ return -1;
+ if (!(diff < 0))
+ return -1;
+
+ err = clib_memset (dst, 0x1, ARRAY_LEN (dst));
+ if (err != EOK)
+ return -1;
+
+ /* s1 == s2, 0 is expected in diff */
+ err = memcmp_s (src, ARRAY_LEN (src), dst, ARRAY_LEN (dst), &diff);
+ if (err != EOK)
+ return -1;
+ if (diff != 0)
+ return -1;
+
+ /* Try negative tests */
+ err = memcmp_s (0, 0, 0, 0, 0);
+ if (err != EINVAL)
+ return -1;
+
+ /* Try s2max > s1max */
+ err = memcmp_s (src, ARRAY_LEN (src) - 1, dst, ARRAY_LEN (dst), &diff);
+ if (err != EINVAL)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_clib_memcmp (vlib_main_t * vm, unformat_input_t * input)
+{
+ char src[64], dst[64];
+ errno_t err;
+ char *s;
+
+ vlib_cli_output (vm, "Test clib_memcmp...");
+
+ /* Fill array with different values */
+ err = clib_memset (src, 0x1, ARRAY_LEN (src));
+ if (err != EOK)
+ return -1;
+ err = clib_memset (dst, 0x3, ARRAY_LEN (dst));
+ if (err != EOK)
+ return -1;
+
+ /* s1 > s2, > 0 is expected in diff */
+ if (!(clib_memcmp (dst, src, ARRAY_LEN (src)) > 0))
+ return -1;
+ /* verify it against memcmp */
+ if (!(memcmp (dst, src, ARRAY_LEN (src)) > 0))
+ return -1;
+
+ /* s1 < s2, < 0 is expected in diff */
+ if (!(clib_memcmp (src, dst, ARRAY_LEN (dst)) < 0))
+ return -1;
+ /* verify it against memcmp */
+ if (!(memcmp (src, dst, ARRAY_LEN (dst)) < 0))
+ return -1;
+
+ err = clib_memset (dst, 0x1, ARRAY_LEN (dst));
+ if (err != EOK)
+ return -1;
+
+ /* s1 == s2, 0 is expected in diff */
+ if (clib_memcmp (src, dst, ARRAY_LEN (dst)) != 0)
+ return -1;
+ /* verify it against memcmp */
+ if (memcmp (src, dst, ARRAY_LEN (dst)) != 0)
+ return -1;
+
+ /* Try negative tests */
+ s = 0;
+ if (clib_memcmp (s, s, 0) != 0)
+ return -1;
+ /* verify it against memcmp */
+ if (memcmp (s, s, 0) != 0)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_strcmp_s (vlib_main_t * vm, unformat_input_t * input)
+{
+ char s1[] = "Simplicity is the ultimate sophistication";
+ uword s1len = sizeof (s1) - 1; // excluding null
+ errno_t err;
+ int indicator = 0;
+
+ vlib_cli_output (vm, "Test strcmp_s...");
+
+ /* s1 == s2, 0 is expected */
+ err = strcmp_s (s1, s1len, "Simplicity is the ultimate sophistication",
+ &indicator);
+ if (err != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* s1 > s2, > 0 is expected */
+ err = strcmp_s (s1, s1len, "Simplicity is the ultimate", &indicator);
+ if (err != EOK)
+ return -1;
+ if (!(indicator > 0))
+ return -1;
+
+ /* s1 < s2, < 0 is expected */
+ err = strcmp_s (s1, s1len, "Simplicity is the ultimate sophistication!",
+ &indicator);
+ if (err != EOK)
+ return -1;
+ if (!(indicator < 0))
+ return -1;
+
+ /* Try some negative tests */
+
+ /* Null pointers test */
+ err = strcmp_s (0, 0, 0, 0);
+ if (err != EINVAL)
+ return -1;
+
+ /* non-null terminated s1 */
+ s1[s1len] = 0x1;
+ err = strcmp_s (s1, s1len, "Simplicity is the ultimate sophistication",
+ &indicator);
+ if (err != EINVAL)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_clib_strcmp (vlib_main_t * vm, unformat_input_t * input)
+{
+ char s1[] = "Simplicity is the ultimate sophistication";
+ int indicator;
+ char *s;
+
+ vlib_cli_output (vm, "Test clib_strcmp...");
+
+ /* s1 == s2, 0 is expected */
+ indicator = clib_strcmp (s1, "Simplicity is the ultimate sophistication");
+ if (indicator != 0)
+ return -1;
+ /* verify it against strcmp */
+ indicator = strcmp (s1, "Simplicity is the ultimate sophistication");
+ if (indicator != 0)
+ return -1;
+
+ /* s1 > s2, > 0 is expected */
+ indicator = clib_strcmp (s1, "Simplicity is the ultimate");
+ if (!(indicator > 0))
+ return -1;
+ /* verify it against strcmp */
+ indicator = strcmp (s1, "Simplicity is the ultimate");
+ if (!(indicator > 0))
+ return -1;
+
+ /* s1 < s2, < 0 is expected */
+ indicator = clib_strcmp (s1, "Simplicity is the ultimate sophistication!");
+ if (!(indicator < 0))
+ return -1;
+ /* verify it against strcmp */
+ indicator = strcmp (s1, "Simplicity is the ultimate sophistication!");
+ if (!(indicator < 0))
+ return -1;
+
+ /* Try some negative tests */
+
+ /* Null pointers comparison */
+ s = 0;
+ indicator = clib_strcmp (s, s);
+ if (indicator != 0)
+ return -1;
+ /* verify it against strcmp */
+ indicator = strcmp (s, s);
+ if (indicator != 0)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_strncmp_s (vlib_main_t * vm, unformat_input_t * input)
+{
+ char s1[] = "Every moment is a fresh beginning";
+ uword s1len = sizeof (s1) - 1; // excluding null
+ errno_t err;
+ int indicator = 0;
+
+ vlib_cli_output (vm, "Test strncmp_s...");
+
+ /* s1 == s2, 0 is expected */
+ err = strncmp_s (s1, s1len, "Every moment is a fresh beginning", s1len,
+ &indicator);
+ if (err != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* s1 > s2, 0 is expected since comparison is no more than n character */
+ err = strncmp_s (s1, s1len, "Every moment is a fresh begin",
+ sizeof ("Every moment is a fresh begin") - 1, &indicator);
+ if (err != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* s1 < s2, < 0 is expected */
+ err = strncmp_s (s1, s1len, "Every moment is fresh beginning",
+ sizeof ("Every moment is fresh beginning") - 1,
+ &indicator);
+ if (err != EOK)
+ return -1;
+ if (!(indicator < 0))
+ return -1;
+
+ /* s1 > s2, > 0 is expected */
+ err = strncmp_s ("Every moment is fresh beginning. ",
+ sizeof ("Every moment is fresh beginning. ") - 1, s1,
+ s1len, &indicator);
+ if (err != EOK)
+ return -1;
+ if (!(indicator > 0))
+ return -1;
+
+ /* Try some negative tests */
+
+ /* Null pointers */
+ err = strncmp_s (0, 0, 0, 0, 0);
+ if (err != EINVAL)
+ return -1;
+
+ /* n > s1max */
+ err = strncmp_s (s1, s1len, "Every moment is a fresh beginning", s1len + 1,
+ &indicator);
+ if (err != EINVAL)
+ return -1;
+
+ /* unterminated s1 */
+ s1[s1len] = 0x1;
+ err = strncmp_s (s1, s1len, "Every moment is a fresh beginning",
+ sizeof ("Every moment is a fresh beginning") - 1,
+ &indicator);
+ if (err != EINVAL)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_clib_strncmp (vlib_main_t * vm, unformat_input_t * input)
+{
+ char s1[] = "Every moment is a fresh beginning";
+ uword s1len = sizeof (s1) - 1; // excluding null
+ int indicator, v_indicator;
+
+ vlib_cli_output (vm, "Test clib_strncmp...");
+
+ /* s1 == s2, 0 is expected */
+ indicator = clib_strncmp (s1, "Every moment is a fresh beginning", s1len);
+ if (indicator != 0)
+ return -1;
+ /* verify it against strncmp */
+ v_indicator = strncmp (s1, "Every moment is a fresh beginning", s1len);
+ if (v_indicator != 0)
+ return -1;
+ if (v_indicator != indicator)
+ return -1;
+
+ /* s1 > s2, 0 is expected since comparison is no more than n character */
+ indicator = clib_strncmp (s1, "Every moment is a fresh begin",
+ sizeof ("Every moment is a fresh begin") - 1);
+ if (indicator != 0)
+ return -1;
+ /* verify it against strncmp */
+ v_indicator = strncmp (s1, "Every moment is a fresh begin",
+ sizeof ("Every moment is a fresh begin") - 1);
+ if (v_indicator != 0)
+ return -1;
+ if (v_indicator != indicator)
+ return -1;
+
+ /* s1 < s2, < 0 is expected */
+ indicator = clib_strncmp (s1, "Every moment is fresh beginning",
+ sizeof ("Every moment is fresh beginning") - 1);
+ if (!(indicator < 0))
+ return -1;
+ /* verify it against strncmp */
+ v_indicator = strncmp (s1, "Every moment is fresh beginning",
+ sizeof ("Every moment is fresh beginning") - 1);
+ if (!(v_indicator < 0))
+ return -1;
+ if (v_indicator != indicator)
+ return -1;
+
+ /* s1 > s2, > 0 is expected */
+ indicator = clib_strncmp ("Every moment is fresh beginning. ", s1, s1len);
+ if (!(indicator > 0))
+ return -1;
+ /* verify it against strncmp */
+ v_indicator = strncmp ("Every moment is fresh beginning. ", s1, s1len);
+ if (!(v_indicator > 0))
+ return -1;
+ if (v_indicator != indicator)
+ return -1;
+
+ /* Try some negative tests */
+
+ /* Null pointers */
+
+ /* make sure we don't crash */
+ indicator = clib_strncmp (0, 0, 0);
+ if (indicator != EOK)
+ return -1;
+
+ /* n > s1 len */
+ indicator =
+ clib_strncmp (s1, "Every moment is a fresh beginning", s1len + 1);
+ if (indicator != 0)
+ return -1;
+ /* verify it against strncmp */
+ v_indicator = strncmp (s1, "Every moment is a fresh beginning", s1len + 1);
+ if (v_indicator != 0)
+ return -1;
+ if (v_indicator != indicator)
+ return -1;
+
+ /* unterminated s1 */
+ s1[s1len] = 0x1;
+ indicator = clib_strncmp (s1, "Every moment is a fresh beginning",
+ sizeof ("every moment is a fresh beginning") - 1);
+ if (indicator != 0)
+ return -1;
+ /* verify it against strncmp */
+ v_indicator = strncmp (s1, "Every moment is a fresh beginning",
+ sizeof ("Every moment is a fresh beginning") - 1);
+ if (v_indicator != 0)
+ return -1;
+ if (v_indicator != indicator)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_strcpy_s (vlib_main_t * vm, unformat_input_t * input)
+{
+ char src[] = "To err is human.";
+ char dst[64];
+ int indicator;
+ size_t s1size = sizeof (dst); // including null
+ errno_t err;
+
+ vlib_cli_output (vm, "Test strcpy_s...");
+
+ err = strcpy_s (dst, s1size, src);
+ if (err != EOK)
+ return -1;
+
+ /* This better not fail but check anyhow */
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* Negative tests */
+
+ err = strcpy_s (0, 0, 0);
+ if (err == EOK)
+ return -1;
+
+ /* Size fail */
+ err = strcpy_s (dst, 10, src);
+ if (err == EOK)
+ return -1;
+
+ /* overlap fail */
+ err = strcpy_s (dst, s1size, dst);
+ if (err == EOK)
+ return -1;
+
+ /* overlap fail */
+ err = strcpy_s (dst, s1size, dst + 1);
+ if (err == EOK)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_clib_strcpy (vlib_main_t * vm, unformat_input_t * input)
+{
+ char src[] = "The journey of a one thousand miles begins with one step.";
+ char dst[100];
+ int indicator;
+ errno_t err;
+
+ vlib_cli_output (vm, "Test clib_strcpy...");
+
+ err = clib_strcpy (dst, src);
+ if (err != EOK)
+ return -1;
+
+ /* This better not fail but check anyhow */
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* verify it against strcpy */
+ strcpy (dst, src);
+
+ /* This better not fail but check anyhow */
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* Negative tests */
+
+ err = clib_strcpy (0, 0);
+ if (err == EOK)
+ return -1;
+
+ /* overlap fail */
+ err = clib_strcpy (dst, dst);
+ if (err == EOK)
+ return -1;
+
+ /* overlap fail */
+ err = clib_strcpy (dst, dst + 1);
+ if (err == EOK)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_strncpy_s (vlib_main_t * vm, unformat_input_t * input)
+{
+ char src[] = "Those who dare to fail miserably can achieve greatly.";
+ char dst[100], old_dst[100];
+ int indicator;
+ size_t s1size = sizeof (dst); // including null
+ errno_t err;
+
+ vlib_cli_output (vm, "Test strncpy_s...");
+
+ /* dmax includes null, n excludes null */
+
+ /* n == string len of src */
+ err = strncpy_s (dst, s1size, src, clib_strnlen (src, sizeof (src)));
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* limited copy -- strlen src > n, copy up to n */
+ err = strncpy_s (dst, s1size, "The price of greatness is responsibility.",
+ 10);
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* n > string len of src */
+ err = strncpy_s (dst, s1size, src, clib_strnlen (src, sizeof (src)) + 10);
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* truncation, n >= dmax */
+ err = strncpy_s (dst, clib_strnlen (src, sizeof (src)), src,
+ clib_strnlen (src, sizeof (src)));
+ if (err != EOVERFLOW)
+ return -1;
+
+ /* Check dst content */
+ if (dst[strlen (dst)] != '\0')
+ return -1;
+ if (strncmp_s (dst, clib_strnlen (dst, sizeof (dst)), src,
+ clib_strnlen (dst, sizeof (dst)), &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* zero length copy */
+ clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
+ err = strncpy_s (dst, sizeof (dst), src, 0);
+ if (err != EOK)
+ return -1;
+ /* verify dst is untouched */
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), old_dst, &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* Negative tests */
+
+ err = strncpy_s (0, 0, 0, 1);
+ if (err == EOK)
+ return -1;
+
+ /* overlap fail */
+ err = strncpy_s (dst, s1size, dst + 1, s1size - 1);
+ if (err == EOK)
+ return -1;
+
+ /* overlap fail */
+ err = strncpy_s (dst, s1size, dst, s1size);
+ if (err == EOK)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_clib_strncpy (vlib_main_t * vm, unformat_input_t * input)
+{
+ char src[] = "Those who dare to fail miserably can achieve greatly.";
+ char dst[100], old_dst[100];
+ int indicator;
+ size_t s1size = sizeof (dst); // including null
+ errno_t err;
+
+ vlib_cli_output (vm, "Test clib_strncpy...");
+
+ /* n == string len of src */
+ err = clib_strncpy (dst, src, clib_strnlen (src, sizeof (src)));
+ if (err != EOK)
+ return -1;
+
+ /* This better not fail but check anyhow */
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* Verify it against strncpy */
+ strncpy (dst, src, strlen (src));
+
+ /* This better not fail but check anyhow */
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* limited copy -- strlen src > n, copy up to n */
+ err = clib_strncpy (dst, "The price of greatness is responsibility.", 10);
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ /* verify it against strncpy */
+ memset_s (dst, sizeof (dst), 0, sizeof (dst));
+ strncpy (dst, "The price of greatness is responsibility.", 10);
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* n > string len of src */
+ err = clib_strncpy (dst, src, clib_strnlen (src, sizeof (src)) + 10);
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ /* Verify it against strncpy */
+ strncpy (dst, src, strlen (src));
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* zero length copy */
+ clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
+ err = clib_strncpy (dst, src, 0);
+ if (err != EOK)
+ return -1;
+ /* verify dst is untouched */
+ if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), old_dst, &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* Negative tests */
+
+ err = clib_strncpy (0, 0, 1);
+ if (err == EOK)
+ return -1;
+
+ /* overlap fail */
+ err = clib_strncpy (dst, dst + 1, s1size);
+ if (err == EOK)
+ return -1;
+
+ /* overlap fail */
+ err = clib_strncpy (dst, dst, s1size);
+ if (err == EOK)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_strcat_s (vlib_main_t * vm, unformat_input_t * input)
+{
+ char src[100], dst[100], old_dst[100];
+ size_t s1size = sizeof (dst); // including null
+ errno_t err;
+ int indicator;
+
+ vlib_cli_output (vm, "Test strcat_s...");
+
+ strcpy_s (dst, sizeof (dst), "Tough time never last ");
+ strcpy_s (src, sizeof (src), "but tough people do");
+ err = strcat_s (dst, s1size, src);
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, s1size - 1,
+ "Tough time never last but tough people do",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* empty string concatenation */
+ clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
+ err = strcat_s (dst, s1size, "");
+ if (err != EOK)
+ return -1;
+ /* verify dst is untouched */
+ if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* negative stuff */
+ err = strcat_s (0, 0, 0);
+ if (err != EINVAL)
+ return -1;
+
+ /* overlap fail */
+ err = strcat_s (dst, s1size, dst + 1);
+ if (err != EINVAL)
+ return -1;
+
+ /* overlap fail */
+ err = strcat_s (dst, s1size, dst);
+ if (err != EINVAL)
+ return -1;
+
+ /* not enough space for dst */
+ err = strcat_s (dst, 10, src);
+ if (err != EINVAL)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_clib_strcat (vlib_main_t * vm, unformat_input_t * input)
+{
+ char src[100], dst[100], old_dst[100];
+ size_t s1size = sizeof (dst); // including null
+ errno_t err;
+ int indicator;
+
+ vlib_cli_output (vm, "Test clib_strcat...");
+
+ strcpy_s (dst, sizeof (dst), "Tough time never last ");
+ strcpy_s (src, sizeof (src), "but tough people do");
+ err = clib_strcat (dst, src);
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, s1size - 1,
+ "Tough time never last but tough people do",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ /* verify it against strcat */
+ strcpy_s (dst, sizeof (dst), "Tough time never last ");
+ strcpy_s (src, sizeof (src), "but tough people do");
+ strcat (dst, src);
+ if (strcmp_s (dst, s1size - 1,
+ "Tough time never last but tough people do",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* empty string concatenation */
+ clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
+ err = clib_strcat (dst, "");
+ if (err != EOK)
+ return -1;
+ /* verify dst is untouched */
+ if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* negative stuff */
+ err = clib_strcat (0, 0);
+ if (err != EINVAL)
+ return -1;
+
+ /* overlap fail */
+ err = clib_strcat (dst, dst + 1);
+ if (err != EINVAL)
+ return -1;
+
+ /* overlap fail */
+ err = clib_strcat (dst, dst);
+ if (err != EINVAL)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_strncat_s (vlib_main_t * vm, unformat_input_t * input)
+{
+ char src[100], dst[100], old_dst[100];
+ size_t s1size = sizeof (dst); // including null
+ errno_t err;
+ char s1[] = "Two things are infinite: ";
+ char s2[] = "the universe and human stupidity; ";
+ char s3[] = "I am not sure about the universe.";
+ int indicator;
+
+ vlib_cli_output (vm, "Test strncat_s...");
+
+ strcpy_s (dst, sizeof (dst), s1);
+ strcpy_s (src, sizeof (src), s2);
+ err = strncat_s (dst, s1size, src, clib_strnlen (src, sizeof (src)));
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, s1size - 1,
+ "Two things are infinite: the universe and human stupidity; ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* truncation, n >= dmax - strnlen_s (dst, dmax) */
+ err = strncat_s (dst, clib_strnlen (dst, sizeof (dst)) +
+ clib_strnlen (s3, sizeof (s3)), s3,
+ clib_strnlen (s3, sizeof (s3)));
+ if (err != EOVERFLOW)
+ return -1;
+ /*
+ * resulting string is dst + strlen (s3) - 1 characters + null.
+ * notice the "." is missing at the end of the resulting string because
+ * the space is needed to accommodate the null
+ * Notice strcmp_s will check s1 or dst to make sure it is null terminated
+ */
+ if (strcmp_s (dst, s1size - 1,
+ "Two things are infinite: the universe and human stupidity; "
+ "I am not sure about the universe", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* n > strlen src */
+ strcpy_s (dst, sizeof (dst), s1);
+ err = strncat_s (dst, s1size, src, clib_strnlen (src, sizeof (src)) + 10);
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, s1size - 1,
+ "Two things are infinite: the universe and human stupidity; ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* zero length strncat */
+ clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
+ err = strncat_s (dst, sizeof (dst), src, 0);
+ if (err != EOK)
+ return -1;
+ /* verify dst is untouched */
+ if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* empty string, wrong n concatenation */
+ err = strncat_s (dst, sizeof (dst), "", 10);
+ if (err != EOK)
+ return -1;
+ /* verify dst is untouched */
+ if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* limited concatenation, string > n, copy up to n */
+ strcpy_s (dst, sizeof (dst), s1);
+ err = strncat_s (dst, s1size, s2, 13);
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ /* verify it against strncat */
+ strcpy_s (dst, sizeof (dst), s1);
+ strncat (dst, s2, 13);
+ if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* negative stuff */
+ err = strncat_s (0, 0, 0, 1);
+ if (err != EINVAL)
+ return -1;
+
+ /* no room for dst -- dmax - strnlen_s (dst, dmax) == 0 */
+ err = strncat_s (dst, clib_strnlen (dst, sizeof (dst)), s2,
+ clib_strnlen (s2, sizeof (s2)));
+ if (err != EINVAL)
+ return -1;
+
+ /* overlap fail */
+ err = strncat_s (dst, s1size, dst + 1, clib_strnlen (dst + 1, s1size - 1));
+ if (err != EINVAL)
+ return -1;
+
+ /* overlap fail */
+ err = strncat_s (dst, s1size, dst, clib_strnlen (dst, sizeof (dst)));
+ if (err != EINVAL)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_clib_strncat (vlib_main_t * vm, unformat_input_t * input)
+{
+ char src[100], dst[100], old_dst[100];
+ size_t s1size = sizeof (dst); // including null
+ errno_t err;
+ char s1[] = "Two things are infinite: ";
+ char s2[] = "the universe and human stupidity; ";
+ int indicator;
+
+ vlib_cli_output (vm, "Test clib_strncat...");
+
+ /* n == strlen src */
+ strcpy_s (dst, sizeof (dst), s1);
+ strcpy_s (src, sizeof (src), s2);
+ err = clib_strncat (dst, src, clib_strnlen (src, sizeof (src)));
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, s1size - 1,
+ "Two things are infinite: the universe and human stupidity; ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ /* verify it against strncat */
+ strcpy_s (dst, sizeof (dst), s1);
+ strncat (dst, src, clib_strnlen (src, sizeof (src)));
+ if (strcmp_s (dst, s1size - 1,
+ "Two things are infinite: the universe and human stupidity; ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* n > strlen src */
+ strcpy_s (dst, sizeof (dst), s1);
+ err = clib_strncat (dst, src, clib_strnlen (src, sizeof (src)) + 10);
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, s1size - 1,
+ "Two things are infinite: the universe and human stupidity; ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ /* verify it against strncat */
+ strcpy_s (dst, sizeof (dst), s1);
+ strncat (dst, src, clib_strnlen (src, sizeof (src)));
+ if (strcmp_s (dst, s1size - 1,
+ "Two things are infinite: the universe and human stupidity; ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* zero length strncat */
+ clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
+ err = clib_strncat (dst, src, 0);
+ if (err != EOK)
+ return -1;
+ /* verify dst is untouched */
+ if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* empty string, wrong n concatenation */
+ err = clib_strncat (dst, "", 10);
+ if (err != EOK)
+ return -1;
+ /* verify dst is untouched */
+ if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* limited concatenation, string > n, copy up to n */
+ strcpy_s (dst, sizeof (dst), s1);
+ err = clib_strncat (dst, s2, 13);
+ if (err != EOK)
+ return -1;
+ if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ /* verify it against strncat */
+ strcpy_s (dst, sizeof (dst), s1);
+ strncat (dst, s2, 13);
+ if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
+ &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* negative stuff */
+ err = clib_strncat (0, 0, 1);
+ if (err != EINVAL)
+ return -1;
+
+ /* overlap fail */
+ err = clib_strncat (dst, dst + 1, s1size - 1);
+ if (err != EINVAL)
+ return -1;
+
+ /* overlap fail */
+ err = clib_strncat (dst, dst, clib_strnlen (dst, sizeof (dst)));
+ if (err != EINVAL)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_strtok_s (vlib_main_t * vm, unformat_input_t * input)
+{
+ int indicator;
+ char *tok, *ptr;
+ char str2[20];
+ char str1[40];
+ uword len;
+ char *p2str = 0;
+ char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7;
+
+ vlib_cli_output (vm, "Test strtok_s...");
+ strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
+ len = strnlen_s (str1, sizeof (str1));
+ tok1 = strtok_s (str1, &len, " ", &p2str);
+ tok2 = strtok_s (0, &len, " ", &p2str);
+ tok3 = strtok_s (0, &len, " ", &p2str);
+ tok4 = strtok_s (0, &len, " ", &p2str);
+ tok5 = strtok_s (0, &len, " ", &p2str);
+ tok6 = strtok_s (0, &len, " ", &p2str);
+ tok7 = strtok_s (0, &len, " ", &p2str);
+ if ((tok1 == 0) ||
+ strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok4 == 0)
+ || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if (tok7 != 0)
+ return -1;
+
+ /* delimiter not present in the string -- the whole string is returned */
+ strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
+ len = strnlen_s (str1, sizeof (str1) - 1);
+ p2str = 0;
+ tok1 = strtok_s (str1, &len, ",", &p2str);
+ if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* negative stuff */
+ tok = strtok_s (0, 0, 0, 0);
+ if (tok != 0)
+ return -1;
+
+ /* s1 and ptr contents are null */
+ ptr = 0;
+ tok = strtok_s (0, 0, 0, &ptr);
+ if (tok != 0)
+ return -1;
+
+ /* unterminate s1 */
+ p2str = 0;
+ len = strnlen_s (str1, sizeof (str1) - 1);
+ str1[strlen (str1)] = 0x2;
+ tok = strtok_s (str1, &len, ",", &p2str);
+ if (tok != 0)
+ return -1;
+
+ /*
+ * unterminated s2. This test case in not perfect because there is no
+ * argument for s2max. But s2 len is limited to 16 characters. If the API
+ * does not find the null character at s2[15], it declares the string s2
+ * as unterminated.
+ */
+ memset_s (str2, sizeof (str2), 0xfa, sizeof (str2));
+ tok = strtok_s (str1, &len, str2, &p2str);
+ if (tok != 0)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_clib_strtok (vlib_main_t * vm, unformat_input_t * input)
+{
+ int indicator;
+ char *tok, *ptr, *s1;
+ char str1[40];
+ char *p2str;
+ char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7;
+
+ vlib_cli_output (vm, "Test clib_strtok...");
+ strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
+ p2str = 0;
+ tok1 = clib_strtok (str1, " ", &p2str);
+ tok2 = clib_strtok (0, " ", &p2str);
+ tok3 = clib_strtok (0, " ", &p2str);
+ tok4 = clib_strtok (0, " ", &p2str);
+ tok5 = clib_strtok (0, " ", &p2str);
+ tok6 = clib_strtok (0, " ", &p2str);
+ tok7 = clib_strtok (0, " ", &p2str);
+ if ((tok1 == 0) ||
+ strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok4 == 0)
+ || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if (tok7 != 0)
+ return -1;
+ /* verify it againest strtok_r */
+ strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
+ p2str = 0;
+ tok1 = strtok_r (str1, " ", &p2str);
+ tok2 = strtok_r (0, " ", &p2str);
+ tok3 = strtok_r (0, " ", &p2str);
+ tok4 = strtok_r (0, " ", &p2str);
+ tok5 = strtok_r (0, " ", &p2str);
+ tok6 = strtok_r (0, " ", &p2str);
+ tok7 = strtok_r (0, " ", &p2str);
+ if ((tok1 == 0) ||
+ strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok4 == 0)
+ || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ if (tok7 != 0)
+ return -1;
+
+ /* delimiter not present in the string -- the whole string is returned */
+ strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
+ p2str = 0;
+ tok1 = clib_strtok (str1, ",", &p2str);
+ if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ /* verify it against strtok_r */
+ strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
+ p2str = 0;
+ tok1 = strtok_r (str1, ",", &p2str);
+ if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* negative stuff */
+ s1 = 0;
+ ptr = 0;
+ tok = clib_strtok (s1, s1, (char **) 0);
+ if (tok != 0)
+ return -1;
+
+ /* s1 and ptr contents are null */
+ tok = clib_strtok (s1, s1, &ptr);
+ if (tok != 0)
+ return -1;
+ /* verify it against strtok_r */
+ /* No can do. This causes a crash in strtok_r */
+ // tok = strtok_r (s1, " ", &ptr);
+ // if (tok != 0)
+ // return -1;
+
+ /*
+ * Can't test unterminated string s1 and s2 becuase clib_strtok does not
+ * supply s1 and s2 max
+ */
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_strnlen_s (vlib_main_t * vm, unformat_input_t * input)
+{
+ const char s1[] = "Truth is incontrovertible";
+ size_t len;
+
+ vlib_cli_output (vm, "Test strnlen_s...");
+
+ len = strnlen_s (s1, sizeof (s1));
+ if (len != sizeof (s1) - 1)
+ return -1;
+
+ len = strnlen_s (s1, 5);
+ if (len != 5)
+ return -1;
+
+ /* negative stuff */
+ len = strnlen_s (0, 0);
+ if (len != 0)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_clib_strnlen (vlib_main_t * vm, unformat_input_t * input)
+{
+ const char s1[] = "Truth is incontrovertible";
+ size_t len;
+
+ vlib_cli_output (vm, "Test clib_strnlen...");
+
+ len = clib_strnlen (s1, sizeof (s1));
+ if (len != sizeof (s1) - 1)
+ return -1;
+
+ len = clib_strnlen (s1, 5);
+ if (len != 5)
+ return -1;
+
+ /* negative stuff */
+ len = clib_strnlen (0, 0);
+ if (len != 0)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_strstr_s (vlib_main_t * vm, unformat_input_t * input)
+{
+ errno_t err;
+ char *sub = 0;
+ char s1[64];
+ size_t s1len = sizeof (s1) - 1; // excluding null
+ int indicator;
+
+ vlib_cli_output (vm, "Test strstr_s...");
+
+ /* substring not present */
+ strcpy_s (s1, s1len, "success is not final, failure is not fatal.");
+ err = strstr_s (s1, s1len, "failures", sizeof ("failures"), &sub);;
+ if (err != ESRCH)
+ return -1;
+
+ /* substring present */
+ err = strstr_s (s1, s1len, "failure", sizeof ("failure"), &sub);
+ if (err != EOK)
+ return -1;
+
+ if ((sub == 0) ||
+ strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator)
+ != EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* negative stuff */
+
+ /* Null pointers test */
+ err = strstr_s (0, 0, 0, 0, 0);
+ if (err != EINVAL)
+ return -1;
+
+ /* unterminated s1 and s2 */
+ memset_s (s1, ARRAY_LEN (s1), 0xfe, ARRAY_LEN (s1));
+ err = strstr_s (s1, s1len, s1, s1len, &sub);
+ if (err != EINVAL)
+ return -1;
+
+ /* OK, seems to work */
+ return 0;
+}
+
+static int
+test_clib_strstr (vlib_main_t * vm, unformat_input_t * input)
+{
+ char *sub, *s;
+ char s1[64];
+ size_t s1len = sizeof (s1) - 1; // excluding null
+ int indicator;
+
+ vlib_cli_output (vm, "Test clib_strstr...");
+
+ /* substring not present */
+ strcpy_s (s1, s1len, "success is not final, failure is not fatal.");
+ sub = clib_strstr (s1, "failures");
+ if (sub != 0)
+ return -1;
+ /* verify it against strstr */
+ sub = strstr (s1, "failures");
+ if (sub != 0)
+ return -1;
+
+ /* substring present */
+ sub = clib_strstr (s1, "failure");
+ if (sub == 0)
+ return -1;
+ if (strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+ /* verify it against strstr */
+ sub = strstr (s1, "failure");
+ if (sub == 0)
+ return -1;
+ if (strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator) !=
+ EOK)
+ return -1;
+ if (indicator != 0)
+ return -1;
+
+ /* negative stuff */
+
+ /* Null pointers test */
+ s = 0;
+ sub = clib_strstr (s, s);
+ if (sub != 0)
+ return -1;
+ /*
+ * Can't verify it against strstr for this test. Null pointers cause strstr
+ * to crash. Go figure!
+ */
+
+ /* unterminated s1 and s2 */
+ memset_s (s1, ARRAY_LEN (s1), 0xfe, ARRAY_LEN (s1));
+ sub = clib_strstr (s1, s1);
+ if (sub == 0)
+ return -1;
+ /*
+ * Can't verify it against strstr for this test. Unterminated string causes
+ * strstr to crash. Go figure!
+ */
+
+ /* OK, seems to work */
+ return 0;
+}
+
+#define foreach_string_test \
+ _ (0, MEMCPY_S, "memcpy_s", memcpy_s) \
+ _ (1, CLIB_MEMCPY, "clib_memcpy", clib_memcpy) \
+ _ (2, MEMSET_S , "memset_s", memset_s) \
+ _ (3, CLIB_MEMSET , "clib_memset", clib_memset) \
+ _ (4, MEMCMP_S, "memcmp_s", memcmp_s) \
+ _ (5, CLIB_MEMCMP, "clib_memcmp", clib_memcmp) \
+ _ (6, STRCMP_S, "strcmp_s", strcmp_s) \
+ _ (7, CLIB_STRCMP, "clib_strcmp", clib_strcmp) \
+ _ (8, STRNCMP_S, "strncmp_s", strncmp_s) \
+ _ (9, CLIB_STRNCMP, "clib_strncmp", clib_strncmp) \
+ _ (10, STRCPY_S, "strcpy_s", strcpy_s) \
+ _ (11, CLIB_STRCPY, "clib_strcpy", clib_strcpy) \
+ _ (12, STRNCPY_S, "strncpy_s", strncpy_s) \
+ _ (13, CLIB_STRNCPY, "clib_strncpy", clib_strncpy) \
+ _ (14, STRCAT_S, "strcat_s", strcat_s) \
+ _ (15, CLIB_STRCAT, "clib_strcat", clib_strcat) \
+ _ (16, STRNCAT_S, "strncat_s", strncat_s) \
+ _ (17, CLIB_STRNCAT, "clib_strncat", clib_strncat) \
+ _ (18, STRTOK_S, "strtok_s", strtok_s) \
+ _ (19, CLIB_STRTOK, "clib_strtok", clib_strtok) \
+ _ (20, STRNLEN_S, "strnlen_s", strnlen_s) \
+ _ (21, CLIB_STRNLEN, "clib_strnlen", clib_strnlen) \
+ _ (22, STRSTR_S, "strstr_s", strstr_s) \
+ _ (23, CLIB_STRSTR, "clib_strstr", clib_strstr)
+
+typedef enum
+{
+#define _(v,f,s,p) STRING_TEST_##f = v,
+ foreach_string_test
+#undef _
+} string_test_t;
+
+static uword
+unformat_string_test (unformat_input_t * input, va_list * args)
+{
+ u8 *r = va_arg (*args, u8 *);
+
+ if (0)
+ ;
+#define _(v,f,s,p) else if (unformat (input, s)) *r = STRING_TEST_##f;
+ foreach_string_test
+#undef _
+ else
+ return 0;
+
+ return 1;
+}
+
+typedef int (*string_test_func) (vlib_main_t * vm, unformat_input_t * input);
+
+typedef struct
+{
+ string_test_func test;
+} string_test_func_t;
+
static clib_error_t *
string_test_command_fn (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd_arg)
{
- int res = 0;
- u8 t_memcpy = 0;
- u8 t_clib_memset = 0;
- u8 specific_test;
+ string_test_func_t string_func[] = {
+#define _(v,f,s,p) { test_##p },
+ foreach_string_test
+#undef _
+ };
+ const char *string_table[] = {
+#define _(v,f,s,p) s,
+ foreach_string_test
+#undef _
+ };
+ int res = 0, ok;
+ i8 specific_test = ~0;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
- if (unformat (input, "memcpy_s"))
- t_memcpy = 1;
- else if (unformat (input, "memset_s"))
- t_clib_memset = 1;
- break;
+ if (unformat (input, "%U", unformat_string_test, &specific_test))
+ break;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
}
- specific_test = t_memcpy + t_clib_memset;
-
- if (specific_test == 0)
+ if (specific_test == ~0)
{
- res = test_memcpy (vm, input);
- res += test_clib_memset (vm, input);
- goto done;
+ for (specific_test = STRING_TEST_MEMCPY_S;
+ specific_test <= STRING_TEST_CLIB_STRSTR; specific_test++)
+ {
+ ok = (string_func[specific_test]).test (vm, input);
+ res += ok;
+ if (ok != 0)
+ vlib_cli_output (vm, "test_%s failed",
+ string_table[specific_test]);
+ }
}
-
- if (t_memcpy)
- res = test_memcpy (vm, input);
- else if (t_clib_memset)
- res = test_clib_memset (vm, input);
-
-done:
+ else
+ res = (string_func[specific_test]).test (vm, input);
if (res)
vlib_cli_output (vm, "String unit test(s) failed...");
else
@@ -131,7 +1660,12 @@ done:
VLIB_CLI_COMMAND (string_test_command, static) =
{
.path = "test string",
- .short_help = "string library tests",
+ .short_help = "test string [memcpy_s | clib_memcpy | memset_s | "
+ "clib_memset | memcmp_s | clib_memcmp | strcmp_s | clib_strcmp | "
+ "strncmp_s | clib_strncmp | strcpy_s | clib_strcpy | strncpy_s | "
+ "clib_strncpy | strcat_s | clib_strcat | strncat_s | clib_strncat | "
+ "strtok_s | clib_strtok | strnlen_s | clib_strnlen | strstr_s | "
+ "clib_strstr]",
.function = string_test_command_fn,
};
/* *INDENT-ON* */