libctf, archive: stop ctf_arc_bufopen triggering crazy unmaps

The archive machinery mmap()s its archives when possible: so it arranges
to do appropriately-sized unmaps by recording the unmap length in the
ctfa_magic value and unmapping that.

This brilliant (horrible) trick works less well when ctf_arc_bufopen is
called with an existing buffer (which might be a readonly mapping).
ctf_arc_bufopen always returns a ctf_archive_t wrapper, so record in
there the necessity to not unmap anything when a bufopen'ed archive is
closed again.

libctf/
	* ctf-impl.h (struct ctf_archive_internal)
	<ctfi_unmap_on_close>: New.
	(ctf_new_archive_internal): Adjust.
	* ctf-archive.c (ctf_new_archive_internal): Likewise.
	Initialize ctfi_unmap_on_close.  Adjust error path.
	(ctf_arc_bufopen): Adjust ctf_new_archive_internal call
	(unmap_on_close is 0).
	(ctf_arc_close): Only unmap if ctfi_unmap_on_close.
	* ctf-open-bfd.c (ctf_fdopen): Adjust.
This commit is contained in:
Nick Alcock 2020-06-02 20:55:05 +01:00
parent 96e3ec2966
commit 601e455b75
4 changed files with 40 additions and 12 deletions

View file

@ -336,10 +336,11 @@ search_modent_by_name (const void *key, const void *ent, void *arg)
/* Make a new struct ctf_archive_internal wrapper for a ctf_archive or a
ctf_file. Closes ARC and/or FP on error. Arrange to free the SYMSECT or
STRSECT, as needed, on close. */
STRSECT, as needed, on close. Possibly do not unmap on close. */
struct ctf_archive_internal *
ctf_new_archive_internal (int is_archive, struct ctf_archive *arc,
ctf_new_archive_internal (int is_archive, int unmap_on_close,
struct ctf_archive *arc,
ctf_file_t *fp, const ctf_sect_t *symsect,
const ctf_sect_t *strsect,
int *errp)
@ -349,7 +350,10 @@ ctf_new_archive_internal (int is_archive, struct ctf_archive *arc,
if ((arci = calloc (1, sizeof (struct ctf_archive_internal))) == NULL)
{
if (is_archive)
ctf_arc_close_internal (arc);
{
if (unmap_on_close)
ctf_arc_close_internal (arc);
}
else
ctf_file_close (fp);
return (ctf_set_open_errno (errp, errno));
@ -364,6 +368,7 @@ ctf_new_archive_internal (int is_archive, struct ctf_archive *arc,
if (strsect)
memcpy (&arci->ctfi_strsect, strsect, sizeof (struct ctf_sect));
arci->ctfi_free_symsect = 0;
arci->ctfi_unmap_on_close = unmap_on_close;
return arci;
}
@ -382,7 +387,13 @@ ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
if (ctfsect->cts_size > sizeof (uint64_t) &&
((*(uint64_t *) ctfsect->cts_data) == CTFA_MAGIC))
{
/* The archive is mmappable, so this operation is trivial. */
/* The archive is mmappable, so this operation is trivial.
This buffer is nonmodifiable, so the trick involving mmapping only part
of it and storing the length in the magic number is not applicable: so
record this fact in the archive-wrapper header. (We cannot record it
in the archive, because the archive may very well be a read-only
mapping.) */
is_archive = 1;
arc = (struct ctf_archive *) ctfsect->cts_data;
@ -397,7 +408,7 @@ ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
return NULL;
}
}
return ctf_new_archive_internal (is_archive, arc, fp, symsect, strsect,
return ctf_new_archive_internal (is_archive, 0, arc, fp, symsect, strsect,
errp);
}
@ -474,7 +485,10 @@ ctf_arc_close (ctf_archive_t *arc)
return;
if (arc->ctfi_is_archive)
ctf_arc_close_internal (arc->ctfi_archive);
{
if (arc->ctfi_unmap_on_close)
ctf_arc_close_internal (arc->ctfi_archive);
}
else
ctf_file_close (arc->ctfi_file);
if (arc->ctfi_free_symsect)