Merge from upstream libelf 0.194

This commit is contained in:
Chris Webb 2025-10-27 20:39:21 +00:00
commit f38ceb5a8a
13 changed files with 128 additions and 46 deletions

View File

@ -6,7 +6,7 @@ LDFLAGS =
LDLIBS = -lz -lzstd
MAJOR = 1
MINOR = 0.193
MINOR = 0.194
HEADERS = $(wildcard include/*.h src/*.h)
SOURCES = $(wildcard src/*.c)

View File

@ -73,14 +73,15 @@ elfw2(LIBELFBITS,offscn) (Elf *elf, ElfW2(LIBELFBITS,Off) offset)
for (unsigned int i = 0; i < runp->cnt; ++i)
if (runp->data[i].shdr.ELFW(e,LIBELFBITS)->sh_offset == offset)
{
result = &runp->data[i];
/* If this section is empty, the following one has the same
sh_offset. We presume the caller is looking for a nonempty
section, so keep looking if this one is empty. */
if (runp->data[i].shdr.ELFW(e,LIBELFBITS)->sh_size != 0
&& runp->data[i].shdr.ELFW(e,LIBELFBITS)->sh_type != SHT_NOBITS)
goto out;
{
result = &runp->data[i];
goto out;
}
}
runp = runp->next;

View File

@ -135,7 +135,8 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
/* Set the default values. */
if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
if (ehdr == NULL
|| ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
return -1;
/* At least the ELF header is there. */

View File

@ -62,7 +62,7 @@ file_read_ar (int fildes, void *map_address, off_t offset, size_t maxsize,
happen on demand. */
elf->state.ar.offset = offset + SARMAG;
elf->state.ar.elf_ar_hdr.ar_rawname = elf->state.ar.raw_name;
elf->state.ar.cur_ar_hdr.ar_rawname = elf->state.ar.raw_name;
}
return elf;
@ -815,6 +815,50 @@ read_long_names (Elf *elf)
}
/* Copy archive header from parent archive ref to member descriptor elf. */
static int
copy_arhdr (Elf_Arhdr *dest, Elf *ref)
{
Elf_Arhdr *hdr;
hdr = &ref->state.ar.cur_ar_hdr;
char *ar_name = hdr->ar_name;
char *ar_rawname = hdr->ar_rawname;
if (ar_name == NULL || ar_rawname == NULL)
{
/* ref doesn't have an Elf_Arhdr or it was marked as unusable. */
return 0;
}
/* Allocate copies of ar_name and ar_rawname. */
size_t name_len = strlen (ar_name) + 1;
char *name_copy = malloc (MAX (name_len, 16));
if (name_copy == NULL)
{
__libelf_seterrno (ELF_E_NOMEM);
return -1;
}
memcpy (name_copy, ar_name, name_len);
size_t rawname_len = strlen (ar_rawname) + 1;
char *rawname_copy = malloc (MAX (rawname_len, 17));
if (rawname_copy == NULL)
{
free (name_copy);
__libelf_seterrno (ELF_E_NOMEM);
return -1;
}
memcpy (rawname_copy, ar_rawname, rawname_len);
*dest = *hdr;
dest->ar_name = name_copy;
dest->ar_rawname = rawname_copy;
return 0;
}
/* Read the next archive header. */
int
internal_function
@ -862,7 +906,7 @@ __libelf_next_arhdr_wrlock (Elf *elf)
/* Copy the raw name over to a NUL terminated buffer. */
*((char *) mempcpy (elf->state.ar.raw_name, ar_hdr->ar_name, 16)) = '\0';
elf_ar_hdr = &elf->state.ar.elf_ar_hdr;
elf_ar_hdr = &elf->state.ar.cur_ar_hdr;
/* Now convert the `struct ar_hdr' into `Elf_Arhdr'.
Determine whether this is a special entry. */
@ -1055,21 +1099,42 @@ dup_elf (int fildes, Elf_Cmd cmd, Elf *ref)
member the internal pointer of the archive file descriptor is
pointing to. First read the header of the next member if this
has not happened already. */
if (ref->state.ar.elf_ar_hdr.ar_name == NULL
if (ref->state.ar.cur_ar_hdr.ar_name == NULL
&& __libelf_next_arhdr_wrlock (ref) != 0)
/* Something went wrong. Maybe there is no member left. */
return NULL;
/* We have all the information we need about the next archive member.
Now create a descriptor for it. */
result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr),
ref->state.ar.elf_ar_hdr.ar_size, cmd, ref);
Now create a descriptor for it. Check parent size can contain member. */
if (ref->state.ar.offset < ref->start_offset)
return NULL;
size_t max_size = ref->maximum_size;
size_t offset = (size_t) (ref->state.ar.offset - ref->start_offset);
size_t hdr_size = sizeof (struct ar_hdr);
size_t ar_size = (size_t) ref->state.ar.cur_ar_hdr.ar_size;
if (max_size < hdr_size || max_size - hdr_size < offset)
return NULL;
Elf_Arhdr ar_hdr = {0};
if (copy_arhdr (&ar_hdr, ref) != 0)
/* Out of memory. */
return NULL;
result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr),
MIN (max_size - hdr_size - offset, ar_size), cmd, ref);
/* Enlist this new descriptor in the list of children. */
if (result != NULL)
{
/* Enlist this new descriptor in the list of children. */
result->next = ref->state.ar.children;
ref->state.ar.children = result;
result->elf_ar_hdr = ar_hdr;
}
else
{
free (ar_hdr.ar_name);
free (ar_hdr.ar_rawname);
}
return result;

