/* opncls.c -- open and close a BFD.
- Copyright (C) 1990-2018 Free Software Foundation, Inc.
+ Copyright (C) 1990-2020 Free Software Foundation, Inc.
Written by Cygnus Support.
if (!bfd_hash_table_init_n (& nbfd->section_htab, bfd_section_hash_newfunc,
sizeof (struct section_hash_entry), 13))
{
+ objalloc_free ((struct objalloc *) nbfd->memory);
free (nbfd);
return NULL;
}
bfd_hash_table_free (&abfd->section_htab);
objalloc_free ((struct objalloc *) abfd->memory);
}
+ else
+ free ((char *) bfd_get_filename (abfd));
- if (abfd->filename)
- free ((char *) abfd->filename);
free (abfd->arelt_data);
free (abfd);
}
{
if (abfd->memory)
{
+ const char *filename = bfd_get_filename (abfd);
+ if (filename)
+ {
+ /* We can't afford to lose the bfd filename when freeing
+ abfd->memory, because that would kill the cache.c scheme
+ of closing and reopening files in order to limit the
+ number of open files. To reopen, you need the filename.
+ And indeed _bfd_compute_and_write_armap calls
+ _bfd_free_cached_info to free up space used by symbols
+ and by check_format_matches. Which we want to continue
+ doing to handle very large archives. Later the archive
+ elements are copied, which might require reopening files.
+ We also want to keep using objalloc memory for the
+ filename since that allows the name to be updated
+ without either leaking memory or implementing some sort
+ of reference counted string for copies of the filename. */
+ size_t len = strlen (filename) + 1;
+ char *copy = bfd_malloc (len);
+ if (copy == NULL)
+ return FALSE;
+ memcpy (copy, filename, len);
+ abfd->filename = copy;
+ }
bfd_hash_table_free (&abfd->section_htab);
objalloc_free ((struct objalloc *) abfd->memory);
if (nbfd->iostream == NULL)
{
bfd_set_error (bfd_error_system_call);
+ if (fd != -1)
+ close (fd);
_bfd_delete_bfd (nbfd);
return NULL;
}
/* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */
- nbfd->filename = xstrdup (filename);
+ if (!bfd_set_filename (nbfd, filename))
+ {
+ fclose (nbfd->iostream);
+ _bfd_delete_bfd (nbfd);
+ return NULL;
+ }
/* Figure out whether the user is opening the file for reading,
writing, or both, by looking at the MODE argument. */
else
nbfd->direction = write_direction;
- if (! bfd_cache_init (nbfd))
+ if (!bfd_cache_init (nbfd))
{
+ fclose (nbfd->iostream);
_bfd_delete_bfd (nbfd);
return NULL;
}
nbfd->iostream = stream;
/* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */
- nbfd->filename = xstrdup (filename);
+ if (!bfd_set_filename (nbfd, filename))
+ {
+ _bfd_delete_bfd (nbfd);
+ return NULL;
+ }
nbfd->direction = read_direction;
if (! bfd_cache_init (nbfd))
/* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */
- nbfd->filename = xstrdup (filename);
+ if (!bfd_set_filename (nbfd, filename))
+ {
+ _bfd_delete_bfd (nbfd);
+ return NULL;
+ }
nbfd->direction = read_direction;
/* `open_p (...)' would get expanded by an the open(2) syscall macro. */
/* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */
- nbfd->filename = xstrdup (filename);
+ if (!bfd_set_filename (nbfd, filename))
+ {
+ _bfd_delete_bfd (nbfd);
+ return NULL;
+ }
nbfd->direction = write_direction;
if (bfd_open_file (nbfd) == NULL)
{
struct stat buf;
- if (stat (abfd->filename, &buf) == 0
+ if (stat (bfd_get_filename (abfd), &buf) == 0
/* Do not attempt to change non-regular files. This is
here especially for configure scripts and kernel builds
which run tests with "ld [...] -o /dev/null". */
unsigned int mask = umask (0);
umask (mask);
- chmod (abfd->filename,
+ chmod (bfd_get_filename (abfd),
(0777
& (buf.st_mode | ((S_IXUSR | S_IXGRP | S_IXOTH) &~ mask))));
}
return NULL;
/* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */
- nbfd->filename = xstrdup (filename);
+ if (!bfd_set_filename (nbfd, filename))
+ {
+ _bfd_delete_bfd (nbfd);
+ return NULL;
+ }
if (templ)
nbfd->xvec = templ->xvec;
nbfd->direction = no_direction;
return ret;
}
-/*
-INTERNAL_FUNCTION
- bfd_alloc2
-
-SYNOPSIS
- void *bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size);
-
-DESCRIPTION
- Allocate a block of @var{nmemb} elements of @var{size} bytes each
- of memory attached to <<abfd>> and return a pointer to it.
-*/
-
-void *
-bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size)
-{
- if ((nmemb | size) >= HALF_BFD_SIZE_TYPE
- && size != 0
- && nmemb > ~(bfd_size_type) 0 / size)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
-
- return bfd_alloc (abfd, size * nmemb);
-}
-
/*
FUNCTION
bfd_zalloc
return res;
}
-/*
-INTERNAL_FUNCTION
- bfd_zalloc2
-
-SYNOPSIS
- void *bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size);
-
-DESCRIPTION
- Allocate a block of @var{nmemb} elements of @var{size} bytes each
- of zeroed memory attached to <<abfd>> and return a pointer to it.
-*/
-
-void *
-bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size)
-{
- void *res;
-
- if ((nmemb | size) >= HALF_BFD_SIZE_TYPE
- && size != 0
- && nmemb > ~(bfd_size_type) 0 / size)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
-
- size *= nmemb;
-
- res = bfd_alloc (abfd, size);
- if (res)
- memset (res, 0, (size_t) size);
- return res;
-}
-
/* Free a block allocated for a BFD.
Note: Also frees all more recently allocated blocks! */
bfd_byte *contents;
unsigned int crc_offset;
char *name;
+ bfd_size_type size;
+ ufile_ptr file_size;
BFD_ASSERT (abfd);
BFD_ASSERT (crc32_out);
if (sect == NULL)
return NULL;
+ size = bfd_section_size (sect);
+ file_size = bfd_get_size (abfd);
+
+ /* PR 22794: Make sure that the section has a reasonable size. */
+ if (size < 8 || (file_size != 0 && size >= file_size))
+ return NULL;
+
if (!bfd_malloc_and_get_section (abfd, sect, &contents))
{
- if (contents != NULL)
- free (contents);
+ free (contents);
return NULL;
}
/* CRC value is stored after the filename, aligned up to 4 bytes. */
name = (char *) contents;
- /* PR 17597: avoid reading off the end of the buffer. */
- crc_offset = strnlen (name, bfd_get_section_size (sect)) + 1;
+ /* PR 17597: Avoid reading off the end of the buffer. */
+ crc_offset = strnlen (name, size) + 1;
crc_offset = (crc_offset + 3) & ~3;
- if (crc_offset + 4 > bfd_get_section_size (sect))
+ if (crc_offset + 4 > size)
return NULL;
*crc32 = bfd_get_32 (abfd, contents + crc_offset);
bfd_byte *contents;
unsigned int buildid_offset;
char *name;
+ bfd_size_type size;
+ ufile_ptr file_size;
BFD_ASSERT (abfd);
BFD_ASSERT (buildid_len);
if (sect == NULL)
return NULL;
+ size = bfd_section_size (sect);
+ file_size = bfd_get_size (abfd);
+ if (size < 8 || (file_size != 0 && size >= file_size))
+ return NULL;
+
if (!bfd_malloc_and_get_section (abfd, sect, & contents))
{
- if (contents != NULL)
- free (contents);
+ free (contents);
return NULL;
}
/* BuildID value is stored after the filename. */
name = (char *) contents;
- buildid_offset = strnlen (name, bfd_get_section_size (sect)) + 1;
- if (buildid_offset >= bfd_get_section_size (sect))
+ buildid_offset = strnlen (name, size) + 1;
+ if (buildid_offset >= bfd_section_size (sect))
return NULL;
- *buildid_len = bfd_get_section_size (sect) - buildid_offset;
+ *buildid_len = size - buildid_offset;
*buildid_out = bfd_malloc (*buildid_len);
memcpy (*buildid_out, contents + buildid_offset, *buildid_len);
debug_file_directory = ".";
/* BFD may have been opened from a stream. */
- if (abfd->filename == NULL)
+ if (bfd_get_filename (abfd) == NULL)
{
bfd_set_error (bfd_error_invalid_operation);
return NULL;
if (include_dirs)
{
- for (dirlen = strlen (abfd->filename); dirlen > 0; dirlen--)
- if (IS_DIR_SEPARATOR (abfd->filename[dirlen - 1]))
+ const char *fname = bfd_get_filename (abfd);
+ for (dirlen = strlen (fname); dirlen > 0; dirlen--)
+ if (IS_DIR_SEPARATOR (fname[dirlen - 1]))
break;
dir = (char *) bfd_malloc (dirlen + 1);
free (base);
return NULL;
}
- memcpy (dir, abfd->filename, dirlen);
+ memcpy (dir, fname, dirlen);
dir[dirlen] = '\0';
}
else
/* Compute the canonical name of the bfd object with all symbolic links
resolved, for use in the global debugfile directory. */
- canon_dir = lrealpath (abfd->filename);
+ canon_dir = lrealpath (bfd_get_filename (abfd));
for (canon_dirlen = strlen (canon_dir); canon_dirlen > 0; canon_dirlen--)
if (IS_DIR_SEPARATOR (canon_dir[canon_dirlen - 1]))
break;
debuglink_size &= ~3;
debuglink_size += 4;
- if (! bfd_set_section_size (abfd, sect, debuglink_size))
+ if (!bfd_set_section_size (sect, debuglink_size))
/* XXX Should we delete the section from the bfd ? */
return NULL;
/* PR 21193: Ensure that the section has 4-byte alignment for the CRC.
Note - despite the name of the function being called, we are
setting an alignment power, not a byte alignment value. */
- bfd_set_section_alignment (abfd, sect, 2);
+ bfd_set_section_alignment (sect, 2);
return sect;
}
return NULL;
}
- size = bfd_get_section_size (sect);
+ size = bfd_section_size (sect);
/* FIXME: Should we support smaller build-id notes ? */
if (size < 0x24)
{
if (!bfd_malloc_and_get_section (abfd, sect, & contents))
{
- if (contents != NULL)
- free (contents);
+ free (contents);
return NULL;
}
/* FIXME: Paranoia - allow for compressed build-id sections.
Maybe we should complain if this size is different from
the one obtained above... */
- size = bfd_get_section_size (sect);
+ size = bfd_section_size (sect);
if (size < sizeof (Elf_External_Note))
{
bfd_set_error (bfd_error_invalid_operation);
inote.descdata = inote.namedata + BFD_ALIGN (inote.namesz, 4);
/* FIXME: Should we check for extra notes in this section ? */
- if (inote.descsz == 0
+ if (inote.descsz <= 0
|| inote.type != NT_GNU_BUILD_ID
|| inote.namesz != 4 /* sizeof "GNU" */
|| strncmp (inote.namedata, "GNU", 4) != 0
+ || inote.descsz > 0x7ffffffe
|| size < (12 + BFD_ALIGN (inote.namesz, 4) + inote.descsz))
{
free (contents);
bfd_size_type s;
bfd_byte *d;
- if (abfd == NULL || abfd->filename == NULL || build_id_out == NULL)
+ if (abfd == NULL || bfd_get_filename (abfd) == NULL || build_id_out == NULL)
{
bfd_set_error (bfd_error_invalid_operation);
return NULL;
get_build_id_name,
check_build_id_file, &build_id);
}
+
+/*
+FUNCTION
+ bfd_set_filename
+
+SYNOPSIS
+ const char *bfd_set_filename (bfd *abfd, const char *filename);
+
+DESCRIPTION
+ Set the filename of @var{abfd}, copying the FILENAME parameter to
+ bfd_alloc'd memory owned by @var{abfd}. Returns a pointer the
+ newly allocated name, or NULL if the allocation failed.
+*/
+
+const char *
+bfd_set_filename (bfd *abfd, const char *filename)
+{
+ size_t len = strlen (filename) + 1;
+ char *n = bfd_alloc (abfd, len);
+ if (n)
+ {
+ memcpy (n, filename, len);
+ abfd->filename = n;
+ }
+ return n;
+}