libctf: drop mmap()-based CTF data allocator

This allocator has the ostensible benefit that it lets us mprotect() the
memory used for CTF storage: but in exchange for this it adds
considerable complexity, since we have to track allocation sizes
ourselves for use at freeing time, note whether the data we are storing
was ctf_data_alloc()ed or not so we know if we can safely mprotect()
it... and while the mprotect()ing has found few bugs, it *has* been the
cause of more than one due to errors in all this tracking leading to us
mprotect()ing bits of the heap and stuff like that.

We are about to start composing CTF buffers from pieces so that we can
do usage-based optimizations on the strtab.  This means we need
realloc(), which needs nonportable mremap() and *more* tracking of the
*original* allocation size, and the complexity and bureaucracy of all of
this is just too high for its negligible benefits.

Drop the whole thing and just use malloc() like everyone else.  It knows
better than we do when it is safe to use mmap() under the covers,
anyway.

While we're at it, don't leak the entire buffer if ctf_compress_write()
fails to compress it.

libctf/
	* ctf-subr.c (_PAGESIZE): Remove.
	(ctf_data_alloc): Likewise.
	(ctf_data_free): Likewise.
	(ctf_data_protect): Likewise.
	* ctf-impl.h: Remove declarations.
	* ctf-create.c (ctf_update): No longer call ctf_data_protect: use
	ctf_free, not ctf_data_free.
	(ctf_compress_write): Use ctf_data_alloc, not ctf_alloc.  Free
	the buffer again on compression error.
	* ctf-open.c (ctf_set_base): No longer track the size: call
	ctf_free, not ctf_data_free.
	(upgrade_types): Likewise.  Call ctf_alloc, not ctf_data_alloc.
	(ctf_bufopen): Likewise.  No longer call ctf_data_protect.
This commit is contained in:
Nick Alcock 2019-06-19 12:20:47 +01:00
parent 2486542803
commit 65365aa856
5 changed files with 32 additions and 89 deletions

View file

@ -1,3 +1,19 @@
2019-06-19 Nick Alcock <nick.alcock@oracle.com>
* ctf-subr.c (_PAGESIZE): Remove.
(ctf_data_alloc): Likewise.
(ctf_data_free): Likewise.
(ctf_data_protect): Likewise.
* ctf-impl.h: Remove declarations.
* ctf-create.c (ctf_update): No longer call ctf_data_protect: use
ctf_free, not ctf_data_free.
(ctf_compress_write): Use ctf_data_alloc, not ctf_alloc. Free
the buffer again on compression error.
* ctf-open.c (ctf_set_base): No longer track the size: call
ctf_free, not ctf_data_free.
(upgrade_types): Likewise. Call ctf_alloc, not ctf_data_alloc.
(ctf_bufopen): Likewise. No longer call ctf_data_protect.
2019-06-19 Nick Alcock <nick.alcock@oracle.com> 2019-06-19 Nick Alcock <nick.alcock@oracle.com>
* ctf-create.c (ctf_dtd_insert): Pass on error returns from * ctf-create.c (ctf_dtd_insert): Pass on error returns from

View file

