From 477b7b679d58455dc38c2594b29a1ecfbe88e80c Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Mon, 2 Nov 2020 14:55:27 -0500 Subject: [PATCH 1/2] Fix: libcrmcommon: Prevent a segfault in pcmk__cmdline_preproc. The list of special single-character args is optional. The function currently handles it being an empty string, but it should handle a NULL as well. --- lib/common/cmdline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/cmdline.c b/lib/common/cmdline.c index d66ccc7..66f1976 100644 --- a/lib/common/cmdline.c +++ b/lib/common/cmdline.c @@ -203,7 +203,7 @@ pcmk__cmdline_preproc(char **argv, const char *special) { * glib does not. Grab both the argument and its value and * separate them into a new argument. */ - if (strchr(special, *ch) != NULL) { + if (special != NULL && strchr(special, *ch) != NULL) { /* The argument does not occur at the end of this string of * arguments. Take everything through the end as its value. */ -- 1.8.3.1 From d1f4a975fa783045254521f415f1899b34ee96e3 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Mon, 2 Nov 2020 16:06:29 -0500 Subject: [PATCH 2/2] Test: libcrmcommon: Add unit tests for pcmk__cmdline_preproc. --- configure.ac | 1 + lib/common/tests/Makefile.am | 2 +- lib/common/tests/cmdline/Makefile.am | 29 ++++++ .../tests/cmdline/pcmk__cmdline_preproc_test.c | 102 +++++++++++++++++++++ 4 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 lib/common/tests/cmdline/Makefile.am create mode 100644 lib/common/tests/cmdline/pcmk__cmdline_preproc_test.c diff --git a/configure.ac b/configure.ac index 7ed4a30..36e85a9 100644 --- a/configure.ac +++ b/configure.ac @@ -2006,6 +2006,7 @@ AC_CONFIG_FILES(Makefile \ lib/pacemaker-cluster.pc \ lib/common/Makefile \ lib/common/tests/Makefile \ + lib/common/tests/cmdline/Makefile \ lib/common/tests/flags/Makefile \ lib/common/tests/operations/Makefile \ lib/common/tests/strings/Makefile \ diff --git a/lib/common/tests/Makefile.am b/lib/common/tests/Makefile.am index 33c45cb..f3eaeec 100644 --- a/lib/common/tests/Makefile.am +++ b/lib/common/tests/Makefile.am @@ -1 +1 @@ -SUBDIRS = flags operations strings utils +SUBDIRS = cmdline flags operations strings utils diff --git a/lib/common/tests/cmdline/Makefile.am b/lib/common/tests/cmdline/Makefile.am new file mode 100644 index 0000000..e69ef21 --- /dev/null +++ b/lib/common/tests/cmdline/Makefile.am @@ -0,0 +1,29 @@ +# +# Copyright 2020 the Pacemaker project contributors +# +# The version control history for this file may have further details. +# +# This source code is licensed under the GNU General Public License version 2 +# or later (GPLv2+) WITHOUT ANY WARRANTY. +# +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include +LDADD = $(top_builddir)/lib/common/libcrmcommon.la + +include $(top_srcdir)/mk/glib-tap.mk + +# Add each test program here. Each test should be written as a little standalone +# program using the glib unit testing functions. See the documentation for more +# information. +# +# https://developer.gnome.org/glib/unstable/glib-Testing.html +# +# Add "_test" to the end of all test program names to simplify .gitignore. +test_programs = pcmk__cmdline_preproc_test + +# If any extra data needs to be added to the source distribution, add it to the +# following list. +dist_test_data = + +# If any extra data needs to be used by tests but should not be added to the +# source distribution, add it to the following list. +test_data = diff --git a/lib/common/tests/cmdline/pcmk__cmdline_preproc_test.c b/lib/common/tests/cmdline/pcmk__cmdline_preproc_test.c new file mode 100644 index 0000000..e13c983 --- /dev/null +++ b/lib/common/tests/cmdline/pcmk__cmdline_preproc_test.c @@ -0,0 +1,102 @@ +/* + * Copyright 2020 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU Lesser General Public License + * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. + */ + +#include +#include + +#define LISTS_EQ(a, b) { \ + g_assert_cmpint(g_strv_length((gchar **) (a)), ==, g_strv_length((gchar **) (b))); \ + for (int i = 0; i < g_strv_length((a)); i++) { \ + g_assert_cmpstr((a)[i], ==, (b)[i]); \ + } \ +} + +static void +empty_input(void) { + g_assert_cmpint(pcmk__cmdline_preproc(NULL, "") == NULL, ==, TRUE); +} + +static void +no_specials(void) { + const char *argv[] = { "-a", "-b", "-c", "-d", NULL }; + const gchar *expected[] = { "-a", "-b", "-c", "-d", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, NULL); + LISTS_EQ(processed, expected); + g_strfreev(processed); + + processed = pcmk__cmdline_preproc((char **) argv, ""); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +single_dash(void) { + const char *argv[] = { "-", NULL }; + const gchar *expected[] = { "-", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, NULL); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +double_dash(void) { + const char *argv[] = { "-a", "--", "-bc", NULL }; + const gchar *expected[] = { "-a", "--", "-bc", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, NULL); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +special_args(void) { + const char *argv[] = { "-aX", "-Fval", NULL }; + const gchar *expected[] = { "-a", "X", "-F", "val", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, "aF"); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +special_arg_at_end(void) { + const char *argv[] = { "-a", NULL }; + const gchar *expected[] = { "-a", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, "a"); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +long_arg(void) { + const char *argv[] = { "--blah=foo", NULL }; + const gchar *expected[] = { "--blah=foo", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, NULL); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +int +main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/common/cmdline/preproc/empty_input", empty_input); + g_test_add_func("/common/cmdline/preproc/no_specials", no_specials); + g_test_add_func("/common/cmdline/preproc/single_dash", single_dash); + g_test_add_func("/common/cmdline/preproc/double_dash", double_dash); + g_test_add_func("/common/cmdline/preproc/special_args", special_args); + g_test_add_func("/common/cmdline/preproc/special_arg_at_end", special_arg_at_end); + g_test_add_func("/common/cmdline/preproc/long_arg", long_arg); + return g_test_run(); +} -- 1.8.3.1