libctf: fix linking of non-root-visible types

If you deduplicate non-root-visible types, the resulting type should still
be non-root-visible! We were promoting all such types to root-visible, and
re-demoting them only if their names collided (which might happen on
cu-mapped links if multiple compilation units with conflicting types are
fused into one child dict).

This "worked" before now, in that linking at least didn't fail (if you don't
mind having your non-root flag value destroyed if you're adding
non-root-visible types), but now that conflicting enumerators cause their
containing enums to become conflicted (enums which might have *different
names*), this caused the linker to crash when it hit two enumerators with
conflicting values.

Not testable in ld because cu-mapped links are not exposed to ld, but can be
tested via direct creation of libraries and calls to ctf_link directly.
(This also tests the ctf_dump non-root type printout, which before now
was untested.)

libctf/
	* ctf-dedup.c (ctf_dedup_emit_type): Non-root-visible input types
	should be emitted as non-root-visible output types.
	* testsuite/libctf-writable/ctf-nonroot-linking.c: New test.
	* testsuite/libctf-writable/ctf-nonroot-linking.lk: New test.
This commit is contained in:
Nick Alcock 2024-07-15 19:42:10 +01:00
parent 2b35088f30
commit 87b2f67310
No known key found for this signature in database
3 changed files with 132 additions and 2 deletions

View File

@ -2640,7 +2640,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
int input_num = CTF_DEDUP_GID_TO_INPUT (id);
int output_num = (uint32_t) -1; /* 'shared' */
int cu_mapped = *(int *)arg;
int isroot = 1;
int isroot;
int is_conflicting;
ctf_next_t *i = NULL;
@ -2708,9 +2708,11 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
}
name = ctf_strraw (real_input, tp->ctt_name);
isroot = LCTF_INFO_ISROOT (real_input, tp->ctt_info);
/* Hide conflicting types, if we were asked to: also hide if a type with this
name already exists and is not a forward. */
name already exists and is not a forward, or if this type is hidden on the
input. */
if (cu_mapped && is_conflicting)
isroot = 0;
else if (name

View File

@ -0,0 +1,127 @@
/* Make sure linking a non-root-visible type emits a non-root-visible
type, rather than silently promoting it to root-visible. Do it by dumping,
thus also testing the {non-root sigils} you get when dumping
non-root-visible types. */
#include <ctf-api.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main (int argc, char *argv[])
{
ctf_dict_t *in1;
ctf_dict_t *fp;
ctf_dict_t *dump_fp;
ctf_archive_t *arc1;
ctf_archive_t *final_arc;
ctf_sect_t s;
ctf_encoding_t encoding = { CTF_INT_SIGNED, 0, sizeof (char) };
unsigned char *buf1, *buf2;
size_t buf1_sz, buf2_sz;
ctf_dump_state_t *dump_state = NULL;
ctf_next_t *i = NULL;
int err;
/* Linking does not currently work on mingw because of an unreliable tmpfile
implementation on that platform (see
https://github.com/msys2/MINGW-packages/issues/18878). Simply skip for
now. */
#ifdef __MINGW32__
printf ("UNSUPPORTED: platform bug breaks ctf_link\n");
return 0;
#else
if ((fp = ctf_create (&err)) == NULL)
goto create_err;
if ((in1 = ctf_create (&err)) == NULL)
goto create_err;
/* A non-root addition. */
if ((ctf_add_integer (in1, CTF_ADD_NONROOT, "foo", &encoding)) == CTF_ERR)
{
fprintf (stderr, "Cannot add: %s\n", ctf_errmsg (ctf_errno (in1)));
return 1;
}
/* Write it out and read it back in, to turn it into an archive.
This would be unnecessary if ctf_link_add() were public :( */
if ((buf1 = ctf_write_mem (in1, &buf1_sz, -1)) == NULL)
{
fprintf (stderr, "Cannot serialize: %s\n", ctf_errmsg (ctf_errno (in1)));
return 1;
}
s.cts_name = "foo";
s.cts_data = (void *) buf1;
s.cts_size = buf1_sz;
s.cts_entsize = 64; /* Unimportant. */
if ((arc1 = ctf_arc_bufopen (&s, NULL, NULL, &err)) == NULL)
goto open_err;
ctf_dict_close (in1);
/* Link! Even a one-file link does deduplication. */
if (ctf_link_add_ctf (fp, arc1, "a") < 0)
goto link_err;
if (ctf_link (fp, 0) < 0)
goto link_err;
/* Write it out. We need a new buf here, because the archive is still
using the other buf. */
if ((buf2 = ctf_link_write (fp, &buf2_sz, 4096)) == NULL)
goto link_err;
/* Read it back in. */
s.cts_data = (void *) buf2;
s.cts_size = buf2_sz;
if ((final_arc = ctf_arc_bufopen (&s, NULL, NULL, &err)) == NULL)
goto open_err;
/* Dump the types, and search for the {sigils of non-rootedness}. */
while ((dump_fp = ctf_archive_next (final_arc, &i, NULL, 0, &err)) != NULL)
{
char *dumpstr;
while ((dumpstr = ctf_dump (dump_fp, &dump_state, CTF_SECT_TYPE,
NULL, NULL)) != NULL)
{
if (strchr (dumpstr, '{') != NULL && strchr (dumpstr, '}') != NULL)
printf ("Non-root type found.\n");
free (dumpstr);
}
ctf_dict_close (dump_fp);
}
if (err != ECTF_NEXT_END)
{
fprintf (stderr, "Archive iteration error: %s\n", ctf_errmsg (err));
return 1;
}
ctf_arc_close (final_arc);
free (buf1);
free (buf2);
ctf_dict_close (fp);
return 0;
create_err:
fprintf (stderr, "Cannot create: %s\n", ctf_errmsg (err));
return 1;
open_err:
fprintf (stderr, "Cannot open: %s\n", ctf_errmsg (err));
return 1;
link_err:
fprintf (stderr, "Cannot link: %s\n", ctf_errmsg (ctf_errno (fp)));
return 1;
#endif
}

View File

@ -0,0 +1 @@
Non-root type found.