libctf: create: vlen growth and prefix addition (NEEDS REVIEW)

This commit modifies ctf_grow_vlen to account for the recent changes to
ctf_dtdef_t, and adds a new ctf_add_prefix function to add a prefix to an
existing type, moving the dtd_data and dtd_vlen up accordinly.

It deserves close review, since this is probably the single greatest bug
cluster in libctf: the number of times I added to a variable of type
ctf_type_t and assumed it would move it in bytes rather than ctf_type_t
units is hard to believe.
This commit is contained in:
Nick Alcock
2025-04-24 15:48:16 +01:00
parent 64b65a0a34
commit a93ad066f7

View File

@@ -74,30 +74,96 @@ ctf_grow_ptrtab (ctf_dict_t *fp)
return 0; return 0;
} }
/* Make sure a vlen has enough space: expand it otherwise. Unlike the ptrtab, /* Make sure a vlen has enough space: expand it otherwise. Either grow it to
which grows quite slowly, the vlen grows in big jumps because it is quite roughly enough space for VBYTES, or add precisely VBYTES on to the space
expensive to expand: the caller has to scan the old vlen for string refs reserved for the vlen. (In one mode, VBYTES is a minimum: in the other,
first and remove them, then re-add them afterwards. The initial size is it's an addend. */
more or less arbitrary. */
static int static int
ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen) ctf_add_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vbytes, int additive)
{ {
unsigned char *old = dtd->dtd_vlen; unsigned char *old = (unsigned char *) dtd->dtd_buf;
if (dtd->dtd_vlen_alloc > vlen) size_t size = dtd->dtd_buf_size;
return 0; size_t old_size = size;
size_t vlen_size = dtd->dtd_vlen_size;
size_t prefix_size = size - vlen_size;
size_t old_data_index = dtd->dtd_data - dtd->dtd_buf;
size_t old_vlen_offset = dtd->dtd_vlen - old;
if ((dtd->dtd_vlen = realloc (dtd->dtd_vlen, if (!additive)
dtd->dtd_vlen_alloc * 2)) == NULL)
{ {
dtd->dtd_vlen = old; if ((size - vlen_size) > vbytes)
return 0;
while (vlen_size < vbytes)
{
size *= 2;
vlen_size = size - prefix_size;
}
}
else
{
vlen_size += vbytes;
size += vbytes;
}
if ((dtd->dtd_buf = realloc (dtd->dtd_buf, size)) == NULL)
{
dtd->dtd_buf = (ctf_type_t *) old;
return (ctf_set_errno (fp, ENOMEM)); return (ctf_set_errno (fp, ENOMEM));
} }
memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);
dtd->dtd_vlen_alloc *= 2; memset (((unsigned char *) dtd->dtd_buf) + old_size, 0, size - old_size);
dtd->dtd_data = dtd->dtd_buf + old_data_index;
dtd->dtd_vlen = ((unsigned char *) dtd->dtd_buf) + old_vlen_offset;
dtd->dtd_buf_size = size;
return 0; return 0;
} }
/* Make sure a vlen has enough space: expand it otherwise. Grow it in fairly
big jumps, for amortized-constant-time growth. */
static int
ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vbytes)
{
return ctf_add_vlen (fp, dtd, vbytes, 0);
}
/* Add a prefix to a given DTD, at the end of the prefix chain, and return it.
Make sure the vlen has enough room for at least VBYTES bytes, too. */
static ctf_type_t *
ctf_add_prefix (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vbytes)
{
ctf_type_t *new_prefix;
size_t old_buf_size = dtd->dtd_buf_size;
/* Grow the type, then tweak the vlen forwards and move things around to leave
a gap. If we run off the end of the headers without finding a non-prefix,
something is wrong. */
if (vbytes == 0)
{
if (ctf_add_vlen (fp, dtd, sizeof (ctf_type_t), 1) < 0)
return NULL; /* errno is set for us. */
}
else
{
if (ctf_grow_vlen (fp, dtd, vbytes + sizeof (ctf_type_t)) < 0)
return NULL; /* errno is set for us. */
}
new_prefix = dtd->dtd_data;
memmove (dtd->dtd_data + 1, dtd->dtd_data, old_buf_size
- ((unsigned char *) dtd->dtd_data - (unsigned char *) dtd->dtd_buf));
dtd->dtd_vlen += sizeof (ctf_type_t);
dtd->dtd_data++;
memset (new_prefix, 0, sizeof (ctf_type_t));
return new_prefix;
}
/* To create an empty CTF dict, we just declare a zeroed header and call /* To create an empty CTF dict, we just declare a zeroed header and call
ctf_bufopen() on it. If ctf_bufopen succeeds, we mark the new dict r/w and ctf_bufopen() on it. If ctf_bufopen succeeds, we mark the new dict r/w and
initialize the dynamic members. We start assigning type IDs at 1 because initialize the dynamic members. We start assigning type IDs at 1 because