From 869a750c0ec0abcab84e38a43a1ed73321ef4371 Mon Sep 17 00:00:00 2001 From: Nick Alcock Date: Fri, 7 Apr 2023 20:09:24 +0100 Subject: [PATCH] libctf, link: fix CU-mapped links with CTF_LINK_EMPTY_CU_MAPPINGS This is a bug in the intersection of two obscure options that cannot even be invoked from ld with a feature added to stop ld of the same input file repeatedly from crashing the linker. The latter fix involved tracking input files (internally to libctf) not just with their input CU name but with a version of their input CU name that was augmented with a numeric prefix if their linker input file name was changed, to prevent distinct CTF dicts with the same cuname from overwriting each other. (We can't use just the linker input file name because one linker input can contain many CU dicts, particularly under ld -r). If these inputs then produced conflicting types, those types were emitted into similarly-named output dicts, so we needed similar machinery to detect clashing output dicts and add a numeric prefix to them as well. This works fine, except that if you used the cu-mapping feature to force double-linking of CTF (so that your CTF can be grouped into output dicts larger than a single translation unit) and then also used CTF_LINK_EMPTY_CU_MAPPINGS to force every possible output dict in the mapping to be created (even if empty), we did the creation of empty dicts first, and then all the actual content got considered to be a clash. So you ended up with a pile of useless empty dicts and then all the content was in full dicts with the same names suffixed with a #0. This seems likely to confuse consumers that use this facility. Fixed by generating all the EMPTY_CU_MAPPINGS empty dicts after linking is complete, not before it runs. No impact on ld, which does not do cu-mapped links or pass CTF_LINK_EMPTY_CU_MAPPINGS to ctf_link(). libctf/ * ctf-link.c (ctf_create_per_cu): Don't create new dicts iff one already exists and we are making one for no input in particular. (ctf_link): Emit empty CTF dicts corresponding to no input in particular only after linkiing is complete. --- libctf/ctf-link.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c index 016bce5f6d6..9babec2aa37 100644 --- a/libctf/ctf-link.c +++ b/libctf/ctf-link.c @@ -321,12 +321,12 @@ ctf_create_per_cu (ctf_dict_t *fp, ctf_dict_t *input, const char *cu_name) if (ctf_name == NULL) ctf_name = cu_name; - /* Look up the per-CU dict. If we don't know of one, or it is for - a different input CU which just happens to have the same name, - create a new one. */ + /* Look up the per-CU dict. If we don't know of one, or it is for a different input + CU which just happens to have the same name, create a new one. If we are creating + a dict with no input specified, anything will do. */ if ((cu_fp = ctf_dynhash_lookup (fp->ctf_link_outputs, ctf_name)) == NULL - || cu_fp->ctf_link_in_out != fp) + || (input && cu_fp->ctf_link_in_out != fp)) { int err; @@ -1505,11 +1505,17 @@ ctf_link (ctf_dict_t *fp, int flags) if (fp->ctf_link_outputs == NULL) return ctf_set_errno (fp, ENOMEM); + fp->ctf_flags |= LCTF_LINKING; + ctf_link_deduplicating (fp); + fp->ctf_flags &= ~LCTF_LINKING; + + if ((ctf_errno (fp) != 0) && (ctf_errno (fp) != ECTF_NOCTFDATA)) + return -1; + /* Create empty CUs if requested. We do not currently claim that multiple links in succession with CTF_LINK_EMPTY_CU_MAPPINGS set in some calls and not set in others will do anything especially sensible. */ - fp->ctf_flags |= LCTF_LINKING; if (fp->ctf_link_out_cu_mapping && (flags & CTF_LINK_EMPTY_CU_MAPPINGS)) { ctf_next_t *i = NULL; @@ -1535,11 +1541,6 @@ ctf_link (ctf_dict_t *fp, int flags) } } - ctf_link_deduplicating (fp); - - fp->ctf_flags &= ~LCTF_LINKING; - if ((ctf_errno (fp) != 0) && (ctf_errno (fp) != ECTF_NOCTFDATA)) - return -1; return 0; } -- 2.30.2