From: Francis Deslauriers Date: Fri, 9 Feb 2018 21:56:48 +0000 (-0500) Subject: Fix: probes should be compared strictly by events metadata X-Git-Tag: v2.11.0-rc1~225 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=98b73e886719378d507d500058dd4e4d7e5488bf;p=lttng-tools.git Fix: probes should be compared strictly by events metadata Currently, events are compared using names and signatures. Events with different payloads but identical name and signatures could lead to corrupted trace because the Session Daemon would consider them identical and give them the same event ID. Events should be compared using the name, loglevel, fields and model_emf_uri to ensure that their respective metadata is the same. Signed-off-by: Francis Deslauriers Signed-off-by: Jérémie Galarneau --- diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am index 156b6d822..d57c63963 100644 --- a/src/bin/lttng-sessiond/Makefile.am +++ b/src/bin/lttng-sessiond/Makefile.am @@ -44,7 +44,8 @@ lttng_sessiond_SOURCES = utils.c utils.h \ if HAVE_LIBLTTNG_UST_CTL lttng_sessiond_SOURCES += trace-ust.c ust-registry.c ust-app.c \ ust-consumer.c ust-consumer.h ust-thread.c \ - ust-metadata.c ust-clock.h agent-thread.c agent-thread.h + ust-metadata.c ust-clock.h agent-thread.c agent-thread.h \ + ust-field-utils.h ust-field-utils.c endif # Add main.c at the end for compile order diff --git a/src/bin/lttng-sessiond/ust-field-utils.c b/src/bin/lttng-sessiond/ust-field-utils.c new file mode 100644 index 000000000..8e890557b --- /dev/null +++ b/src/bin/lttng-sessiond/ust-field-utils.c @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2018 - Francis Deslauriers + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include "ust-field-utils.h" + +/* + * The ustctl_field is made of a combination of C basic types + * ustctl_basic_type and _ustctl_basic_type. + * + * ustctl_basic_type contains an enumeration describing the abstract type. + * _ustctl_basic_type does _NOT_ contain an enumeration describing the + * abstract type. + * + * A layer is needed to use the same code for both structures. + * When dealing with _ustctl_basic_type, we need to use the abstract type of + * the ustctl_type struct. + */ + +/* + * Compare two ustctl_integer_type fields. + * Returns 1 if both are identical. + */ +static bool match_ustctl_field_integer(const struct ustctl_integer_type *first, + const struct ustctl_integer_type *second) +{ + if (first->size != second->size) { + goto no_match; + } + if (first->alignment != second->alignment) { + goto no_match; + } + if (first->signedness != second->signedness) { + goto no_match; + } + if (first->encoding != second->encoding) { + goto no_match; + } + if (first->base != second->base) { + goto no_match; + } + if (first->reverse_byte_order != second->reverse_byte_order) { + goto no_match; + } + + return true; + +no_match: + return false; +} + +/* + * Compare two _ustctl_basic_type fields known to be of type integer. + * Returns 1 if both are identical. + */ +static bool match_ustctl_field_integer_from_raw_basic_type( + const union _ustctl_basic_type *first, + const union _ustctl_basic_type *second) +{ + return match_ustctl_field_integer(&first->integer, &second->integer); +} + +/* + * Compare two _ustctl_basic_type fields known to be of type enum. + * Returns 1 if both are identical. + */ +static bool match_ustctl_field_enum_from_raw_basic_type( + const union _ustctl_basic_type *first, + const union _ustctl_basic_type *second) +{ + /* + * Compare enumeration ID. Enumeration ID is provided to the application by + * the session daemon before event registration. + */ + if (first->enumeration.id != second->enumeration.id) { + goto no_match; + } + + /* + * Sanity check of the name and container type. Those were already checked + * during enum registration. + */ + if (strncmp(first->enumeration.name, second->enumeration.name, + LTTNG_UST_SYM_NAME_LEN)) { + goto no_match; + } + if (!match_ustctl_field_integer(&first->enumeration.container_type, + &second->enumeration.container_type)) { + goto no_match; + } + + return true; + +no_match: + return false; +} + +/* + * Compare two _ustctl_basic_type fields known to be of type string. + * Returns 1 if both are identical. + */ +static bool match_ustctl_field_string_from_raw_basic_type( + const union _ustctl_basic_type *first, + const union _ustctl_basic_type *second) +{ + return first->string.encoding == second->string.encoding; +} + +/* + * Compare two _ustctl_basic_type fields known to be of type float. + * Returns 1 if both are identical. + */ +static bool match_ustctl_field_float_from_raw_basic_type( + const union _ustctl_basic_type *first, + const union _ustctl_basic_type *second) +{ + if (first->_float.exp_dig != second->_float.exp_dig) { + goto no_match; + } + + if (first->_float.mant_dig != second->_float.mant_dig) { + goto no_match; + } + + if (first->_float.reverse_byte_order != + second->_float.reverse_byte_order) { + goto no_match; + } + + if (first->_float.alignment != second->_float.alignment) { + goto no_match; + } + + return true; + +no_match: + return false; +} + +/* + * Compare two _ustctl_basic_type fields given their respective abstract types. + * Returns 1 if both are identical. + */ +static bool match_ustctl_field_raw_basic_type( + enum ustctl_abstract_types first_atype, + const union _ustctl_basic_type *first, + enum ustctl_abstract_types second_atype, + const union _ustctl_basic_type *second) +{ + if (first_atype != second_atype) { + goto no_match; + } + + switch (first_atype) { + case ustctl_atype_integer: + if (!match_ustctl_field_integer_from_raw_basic_type(first, second)) { + goto no_match; + } + break; + case ustctl_atype_enum: + if (!match_ustctl_field_enum_from_raw_basic_type(first, second)) { + goto no_match; + } + break; + case ustctl_atype_string: + if (!match_ustctl_field_string_from_raw_basic_type(first, second)) { + goto no_match; + } + break; + case ustctl_atype_float: + if (!match_ustctl_field_float_from_raw_basic_type(first, second)) { + goto no_match; + } + break; + default: + goto no_match; + } + + return true; + +no_match: + return false; +} + +/* + * Compatibility layer between the ustctl_basic_type struct and + * _ustctl_basic_type union. + */ +static bool match_ustctl_field_basic_type(const struct ustctl_basic_type *first, + const struct ustctl_basic_type *second) +{ + return match_ustctl_field_raw_basic_type(first->atype, &first->u.basic, + second->atype, &second->u.basic); +} + +int match_ustctl_field(const struct ustctl_field *first, + const struct ustctl_field *second) +{ + /* Check the name of the field is identical. */ + if (strncmp(first->name, second->name, LTTNG_UST_SYM_NAME_LEN)) { + goto no_match; + } + + /* Check the field type is identical. */ + if (first->type.atype != second->type.atype) { + goto no_match; + } + + /* Check the field layout. */ + switch (first->type.atype) { + case ustctl_atype_integer: + case ustctl_atype_enum: + case ustctl_atype_string: + case ustctl_atype_float: + if (!match_ustctl_field_raw_basic_type(first->type.atype, + &first->type.u.basic, second->type.atype, + &second->type.u.basic)) { + goto no_match; + } + break; + case ustctl_atype_sequence: + /* Match element type of the sequence. */ + if (!match_ustctl_field_basic_type(&first->type.u.sequence.elem_type, + &second->type.u.sequence.elem_type)) { + goto no_match; + } + + /* Match length type of the sequence. */ + if (!match_ustctl_field_basic_type(&first->type.u.sequence.length_type, + &second->type.u.sequence.length_type)) { + goto no_match; + } + break; + case ustctl_atype_array: + /* Match element type of the array. */ + if (!match_ustctl_field_basic_type(&first->type.u.array.elem_type, + &second->type.u.array.elem_type)) { + goto no_match; + } + + /* Match length of the array. */ + if (first->type.u.array.length != second->type.u.array.length) { + goto no_match; + } + break; + case ustctl_atype_variant: + /* Compare number of choice of the variants. */ + if (first->type.u.variant.nr_choices != + second->type.u.variant.nr_choices) { + goto no_match; + } + + /* Compare tag name of the variants. */ + if (strncmp(first->type.u.variant.tag_name, + second->type.u.variant.tag_name, + LTTNG_UST_SYM_NAME_LEN)) { + goto no_match; + } + break; + case ustctl_atype_struct: + /* Compare number of fields of the structs. */ + if (first->type.u._struct.nr_fields != second->type.u._struct.nr_fields) { + goto no_match; + } + break; + default: + goto no_match; + } + + return true; + +no_match: + return false; +} diff --git a/src/bin/lttng-sessiond/ust-field-utils.h b/src/bin/lttng-sessiond/ust-field-utils.h new file mode 100644 index 000000000..e75621f42 --- /dev/null +++ b/src/bin/lttng-sessiond/ust-field-utils.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 - Francis Deslauriers francis.deslauriers@efficios.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef LTTNG_UST_FIELD_UTILS_H +#define LTTNG_UST_FIELD_UTILS_H + +#include "ust-ctl.h" + +/* + * Compare two UST fields. + * Return 1 if both fields have identical definition, 0 otherwise. + */ +int match_ustctl_field(const struct ustctl_field *first, + const struct ustctl_field *second); + +#endif /* LTTNG_UST_FIELD_UTILS_H */ diff --git a/src/bin/lttng-sessiond/ust-registry.c b/src/bin/lttng-sessiond/ust-registry.c index ed830b608..615078b66 100644 --- a/src/bin/lttng-sessiond/ust-registry.c +++ b/src/bin/lttng-sessiond/ust-registry.c @@ -25,17 +25,20 @@ #include "ust-registry.h" #include "ust-app.h" +#include "ust-field-utils.h" #include "utils.h" #include "lttng-sessiond.h" #include "notification-thread-commands.h" + /* * Hash table match function for event in the registry. */ static int ht_match_event(struct cds_lfht_node *node, const void *_key) { - struct ust_registry_event *event; const struct ust_registry_event *key; + struct ust_registry_event *event; + int i; assert(node); assert(_key); @@ -44,15 +47,37 @@ static int ht_match_event(struct cds_lfht_node *node, const void *_key) assert(event); key = _key; - /* It has to be a perfect match. */ + /* It has to be a perfect match. First, compare the event names. */ if (strncmp(event->name, key->name, sizeof(event->name))) { goto no_match; } - /* It has to be a perfect match. */ - if (strncmp(event->signature, key->signature, - strlen(event->signature))) { + /* Compare log levels. */ + if (event->loglevel_value != key->loglevel_value) { + goto no_match; + } + + /* Compare the number of fields. */ + if (event->nr_fields != key->nr_fields) { + goto no_match; + } + + /* Compare each field individually. */ + for (i = 0; i < event->nr_fields; i++) { + if (!match_ustctl_field(&event->fields[i], &key->fields[i])) { + goto no_match; + } + } + + /* Compare model URI. */ + if (event->model_emf_uri != NULL && key->model_emf_uri == NULL) { + goto no_match; + } else if(event->model_emf_uri == NULL && key->model_emf_uri != NULL) { goto no_match; + } else if (event->model_emf_uri != NULL && key->model_emf_uri != NULL) { + if (strcmp(event->model_emf_uri, key->model_emf_uri)) { + goto no_match; + } } /* Match */ @@ -64,15 +89,14 @@ no_match: static unsigned long ht_hash_event(const void *_key, unsigned long seed) { - uint64_t xored_key; + uint64_t hashed_key; const struct ust_registry_event *key = _key; assert(key); - xored_key = (uint64_t) (hash_key_str(key->name, seed) ^ - hash_key_str(key->signature, seed)); + hashed_key = (uint64_t) hash_key_str(key->name, seed); - return hash_key_u64(&xored_key, seed); + return hash_key_u64(&hashed_key, seed); } static int compare_enums(const struct ust_registry_enum *reg_enum_a, diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 1ff6ab1d0..134e8ddc7 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -64,6 +64,7 @@ UST_DATA_TRACE=$(top_builddir)/src/bin/lttng-sessiond/trace-ust.$(OBJEXT) \ $(top_builddir)/src/bin/lttng-sessiond/utils.$(OBJEXT) \ $(top_builddir)/src/bin/lttng-sessiond/buffer-registry.$(OBJEXT) \ $(top_builddir)/src/bin/lttng-sessiond/ust-registry.$(OBJEXT) \ + $(top_builddir)/src/bin/lttng-sessiond/ust-field-utils.$(OBJEXT) \ $(top_builddir)/src/bin/lttng-sessiond/ust-metadata.$(OBJEXT) \ $(top_builddir)/src/bin/lttng-sessiond/ust-app.$(OBJEXT) \ $(top_builddir)/src/bin/lttng-sessiond/ust-consumer.$(OBJEXT) \