@ -310,7 +310,7 @@ ctf_update (ctf_file_t *fp)
buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen; buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
if ((buf = ctf_data_alloc (buf_size)) == NULL) if ((buf = malloc (buf_size)) == NULL)
return (ctf_set_errno (fp, EAGAIN)); return (ctf_set_errno (fp, EAGAIN));
memcpy (buf, &hdr, sizeof (ctf_header_t)); memcpy (buf, &hdr, sizeof (ctf_header_t));
@ -449,11 +449,9 @@ ctf_update (ctf_file_t *fp)
/* Finally, we are ready to ctf_simple_open() the new container. If this /* Finally, we are ready to ctf_simple_open() the new container. If this
is successful, we then switch nfp and fp and free the old container. */ is successful, we then switch nfp and fp and free the old container. */
ctf_data_protect (buf, buf_size);
if ((nfp = ctf_simple_open (buf, buf_size, NULL, 0, 0, NULL, 0, &err)) == NULL) if ((nfp = ctf_simple_open (buf, buf_size, NULL, 0, 0, NULL, 0, &err)) == NULL)
{ {
ctf_data_free (buf, buf_size); ctf_free (buf);
return (ctf_set_errno (fp, err)); return (ctf_set_errno (fp, err));
} }
@ -462,7 +460,7 @@ ctf_update (ctf_file_t *fp)
nfp->ctf_refcnt = fp->ctf_refcnt; nfp->ctf_refcnt = fp->ctf_refcnt;
nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY; nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY;
nfp->ctf_data.cts_data = NULL; /* Force ctf_data_free() on close. */ nfp->ctf_data.cts_data = NULL; /* Force ctf_free() on close. */
nfp->ctf_dthash = fp->ctf_dthash; nfp->ctf_dthash = fp->ctf_dthash;
nfp->ctf_dtdefs = fp->ctf_dtdefs; nfp->ctf_dtdefs = fp->ctf_dtdefs;
nfp->ctf_dtbyname = fp->ctf_dtbyname; nfp->ctf_dtbyname = fp->ctf_dtbyname;
@ -1993,16 +1991,17 @@ ctf_compress_write (ctf_file_t *fp, int fd)
memcpy (hp, fp->ctf_base, header_len); memcpy (hp, fp->ctf_base, header_len);
hp->cth_flags |= CTF_F_COMPRESS; hp->cth_flags |= CTF_F_COMPRESS;
if ((buf = ctf_data_alloc (max_compress_len)) == NULL) if ((buf = ctf_alloc (max_compress_len)) == NULL)
return (ctf_set_errno (fp, ECTF_ZALLOC)); return (ctf_set_errno (fp, ECTF_ZALLOC));
compress_len = max_compress_len; compress_len = max_compress_len;
if ((rc = compress (buf, (uLongf *) & compress_len, if ((rc = compress (buf, (uLongf *) &compress_len,
fp->ctf_base + header_len, fp->ctf_base + header_len,
fp->ctf_size - header_len)) != Z_OK) fp->ctf_size - header_len)) != Z_OK)
{ {
ctf_dprintf ("zlib deflate err: %s\n", zError (rc)); ctf_dprintf ("zlib deflate err: %s\n", zError (rc));
err = ctf_set_errno (fp, ECTF_COMPRESS); err = ctf_set_errno (fp, ECTF_COMPRESS);
ctf_free (buf);
goto ret; goto ret;
} }
@ -2030,7 +2029,7 @@ ctf_compress_write (ctf_file_t *fp, int fd)
} }
ret: ret:
ctf_data_free (buf, max_compress_len); ctf_free (buf);
return err; return err;
} }

View file

@ -342,11 +342,6 @@ extern void ctf_arc_close_internal (struct ctf_archive *);
extern void *ctf_set_open_errno (int *, int); extern void *ctf_set_open_errno (int *, int);
extern unsigned long ctf_set_errno (ctf_file_t *, int); extern unsigned long ctf_set_errno (ctf_file_t *, int);
_libctf_malloc_
extern void *ctf_data_alloc (size_t);
extern void ctf_data_free (void *, size_t);
extern void ctf_data_protect (void *, size_t);
_libctf_malloc_ _libctf_malloc_
extern void *ctf_mmap (size_t length, size_t offset, int fd); extern void *ctf_mmap (size_t length, size_t offset, int fd);
extern void ctf_munmap (void *, size_t); extern void ctf_munmap (void *, size_t);

View file

