Fix: lttng: add-trigger: invalid access past end of exclusions buffer
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 29 Apr 2021 23:01:44 +0000 (19:01 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 7 May 2021 17:47:51 +0000 (13:47 -0400)
The following command causes the `lttng` client to SEGFAULT on 32-bit
machines:
  lttng add-trigger \
    --condition event-rule-matches --domain=user \
                '--name=jean-*' \
                --exclude-name jean-chretien -x jean-charest \
    --action notify

Running with valgrind results in the following report:

Invalid read of size 8
   at 0x12EEA4: validate_exclusion_list (enable_events.c:354)
   by 0x149018: parse_event_rule (add_trigger.c:964)
   by 0x148356: handle_condition_event (add_trigger.c:1222)
   by 0x147EC3: parse_condition (add_trigger.c:1300)
   by 0x147702: cmd_add_trigger (add_trigger.c:2107)
   by 0x154067: handle_command (lttng.c:237)
   by 0x1534D1: parse_args (lttng.c:426)
   by 0x152C54: main (lttng.c:475)

validate_exclusion_list expects a NULL terminated array of exclusions
while handle_condition_event prepares an array of exclusions using
the dynamic pointer array facilities (which doesn't need to
null-terminate arrays).

The code that deals with exclusions "lists" mixes various conventions
(null-terminated vs explicit size) in different places leading to this
kind of errors.

All the code that references exclusion lists, along with the string
utils, are adapted to make use of the common dynamic pointer array
facilities.

Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: Icbb7f0e8601c7ecc887dc9ae64d0ec6390e6aba3

12 files changed:
.gitignore
src/bin/lttng/commands/add_trigger.c
src/bin/lttng/commands/enable_events.c
src/bin/lttng/uprobe.c
src/bin/lttng/utils.h
src/common/Makefile.am
src/common/filter-grammar-test.c [new file with mode: 0644]
src/common/filter/Makefile.am
src/common/filter/filter-grammar-test.c [deleted file]
src/common/string-utils/string-utils.c
src/common/string-utils/string-utils.h
tests/unit/test_string_utils.c

index cbd57ea72ac4877c3624007cbda6006ae512f219..26d3511f0fddc24f74b91241a5dcc123e4e0f776 100644 (file)
@@ -61,7 +61,7 @@ compile_commands.json
 /src/bin/lttng-crash/lttng-crash
 /src/bin/lttng-relayd/lttng-relayd
 /src/lib/lttng-ctl/lttng-ctl.pc
-/src/common/filter/filter-grammar-test
+/src/common/filter-grammar-test
 /src/common/filter/filter-lexer.c
 /src/common/filter/filter-parser.c
 /src/common/filter/filter-parser.h
index ee5c353e4435a398089c2cb205d157c60e11af42..9c6b2cceb7714428092697b881d49a42241e0671 100644 (file)
@@ -209,11 +209,6 @@ error:
        return ret;
 }
 
-/* This is defined in enable_events.c. */
-LTTNG_HIDDEN
-int validate_exclusion_list(
-               const char *event_name, const char *const *exclusions);
-
 /*
  * Parse `str` as a log level in domain `domain_type`.
  *
@@ -961,11 +956,7 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
                        goto error;
                }
 
-               if (validate_exclusion_list(name,
-                                   (const char **) exclude_names.array.buffer
-                                                   .data
-
-                                   ) != 0) {
+               if (validate_exclusion_list(name, &exclude_names) != 0) {
                        /*
                         * Assume validate_exclusion_list already prints an
                         * error message.
@@ -1312,8 +1303,9 @@ end:
 
 static struct lttng_rate_policy *parse_rate_policy(const char *policy_str)
 {
-       int num_token;
-       char **tokens = NULL;
+       int ret;
+       size_t num_token = 0;
+       struct lttng_dynamic_pointer_array tokens;
        struct lttng_rate_policy *policy = NULL;
        enum lttng_rate_policy_type policy_type;
        unsigned long long value;
@@ -1321,12 +1313,13 @@ static struct lttng_rate_policy *parse_rate_policy(const char *policy_str)
        char *policy_value_str;
 
        assert(policy_str);
+       lttng_dynamic_pointer_array_init(&tokens, NULL);
 
-       /*
-        * rate policy fields are separated by ':'.
-        */
-       tokens = strutils_split(policy_str, ':', 1);
-       num_token = strutils_array_of_strings_len(tokens);
+       /* Rate policy fields are separated by ':'. */
+       ret = strutils_split(policy_str, ':', 1, &tokens);
+       if (ret == 0) {
+               num_token = lttng_dynamic_pointer_array_get_count(&tokens);
+       }
 
        /*
         * Early sanity check that the number of parameter is exactly 2.
@@ -1337,8 +1330,8 @@ static struct lttng_rate_policy *parse_rate_policy(const char *policy_str)
                goto end;
        }
 
-       policy_type_str = tokens[0];
-       policy_value_str = tokens[1];
+       policy_type_str = lttng_dynamic_pointer_array_get_pointer(&tokens, 0);
+       policy_value_str = lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
 
        /* Parse the type. */
        if (strcmp(policy_type_str, "once-after") == 0) {
@@ -1378,7 +1371,7 @@ static struct lttng_rate_policy *parse_rate_policy(const char *policy_str)
        }
 
 end:
