]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libelf: Return already gotten Elf_Data from elf_getdata_rawchunk
authorMark Wielaard <mark@klomp.org>
Fri, 1 Apr 2022 10:19:20 +0000 (12:19 +0200)
committerMark Wielaard <mark@klomp.org>
Tue, 5 Apr 2022 13:09:22 +0000 (15:09 +0200)
elf_getdata_rawchunk keeps a list of Elf_Data_Chunk to track which
Elf_Data structures have already been requested. This allows elf_end
to clean up all internal data structures and the Elf_Data d_buf if
it was malloced.

But it didn't check if a chunk was already requested earlier. This
meant that if for example dwelf_elf_gnu_build_id was called multiple
times to lookup a build-id from the phdrs a new Elf_Data_Chunk was
created. This could slowly leak memory.

So also keep track of the offset from which the size and type of
the rawdata was requested so we can return existing data if it is
requested multiple times.

Note that the current cache is a simple linked list but the chain
is normally not that long. It is normally used to get chunks from
the phdrs, and there are normally less than 10.

Signed-off-by: Mark Wielaard <mark@klomp.org>
libelf/ChangeLog
libelf/elf_getdata_rawchunk.c
libelf/libelfP.h

index 299179cbbf31ecfac4c554bdcc092ba8a3f9ce66..985f795df88152bdb827705dbbce5963807c9e03 100644 (file)
@@ -1,3 +1,10 @@
+2022-04-01  Mark Wielaard  <mark@klomp.org>
+
+       * libelfP.h (struct Elf_Data_Chunk): Add an int64_t offset field.
+       * elf_getdata_rawchunk.c (elf_getdata_rawchunk): Check whether the
+       requested chunk, offset, size and type, was already handed out.
+       Set new Elf_Data_Chunk offset field.
+
 2022-03-29  Mark Wielaard  <mark@klomp.org>
 
        * gelf_xlate.c (START): Define and use sz variable.
index 1072f7de9803b8ac6fd76ff032a966a6a017ffd5..2f55cbb472fa7d9f35d104b89fb4e4162acc7a6e 100644 (file)
@@ -1,5 +1,6 @@
 /* Return converted data from raw chunk of ELF file.
    Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
+   Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -75,6 +76,20 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
 
   rwlock_rdlock (elf->lock);
 
+  /* Maybe we already got this chunk?  */
+  Elf_Data_Chunk *rawchunks = elf->state.elf.rawchunks;
+  while (rawchunks != NULL)
+    {
+      if ((rawchunks->offset == offset || size == 0)
+         && rawchunks->data.d.d_size == size
+         && rawchunks->data.d.d_type == type)
+       {
+         result = &rawchunks->data.d;
+         goto out;
+       }
+      rawchunks = rawchunks->next;
+    }
+
   size_t align = __libelf_type_align (elf->class, type);
   if (elf->map_address != NULL)
     {
@@ -171,6 +186,7 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
   chunk->data.d.d_type = type;
   chunk->data.d.d_align = align;
   chunk->data.d.d_version = EV_CURRENT;
+  chunk->offset = offset;
 
   rwlock_unlock (elf->lock);
   rwlock_wrlock (elf->lock);
index 2c6995bbebf60dc6584ae756962c251cd667a3bc..56331f4526e25490d6d2f267fcd4b74e3ee4272e 100644 (file)
@@ -266,6 +266,7 @@ typedef struct Elf_Data_Chunk
     Elf_Scn dummy_scn;
     struct Elf_Data_Chunk *next;
   };
+  int64_t offset;              /* The original raw offset in the Elf image.  */
 } Elf_Data_Chunk;