From 477b7b679d58455dc38c2594b29a1ecfbe88e80c Mon Sep 17 00:00:00 2001
From: Chris Lumens <clumens@redhat.com>
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 <clumens@redhat.com>
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 <crm_internal.h>
+#include <crm/common/cmdline_internal.h>
+
+#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