-       strutils_free_null_terminated_array_of_strings(tokens);
+       lttng_dynamic_pointer_array_reset(&tokens);
        return policy;
 }
 
index 056977412724e297e7b0795eb5033678fed53db1..0704b14756f78ef860b7e283c4e084a4b6f6a40a 100644 (file)
@@ -193,10 +193,11 @@ const char *print_raw_channel_name(const char *name)
  * Mi print exlcusion list
  */
 static
-int mi_print_exclusion(char **names)
+int mi_print_exclusion(const struct lttng_dynamic_pointer_array *exclusions)
 {
-       int i, ret;
-       int count = names ? strutils_array_of_strings_len(names) : 0;
+       int ret;
+       size_t i;
+       const size_t count = lttng_dynamic_pointer_array_get_count(exclusions);
 
        assert(writer);
 
@@ -204,14 +205,18 @@ int mi_print_exclusion(char **names)
                ret = 0;
                goto end;
        }
+
        ret = mi_lttng_writer_open_element(writer, config_element_exclusions);
        if (ret) {
                goto end;
        }
 
        for (i = 0; i < count; i++) {
+               const char *exclusion = lttng_dynamic_pointer_array_get_pointer(
+                               exclusions, i);
+
                ret = mi_lttng_writer_write_element_string(writer,
-                               config_element_exclusion, names[i]);
+                               config_element_exclusion, exclusion);
                if (ret) {
                        goto end;
                }
@@ -228,21 +233,24 @@ end:
  * Return allocated string for pretty-printing exclusion names.
  */
 static
