ir: validate field types on field creation
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Mon, 8 Feb 2016 07:05:35 +0000 (02:05 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 19 Feb 2016 20:15:48 +0000 (15:15 -0500)
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 <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
formats/ctf/ir/event-fields.c
formats/ctf/ir/event-types.c
include/babeltrace/ctf-ir/event-types-internal.h
include/babeltrace/ctf-ir/event-types.h

index 3358ff0ed0f68af8055b7ab6c8a8436b0b3b0c33..65c9aee863a7511ec4629fb9c9aaecfd1b8d6285 100644 (file)
@@ -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;
        }
 
index 761b2c26aae439f99d99255b6c0e5535db60fce0..9b6b10464a4fa06edd57a19fd6d5350f4a805bd8 100644 (file)
@@ -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;
index 5bc46c4ee427f3753b53b93f0d1f9e02febd0e01..5a8538f4a6bb2796b36d8041c25e89e1afa12585 100644 (file)
@@ -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 {
index fbef87c8e08818886a9f3607f18f35bb2445d37e..2dfa433e52e60f27f3f02cb798a34eff19b2de0c 100644 (file)
@@ -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);
This page took 0.030904 seconds and 4 git commands to generate.