}
+/* Copy archive header from parent archive ref to member descriptor elf. */
+static int
+copy_arhdr (Elf_Arhdr *dest, Elf *ref)
+{
+ Elf_Arhdr *hdr;
+
+ if (ref->kind == ELF_K_AR)
+ hdr = &ref->state.ar.elf_ar_hdr;
+ else
+ hdr = &ref->state.elf.elf_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
/* Something went wrong. Maybe there is no member left. */
return NULL;
+ Elf_Arhdr ar_hdr = {0};
+ if (copy_arhdr (&ar_hdr, ref) != 0)
+ /* Out of memory. */
+ 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);
- /* 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;
+ result->state.elf.elf_ar_hdr = ar_hdr;
ref->state.ar.children = result;
}
+ else
+ {
+ free (ar_hdr.ar_name);
+ free (ar_hdr.ar_rawname);
+ }
return result;
}
rwlock_unlock (parent->lock);
}
+ if (elf->kind != ELF_K_AR)
+ {
+ if (elf->state.elf.elf_ar_hdr.ar_name != NULL)
+ free (elf->state.elf.elf_ar_hdr.ar_name);
+
+ if (elf->state.elf.elf_ar_hdr.ar_rawname != NULL)
+ free (elf->state.elf.elf_ar_hdr.ar_rawname);
+ }
+
/* This was the last activation. Free all resources. */
switch (elf->kind)
{
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->state.elf.elf_ar_hdr;
}
read from the file. */
search_tree rawchunk_tree; /* Tree and lock for elf_getdata_rawchunk
results. */
+ Elf_Arhdr elf_ar_hdr; /* Structure returned by 'elf_getarhdr'. */
unsigned int scnincr; /* Number of sections allocate the last
time. */
int ehdr_flags; /* Flags (dirty) for ELF header. */
read from the file. */
search_tree rawchunk_tree; /* Tree and lock for
elf_getdata_rawchunk results. */
+ Elf_Arhdr elf_ar_hdr; /* Structure returned by 'elf_getarhdr'. */
unsigned int scnincr; /* Number of sections allocate the last
time. */
int ehdr_flags; /* Flags (dirty) for ELF header. */
read from the file. */
search_tree rawchunk_tree; /* Tree and lock for
elf_getdata_rawchunk results. */
+ Elf_Arhdr elf_ar_hdr; /* Structure returned by 'elf_getarhdr'. */
unsigned int scnincr; /* Number of sections allocate the last
time. */
int ehdr_flags; /* Flags (dirty) for ELF header. */
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 elf_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
#include <unistd.h>
#include <system.h>
+typedef struct hdr_node {
+ Elf *elf;
+ Elf_Arhdr *hdr;
+ struct hdr_node *next;
+} hdr_node;
+
+hdr_node *hdr_list = NULL;
int
main (int argc, char *argv[])
exit (1);
}
+ /* Keep a list of subelfs and their Elf_Arhdr. This is used to
+ verifiy that each archive member descriptor stores its own
+ Elf_Ahdr as opposed to the archive descriptor storing one
+ Elf_Ahdr at a time for all archive members. */
+ hdr_node *node = calloc (1, sizeof (hdr_node));
+ if (node == NULL)
+ {
+ printf ("calloc failed: %s\n", strerror (errno));
+ exit (1);
+ }
+ node->elf = subelf;
+ node->hdr = arhdr;
+
+ if (hdr_list != NULL)
+ {
+ node->next = hdr_list;
+ hdr_list = node;
+ }
+ else
+ hdr_list = node;
+
if (strcmp (arhdr->ar_name, argv[2]) == 0)
{
int outfd;
exit (1);
}
- /* Close the descriptors. */
- if (elf_end (subelf) != 0 || elf_end (elf) != 0)
+ /* Verify each subelf descriptor contains a unique copy of its arhdr
+ and then close each subelf descriptor. */
+ hdr_node *cur;
+ while ((cur = hdr_list) != NULL)
+ {
+ /* Verify that arhdr names are unique. */
+ for (hdr_node *n = cur->next; n != NULL; n = n->next)
+ {
+ if (strcmp (cur->hdr->ar_name, n->hdr->ar_name) == 0)
+ {
+ puts ("Duplicate ar_name");
+ exit (1);
+ }
+
+ if (strcmp (cur->hdr->ar_rawname, n->hdr->ar_rawname) == 0)
+ {
+ puts ("Duplicate ar_rawname");
+ exit (1);
+ }
+ }
+
+ if (elf_end (cur->elf) != 0)
+ {
+ printf ("Error while freeing subELF descriptor: %s\n",
+ elf_errmsg (-1));
+ exit (1);
+ }
+
+ hdr_list = cur->next;
+ free (cur);
+ }
+
+ /* Close the archive descriptor. */
+ if (elf_end (elf) != 0)
{
printf ("Freeing ELF descriptors failed: %s", elf_errmsg (-1));
exit (1);
/* Get next archive element. */
cmd = elf_next (subelf);
- if (elf_end (subelf) != 0)
- {
- printf ("error while freeing sub-ELF descriptor: %s\n",
- elf_errmsg (-1));
- exit (1);
- }
}
/* When we reach this point we haven't found the given file in the