From: Philippe Proulx Date: Mon, 8 Feb 2016 07:05:35 +0000 (-0500) Subject: ir: validate field types on field creation X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=81e36faca01ab2766a92cabd5a375e2982e9e446 ir: validate field types on field creation This patch removes the validation that is done when adding fields to structure/variant field types, and when creating array/sequence field types with specific element types. This is needed because a variant with an unset tag type may be created and thus exist in any of those compound types. This variant will be resolved when the time comes. A valid field type is still required when creating a concrete field out of it and when serializing it. Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- diff --git a/formats/ctf/ir/event-fields.c b/formats/ctf/ir/event-fields.c index 3358ff0e..65c9aee8 100644 --- a/formats/ctf/ir/event-fields.c +++ b/formats/ctf/ir/event-fields.c @@ -234,14 +234,22 @@ struct bt_ctf_field *bt_ctf_field_create(struct bt_ctf_field_type *type) { struct bt_ctf_field *field = NULL; enum ctf_type_id type_id; + int ret; if (!type) { goto error; } type_id = bt_ctf_field_type_get_type_id(type); - if (type_id <= CTF_TYPE_UNKNOWN || type_id >= NR_CTF_TYPES || - bt_ctf_field_type_validate(type)) { + if (type_id <= CTF_TYPE_UNKNOWN || type_id >= NR_CTF_TYPES) { + goto error; + } + + /* Field class MUST be valid */ + ret = bt_ctf_field_type_validate(type); + + if (ret) { + /* Invalid */ goto error; } diff --git a/formats/ctf/ir/event-types.c b/formats/ctf/ir/event-types.c index 761b2c26..9b6b1046 100644 --- a/formats/ctf/ir/event-types.c +++ b/formats/ctf/ir/event-types.c @@ -267,6 +267,29 @@ int (* const type_compare_funcs[])(struct bt_ctf_field_type *, [CTF_TYPE_STRING] = bt_ctf_field_type_string_compare, }; +static +int bt_ctf_field_type_enumeration_validate(struct bt_ctf_field_type *); +static +int bt_ctf_field_type_structure_validate(struct bt_ctf_field_type *); +static +int bt_ctf_field_type_variant_validate(struct bt_ctf_field_type *); +static +int bt_ctf_field_type_array_validate(struct bt_ctf_field_type *); +static +int bt_ctf_field_type_sequence_validate(struct bt_ctf_field_type *); + +static +int (* const type_validate_funcs[])(struct bt_ctf_field_type *) = { + [CTF_TYPE_INTEGER] = NULL, + [CTF_TYPE_FLOAT] = NULL, + [CTF_TYPE_STRING] = NULL, + [CTF_TYPE_ENUM] = bt_ctf_field_type_enumeration_validate, + [CTF_TYPE_STRUCT] = bt_ctf_field_type_structure_validate, + [CTF_TYPE_VARIANT] = bt_ctf_field_type_variant_validate, + [CTF_TYPE_ARRAY] = bt_ctf_field_type_array_validate, + [CTF_TYPE_SEQUENCE] = bt_ctf_field_type_sequence_validate, +}; + static void destroy_enumeration_mapping(struct enumeration_mapping *mapping) { @@ -399,51 +422,228 @@ void bt_ctf_field_type_destroy(struct bt_object *obj) type_destroy_funcs[type_id](type); } -BT_HIDDEN -int bt_ctf_field_type_validate(struct bt_ctf_field_type *type) +static +int bt_ctf_field_type_enumeration_validate(struct bt_ctf_field_type *type) { int ret = 0; - if (!type) { + struct bt_ctf_field_type_enumeration *enumeration = + container_of(type, struct bt_ctf_field_type_enumeration, + parent); + struct bt_ctf_field_type *container_type = + bt_ctf_field_type_enumeration_get_container_type(type); + + if (!container_type) { ret = -1; goto end; } - switch (type->declaration->id) { - case CTF_TYPE_ENUM: - { - struct bt_ctf_field_type_enumeration *enumeration = - container_of(type, struct bt_ctf_field_type_enumeration, - parent); + ret = bt_ctf_field_type_validate(container_type); + if (ret) { + goto end; + } - /* Ensure enum has entries */ - ret = enumeration->entries->len ? 0 : -1; - break; + /* Ensure enum has entries */ + ret = enumeration->entries->len ? 0 : -1; + +end: + BT_PUT(container_type); + return ret; +} + +static +int bt_ctf_field_type_sequence_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type *element_type = NULL; + struct bt_ctf_field_type_sequence *sequence = + container_of(type, struct bt_ctf_field_type_sequence, + parent); + + /* Length field name should be set at this point */ + if (sequence->length_field_name->len == 0) { + ret = -1; + goto end; } - case CTF_TYPE_SEQUENCE: - { - struct bt_ctf_field_type_sequence *sequence = - container_of(type, struct bt_ctf_field_type_sequence, + + element_type = bt_ctf_field_type_sequence_get_element_type(type); + if (!element_type) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_validate(element_type); + +end: + BT_PUT(element_type); + + return ret; +} + +static +int bt_ctf_field_type_array_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type *element_type = NULL; + + element_type = bt_ctf_field_type_array_get_element_type(type); + if (!element_type) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_validate(element_type); + +end: + BT_PUT(element_type); + + return ret; +} + +static +int bt_ctf_field_type_structure_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type *child_type = NULL; + int field_count = bt_ctf_field_type_structure_get_field_count(type); + int i; + + if (field_count < 0) { + ret = -1; + goto end; + } + + for (i = 0; i < field_count; ++i) { + ret = bt_ctf_field_type_structure_get_field(type, + NULL, &child_type, i); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_validate(child_type); + if (ret) { + goto end; + } + + BT_PUT(child_type); + } + +end: + BT_PUT(child_type); + + return ret; +} + +static +int bt_ctf_field_type_variant_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + int field_count; + struct bt_ctf_field_type *child_type = NULL; + struct bt_ctf_field_type_variant *variant = + container_of(type, struct bt_ctf_field_type_variant, parent); + int i; + int tag_mappings_count; - /* length field name should be set at this point */ - ret = sequence->length_field_name->len ? 0 : -1; - break; + if (variant->tag_name->len == 0 || !variant->tag) { + ret = -1; + goto end; + } + + tag_mappings_count = + bt_ctf_field_type_enumeration_get_mapping_count( + (struct bt_ctf_field_type *) variant->tag); + + if (tag_mappings_count != variant->fields->len) { + ret = -1; + goto end; } - case CTF_TYPE_VARIANT: - { - struct bt_ctf_field_type_variant *variant = - container_of(type, struct bt_ctf_field_type_variant, - parent); - if (variant->tag_name->len == 0 || !variant->tag) { + for (i = 0; i < tag_mappings_count; ++i) { + const char *label; + int64_t range_start, range_end; + struct bt_ctf_field_type *ft; + + ret = bt_ctf_field_type_enumeration_get_mapping( + (struct bt_ctf_field_type *) variant->tag, + i, &label, &range_start, &range_end); + if (ret) { + goto end; + } + if (!label) { ret = -1; + goto end; } - break; + + ft = bt_ctf_field_type_variant_get_field_type_by_name( + type, label); + if (!ft) { + ret = -1; + goto end; + } + + BT_PUT(ft); } - default: - break; + + field_count = bt_ctf_field_type_variant_get_field_count(type); + if (field_count < 0) { + ret = -1; + goto end; + } + + for (i = 0; i < field_count; ++i) { + ret = bt_ctf_field_type_variant_get_field(type, + NULL, &child_type, i); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_validate(child_type); + if (ret) { + goto end; + } + + BT_PUT(child_type); + } + +end: + BT_PUT(child_type); + + return ret; +} + +/* + * This function validates a given field type without considering + * where this field type is located. It only validates the properties + * of the given field type and the properties of its children if + * applicable. + */ +BT_HIDDEN +int bt_ctf_field_type_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + enum ctf_type_id id = bt_ctf_field_type_get_type_id(type); + + if (!type) { + ret = -1; + goto end; + } + + if (type->valid) { + /* Already marked as valid */ + goto end; + } + + if (type_validate_funcs[id]) { + ret = type_validate_funcs[id](type); } + + if (!ret && type->frozen) { + /* Field type is valid */ + type->valid = 1; + } + end: return ret; } @@ -1189,8 +1389,7 @@ int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *type, if (!type || !field_type || type->frozen || bt_ctf_validate_identifier(field_name) || - (type->declaration->id != CTF_TYPE_STRUCT) || - bt_ctf_field_type_validate(field_type)) { + (type->declaration->id != CTF_TYPE_STRUCT)) { ret = -1; goto end; } @@ -1394,8 +1593,7 @@ int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *type, if (!type || !field_type || type->frozen || bt_ctf_validate_identifier(field_name) || - (type->declaration->id != CTF_TYPE_VARIANT) || - bt_ctf_field_type_validate(field_type)) { + (type->declaration->id != CTF_TYPE_VARIANT)) { ret = -1; goto end; } @@ -1544,8 +1742,7 @@ struct bt_ctf_field_type *bt_ctf_field_type_array_create( { struct bt_ctf_field_type_array *array = NULL; - if (!element_type || length == 0 || - bt_ctf_field_type_validate(element_type)) { + if (!element_type || length == 0) { goto error; } @@ -1631,8 +1828,7 @@ struct bt_ctf_field_type *bt_ctf_field_type_sequence_create( { struct bt_ctf_field_type_sequence *sequence = NULL; - if (!element_type || bt_ctf_validate_identifier(length_field_name) || - bt_ctf_field_type_validate(element_type)) { + if (!element_type || bt_ctf_validate_identifier(length_field_name)) { goto error; } @@ -2123,6 +2319,13 @@ int bt_ctf_field_type_serialize(struct bt_ctf_field_type *type, goto end; } + /* Make sure field type is valid before serializing it */ + ret = bt_ctf_field_type_validate(type); + + if (ret) { + goto end; + } + ret = type->serialize(type, context); end: return ret; @@ -2707,11 +2910,6 @@ int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *type, struct bt_ctf_field_type *container_type; int container_signed; - ret = bt_ctf_field_type_validate(type); - if (ret) { - goto end; - } - container_type = bt_ctf_field_type_enumeration_get_container_type(type); if (!container_type) { ret = -1; diff --git a/include/babeltrace/ctf-ir/event-types-internal.h b/include/babeltrace/ctf-ir/event-types-internal.h index 5bc46c4e..5a8538f4 100644 --- a/include/babeltrace/ctf-ir/event-types-internal.h +++ b/include/babeltrace/ctf-ir/event-types-internal.h @@ -71,6 +71,13 @@ struct bt_ctf_field_type { * a field has been instanciated from it. */ int frozen; + + /* + * This flag indicates if the field type is valid. A valid + * field type is _always_ frozen. All the nested field types of + * a valid field type are also valid (and thus frozen). + */ + int valid; }; struct bt_ctf_field_type_integer { diff --git a/include/babeltrace/ctf-ir/event-types.h b/include/babeltrace/ctf-ir/event-types.h index fbef87c8..2dfa433e 100644 --- a/include/babeltrace/ctf-ir/event-types.h +++ b/include/babeltrace/ctf-ir/event-types.h @@ -752,8 +752,8 @@ extern int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *type, * @param type_a Field type A. * @param type_b Field type B. * - * Returns 0 if both field types are semantically equivalent, or a - * negative value when they are not equivalent or on error. + * Returns 0 if both field types are semantically equivalent, a positive + * value if they are not equivalent, or a negative value on error. */ extern int bt_ctf_field_type_compare(struct bt_ctf_field_type *type_a, struct bt_ctf_field_type *type_b);