There was no coverage for a device string with no driver arguments, which is how Bugzilla 2049 went unnoticed: global device syntax with no driver layer left args NULL and drivers crashed passing it to rte_kvargs_parse().
Add a devargs case asserting args is non-NULL and empty for global syntax without a driver layer, and that it parses as kvargs the way a driver would use it. Add a kvargs case for rte_kvargs_parse(NULL), which must give an empty list. Signed-off-by: Stephen Hemminger <[email protected]> --- app/test/test_devargs.c | 60 +++++++++++++++++++++++++++++++++++++++++ app/test/test_kvargs.c | 16 +++++++++++ 2 files changed, 76 insertions(+) diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c index de0dd2364d..693bf362d4 100644 --- a/app/test/test_devargs.c +++ b/app/test/test_devargs.c @@ -193,6 +193,65 @@ test_invalid_devargs(void) return fail; } +/* + * Global device syntax without a driver layer must still leave args set, + * as the legacy syntax does. Drivers pass it straight to + * rte_kvargs_parse(), which used to crash on NULL. + */ +static int +test_devargs_no_driver_layer(void) +{ + static const char * const list[] = { + "bus=vdev,name=net_null0", + "bus=vdev,name=net_null0/class=eth", + "class=eth", + }; + struct rte_kvargs *kvlist; + struct rte_devargs da; + uint32_t i; + int ret; + int fail = TEST_SUCCESS; + + if (rte_bus_find_by_name("vdev") == NULL || + rte_class_find_by_name("eth") == NULL) { + printf("vdev bus or eth class missing, skipping\n"); + return TEST_SKIPPED; + } + + for (i = 0; i < RTE_DIM(list); i++) { + memset(&da, 0, sizeof(da)); + ret = rte_devargs_parse(&da, list[i]); + if (ret < 0) { + printf("rte_devargs_parse(%s) returned %d (but should not)\n", + list[i], ret); + fail = TEST_FAILED; + goto cleanup; + } + if (da.args == NULL) { + printf("rte_devargs_parse(%s) left args NULL\n", list[i]); + fail = TEST_FAILED; + goto cleanup; + } + if (da.args[0] != '\0') { + printf("rte_devargs_parse(%s) args (%s) not empty\n", + list[i], da.args); + fail = TEST_FAILED; + goto cleanup; + } + /* What a driver does with it. */ + kvlist = rte_kvargs_parse(da.args, NULL); + if (kvlist == NULL) { + printf("rte_kvargs_parse(%s args) failed\n", list[i]); + fail = TEST_FAILED; + goto cleanup; + } + rte_kvargs_free(kvlist); +cleanup: + rte_devargs_reset(&da); + } + return fail; +} + struct devargs_parse_case { const char *devargs; uint8_t devargs_count; @@ -300,6 +359,7 @@ static struct unit_test_suite devargs_test_suite = { .unit_test_cases = { TEST_CASE(test_valid_devargs), TEST_CASE(test_invalid_devargs), + TEST_CASE(test_devargs_no_driver_layer), TEST_CASE(test_valid_devargs_parsing), TEST_CASE(test_invalid_devargs_parsing), TEST_CASES_END() /**< NULL terminate unit test array */ diff --git a/app/test/test_kvargs.c b/app/test/test_kvargs.c index a14b75948a..5dd74bec49 100644 --- a/app/test/test_kvargs.c +++ b/app/test/test_kvargs.c @@ -328,6 +328,21 @@ static int test_invalid_kvargs(void) return -1; } +/* NULL means no arguments, and must give an empty list rather than crash. */ +static int +test_parse_null_args(void) +{ + struct rte_kvargs *kvlist; + + kvlist = rte_kvargs_parse(NULL, NULL); + TEST_ASSERT_NOT_NULL(kvlist, "rte_kvargs_parse(NULL) returned NULL"); + TEST_ASSERT_EQUAL(kvlist->count, 0, "rte_kvargs_parse(NULL) count %u, not 0", + kvlist->count); + rte_kvargs_free(kvlist); + + return 0; +} + static struct unit_test_suite kvargs_test_suite = { .suite_name = "Kvargs Unit Test Suite", .setup = NULL, @@ -353,6 +368,7 @@ static struct unit_test_suite kvargs_test_suite = { TEST_CASE(test_parse_list_value), TEST_CASE(test_parse_empty_elements), TEST_CASE(test_parse_with_only_key), + TEST_CASE(test_parse_null_args), TEST_CASE(test_invalid_kvargs), TEST_CASES_END() /**< NULL terminate unit test array */ } -- 2.53.0