View File

@ -116,6 +116,12 @@ elf_end (Elf *elf)
rwlock_unlock (parent->lock);
}
if (elf->elf_ar_hdr.ar_name != NULL)
free (elf->elf_ar_hdr.ar_name);
if (elf->elf_ar_hdr.ar_rawname != NULL)
free (elf->elf_ar_hdr.ar_rawname);
/* This was the last activation. Free all resources. */
switch (elf->kind)
{

View File

@ -44,30 +44,12 @@ elf_getarhdr (Elf *elf)
if (elf == NULL)
return NULL;
Elf *parent = elf->parent;
/* Calling this function is not ok for any file type but archives. */
if (parent == NULL)
if (elf->parent == NULL || elf->parent->kind != ELF_K_AR)
{
__libelf_seterrno (ELF_E_INVALID_OP);
return NULL;
}
/* Make sure we have read the archive header. */
if (parent->state.ar.elf_ar_hdr.ar_name == NULL
&& __libelf_next_arhdr_wrlock (parent) != 0)
{
rwlock_wrlock (parent->lock);
int st = __libelf_next_arhdr_wrlock (parent);
rwlock_unlock (parent->lock);
if (st != 0)
/* Something went wrong. Maybe there is no member left. */
return NULL;
}
/* We can be sure the parent is an archive. */
assert (parent->kind == ELF_K_AR);
return &parent->state.ar.elf_ar_hdr;
return &elf->elf_ar_hdr;
}

View File

