aboutsummaryrefslogtreecommitdiff
path: root/libctf/ctf-create.c
diff options
context:
space:
mode:
authorNick Alcock <nick.alcock@oracle.com>2024-06-11 20:33:03 +0100
committerNick Alcock <nick.alcock@oracle.com>2024-06-18 13:20:32 +0100
commit6e09d4a6e6e62e585fe1237a0094f80f8aeef2fa (patch)
tree02ac80c35cb96b1acad21353df5d1b33aa114bbe /libctf/ctf-create.c
parent9f0fb75b8e121a93b0f63dd823fa86ffd44e8e5d (diff)
downloadbinutils-6e09d4a6e6e62e585fe1237a0094f80f8aeef2fa.zip
binutils-6e09d4a6e6e62e585fe1237a0094f80f8aeef2fa.tar.gz
binutils-6e09d4a6e6e62e585fe1237a0094f80f8aeef2fa.tar.bz2
libctf: prohibit addition of enums with overlapping enumerator constants
libctf has long prohibited addition of enums with overlapping constants in a single enum, but now that we are properly considering enums with overlapping constants to be conflciting types, we can go further and prohibit addition of enumeration constants to a dict if they already exist in any enum in that dict: the same rules as C itself. We do this in a fashion vaguely similar to what we just did in the deduplicator, by considering enumeration constants as identifiers and adding them to the core type/identifier namespace, ctf_dict_t.ctf_names. This is a little fiddly, because we do not want to prohibit opening of existing dicts into which the deduplicator has stuffed enums with overlapping constants! We just want to prohibit the addition of *new* enumerators that violate that rule. Even then, it's fine to add overlapping enumerator constants as long as at least one of them is in a non-root type. (This is essential for proper deduplicator operation in cu-mapped mode, where multiple compilation units can be smashed into one dict, with conflicting types marked as hidden: these types may well contain overlapping enumerators.) So, at open time, keep track of all enums observed, then do a third pass through the enums alone, adding each enumerator either to the ctf_names table as a mapping from the enumerator name to the enum it is part of (if not already present), or to a new ctf_conflicting_enums hashtable that tracks observed duplicates. (The latter is not used yet, but will be soon.) (We need to do a third pass because it's quite possible to have an enum containing an enumerator FOO followed by a type FOO: since they're processed in order, the enumerator would be processed before the type, and at that stage it seems nonconflicting. The easiest fix is to run through the enumerators after all type names are interned.) At ctf_add_enumerator time, if the enumerator to which we are adding a type is root-visible, check for an already-present name and error out if found, then intern the new name in the ctf_names table as is done at open time. (We retain the existing code which scans the enum itself for duplicates because it is still an error to add an enumerator twice to a non-root-visible enum type; but we only need to do this if the enum is non-root-visible, so the cost of enum addition is reduced.) Tested in an upcoming commit. libctf/ * ctf-impl.h (ctf_dict_t) <ctf_names>: Augment comment. <ctf_conflicting_enums>: New. (ctf_dynset_elements): New. * ctf-hash.c (ctf_dynset_elements): Implement it. * ctf-open.c (init_static_types): Split body into... (init_static_types_internal): ... here. Count enumerators; keep track of observed enums in pass 2; populate ctf_names and ctf_conflicting_enums with enumerators in a third pass. (ctf_dict_close): Free ctf_conflicting_enums. * ctf-create.c (ctf_add_enumerator): Prohibit addition of duplicate enumerators in root-visible enum types. include/ * ctf-api.h (CTF_ADD_NONROOT): Describe what non-rootness means for enumeration constants. (ctf_add_enumerator): The name is not a misnomer. We now require that enumerators have unique names. Document the non-rootness of enumerators.
Diffstat (limited to 'libctf/ctf-create.c')
-rw-r--r--libctf/ctf-create.c41
1 files changed, 34 insertions, 7 deletions
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 073006b..d674603 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -1048,7 +1048,6 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, enid);
unsigned char *old_vlen;
ctf_enum_t *en;
- size_t i;
uint32_t kind, vlen, root;
@@ -1068,6 +1067,12 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
+ /* Enumeration constant names are only added, and only checked for duplicates,
+ if the enum they are part of is a root-visible type. */
+
+ if (root == CTF_ADD_ROOT && ctf_dynhash_lookup (fp->ctf_names, name))
+ return (ctf_set_errno (ofp, ECTF_DUPLICATE));
+
if (kind != CTF_K_ENUM)
return (ctf_set_errno (ofp, ECTF_NOTENUM));
@@ -1075,24 +1080,46 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
return (ctf_set_errno (ofp, ECTF_DTFULL));
old_vlen = dtd->dtd_vlen;
+
if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
return -1; /* errno is set for us. */
+
en = (ctf_enum_t *) dtd->dtd_vlen;
/* Remove refs in the old vlen region and reapply them. */
ctf_str_move_refs (fp, old_vlen, sizeof (ctf_enum_t) * vlen, dtd->dtd_vlen);
- for (i = 0; i < vlen; i++)
- if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
- return (ctf_set_errno (ofp, ECTF_DUPLICATE));
+ /* Check for constant duplication within any given enum: only needed for
+ non-root-visible types, since the duplicate detection above does the job
+ for root-visible types just fine. */
- en[i].cte_name = ctf_str_add_movable_ref (fp, name, &en[i].cte_name);
- en[i].cte_value = value;
+ if (root == CTF_ADD_NONROOT)
+ {
+ size_t i;
- if (en[i].cte_name == 0 && name != NULL && name[0] != '\0')
+ for (i = 0; i < vlen; i++)
+ if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
+ return (ctf_set_errno (ofp, ECTF_DUPLICATE));
+ }
+
+ en[vlen].cte_name = ctf_str_add_movable_ref (fp, name, &en[vlen].cte_name);
+ en[vlen].cte_value = value;
+
+ if (en[vlen].cte_name == 0 && name != NULL && name[0] != '\0')
return (ctf_set_errno (ofp, ctf_errno (fp)));
+ /* Put the newly-added enumerator name into the name table if this type is
+ root-visible. */
+
+ if (root == CTF_ADD_ROOT)
+ {
+ if (ctf_dynhash_insert (fp->ctf_names,
+ (char *) ctf_strptr (fp, en[vlen].cte_name),
+ (void *) (uintptr_t) enid) < 0)
+ return ctf_set_errno (fp, ENOMEM);
+ }
+
dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
return 0;