diff --git a/libpromises/evalfunction.c b/libpromises/evalfunction.c index 8dfcdc8e42..937a619ec8 100644 --- a/libpromises/evalfunction.c +++ b/libpromises/evalfunction.c @@ -10409,8 +10409,9 @@ void ModuleProtocol(EvalContext *ctx, const char *command, const char *line, int if (CheckID(name)) { - Rlist *list = RlistParseString(content); - if (!list) + /* An empty list is NULL too, so check the return value */ + Rlist *list = NULL; + if (!RlistParseString(content, &list)) { Log(LOG_LEVEL_ERR, "Module protocol could not parse variable %s's data content %s", name, content); } diff --git a/libpromises/rlist.c b/libpromises/rlist.c index 829b1ca254..095ca5040e 100644 --- a/libpromises/rlist.c +++ b/libpromises/rlist.c @@ -828,6 +828,12 @@ static int LaunchParsingMachine(const char *str, Rlist **newlist) BufferClear(buf); current_state = ST_ELM2; } + else if (CLASS_BRA2(*s)) + { + /* "{}" -- a closing brace before any element. Has to come + * before the catch-all below. */ + current_state = ST_PRECLOSED; + } else if (CLASS_ANY1(*s)) { current_state = ST_ERROR; @@ -955,19 +961,26 @@ static int LaunchParsingMachine(const char *str, Rlist **newlist) clean: BufferDestroy(buf); RlistDestroy(*newlist); + *newlist = NULL; assert(ret != 0); return ret; } -Rlist *RlistParseString(const char *string) +/** + * @brief Parse a list in the format used by the module protocol, e.g. { "a", "b" } + * @param string String to parse + * @param[out] newlist The parsed list, NULL for the empty list "{}" + * @return Whether the string was parsed successfully + * + * An empty list parses fine and gives NULL, so check the return value. + */ +bool RlistParseString(const char *string, Rlist **newlist) { - Rlist *newlist = NULL; - if (LaunchParsingMachine(string, &newlist)) - { - return NULL; - } + assert(newlist != NULL); - return newlist; + *newlist = NULL; + + return (LaunchParsingMachine(string, newlist) == 0); } /*******************************************************************/ diff --git a/libpromises/rlist.h b/libpromises/rlist.h index a690284341..37d39d88c9 100644 --- a/libpromises/rlist.h +++ b/libpromises/rlist.h @@ -80,7 +80,7 @@ char *RlistScalarValueSafe(const Rlist *rlist); FnCall *RlistFnCallValue(const Rlist *rlist); Rlist *RlistRlistValue(const Rlist *rlist); Rlist *RlistParseShown(const char *string); -Rlist *RlistParseString(const char *string); +bool RlistParseString(const char *string, Rlist **newlist); Rlist *RlistKeyIn(Rlist *list, const char *key); Rlist *RlistKeyIn_IgnoreCase(Rlist *list, const char *key); int RlistLen(const Rlist *start); diff --git a/tests/acceptance/08_commands/01_modules/module_allows_empty_lists.cf b/tests/acceptance/08_commands/01_modules/module_allows_empty_lists.cf index 9854d148a2..e6ca91b442 100644 --- a/tests/acceptance/08_commands/01_modules/module_allows_empty_lists.cf +++ b/tests/acceptance/08_commands/01_modules/module_allows_empty_lists.cf @@ -14,9 +14,12 @@ body common control bundle agent test { meta: + "description" -> { "CFE-2139", "redmine7577" } + string => "Test that modules are allowed to emit empty lists"; + "test_soft_fail" - string => "any", - meta => { "redmine7577" }; + string => "windows", + meta => { "ENT-10257" }; commands: "$(G.cat)" diff --git a/tests/unit/rlist_test.c b/tests/unit/rlist_test.c index 9703b1394e..25cc85db16 100644 --- a/tests/unit/rlist_test.c +++ b/tests/unit/rlist_test.c @@ -292,6 +292,11 @@ static struct ParseRoulette char *str; } PR[] = { + /*Empty list */ + { + 0, "{}"}, + { + 0, "{ }"}, /*Simple */ { 1, "{\"a\"}"}, @@ -567,7 +572,7 @@ static void test_new_parser_success() int i = 0; while (PR[i].nfields != -1) { - list = RlistParseString(PR[i].str); + assert_true(RlistParseString(PR[i].str, &list)); assert_int_equal(PR[i].nfields, RlistLen(list)); if (list != NULL) { @@ -583,7 +588,7 @@ static void test_new_parser_failure() Rlist *list = NULL; while (PFR[i] != NULL) { - list = RlistParseString(PFR[i]); + assert_false(RlistParseString(PFR[i], &list)); assert_true(RlistLast(list) == NULL); if(list) RlistDestroy(list); i++;