@ -43,7 +43,7 @@ elf_getaroff (Elf *elf)
{
/* Be gratious, the specs demand it. */
if (elf == NULL || elf->parent == NULL)
return ELF_C_NULL;
return -1;
/* We can be sure the parent is an archive. */
Elf *parent = elf->parent;

View File

@ -87,7 +87,7 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
int flags = 0;
Elf_Data *result = NULL;
rwlock_rdlock (elf->lock);
rwlock_wrlock (elf->lock);
/* Maybe we already got this chunk? */
Elf_Data_Chunk key;
@ -95,7 +95,7 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
key.data.d.d_size = size;
key.data.d.d_type = type;
Elf_Data_Chunk **found
= eu_tsearch (&key, &elf->state.elf.rawchunk_tree, &chunk_compare);
= eu_tsearch_nolock (&key, &elf->state.elf.rawchunk_tree, &chunk_compare);
if (found == NULL)
goto nomem;
@ -136,7 +136,8 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
if (rawchunk == NULL)
{
nomem:
eu_tdelete (&key, &elf->state.elf.rawchunk_tree, &chunk_compare);
eu_tdelete_nolock (&key, &elf->state.elf.rawchunk_tree,
&chunk_compare);
__libelf_seterrno (ELF_E_NOMEM);
goto out;
}
@ -147,7 +148,8 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
!= size))
{
/* Something went wrong. */
eu_tdelete (&key, &elf->state.elf.rawchunk_tree, &chunk_compare);
eu_tdelete_nolock (&key, &elf->state.elf.rawchunk_tree,
&chunk_compare);
free (rawchunk);
__libelf_seterrno (ELF_E_READ_ERROR);
goto out;
@ -217,9 +219,6 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
chunk->data.d.d_version = EV_CURRENT;
chunk->offset = offset;
rwlock_unlock (elf->lock);
rwlock_wrlock (elf->lock);
*found = chunk;
result = &chunk->data.d;

View File

@ -56,7 +56,7 @@ elf_next (Elf *elf)
/* Now advance the offset. */
parent->state.ar.offset += (sizeof (struct ar_hdr)
+ ((parent->state.ar.elf_ar_hdr.ar_size + 1)
+ ((parent->state.ar.cur_ar_hdr.ar_size + 1)
& ~1l));
/* Get the next archive header. */
@ -64,7 +64,7 @@ elf_next (Elf *elf)
/* If necessary, mark the archive header as unusable. */
if (ret == ELF_C_NULL)
parent->state.ar.elf_ar_hdr.ar_name = NULL;
parent->state.ar.cur_ar_hdr.ar_name = NULL;
rwlock_unlock (parent->lock);

View File

@ -53,7 +53,7 @@ elf_rand (Elf *elf, size_t offset)
if (__libelf_next_arhdr_wrlock (elf) != 0)
{
/* Mark the archive header as unusable. */
elf->state.ar.elf_ar_hdr.ar_name = NULL;
elf->elf_ar_hdr.ar_name = NULL;
return 0;
}

View File

@ -52,6 +52,30 @@ extern void *eu_tfind (const void *key, search_tree *tree,
extern void *eu_tdelete (const void *key, search_tree *tree,
int (*compare)(const void *, const void *));
/* Search TREE for KEY and add KEY if not found. No locking is performed. */
static inline void *
eu_tsearch_nolock (const void *key, search_tree *tree,
int (*compare)(const void *, const void *))
{
return tsearch (key, &tree->root, compare);
}
/* Search TREE for KEY. No locking is performed. */
static inline void *
eu_tfind_nolock (const void *key, search_tree *tree,
int (*compare)(const void *, const void *))
{
return tfind (key, &tree->root, compare);
}
/* Delete key from TREE. No locking is performed. */
static inline void *
eu_tdelete_nolock (const void *key, search_tree *tree,
int (*compare)(const void *, const void *))
{
return tdelete (key, &tree->root, compare);
}
/* Free all nodes from TREE. */
void eu_tdestroy (search_tree *tree, void (*free_node)(void *));

View File

@ -51,8 +51,8 @@ gelf_getnote (Elf_Data *data, size_t offset, GElf_Nhdr *result,
/* It's easy to handle this type. It has the same size for 32 and
64 bit objects. */
assert (sizeof (GElf_Nhdr) == sizeof (Elf32_Nhdr));
assert (sizeof (GElf_Nhdr) == sizeof (Elf64_Nhdr));
eu_static_assert (sizeof (GElf_Nhdr) == sizeof (Elf32_Nhdr));
eu_static_assert (sizeof (GElf_Nhdr) == sizeof (Elf64_Nhdr));
rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock);

View File

@ -306,6 +306,9 @@ struct Elf
/* Reference counting for the descriptor. */
int ref_count;
/* Structure returned by 'elf_getarhdr'. */
Elf_Arhdr elf_ar_hdr;
/* Lock to handle multithreaded programs. */
rwlock_define (,lock);
@ -394,7 +397,8 @@ struct Elf
int64_t offset; /* Offset in file we are currently at.
elf_next() advances this to the next
member of the archive. */
Elf_Arhdr elf_ar_hdr; /* Structure returned by 'elf_getarhdr'. */
Elf_Arhdr cur_ar_hdr; /* Copy of current archive member's structure
returned by 'elf_getarhdr'. */
struct ar_hdr ar_hdr; /* Header read from file. */
char ar_name[16]; /* NUL terminated ar_name of elf_ar_hdr. */
char raw_name[17]; /* This is a buffer for the NUL terminated