It didn't take long for oss-fuzz to find double frees due to a bug in
the cleanup logic. It's seen when reading in any alpha-vms object
file except when alpha_vms_vec is the default. But alpha_vms_vec is
of course the default when building for --target=alpha-dec-vms (and
naturally what I used to test the cleanup support since that is the
only target with a cleanup that does anything currently).
Anyway, the bug is that if bfd_check_format_matches is to preserve a
match the cleanup for that match can't be run. Quite obviously that
would destroy part of the match state.
* format.c (struct bfd_preserve): Add cleanup field.
(bfd_preserve_save): Add cleanup param and save.
(bfd_preserve_restore): Return cleanup.
(bfd_preserve_finish): Call the cleanup for the discarded match.
(bfd_check_format_matches): Pass cleanup to bfd_preserve_save,
and clear when preserving a match. Restore cleanup too when
restoring that match.
The object_p (and archive_p, core_file_p) functions are not supposed
to have any target specific malloc'd memory attached to the bfd on
their return. This should be obvious on a failure return, but it's
also true for a successful return. The reason is that even though the
object_p recognises the file, that particular target may not be used
and thus the bfd won't be closed calling close_and_cleanup for the
target that allocated the memory.
It turns out that the object_p bfd_target* return value isn't needed.
In all cases except ld/plugin.c the target is abfd->xvec and with
ld/plugin.c the target isn't used. So this patch returns a cleanup
function from object_p instead, called in bfd_check_format_matches to
tidy the bfd before trying a different target match. The only cleanup
that does anything at this stage is the alpha-vms one.
bfd/
* targets.c (bfd_cleanup): New typedef.
(struct bfd <_bfd_check_format>): Return a bfd_cleanup.
* libbfd-in.h (_bfd_no_cleanup): Define.
* format.c (bfd_reinit): Add cleanup parameter, call it.
(bfd_check_format_matches): Set cleanup from _bfd_check_format
call and pass to bfd_reinit. Delete temp, use abfd->xvec instead.
* aout-target.h (callback, object_p): Return bfd_cleanup.
* aout-tic30.c (tic30_aout_callback, tic30_aout_object_p): Likewise.
* archive.c (bfd_generic_archive_p): Likewise.
* binary.c (binary_object_p): Likewise.
* coff-alpha.c (alpha_ecoff_object_p): Likewise.
* coff-ia64.c (ia64coff_object_p): Likewise.
* coff-rs6000.c (_bfd_xcoff_archive_p, rs6000coff_core_p): Likewise.
* coff-sh.c (coff_small_object_p): Likewise.
* coff-stgo32.c (go32_check_format): Likewise.
* coff64-rs6000.c (xcoff64_archive_p, rs6000coff_core_p),
(xcoff64_core_p): Likewise.
* coffgen.c (coff_real_object_p, coff_object_p): Likewise.
* elf-bfd.h (bfd_elf32_object_p, bfd_elf32_core_file_p),
(bfd_elf64_object_p, bfd_elf64_core_file_p): Likewise.
* elfcode.h (elf_object_p): Likewise.
* elfcore.h (elf_core_file_p): Likewise.
* i386msdos.c (msdos_object_p): Likewise.
* ihex.c (ihex_object_p): Likewise.
* libaout.h (some_aout_object_p): Likewise.
* libbfd-in.h (bfd_generic_archive_p, _bfd_dummy_target),
(_bfd_vms_lib_alpha_archive_p, _bfd_vms_lib_ia64_archive_p): Likewise.
* libbfd.c (_bfd_dummy_target): Likewise.
* libcoff-in.h (coff_object_p): Likewise.
* mach-o-aarch64.c (bfd_mach_o_arm64_object_p),
(bfd_mach_o_arm64_core_p): Likewise.
* mach-o-arm.c (bfd_mach_o_arm_object_p),
(bfd_mach_o_arm_core_p): Likewise.
* mach-o-i386.c (bfd_mach_o_i386_object_p),
(bfd_mach_o_i386_core_p): Likewise.
* mach-o-x86-64.c (bfd_mach_o_x86_64_object_p),
(bfd_mach_o_x86_64_core_p): Likewise.
* mach-o.c (bfd_mach_o_header_p, bfd_mach_o_gen_object_p),
(bfd_mach_o_gen_core_p, bfd_mach_o_fat_archive_p): Likewise.
* mach-o.h (bfd_mach_o_object_p, bfd_mach_o_core_p),
(bfd_mach_o_fat_archive_p, bfd_mach_o_header_p): Likewise.
* mmo.c (mmo_object_p): Likewise.
* pef.c (bfd_pef_object_p, bfd_pef_xlib_object_p): Likewise.
* peicode.h (coff_real_object_p, pe_ILF_object_p),
(pe_bfd_object_p): Likewise.
* plugin.c (ld_plugin_object_p, bfd_plugin_object_p): Likewise.
* ppcboot.c (ppcboot_object_p): Likewise.
* rs6000-core.c (rs6000coff_core_p): Likewise.
* som.c (som_object_setup, som_object_p): Likewise.
* srec.c (srec_object_p, symbolsrec_object_p): Likewise.
* tekhex.c (tekhex_object_p): Likewise.
* vms-alpha.c (alpha_vms_object_p): Likewise.
* vms-lib.c (_bfd_vms_lib_archive_p, _bfd_vms_lib_alpha_archive_p),
(_bfd_vms_lib_ia64_archive_p, _bfd_vms_lib_txt_archive_p): Likewise.
* wasm-module.c (wasm_object_p): Likewise.
* xsym.c (bfd_sym_object_p): Likewise.
* xsym.h (bfd_sym_object_p): Likewise.
* aoutx.h (some_aout_object_p): Likewise, and callback parameter
return type.
* pdp11.c (some_aout_object_p): Likewise.
* plugin.c (register_ld_plugin_object_p): Update object_p
parameter type.
* plugin.h (register_ld_plugin_object_p): Likewise.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
* libcoff.h: Regenerate.
ld/
* plugin.c (plugin_object_p): Return a bfd_cleanup.
(plugin_cleanup): New function.
Since 1993-11-05 git commit c188b0bec3, bfd_check_format has failed
if any of the target object_p functions returns false with any error
but bfd_error_wrong_format. That's just weird. There is really no
reason why coff_real_object_p should be fixed to only return that
error instead of numerous other possible errors. Even an out of
memory condition for one target doesn't necessarily mean other targets
can't match, assuming the failing target nicely returns all memory it
might have used.
* format.c (bfd_check_format_matches): Ignore bfd_error on target
match failures. Don't init to bfd_error_wrong_format before
calling _bfd_check_format.
It's a little tricky. We can release any memory back when we have a
match failure, but after a match success which we might want to
preserve for later use the high water mark must change to that of the
matched bfd.
* format.c (bfd_check_format_matches): Add preserve_match.
Save initial bfd state in "preserve", matched bfd state in
"preserve_match". Save just the first match. Release
bfd_alloc memory. Restore and finish preserved state as
appropriate on all function exit paths.
This patch fixes failures with LTO on mingw32 targets. Since git
commit 7cf7fcc83c all possible targets (minus binary) are matched in
bfd_check_format_matches rather than lower priority targets being
excluded once a higher priority target matches. During linking that
results in the ld/plugin.c plugin_object_p function being called with
the input file xvec set to plugin_vec, which means
plugin_get_ir_dummy_bfd doesn't see the real format of the file
(pe-i386). It defaults to the output format instead, which happens to
be pei-i386, and this wrong choice persists for the dummy bfd.
pei-i386 isn't recognised as a valid linker input file.
So, omit recognizing a plugin object in bfd_check_format_matches when
some other object format matches, and make sure those other object
formats are checked first.
* format.c (bfd_check_format_matches): Don't match plugin target
if another target matches. Expand comment.
* targets.c (_bfd_target_vector): Move plugin_vec after all other
non-corefile targets, outside !SELECT_VECS.
* config.bfd: Don't handle targ=plugin here.
* configure.ac: Don't add plugin to enable_targets or handle in
target loop setting selvecs and other target vars.
* configure: Regenerate.
https://sourceware.org/ml/binutils/2013-05/msg00271.html was supposed
to banish "file format is ambiguous" errors for ELF. It didn't,
because the code supposedly detecting formats that implement
match_priority didn't work. That was due to not placing all matching
targets into the vector of matching targets. ELF objects should all
match the generic ELF target (priority 2), plus one or more machine
specific targets (priority 1), and perhaps a single machine specific
target with OS/ABI set (priority 0, best match). So the armel object
in the testcase actually matches elf32-littlearm,
elf32-littlearm-symbian, and elf32-littlearm-vxworks (all priority 1),
and elf32-little (priority 2). As the PR reported, elf32-little
wasn't seen as matching. Fixing that part of the problem wasn't too
difficult but matching the generic ELF target as well as the ARM ELF
targets resulted in ARM testsuite failures.
These proved to be the annoying reordering of stubs that occurs from
time to time due to the stub names containing the section id.
Matching another target causes more sections to be created in
elf_object_p. If section ids change, stub names change, which results
in different hashing and can therefore result in different hash table
traversal and stub creation order. That particular problem is fixed
by resetting section_id to the initial state before attempting each
target match, and taking a snapshot of its value after a successful
match.
PR 22458
* format.c (struct bfd_preserve): Add section_id.
(bfd_preserve_save, bfd_preserve_restore): Save and restore
_bfd_section_id.
(bfd_reinit): Set _bfd_section_id.
(bfd_check_format_matches): Put all matches of any priority into
matching_vector. Save initial section id and start each attempted
match at that section id.
* libbfd-in.h (_bfd_section_id): Declare.
* section.c (_bfd_section_id): Rename from section_id and make
global. Adjust uses.
(bfd_get_next_section_id): Delete.
* elf64-ppc.c (ppc64_elf_setup_section_lists): Replace use of
bfd_get_section_id with _bfd_section_id.
* libbfd.h: Regenerate.
* bfd-in2.h: Regenerate.
In <https://sourceware.org/ml/binutils/2015-12/msg00190.html> (commit
4a07dc8135), Kwok fixed a problem with
the template used for a dummy BFD for an IR file for LTO on MinGW,
where the input and output formats are not the same.
A problem, however, remains in the case of linking for
x86_64-w64-mingw32 -m32, where LTO linking reports an ambiguity
between the pe-i386 and pei-i386 formats. An object (pe-i386) with
plugin data is being tested by the linker to see what formats match.
The default format initially set by the linker when
bfd_check_format_matches is called is pei-i386 (as that's the output
format from the linker script), which does not match, so the function
goes on to the loop over possible BFD vectors. The pe-i386 vector
matches, as it should. One other vector matches: the plugin vector.
bfd_check_format_matches tests a vector for matching by temporarily
modifying the BFD object to use that vector then using
_bfd_check_format on it. So the BFD object is temporarily using
plugin_vec. _bfd_check_format ends up using bfd_plugin_object_p which
uses plugin_object_p from ld which uses plugin_get_ir_dummy_bfd which
succeeds, having created a BFD based on link_info.output_bfd (because
srctemplate is the BFD temporarily using plugin_vec, even after Kwok's
patch link_info.output_bfd is all that's available to base the dummy
BFD on). So we end up with a match from the plugin vector which uses
the pei-i386 vector even though the pei-i386 vector itself does not
match the input object. (In the i686-mingw32 case, as opposed to this
multilib case, pe-i386 is the default BFD target, which would
short-circuit that logic.)
There are two cases of the linker handling inputs with a plugin: they
may be inputs that are also accepted by some non-plugin BFD format, as
here, or they may be a format that would not be recognized at all, as
with some tests in the ld testsuite. In the former case, there is no
need for BFD to accept the objects using the plugin vector, as the
linker has its own logic to allow plugins to claim objects accepted by
some other BFD vector. Thus, this patch arranges for the plugin
vector to have the lowest match priority, and for the priority from
that vector to be used in the relevant case (the attempted match to
the plugin vector results in TEMP pointing to the pei-i386 vector).
Tested for GCC and Binutils testsuites for x86_64-pc-linux-gnu, as
well as verifying that it fixes the observed LTO issue for
x86_64-w64-mingw32.
* plugin.c (plugin_vec): Set match priority to 255.
* format.c (bfd_check_format_matches) [BFD_SUPPORTS_PLUGINS]: When
matching against the plugin vector, take priority from there not
from TEMP.
PR binutils/17512
* format.c (bfd_check_format_matches): Check for a matching vector
before using match priorities.
* mach-o.c (bfd_mach_o_canonicalize_one_reloc): Fix off-by-one
errors with previous delta.
when "matching" is NULL to allow bfd_associated_vector matches.
Consolidate error return code. Consolidate ok return code. Always
restore original target and format on error.
PR ld/2008
* elf.c (_bfd_elf_setup_sections): Return FALSE if
elf_linked_to_section will be set to NULL.
* format.c (bfd_check_format_matches): Don't check the default
target twice.
elf_shstrtab.
* format.c (bfd_check_format_matches): Set output_has_begun
for both_direction.
* section.c (bfd_set_section_contents): Use bfd_write_p. Remove
special case for both_direction.
vectors in target_selvecs.
(shle-*-netbsdelf*): Use bfd_elf*_sh64*nbsd_vec as sh64 vectors
in target_selvecs.
(sh-*-netbsdelf*): Likewise.
* configure.in (assocvecs): New variable. Handle assocvecs like
selvecs.
* configure: Regenerate.
* format.c (bfd_check_format_matches): Store bfd_target pointers
in matching_vector instead of target names. Select first target
from bfd_associated_vector that matches a list of ambiguous targets.
* targets.c (_bfd_associated_vector): New array.
(bfd_associated_vector): New variable.
(_bfd_target_vector): Add bfd_elf*_sh64*lin_vec.
* libbfd-in.h (bfd_associated_vector): Declare.
* libbfd.h: Regenerate.
unsigned int. Cast RELOC_BASE10, RELOC_BASE13 and RELOC_BASE22 to
unsigned int.
(NAME(aout,final_link)): Cast enum used in assignment.
(aout_link_write_symbols): Cast enums in comparisons, int values to
boolean, enums in assignments to int.
(aout_link_input_section_std): Cast rel->r_index to unsigned int.
(aout_link_input_section_ext): Likewise. Cast enums used in comparisons
with unsigned ints.
(aout_link_reloc_link_order): Cast enum to int in assignment.
* archive.c (_bfd_generic_read_ar_hdr_mag): Cast result of memchr
calls to char *.
* bfd-in.h (bfd_set_section_vma): Cast enum true to unsigned int in
assignment.
* bfd-in2.h (bfd_set_section_vma): Likewise.
* bfd.c (bfd_record_phdr): Cast enums in assignments.
* binary.c (bfd_alloc): Cast enum to long.
* coffgen.c (_bfd_coff_is_local_label_name): Cast return to boolean.
* dwarf2.c (read_abbrevs): Add casts to enum types.
(read_attribute_value): Likewise.
(arange_add): Cast result of bfd_zalloc call.
(comp_unit_contains_address): Return true and false.
(comp_unit_find_nearest_line): Cast return to boolean.
* format.c (bfd_check_format_matches, bfd_set_format): Likewise.
* gen-aout.c: define macro '_' if not defined.
* libbfd.c (bfd_realloc): Cast malloc and realloc to PTR.
(bfd_bwrite): Cast bfd_realloc to bfd_byte *.
(bfd_write_bigendian_4byte_int): Cast return to boolean.
(bfd_seek): Cast bfd_realloc to bfd_byte *.
(bfd_generic_is_local_label_name): Cast return to boolean.
* libcoff.h (_bfd_coff_adjust_symndx): Remove extraneous '\'.
* linker.c (_bfd_link_hash_newfunc): Cast bfd_hash_allocate result to
struct bfd_hash_entry *.
(_bfd_generic_link_hash_newfunc): likewise.
(_bfd_generic_final_link): Cast enum to unsigned int.
* merge.c (sec_merge_emit): Cast return to boolean.
(merge_strings): Add casts to const unsigned char *.
* reloc.c (bfd_get_reloc_code_name): Cast enums in comparison to int.
(bfd_generic_get_relocated_section_content): Cast enum to unsigned int.
* section.c (bfd_section_hash_newfunc): Cast bfd_hash_allocate result to
struct bfd_hash_entry *.
(bfd_set_section_content): Add cast to PTR in comparison.
* simple.c (simple_dummy_warning, simple_dummy_undefined_symbol,
simple_dummy_reloc_overflow, simple_dummy_reloc_dangerous,
simple_dummy_unattached_reloc,
bfd_simple_get_relocated_section_contents): Add K&R declarations and
function definitions.
* srec.c (S3Forced): Initialize to false.
(srec_get_symtab): Cast return value from bfd_alloc to asymbol *.
* stabs.c (_bfd_link_section_stabs): Cast enum to int in comparisons.
(_bfd_discard_section_stabs): Likewise. Also cast return to boolean.
* syms.c (bfd_is_undefined_symclass): Cast return to boolean.
(_bfd_stab_section_find_nearest_line): Cast enum to bfd_byte in
comparisons.
o bfd_read and bfd_write lose an unnecessary param and become
bfd_bread and bfd_bwrite.
o bfd_*alloc now all take a bfd_size_type arg, and will error if
size_t is too small. eg. 32 bit host, 64 bit bfd, verrry big files
or bugs in linker scripts etc.
o file_ptr becomes a bfd_signed_vma. Besides matching sizes with
various other types involved in handling sections, this should make
it easier for bfd to support a 64 bit off_t on 32 bit hosts that
provide it.
o I've made the H_GET_* and H_PUT_* macros (which invoke bfd_h_{get,put}_*)
generally available. They now cast their args to bfd_vma and
bfd_byte * as appropriate, which removes a swag of casts from the
source.
o Bug fixes to bfd_get8, aix386_core_vec, elf32_h8_relax_section, and
aout-encap.c.
o Zillions of formatting and -Wconversion fixes.
(bfd_errmsgs): Add corresponding message.
* archive.c (bfd_generic_archive_p): Don't release bfd_ardata when
finding an archive that contains different format object files.
Return bfd_error_wrong_object_format for this case.
* format.c: Formatting fixes. s/CONST/const/.
(bfd_check_format_matches): Accept archives that give
bfd_error_wrong_object_format if no full match is found. Tidy
code handling matching_vector. Don't return a pointer to freed
memory in `matching'. Handle ambiguous matches as for partial
archive matches.
* bfd-in2.h: Regenerate.