-char *print_exclusions(char **names)
+char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusions)
 {
        int length = 0;
-       int i;
+       size_t i;
        const char preamble[] = " excluding ";
        char *ret;
-       int count = names ? strutils_array_of_strings_len(names) : 0;
+       const size_t count = lttng_dynamic_pointer_array_get_count(exclusions);
 
        if (count == 0) {
                return strdup("");
        }
 
-       /* calculate total required length */
+       /* Calculate total required length. */
        for (i = 0; i < count; i++) {
-               length += strlen(names[i]) + 4;
+               const char *exclusion = lttng_dynamic_pointer_array_get_pointer(
+                               exclusions, i);
+
+               length += strlen(exclusion) + 4;
        }
 
        length += sizeof(preamble);
@@ -250,10 +258,14 @@ char *print_exclusions(char **names)
        if (!ret) {
                return NULL;
        }
+
        strncpy(ret, preamble, length);
        for (i = 0; i < count; i++) {
+               const char *exclusion = lttng_dynamic_pointer_array_get_pointer(
+                               exclusions, i);
+
                strcat(ret, "\"");
-               strcat(ret, names[i]);
+               strcat(ret, exclusion);
                strcat(ret, "\"");
                if (i != count - 1) {
                        strcat(ret, ", ");
@@ -323,16 +335,8 @@ end:
        return ret;
 }
 
-/*
- * FIXME: find a good place to declare this since add trigger also uses it
- */
-LTTNG_HIDDEN
-int validate_exclusion_list(
-               const char *event_name, const char *const *exclusions);
-
-LTTNG_HIDDEN
-int validate_exclusion_list(
-               const char *event_name, const char *const *exclusions)
+int validate_exclusion_list(const char *event_name,
+               const struct lttng_dynamic_pointer_array *exclusions)
 {
        int ret;
 
@@ -349,12 +353,18 @@ int validate_exclusion_list(
         * all exclusions are passed to the session daemon.
         */
        if (strutils_is_star_at_the_end_only_glob_pattern(event_name)) {
-               const char *const *exclusion;
+               size_t i, num_exclusions;
+
+               num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions);
+
+               for (i = 0; i < num_exclusions; i++) {
+                       const char *exclusion =
+                                       lttng_dynamic_pointer_array_get_pointer(
+                                                       exclusions, i);
 
-               for (exclusion = exclusions; *exclusion; exclusion++) {
-                       if (!strutils_is_star_glob_pattern(*exclusion) ||
-                                       strutils_is_star_at_the_end_only_glob_pattern(*exclusion)) {
-                               ret = check_exclusion_subsets(event_name, *exclusion);
+                       if (!strutils_is_star_glob_pattern(exclusion) ||
+                                       strutils_is_star_at_the_end_only_glob_pattern(exclusion)) {
+                               ret = check_exclusion_subsets(event_name, exclusion);
                                if (ret) {
                                        goto error;
                                }
@@ -374,43 +384,43 @@ end:
 
 static int create_exclusion_list_and_validate(const char *event_name,
                const char *exclusions_arg,
-               char ***exclusion_list)
+               struct lttng_dynamic_pointer_array *exclusions)
 {
        int ret = 0;
-       char **exclusions = NULL;
 
        /* Split exclusions. */
-       exclusions = strutils_split(exclusions_arg, ',', true);
-       if (!exclusions) {
+       ret = strutils_split(exclusions_arg, ',', true, exclusions);
+       if (ret < 0) {
                goto error;
        }
 
-       if (validate_exclusion_list(event_name, (const char **) exclusions) !=
+       if (validate_exclusion_list(event_name, exclusions) !=
                        0) {
                goto error;
        }
 
-       *exclusion_list = exclusions;
-
        goto end;
 
 error:
        ret = -1;
-       strutils_free_null_terminated_array_of_strings(exclusions);
+       lttng_dynamic_pointer_array_reset(exclusions);
 
 end:
        return ret;
 }
 
-static void warn_on_truncated_exclusion_names(char * const *exclusion_list,
+static void warn_on_truncated_exclusion_names(const struct lttng_dynamic_pointer_array *exclusions,
        int *warn)
 {
-       char * const *exclusion;
+       size_t i;
+       const size_t num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions);
+
+       for (i = 0; i < num_exclusions; i++) {
+               const char * const exclusion = lttng_dynamic_pointer_array_get_pointer(exclusions, i);
 
-       for (exclusion = exclusion_list; *exclusion; exclusion++) {
-               if (strlen(*exclusion) >= LTTNG_SYMBOL_NAME_LEN) {
+               if (strlen(exclusion) >= LTTNG_SYMBOL_NAME_LEN) {
                        WARN("Event exclusion \"%s\" will be truncated",
-                               *exclusion);
+                                       exclusion);
                        *warn = 1;
                }
        }
@@ -426,11 +436,11 @@ static int enable_events(char *session_name)
        int error_holder = CMD_SUCCESS, warn = 0, error = 0, success = 1;
        char *event_name, *channel_name = NULL;
        struct lttng_event *ev;
-       struct lttng_domain dom;
-       char **exclusion_list = NULL;
+       struct lttng_domain dom = {};
+       struct lttng_dynamic_pointer_array exclusions;
        struct lttng_userspace_probe_location *uprobe_loc = NULL;
 
-       memset(&dom, 0, sizeof(dom));
+       lttng_dynamic_pointer_array_init(&exclusions, NULL);
 
        ev = lttng_event_create();
        if (!ev) {
@@ -589,22 +599,22 @@ static int enable_events(char *session_name)
 
                if (opt_exclude) {
                        ret = create_exclusion_list_and_validate("*",
-                               opt_exclude, &exclusion_list);
+                               opt_exclude, &exclusions);
                        if (ret) {
                                ret = CMD_ERROR;
                                goto error;
                        }
 
                        ev->exclusion = 1;
-                       warn_on_truncated_exclusion_names(exclusion_list,
+                       warn_on_truncated_exclusion_names(&exclusions,
                                &warn);
                }
                if (!opt_filter) {
                        ret = lttng_enable_event_with_exclusions(handle,
                                        ev, channel_name,
                                        NULL,
-                                       exclusion_list ? strutils_array_of_strings_len(exclusion_list) : 0,
-                                       exclusion_list);
+                                       lttng_dynamic_pointer_array_get_count(&exclusions),
+                                       (char **) exclusions.array.buffer.data);
                        if (ret < 0) {
                                switch (-ret) {
                                case LTTNG_ERR_KERN_EVENT_EXIST:
@@ -638,7 +648,7 @@ static int enable_events(char *session_name)
                        switch (opt_event_type) {
                        case LTTNG_EVENT_TRACEPOINT:
                                if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) {
-                                       char *exclusion_string = print_exclusions(exclusion_list);
+                                       char *exclusion_string = print_exclusions(&exclusions);
 
                                        if (!exclusion_string) {
                                                PERROR("Cannot allocate exclusion_string");
@@ -652,7 +662,7 @@ static int enable_events(char *session_name)
                                                        opt_loglevel);
                                        free(exclusion_string);
                                } else {
-                                       char *exclusion_string = print_exclusions(exclusion_list);
+                                       char *exclusion_string = print_exclusions(&exclusions);
 
                                        if (!exclusion_string) {
                                                PERROR("Cannot allocate exclusion_string");
@@ -675,7 +685,7 @@ static int enable_events(char *session_name)
                                break;
                        case LTTNG_EVENT_ALL:
                                if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) {
-                                       char *exclusion_string = print_exclusions(exclusion_list);
+                                       char *exclusion_string = print_exclusions(&exclusions);
 
                                        if (!exclusion_string) {
                                                PERROR("Cannot allocate exclusion_string");
@@ -689,7 +699,7 @@ static int enable_events(char *session_name)
                                                        opt_loglevel);
                                        free(exclusion_string);
                                } else {
-                                       char *exclusion_string = print_exclusions(exclusion_list);
+                                       char *exclusion_string = print_exclusions(&exclusions);
 
                                        if (!exclusion_string) {
                                                PERROR("Cannot allocate exclusion_string");
@@ -714,9 +724,9 @@ static int enable_events(char *session_name)
 
                if (opt_filter) {
                        command_ret = lttng_enable_event_with_exclusions(handle, ev, channel_name,
-                                               opt_filter,
-                                               exclusion_list ? strutils_array_of_strings_len(exclusion_list) : 0,
-                                               exclusion_list);
+                                       opt_filter,
+                                       lttng_dynamic_pointer_array_get_count(&exclusions),
+                                       (char **) exclusions.array.buffer.data);
                        if (command_ret < 0) {
                                switch (-command_ret) {
                                case LTTNG_ERR_FILTER_EXIST:
@@ -776,7 +786,7 @@ static int enable_events(char *session_name)
                        }
 
                        /* print exclusion */
-                       ret = mi_print_exclusion(exclusion_list);
+                       ret = mi_print_exclusion(&exclusions);
                        if (ret) {
                                ret = CMD_ERROR;
                                goto error;
@@ -911,20 +921,18 @@ static int enable_events(char *session_name)
                                        ret = CMD_ERROR;
                                        goto error;
                                }
-                               /* Free previously allocated items */
-                               strutils_free_null_terminated_array_of_strings(
-                                       exclusion_list);
-                               exclusion_list = NULL;
+                               /* Free previously allocated items. */
+                               lttng_dynamic_pointer_array_reset(&exclusions);
                                ret = create_exclusion_list_and_validate(
                                        event_name, opt_exclude,
-                                       &exclusion_list);
+                                       &exclusions);
                                if (ret) {
                                        ret = CMD_ERROR;
                                        goto error;
                                }
 
                                warn_on_truncated_exclusion_names(
-                                       exclusion_list, &warn);
+                                       &exclusions, &warn);
                        }
 
                        ev->loglevel_type = opt_loglevel_type;
@@ -999,9 +1007,9 @@ static int enable_events(char *session_name)
                        command_ret = lttng_enable_event_with_exclusions(handle,
                                        ev, channel_name,
                                        NULL,
-                                       exclusion_list ? strutils_array_of_strings_len(exclusion_list) : 0,
-                                       exclusion_list);
-                       exclusion_string = print_exclusions(exclusion_list);
+                                       lttng_dynamic_pointer_array_get_count(&exclusions),
+                                       (char **) exclusions.array.buffer.data);
+                       exclusion_string = print_exclusions(&exclusions);
                        if (!exclusion_string) {
                                PERROR("Cannot allocate exclusion_string");
                                error = 1;
@@ -1083,9 +1091,9 @@ static int enable_events(char *session_name)
 
                        command_ret = lttng_enable_event_with_exclusions(handle, ev, channel_name,
                                        opt_filter,
-                                       exclusion_list ? strutils_array_of_strings_len(exclusion_list) : 0,
-                                       exclusion_list);
-                       exclusion_string = print_exclusions(exclusion_list);
+                                       lttng_dynamic_pointer_array_get_count(&exclusions),
+                                       (char **) exclusions.array.buffer.data);
+                       exclusion_string = print_exclusions(&exclusions);
                        if (!exclusion_string) {
                                PERROR("Cannot allocate exclusion_string");
                                error = 1;
@@ -1148,7 +1156,7 @@ static int enable_events(char *session_name)
                        }
 
                        /* print exclusion */
-                       ret = mi_print_exclusion(exclusion_list);
+                       ret = mi_print_exclusion(&exclusions);
                        if (ret) {
                                ret = CMD_ERROR;
                                goto error;
@@ -1194,7 +1202,7 @@ error:
                ret = CMD_ERROR;
        }
        lttng_destroy_handle(handle);
-       strutils_free_null_terminated_array_of_strings(exclusion_list);
+       lttng_dynamic_pointer_array_reset(&exclusions);
        lttng_userspace_probe_location_destroy(uprobe_loc);
 
        /* Overwrite ret with error_holder if there was an actual error with
index c51c44af05d2650a3edd79605f0ff77d92b3e729..6af20bbdee0e6836a5bd668058345898390d6f3a 100644 (file)
@@ -200,22 +200,24 @@ int parse_userspace_probe_opts(const char *opt,
                struct lttng_userspace_probe_location **probe_location)
 {
        int ret = CMD_SUCCESS;
-       int num_token;
-       char **tokens = NULL;
+       size_t num_token = 0;
        char *target_path = NULL;
        char *unescaped_target_path = NULL;
        char *real_target_path = NULL;
        char *symbol_name = NULL, *probe_name = NULL, *provider_name = NULL;
        struct lttng_userspace_probe_location *probe_location_local = NULL;
        struct lttng_userspace_probe_location_lookup_method *lookup_method = NULL;
+       struct lttng_dynamic_pointer_array tokens;
 
        assert(opt);
 
        /*
         * userspace probe fields are separated by ':'.
         */
-       tokens = strutils_split(opt, ':', 1);
-       num_token = strutils_array_of_strings_len(tokens);
+       ret = strutils_split(opt, ':', true, &tokens);
+       if (ret == 0) {
+               num_token = lttng_dynamic_pointer_array_get_count(&tokens);
+       }
 
        /*
         * Early sanity check that the number of parameter is between 2 and 4
@@ -224,7 +226,7 @@ int parse_userspace_probe_opts(const char *opt,
         * std:PATH:PROVIDER_NAME:PROBE_NAME
         * PATH:SYMBOL (same behavior as ELF)
         */
-       if (num_token < 2 || num_token > 4) {
+       if (ret < 0 || num_token < 2 || num_token > 4) {
                ret = CMD_ERROR;
                goto end;
        }
@@ -237,12 +239,12 @@ int parse_userspace_probe_opts(const char *opt,
        case 2:
                /* When the probe type is omitted we assume ELF for now. */
        case 3:
-               if (num_token == 3 && strcmp(tokens[0], "elf") == 0) {
-                       target_path = tokens[1];
-                       symbol_name = tokens[2];
+               if (num_token == 3 && strcmp(lttng_dynamic_pointer_array_get_pointer(&tokens, 0), "elf") == 0) {
+                       target_path = lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
+                       symbol_name = lttng_dynamic_pointer_array_get_pointer(&tokens, 2);
                } else if (num_token == 2) {
-                       target_path = tokens[0];
-                       symbol_name = tokens[1];
+                       target_path = lttng_dynamic_pointer_array_get_pointer(&tokens, 0);
+                       symbol_name = lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
                } else {
                        ret = CMD_ERROR;
                        goto end;
@@ -256,10 +258,10 @@ int parse_userspace_probe_opts(const char *opt,
                }
                break;
        case 4:
-               if (strcmp(tokens[0], "sdt") == 0) {
-                       target_path = tokens[1];
-                       provider_name = tokens[2];
-                       probe_name = tokens[3];
+               if (strcmp(lttng_dynamic_pointer_array_get_pointer(&tokens, 0), "sdt") == 0) {
+                       target_path = lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
+                       provider_name = lttng_dynamic_pointer_array_get_pointer(&tokens, 2);
+                       probe_name = lttng_dynamic_pointer_array_get_pointer(&tokens, 3);
                } else {
                        ret = CMD_ERROR;
                        goto end;
@@ -375,7 +377,7 @@ int parse_userspace_probe_opts(const char *opt,
 end:
        lttng_userspace_probe_location_destroy(probe_location_local);
        lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
-       strutils_free_null_terminated_array_of_strings(tokens);
+       lttng_dynamic_pointer_array_reset(&tokens);
        /*
         * Freeing both char * here makes the error handling simplier. free()
         * performs not action if the pointer is NULL.
index a51c8579a8e42d7de4549f44d0792ae0a5971f25..97fb202ba3f15b3924a1d1dd483331c8ce2b3b94 100644 (file)
@@ -9,7 +9,8 @@
 #define _LTTNG_UTILS_H
 
 #include <popt.h>
-#include "common/argpar/argpar.h"
+#include <common/argpar/argpar.h>
+#include <common/dynamic-array.h>
 
 #include <lttng/lttng.h>
 
@@ -60,4 +61,7 @@ int print_trace_archive_location(
                const struct lttng_trace_archive_location *location,
                const char *session_name);
 
+int validate_exclusion_list(const char *event_name,
+               const struct lttng_dynamic_pointer_array *exclusions);
+
 #endif /* _LTTNG_UTILS_H */
index df278fa4796cf497bcb70e573061c92aaf1eec46..e6a88a1fabb1177fbb8b6d731317e2b1523c34b6 100644 (file)
@@ -180,6 +180,12 @@ noinst_HEADERS = \
        uri.h \
        utils.h
 
+noinst_PROGRAMS = filter-grammar-test
+filter_grammar_test_SOURCES = filter-grammar-test.c
+filter_grammar_test_LDADD = \
+       libcommon.la
+filter_grammar_test_CFLAGS = -I $(top_builddir)/src/common
+
 all-local:
        @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
                for script in $(EXTRA_DIST); do \
diff --git a/src/common/filter-grammar-test.c b/src/common/filter-grammar-test.c
new file mode 100644 (file)
index 0000000..bd21cf8
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * filter-grammar-test.c
+ *
+ * LTTng filter grammar test
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <inttypes.h>
+
+#include <common/compat/errno.h>
+#include "common/bytecode/bytecode.h"
+#include "filter/filter-ast.h"
+#include "filter/filter-parser.h"
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+int main(int argc, char **argv)
+{
+       struct filter_parser_ctx *ctx;
+       int ret;
+       int print_xml = 0, generate_ir = 0, generate_bytecode = 0,
+               print_bytecode = 0;
+       int argidx;
+
+       for (argidx = 1; argidx < argc; argidx++) {
+               if (strcmp(argv[argidx], "-p") == 0)
+                       print_xml = 1;
+               else if (strcmp(argv[argidx], "-i") == 0)
+                       generate_ir = 1;
+               else if (strcmp(argv[argidx], "-b") == 0)
+                       generate_bytecode = 1;
+               else if (strcmp(argv[argidx], "-d") == 0)
+                       filter_parser_debug = 1;
+               else if (strcmp(argv[argidx], "-B") == 0)
+                       print_bytecode = 1;
+       }
+
+       /*
+        * Force generate the bytecode if the user asks to print the bytecode
+        * (can't print it without generating it first).
+        */
+       if (print_bytecode) {
+               generate_bytecode = 1;
+       }
+
+       /*
+        * Force generate the IR if the user asks to generate the bytecode
+        * (the bytecode is generated by visiting the IR).
+        */
+       if (generate_bytecode) {
+               generate_ir = 1;
+       }
+
+       ctx = filter_parser_ctx_alloc(stdin);
+       if (!ctx) {
+               fprintf(stderr, "Error allocating parser\n");
+               goto alloc_error;
+       }
+       ret = filter_parser_ctx_append_ast(ctx);
+       if (ret) {
+               fprintf(stderr, "Parse error\n");
+               goto parse_error;
+       }
+       if (print_xml) {
+               ret = filter_visitor_print_xml(ctx, stdout, 0);
+               if (ret) {
+                       fflush(stdout);
+                       fprintf(stderr, "XML print error\n");
+                       goto parse_error;
+               }
+       }
+       if (generate_ir) {
+               printf("Generating IR... ");
+               fflush(stdout);
+               ret = filter_visitor_ir_generate(ctx);
+               if (ret) {
+                       fprintf(stderr, "Generate IR error\n");
+                       goto parse_error;
+               }
+               printf("done\n");
+
+               printf("Validating IR... ");
+               fflush(stdout);
+               ret = filter_visitor_ir_check_binary_op_nesting(ctx);
+               if (ret) {
+                       goto parse_error;
+               }
+               printf("done\n");
+       }
+       if (generate_bytecode) {
+               printf("Generating bytecode... ");
+               fflush(stdout);
+               ret = filter_visitor_bytecode_generate(ctx);
+               if (ret) {
+                       fprintf(stderr, "Generate bytecode error\n");
+                       goto parse_error;
+               }
+               printf("done\n");
+               printf("Size of bytecode generated: %u bytes.\n",
+                       bytecode_get_len(&ctx->bytecode->b));
+       }
+
+       if (print_bytecode) {
+               unsigned int bytecode_len, len, i;
+
+               len = bytecode_get_len(&ctx->bytecode->b);
+               bytecode_len = ctx->bytecode->b.reloc_table_offset;
+               printf("Bytecode:\n");
+               for (i = 0; i < bytecode_len; i++) {
+                       printf("0x%X ",
+                               ((uint8_t *) ctx->bytecode->b.data)[i]);
+               }
+               printf("\n");
+               printf("Reloc table:\n");
+               for (i = bytecode_len; i < len;) {
+                       printf("{ 0x%X, ",
+                               *(uint16_t *) &ctx->bytecode->b.data[i]);
+                       i += sizeof(uint16_t);
+                       printf("%s } ", &((char *) ctx->bytecode->b.data)[i]);
+                       i += strlen(&((char *) ctx->bytecode->b.data)[i]) + 1;
+               }
+               printf("\n");
+       }
+
+       filter_bytecode_free(ctx);
+       filter_ir_free(ctx);
+       filter_parser_ctx_free(ctx);
+       return 0;
+
+parse_error:
+       filter_bytecode_free(ctx);
+       filter_ir_free(ctx);
+       filter_parser_ctx_free(ctx);
+alloc_error:
+       exit(EXIT_FAILURE);
+}
index 261acc0861740b82297d342f9183fc4a4446803b..62928035654f65b48d413e0239cb5a6cadc9f74e 100644 (file)
@@ -2,7 +2,6 @@
 
 AM_CPPFLAGS += -I$(srcdir) -I$(builddir)
 
-noinst_PROGRAMS = filter-grammar-test
 noinst_LTLIBRARIES = libfilter.la
 noinst_HEADERS = filter-ast.h \
                filter-symbols.h
@@ -60,8 +59,3 @@ filter-lexer.c: filter-lexer.l
 
 all-local: filter-lexer.c
 endif # HAVE_FLEX
-
-filter_grammar_test_SOURCES = filter-grammar-test.c
-filter_grammar_test_LDADD = \
-       libfilter.la \
-       ../bytecode/libbytecode.la
diff --git a/src/common/filter/filter-grammar-test.c b/src/common/filter/filter-grammar-test.c
deleted file mode 100644 (file)
index 349dc47..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * filter-grammar-test.c
- *
- * LTTng filter grammar test
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <inttypes.h>
-
-#include <common/compat/errno.h>
-#include "common/bytecode/bytecode.h"
-#include "filter-ast.h"
-#include "filter-parser.h"
-
-int main(int argc, char **argv)
-{
-       struct filter_parser_ctx *ctx;
-       int ret;
-       int print_xml = 0, generate_ir = 0, generate_bytecode = 0,
-               print_bytecode = 0;
-       int argidx;
-
-       for (argidx = 1; argidx < argc; argidx++) {
-               if (strcmp(argv[argidx], "-p") == 0)
-                       print_xml = 1;
-               else if (strcmp(argv[argidx], "-i") == 0)
-                       generate_ir = 1;
-               else if (strcmp(argv[argidx], "-b") == 0)
-                       generate_bytecode = 1;
-               else if (strcmp(argv[argidx], "-d") == 0)
-                       filter_parser_debug = 1;
-               else if (strcmp(argv[argidx], "-B") == 0)
-                       print_bytecode = 1;
-       }
-
-       /*
-        * Force generate the bytecode if the user asks to print the bytecode
-        * (can't print it without generating it first).
-        */
-       if (print_bytecode) {
-               generate_bytecode = 1;
-       }
-
-       /*
-        * Force generate the IR if the user asks to generate the bytecode
-        * (the bytecode is generated by visiting the IR).
-        */
-       if (generate_bytecode) {
-               generate_ir = 1;
-       }
-
-       ctx = filter_parser_ctx_alloc(stdin);
-       if (!ctx) {
-               fprintf(stderr, "Error allocating parser\n");
-               goto alloc_error;
-       }
-       ret = filter_parser_ctx_append_ast(ctx);
-       if (ret) {
-               fprintf(stderr, "Parse error\n");
-               goto parse_error;
-       }
-       if (print_xml) {
-               ret = filter_visitor_print_xml(ctx, stdout, 0);
-               if (ret) {
-                       fflush(stdout);
-                       fprintf(stderr, "XML print error\n");
-                       goto parse_error;
-               }
-       }
-       if (generate_ir) {
-               printf("Generating IR... ");
-               fflush(stdout);
-               ret = filter_visitor_ir_generate(ctx);
-               if (ret) {
-                       fprintf(stderr, "Generate IR error\n");
-                       goto parse_error;
-               }
-               printf("done\n");
-
-               printf("Validating IR... ");
-               fflush(stdout);
-               ret = filter_visitor_ir_check_binary_op_nesting(ctx);
-               if (ret) {
-                       goto parse_error;
-               }
-               printf("done\n");
-       }
-       if (generate_bytecode) {
-               printf("Generating bytecode... ");
-               fflush(stdout);
-               ret = filter_visitor_bytecode_generate(ctx);
-               if (ret) {
-                       fprintf(stderr, "Generate bytecode error\n");
-                       goto parse_error;
-               }
-               printf("done\n");
-               printf("Size of bytecode generated: %u bytes.\n",
-                       bytecode_get_len(&ctx->bytecode->b));
-       }
-
-       if (print_bytecode) {
-               unsigned int bytecode_len, len, i;
-
-               len = bytecode_get_len(&ctx->bytecode->b);
-               bytecode_len = ctx->bytecode->b.reloc_table_offset;
-               printf("Bytecode:\n");
-               for (i = 0; i < bytecode_len; i++) {
-                       printf("0x%X ",
-                               ((uint8_t *) ctx->bytecode->b.data)[i]);
-               }
-               printf("\n");
-               printf("Reloc table:\n");
-               for (i = bytecode_len; i < len;) {
-                       printf("{ 0x%X, ",
-                               *(uint16_t *) &ctx->bytecode->b.data[i]);
-                       i += sizeof(uint16_t);
-                       printf("%s } ", &((char *) ctx->bytecode->b.data)[i]);
-                       i += strlen(&((char *) ctx->bytecode->b.data)[i]) + 1;
-               }
-               printf("\n");
-       }
-
-       filter_bytecode_free(ctx);
-       filter_ir_free(ctx);
-       filter_parser_ctx_free(ctx);
-       return 0;
-
-parse_error:
-       filter_bytecode_free(ctx);
-       filter_ir_free(ctx);
-       filter_parser_ctx_free(ctx);
-alloc_error:
-       exit(EXIT_FAILURE);
-}
index e77ddfedbf51a1a88ad3c1f47d5b498ff3611032..669f7d05fd01c64513b68128a740c8940fdcaa9d 100644 (file)
@@ -194,11 +194,9 @@ void strutils_free_null_terminated_array_of_strings(char **array)
 /*
  * Splits the input string `input` using the given delimiter `delim`.
  *
- * The return value is an allocated null-terminated array of the
- * resulting substrings (also allocated). You can free this array and
- * its content with strutils_free_null_terminated_array_of_strings(). You
- * can get the number of substrings in it with
- * strutils_array_of_strings_len().
+ * The return value is a dynamic pointer array that is assumed to be empty. The
+ * array must be discarded by the caller by invoking
+ * lttng_dynamic_pointer_array_reset().
  *
  * Empty substrings are part of the result. For example:
  *
@@ -241,21 +239,25 @@ void strutils_free_null_terminated_array_of_strings(char **array)
  *       `\`
  *       `hi`
  *
- * Returns NULL if there's an error.
+ * Returns -1 if there's an error.
  */
 LTTNG_HIDDEN
-char **strutils_split(const char *input, char delim, bool escape_delim)
+int strutils_split(const char *input,
+               char delim,
+               bool escape_delim,
+               struct lttng_dynamic_pointer_array *out_strings)
 {
+       int ret;
        size_t at;
        size_t number_of_substrings = 1;
        size_t longest_substring_len = 0;
        const char *s;
        const char *last;
-       char **substrings = NULL;
 
        assert(input);
        assert(!(escape_delim && delim == '\\'));
        assert(delim != '\0');
+       lttng_dynamic_pointer_array_init(out_strings, free);
 
        /* First pass: count the number of substrings. */
        for (s = input, last = input - 1; *s != '\0'; s++) {
@@ -285,18 +287,20 @@ char **strutils_split(const char *input, char delim, bool escape_delim)
                longest_substring_len = s - last - 1;
        }
 
-       substrings = calloc(number_of_substrings + 1, sizeof(*substrings));
-       if (!substrings) {
-               goto error;
-       }
-
        /* Second pass: actually split and copy substrings. */
        for (at = 0, s = input; at < number_of_substrings; at++) {
                const char *ss;
                char *d;
+               char *substring = zmalloc(longest_substring_len + 1);
+
+               if (!substring) {
+                       goto error;
+               }
 
-               substrings[at] = zmalloc(longest_substring_len + 1);
-               if (!substrings[at]) {
+               ret = lttng_dynamic_pointer_array_add_pointer(
+                               out_strings, substring);
+               if (ret) {
+                       free(substring);
                        goto error;
                }
 
@@ -304,7 +308,7 @@ char **strutils_split(const char *input, char delim, bool escape_delim)
                 * Copy characters to substring until we find the next
                 * delimiter or the end of the input string.
                 */
-               for (ss = s, d = substrings[at]; *ss != '\0'; ss++) {
+               for (ss = s, d = substring; *ss != '\0'; ss++) {
                        if (escape_delim && *ss == '\\') {
                                if (ss[1] == delim) {
                                        /*
@@ -343,13 +347,13 @@ char **strutils_split(const char *input, char delim, bool escape_delim)
                s = ss + 1;
        }
 
+       ret = 0;
        goto end;
 
 error:
-       strutils_free_null_terminated_array_of_strings(substrings);
-       substrings = NULL;
+       ret = -1;
 end:
-       return substrings;
+       return ret;
 }
 
 LTTNG_HIDDEN
index 3c1a413cee5e51cbce03c4fa410e4d7042d6e6e7..9d287f3d9b4f7aa0849d4ecb42c1a7ef211f5ea1 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <stdbool.h>
 #include <common/macros.h>
+#include <common/dynamic-array.h>
 
 LTTNG_HIDDEN
 void strutils_normalize_star_glob_pattern(char *pattern);
@@ -24,7 +25,8 @@ LTTNG_HIDDEN
 char *strutils_unescape_string(const char *input, char only_char);
 
 LTTNG_HIDDEN
-char **strutils_split(const char *input, char delim, bool escape_delim);
+int strutils_split(const char *input, char delim, bool escape_delim,
+               struct lttng_dynamic_pointer_array *out_strings);
 
 LTTNG_HIDDEN
 void strutils_free_null_terminated_array_of_strings(char **array);
index b11091637298b4b549ab2888077c47a5c2e78ed8..1d61bc41fbfc8e4c3dae3a2d0c52dca054fe4560 100644 (file)
 /* Number of TAP tests in this file */
 #define NUM_TESTS 69
 
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
 static void test_one_split(const char *input, char delim, int escape_delim,
                ...)
 {
        va_list vl;
-       char **substrings;
-       char * const *substring;
        bool all_ok = true;
+       struct lttng_dynamic_pointer_array strings;
+       int split_ret;
+       size_t i, string_count;
 
-       substrings = strutils_split(input, delim, escape_delim);
-       assert(substrings);
+       split_ret = strutils_split(input, delim, escape_delim, &strings);
+       assert(split_ret == 0);
        va_start(vl, escape_delim);
 
-       for (substring = substrings; *substring; substring++) {
+       string_count = lttng_dynamic_pointer_array_get_count(&strings);
+
+       for (i = 0; i < string_count; i++) {
                const char *expected_substring = va_arg(vl, const char *);
+               const char *substring =
+                               lttng_dynamic_pointer_array_get_pointer(
+                                               &strings, i);
 
-               diag("  got `%s`, expecting `%s`", *substring, expected_substring);
+               diag("  got `%s`, expecting `%s`", substring, expected_substring);
 
                if (!expected_substring) {
                        all_ok = false;
                        break;
                }
 
-               if (strcmp(*substring, expected_substring) != 0) {
+               if (strcmp(substring, expected_substring) != 0) {
                        all_ok = false;
                        break;
                }
        }
 
-       strutils_free_null_terminated_array_of_strings(substrings);
+       lttng_dynamic_pointer_array_reset(&strings);
        va_end(vl);
        ok(all_ok, "strutils_split() produces the expected substrings: `%s` (delim. `%c`, escape `%d`)",
-               input, delim, escape_delim);
+                       input, delim, escape_delim);
 }
 
 static void test_split(void)
This page took 0.045541 seconds and 4 git commands to generate.