Fix: ctf-writertype serialization must 'escape' '_'-prefixed field names
[babeltrace.git] / lib / ctf-ir / field-types.c
index 485c5e8f3ea71e2f68d6b84f62559af01c5a57e2..abd16586996b8e9c25426c8263ce3c5d3ddabe4f 100644 (file)
@@ -425,7 +425,19 @@ int add_structure_field(GPtrArray *fields,
 {
        int ret = 0;
        GQuark name_quark = g_quark_from_string(field_name);
+       GQuark underscore_name_quark;
        struct structure_field *field;
+       GString *underscore_name = g_string_new(NULL);
+
+       if (!underscore_name) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               ret = -1;
+               goto end;
+       }
+
+       g_string_assign(underscore_name, "_");
+       g_string_append(underscore_name, field_name);
+       underscore_name_quark = g_quark_from_string(underscore_name->str);
 
        /* Make sure structure does not contain a field of the same name */
        if (g_hash_table_lookup_extended(field_name_to_index,
@@ -436,6 +448,14 @@ int add_structure_field(GPtrArray *fields,
                goto end;
        }
 
+       if (g_hash_table_lookup_extended(field_name_to_index,
+                       GUINT_TO_POINTER(underscore_name_quark), NULL, NULL)) {
+               BT_LOGW("Structure or variant field type already contains a field type with this name: "
+                       "field-name=\"%s\"", underscore_name->str);
+               ret = -1;
+               goto end;
+       }
+
        field = g_new0(struct structure_field, 1);
        if (!field) {
                BT_LOGE_STR("Failed to allocate one structure/variant field type field.");
@@ -449,10 +469,14 @@ int add_structure_field(GPtrArray *fields,
        g_hash_table_insert(field_name_to_index,
                GUINT_TO_POINTER(name_quark),
                GUINT_TO_POINTER(fields->len));
+       g_hash_table_insert(field_name_to_index,
+               GUINT_TO_POINTER(underscore_name_quark),
+               GUINT_TO_POINTER(fields->len));
        g_ptr_array_add(fields, field);
        BT_LOGV("Added structure/variant field type field: field-ft-addr=%p, "
                "field-name=\"%s\"", field_type, field_name);
 end:
+       g_string_free(underscore_name, TRUE);
        return ret;
 }
 
@@ -697,25 +721,6 @@ bt_bool bt_ctf_field_type_enumeration_has_overlapping_ranges(
        return enumeration_type->has_overlapping_ranges;
 }
 
-static
-int bt_ctf_field_type_enumeration_get_mapping_name(
-               struct bt_ctf_field_type *enum_field_type,
-               uint64_t index,
-               const char **mapping_name)
-{
-       int ret = 0;
-       struct enumeration_mapping *mapping;
-
-       assert(enum_field_type);
-       mapping = get_enumeration_mapping(enum_field_type, index);
-       assert(mapping);
-       if (mapping_name) {
-               *mapping_name = g_quark_to_string(mapping->string);
-       }
-
-       return ret;
-}
-
 static
 int bt_ctf_field_type_variant_validate(struct bt_ctf_field_type *type)
 {
@@ -726,7 +731,6 @@ int bt_ctf_field_type_variant_validate(struct bt_ctf_field_type *type)
                container_of(type, struct bt_ctf_field_type_variant,
                        parent);
        int64_t i;
-       int64_t tag_mappings_count;
 
        if (variant->tag_name->len == 0) {
                BT_LOGW("Invalid variant field type: no tag field name: "
@@ -753,44 +757,20 @@ int bt_ctf_field_type_variant_validate(struct bt_ctf_field_type *type)
                goto end;
        }
 
-       tag_mappings_count =
-               bt_ctf_field_type_enumeration_get_mapping_count(
-                       (struct bt_ctf_field_type *) variant->tag);
-       assert(tag_mappings_count >= 0);
-
        /*
-        * Validate that each mapping found in the tag has a name which
-        * is also the name of a field in this variant field type.
+        * It is valid to have a variant field type which does not have
+        * the fields corresponding to each label in the associated
+        * enumeration.
+        *
+        * It is also valid to have variant field type fields which
+        * cannot be selected because the variant field type tag has no
+        * mapping named as such. This scenario, while not ideal, cannot
+        * cause any error.
         *
-        * The opposite is accepted: variant FT fields which cannot be
-        * selected because the variant FT tag has no mapping named as
-        * such. This scenario, while not ideal, cannot cause any error.
+        * If a non-existing field happens to be selected by an
+        * enumeration while reading a variant field, an error will be
+        * generated at that point (while reading the stream).
         */
-       for (i = 0; i < tag_mappings_count; ++i) {
-               const char *label;
-               struct bt_ctf_field_type *ft;
-
-               ret = bt_ctf_field_type_enumeration_get_mapping_name(
-                       (struct bt_ctf_field_type *) variant->tag,
-                       i, &label);
-               assert(ret == 0);
-               assert(label);
-               ft = bt_ctf_field_type_variant_get_field_type_by_name(
-                       type, label);
-               if (!ft) {
-                       BT_LOGW("Invalid variant field type: "
-                               "enumeration tag field type contains a mapping which does not name a variant field type field: "
-                               "variant-ft-addr=%p, tag-field-name=\"%s\", "
-                               "enum-ft-addr=%p, mapping-name=\"%s\"",
-                               type, variant->tag_name->str, variant->tag,
-                               label);
-                       ret = -1;
-                       goto end;
-               }
-
-               BT_PUT(ft);
-       }
-
        field_count = bt_ctf_field_type_variant_get_field_count(type);
        if (field_count < 0) {
                BT_LOGW("Invalid variant field type: no fields: "
@@ -1323,21 +1303,12 @@ bt_ctf_field_type_enumeration_find_mappings_by_name(
 
        iter->u.name_quark = g_quark_try_string(name);
        if (!iter->u.name_quark) {
-               BT_LOGV("No such enumeration field type mapping name: "
-                       "ft-addr=%p, mapping-name=\"%s\"",
-                       type, name);
-               goto error;
-       }
-
-       /* Advance iterator to first entry, or leave index at -1. */
-       if (bt_ctf_field_type_enumeration_mapping_iterator_next(iter)) {
-               /* No entry found. */
-               BT_LOGV("No such enumeration field type mapping name: "
-                       "ft-addr=%p, mapping-name=\"%s\"",
-                       type, name);
-               goto error;
+               /*
+                * No results are possible, set the iterator's position at the
+                * end.
+                */
+               iter->index = iter->enumeration_type->entries->len;
        }
-
        return iter;
 error:
        bt_put(iter);
@@ -1428,13 +1399,6 @@ bt_ctf_field_type_enumeration_find_mappings_by_signed_value(
        }
 
        iter->u.signed_value = value;
-
-       /* Advance iterator to first entry, or leave index at -1. */
-       if (bt_ctf_field_type_enumeration_mapping_iterator_next(iter)) {
-               /* No entry found. */
-               goto error;
-       }
-
        return iter;
 error:
        bt_put(iter);
@@ -1445,12 +1409,7 @@ struct bt_ctf_field_type_enumeration_mapping_iterator *
 bt_ctf_field_type_enumeration_find_mappings_by_unsigned_value(
                struct bt_ctf_field_type *type, uint64_t value)
 {
-       struct bt_ctf_field_type_enumeration_mapping_iterator *iter = NULL;
-
-       if (!type) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               goto error;
-       }
+       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
 
        iter = bt_ctf_field_type_enumeration_find_mappings_type(
                        type, ITERATOR_BY_UNSIGNED_VALUE);
@@ -1468,13 +1427,6 @@ bt_ctf_field_type_enumeration_find_mappings_by_unsigned_value(
                goto error;
        }
        iter->u.unsigned_value = value;
-
-       /* Advance iterator to first entry, or leave index at -1. */
-       if (bt_ctf_field_type_enumeration_mapping_iterator_next(iter)) {
-               /* No entry found. */
-               goto error;
-       }
-
        return iter;
 error:
        bt_put(iter);
@@ -1494,6 +1446,12 @@ int bt_ctf_field_type_enumeration_mapping_iterator_get_signed(
                goto end;
        }
 
+       if (iter->index == -1) {
+               BT_LOGW_STR("Invalid enumeration field type mapping iterator access: position=-1");
+               ret = -1;
+               goto end;
+       }
+
        ret = bt_ctf_field_type_enumeration_get_mapping_signed(
                        &iter->enumeration_type->parent, iter->index,
                        mapping_name, range_begin, range_end);
@@ -1514,6 +1472,12 @@ int bt_ctf_field_type_enumeration_mapping_iterator_get_unsigned(
                goto end;
        }
 
+       if (iter->index == -1) {
+               BT_LOGW_STR("Invalid enumeration field type mapping iterator access: position=-1");
+               ret = -1;
+               goto end;
+       }
+
        ret = bt_ctf_field_type_enumeration_get_mapping_unsigned(
                        &iter->enumeration_type->parent, iter->index,
                        mapping_name, range_begin, range_end);
@@ -2095,14 +2059,6 @@ int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *type,
                goto end;
        }
 
-       if (bt_ctf_validate_identifier(field_name)) {
-               BT_LOGW("Invalid parameter: field name is not a valid CTF identifier: "
-                       "struct-ft-addr=%p, field-name=\"%s\"",
-                       type, field_name);
-               ret = -1;
-               goto end;
-       }
-
        if (type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
                BT_LOGW("Invalid parameter: field type is not a structure field type: "
                        "addr=%p, ft-id=%s", type,
@@ -2428,14 +2384,6 @@ int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *type,
                goto end;
        }
 
-       if (bt_ctf_validate_identifier(field_name)) {
-               BT_LOGW("Invalid parameter: field name is not a valid CTF identifier: "
-                       "variant-ft-addr=%p, field-name=\"%s\"",
-                       type, field_name);
-               ret = -1;
-               goto end;
-       }
-
        if (type->id != BT_CTF_FIELD_TYPE_ID_VARIANT) {
                BT_LOGW("Invalid parameter: field type is not a variant field type: "
                        "addr=%p, ft-id=%s", type,
@@ -2569,7 +2517,8 @@ struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_from_tag(
        }
 
        iter = bt_ctf_field_enumeration_get_mappings(tag);
-       if (!iter) {
+       ret = bt_ctf_field_type_enumeration_mapping_iterator_next(iter);
+       if (!iter || ret) {
                BT_LOGE("Cannot get enumeration field type mapping iterator from enumeration field: "
                        "enum-field-addr=%p", tag);
                goto end;
@@ -3921,6 +3870,19 @@ const char *get_integer_base_string(enum bt_ctf_integer_base base)
        return base_string;
 }
 
+static
+void append_field_name(struct metadata_context *context,
+               const char *name)
+{
+       g_string_append_c(context->string, ' ');
+
+       if (bt_ctf_validate_identifier(name) || *name == '_') {
+               g_string_append_c(context->string, '_');
+       }
+
+       g_string_append(context->string, name);
+}
+
 static
 int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type *type,
                struct metadata_context *context)
@@ -4018,7 +3980,7 @@ int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *type,
        }
 
        if (context->field_name->len) {
-               g_string_append_printf(context->string, " %s",
+               append_field_name(context,
                        context->field_name->str);
                g_string_assign(context->field_name, "");
        }
@@ -4089,7 +4051,7 @@ int bt_ctf_field_type_structure_serialize(struct bt_ctf_field_type *type,
                }
 
                if (context->field_name->len) {
-                       g_string_append_printf(context->string, " %s",
+                       append_field_name(context,
                                context->field_name->str);
                }
                g_string_append(context->string, ";\n");
@@ -4124,8 +4086,9 @@ int bt_ctf_field_type_variant_serialize(struct bt_ctf_field_type *type,
                "ft-addr=%p, metadata-context-addr=%p", type, context);
        context->field_name = g_string_new("");
        if (variant->tag_name->len > 0) {
-               g_string_append_printf(context->string,
-                       "variant <%s> {\n", variant->tag_name->str);
+               g_string_append(context->string, "variant <");
+               append_field_name(context, variant->tag_name->str);
+               g_string_append(context->string, "> {\n");
        } else {
                g_string_append(context->string, "variant {\n");
        }
@@ -4159,8 +4122,9 @@ int bt_ctf_field_type_variant_serialize(struct bt_ctf_field_type *type,
                }
 
                if (context->field_name->len) {
-                       g_string_append_printf(context->string, " %s;",
+                       append_field_name(context,
                                context->field_name->str);
+                       g_string_append_c(context->string, ';');
                }
 
                g_string_append_c(context->string, '\n');
@@ -4198,8 +4162,10 @@ int bt_ctf_field_type_array_serialize(struct bt_ctf_field_type *type,
        }
 
        if (context->field_name->len) {
-               g_string_append_printf(context->string, " %s[%u]",
-                       context->field_name->str, array->length);
+               append_field_name(context,
+                       context->field_name->str);
+
+               g_string_append_printf(context->string, "[%u]", array->length);
                g_string_assign(context->field_name, "");
        } else {
                g_string_append_printf(context->string, "[%u]", array->length);
@@ -4227,14 +4193,12 @@ int bt_ctf_field_type_sequence_serialize(struct bt_ctf_field_type *type,
        }
 
        if (context->field_name->len) {
-               g_string_append_printf(context->string, " %s[%s]",
-                       context->field_name->str,
-                       sequence->length_field_name->str);
+               append_field_name(context, context->field_name->str);
                g_string_assign(context->field_name, "");
-       } else {
-               g_string_append_printf(context->string, "[%s]",
-                       sequence->length_field_name->str);
        }
+       g_string_append(context->string, "[");
+       append_field_name(context, sequence->length_field_name->str);
+       g_string_append(context->string, "]");
 end:
        return ret;
 }
@@ -5284,9 +5248,15 @@ struct bt_ctf_field_type *bt_ctf_field_type_get_field_at_index(
 
        switch (type_id) {
        case CTF_TYPE_STRUCT:
-               bt_ctf_field_type_structure_get_field_by_index(field_type,
-                       NULL, &field, index);
+       {
+               int ret = bt_ctf_field_type_structure_get_field_by_index(
+                       field_type, NULL, &field, index);
+               if (ret) {
+                       field = NULL;
+                       goto end;
+               }
                break;
+       }
        case CTF_TYPE_VARIANT:
        {
                int ret = bt_ctf_field_type_variant_get_field_by_index(
This page took 0.026981 seconds and 4 git commands to generate.