@ -345,24 +345,17 @@ ctf_set_base (ctf_file_t *fp, const ctf_header_t *hp, void *base)
/* Free a ctf_base pointer: the pointer passed, or (if NULL) fp->ctf_base. */ /* Free a ctf_base pointer: the pointer passed, or (if NULL) fp->ctf_base. */
static void static void
ctf_free_base (ctf_file_t *fp, unsigned char *ctf_base, size_t ctf_size) ctf_free_base (ctf_file_t *fp, unsigned char *ctf_base)
{ {
unsigned char *base; unsigned char *base;
size_t size;
if (ctf_base) if (ctf_base)
{
base = ctf_base; base = ctf_base;
size = ctf_size;
}
else else
{
base = (unsigned char *) fp->ctf_base; base = (unsigned char *) fp->ctf_base;
size = fp->ctf_size;
}
if (base != fp->ctf_data.cts_data && base != NULL) if (base != fp->ctf_data.cts_data && base != NULL)
ctf_data_free (base, size); ctf_free (base);
} }
/* Set the version of the CTF file. */ /* Set the version of the CTF file. */
@ -392,7 +385,6 @@ upgrade_types (ctf_file_t *fp, ctf_header_t *cth)
const ctf_type_v1_t *tbuf; const ctf_type_v1_t *tbuf;
const ctf_type_v1_t *tend; const ctf_type_v1_t *tend;
unsigned char *ctf_base, *old_ctf_base = (unsigned char *) fp->ctf_base; unsigned char *ctf_base, *old_ctf_base = (unsigned char *) fp->ctf_base;
size_t old_ctf_size = fp->ctf_size;
ctf_type_t *t2buf; ctf_type_t *t2buf;
ssize_t increase = 0, size, increment, v2increment, vbytes, v2bytes; ssize_t increase = 0, size, increment, v2increment, vbytes, v2bytes;
@ -439,7 +431,7 @@ upgrade_types (ctf_file_t *fp, ctf_header_t *cth)
version number unchanged, so that LCTF_INFO_* still works on the version number unchanged, so that LCTF_INFO_* still works on the
as-yet-untranslated type info. */ as-yet-untranslated type info. */
if ((ctf_base = ctf_data_alloc (fp->ctf_size + increase)) == NULL) if ((ctf_base = ctf_alloc (fp->ctf_size + increase)) == NULL)
return ECTF_ZALLOC; return ECTF_ZALLOC;
memcpy (ctf_base, fp->ctf_base, sizeof (ctf_header_t) + cth->cth_typeoff); memcpy (ctf_base, fp->ctf_base, sizeof (ctf_header_t) + cth->cth_typeoff);
@ -608,7 +600,7 @@ upgrade_types (ctf_file_t *fp, ctf_header_t *cth)
assert ((size_t) t2p - (size_t) fp->ctf_buf == new_cth->cth_stroff); assert ((size_t) t2p - (size_t) fp->ctf_buf == new_cth->cth_stroff);
ctf_set_version (fp, (ctf_header_t *) ctf_base, CTF_VERSION_1_UPGRADED_3); ctf_set_version (fp, (ctf_header_t *) ctf_base, CTF_VERSION_1_UPGRADED_3);
ctf_free_base (fp, old_ctf_base, old_ctf_size); ctf_free_base (fp, old_ctf_base);
memcpy (cth, new_cth, sizeof (ctf_header_t)); memcpy (cth, new_cth, sizeof (ctf_header_t));
return 0; return 0;
@ -1319,7 +1311,7 @@ ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
const void *src; const void *src;
int rc = Z_OK; int rc = Z_OK;
if ((base = ctf_data_alloc (size + hdrsz)) == NULL) if ((base = ctf_alloc (size + hdrsz)) == NULL)
return (ctf_set_open_errno (errp, ECTF_ZALLOC)); return (ctf_set_open_errno (errp, ECTF_ZALLOC));
memcpy (base, ctfsect->cts_data, hdrsz); memcpy (base, ctfsect->cts_data, hdrsz);
@ -1333,7 +1325,7 @@ ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
if ((rc = uncompress (buf, &dstlen, src, srclen)) != Z_OK) if ((rc = uncompress (buf, &dstlen, src, srclen)) != Z_OK)
{ {
ctf_dprintf ("zlib inflate err: %s\n", zError (rc)); ctf_dprintf ("zlib inflate err: %s\n", zError (rc));
ctf_data_free (base, size + hdrsz); free (base);
return (ctf_set_open_errno (errp, ECTF_DECOMPRESS)); return (ctf_set_open_errno (errp, ECTF_DECOMPRESS));
} }
@ -1341,14 +1333,14 @@ ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
{ {
ctf_dprintf ("zlib inflate short -- got %lu of %lu " ctf_dprintf ("zlib inflate short -- got %lu of %lu "
"bytes\n", (unsigned long) dstlen, (unsigned long) size); "bytes\n", (unsigned long) dstlen, (unsigned long) size);
ctf_data_free (base, size + hdrsz); free (base);
return (ctf_set_open_errno (errp, ECTF_CORRUPT)); return (ctf_set_open_errno (errp, ECTF_CORRUPT));
} }
} }
else if (foreign_endian) else if (foreign_endian)
{ {
if ((base = ctf_data_alloc (size + hdrsz)) == NULL) if ((base = ctf_alloc (size + hdrsz)) == NULL)
return (ctf_set_open_errno (errp, ECTF_ZALLOC)); return (ctf_set_open_errno (errp, ECTF_ZALLOC));
} }
else else
@ -1425,14 +1417,6 @@ ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
goto bad; goto bad;
} }
/* The ctf region may have been reallocated by init_types(), but now
that is done, it will not move again, so we can protect it, as long
as it didn't come from the ctfsect, which might have been allocated
with malloc(). */
if (fp->ctf_base != (void *) ctfsect->cts_data)
ctf_data_protect ((void *) fp->ctf_base, fp->ctf_size);
/* If we have a symbol table section, allocate and initialize /* If we have a symbol table section, allocate and initialize
the symtab translation table, pointed to by ctf_sxlate. */ the symtab translation table, pointed to by ctf_sxlate. */
@ -1551,7 +1535,7 @@ ctf_file_close (ctf_file_t *fp)
else if (fp->ctf_data_mmapped) else if (fp->ctf_data_mmapped)
ctf_munmap (fp->ctf_data_mmapped, fp->ctf_data_mmapped_len); ctf_munmap (fp->ctf_data_mmapped, fp->ctf_data_mmapped_len);
ctf_free_base (fp, NULL, 0); ctf_free_base (fp, NULL);
if (fp->ctf_sxlate != NULL) if (fp->ctf_sxlate != NULL)
ctf_free (fp->ctf_sxlate); ctf_free (fp->ctf_sxlate);

View file

@ -26,49 +26,9 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
static size_t _PAGESIZE _libctf_unused_;
int _libctf_version = CTF_VERSION; /* Library client version. */ int _libctf_version = CTF_VERSION; /* Library client version. */
int _libctf_debug = 0; /* Debugging messages enabled. */ int _libctf_debug = 0; /* Debugging messages enabled. */
_libctf_malloc_ void *
ctf_data_alloc (size_t size)
{
void *ret;
#ifdef HAVE_MMAP
if (_PAGESIZE == 0)
_PAGESIZE = sysconf(_SC_PAGESIZE);
if (size > _PAGESIZE)
{
ret = mmap (NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
if (ret == MAP_FAILED)
ret = NULL;
}
else
ret = calloc (1, size);
#else
ret = calloc (1, size);
#endif
return ret;
}
void
ctf_data_free (void *buf, size_t size _libctf_unused_)
{
#ifdef HAVE_MMAP
/* Must be the same as the check in ctf_data_alloc(). */
if (size > _PAGESIZE)
(void) munmap (buf, size);
else
free (buf);
#else
free (buf);
#endif
}
/* Private, read-only mmap from a file, with fallback to copying. /* Private, read-only mmap from a file, with fallback to copying.
No handling of page-offset issues at all: the caller must allow for that. */ No handling of page-offset issues at all: the caller must allow for that. */
@ -105,17 +65,6 @@ ctf_munmap (void *buf, size_t length _libctf_unused_)
#endif #endif
} }
void
ctf_data_protect (void *buf _libctf_unused_, size_t size _libctf_unused_)
{
#ifdef HAVE_MMAP
/* Must be the same as the check in ctf_data_alloc(). */
if (size > _PAGESIZE)
(void) mprotect (buf, size, PROT_READ);
#endif
}
_libctf_malloc_ void * _libctf_malloc_ void *
ctf_alloc (size_t size) ctf_alloc (size_t size)
{ {