Coverage Report

Created: 2025-07-18 06:08

/src/elfutils/libelf/elf_end.c
Line
Count
Source (jump to first uncovered line)
1
/* Free resources associated with Elf descriptor.
2
   Copyright (C) 1998,1999,2000,2001,2002,2004,2005,2007,2015,2016 Red Hat, Inc.
3
   Copyright (C) 2023 Mark J. Wielaard <mark@klomp.org>
4
   This file is part of elfutils.
5
   Written by Ulrich Drepper <drepper@redhat.com>, 1998.
6
7
   This file is free software; you can redistribute it and/or modify
8
   it under the terms of either
9
10
     * the GNU Lesser General Public License as published by the Free
11
       Software Foundation; either version 3 of the License, or (at
12
       your option) any later version
13
14
   or
15
16
     * the GNU General Public License as published by the Free
17
       Software Foundation; either version 2 of the License, or (at
18
       your option) any later version
19
20
   or both in parallel, as here.
21
22
   elfutils is distributed in the hope that it will be useful, but
23
   WITHOUT ANY WARRANTY; without even the implied warranty of
24
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25
   General Public License for more details.
26
27
   You should have received copies of the GNU General Public License and
28
   the GNU Lesser General Public License along with this program.  If
29
   not, see <http://www.gnu.org/licenses/>.  */
30
31
#ifdef HAVE_CONFIG_H
32
# include <config.h>
33
#endif
34
35
#include <assert.h>
36
#include <search.h>
37
#include <stddef.h>
38
#include <stdlib.h>
39
40
#include "libelfP.h"
41
42
43
static void
44
free_chunk (void *n)
45
6.12k
{
46
6.12k
  Elf_Data_Chunk *rawchunk = (Elf_Data_Chunk *)n;
47
6.12k
  if (rawchunk->dummy_scn.flags & ELF_F_MALLOCED)
48
4.00k
    free (rawchunk->data.d.d_buf);
49
6.12k
  free (rawchunk);
50
6.12k
}
51
52
int
53
elf_end (Elf *elf)
54
217k
{
55
217k
  Elf *parent;
56
57
217k
  if (elf == NULL)
58
    /* This is allowed and is a no-op.  */
59
108
    return 0;
60
61
  /* Make sure we are alone.  */
62
217k
  rwlock_wrlock (elf->lock);
63
64
217k
  if (elf->ref_count != 0 && --elf->ref_count != 0)
65
0
    {
66
      /* Not yet the last activation.  */
67
0
      int result = elf->ref_count;
68
0
      rwlock_unlock (elf->lock);
69
0
      return result;
70
0
    }
71
72
217k
  if (elf->kind == ELF_K_AR)
73
190k
    {
74
      /* We cannot remove the descriptor now since we still have some
75
   descriptors which depend on it.  But we can free the archive
76
   symbol table since this is only available via the archive ELF
77
   descriptor.  The long name table cannot be freed yet since
78
   the archive headers for the ELF files in the archive point
79
   into this array.  */
80
190k
      if (elf->state.ar.ar_sym != (Elf_Arsym *) -1l)
81
190k
  free (elf->state.ar.ar_sym);
82
190k
      elf->state.ar.ar_sym = NULL;
83
84
190k
      if (elf->state.ar.children != NULL)
85
17.7k
  {
86
17.7k
    rwlock_unlock(elf->lock);
87
17.7k
    return 0;
88
17.7k
  }
89
190k
    }
90
91
  /* Remove this structure from the children list.  */
92
199k
  parent = elf->parent;
93
199k
  if (parent != NULL)
94
185k
    {
95
      /* This is tricky.  Lock must be acquire from the father to
96
   the child but here we already have the child lock.  We
97
   solve this problem by giving free the child lock.  The
98
   state of REF_COUNT==0 is handled all over the library, so
99
   this should be ok.  */
100
185k
      rwlock_unlock (elf->lock);
101
185k
      rwlock_rdlock (parent->lock);
102
185k
      rwlock_wrlock (elf->lock);
103
104
185k
      if (parent->state.ar.children == elf)
105
172k
  parent->state.ar.children = elf->next;
106
13.1k
      else
107
13.1k
  {
108
13.1k
    struct Elf *child = parent->state.ar.children;
109
110
595k
    while (child->next != elf)
111
582k
      child = child->next;
112
113
13.1k
    child->next = elf->next;
114
13.1k
  }
115
116
185k
      rwlock_unlock (parent->lock);
117
185k
    }
118
119
  /* This was the last activation.  Free all resources.  */
120
199k
  switch (elf->kind)
121
199k
    {
122
172k
    case ELF_K_AR:
123
172k
      if (elf->state.ar.long_names != NULL)
124
403
  free (elf->state.ar.long_names);
125
172k
      break;
126
127
21.4k
    case ELF_K_ELF:
128
21.4k
      {
129
21.4k
  search_tree *rawchunk_tree
130
21.4k
    = (elf->class == ELFCLASS32
131
21.4k
       || (offsetof (struct Elf, state.elf32.rawchunk_tree)
132
6.87k
     == offsetof (struct Elf, state.elf64.rawchunk_tree))
133
21.4k
       ? &elf->state.elf32.rawchunk_tree
134
21.4k
       : &elf->state.elf64.rawchunk_tree);
135
136
21.4k
  eu_search_tree_fini (rawchunk_tree, free_chunk);
137
138
21.4k
  Elf_ScnList *list = (elf->class == ELFCLASS32
139
21.4k
           || (offsetof (struct Elf, state.elf32.scns)
140
6.87k
         == offsetof (struct Elf, state.elf64.scns))
141
21.4k
           ? &elf->state.elf32.scns
142
21.4k
           : &elf->state.elf64.scns);
143
144
21.4k
  do
145
21.4k
    {
146
      /* Free all separately allocated section headers.  */
147
21.4k
      size_t cnt = list->max;
148
149
4.98M
      while (cnt-- > 0)
150
4.96M
        {
151
    /* These pointers can be NULL; it's safe to use
152
       'free' since it will check for this.  */
153
4.96M
    Elf_Scn *scn = &list->data[cnt];
154
4.96M
    Elf_Data_List *runp;
155
156
4.96M
    if ((scn->shdr_flags & ELF_F_MALLOCED) != 0)
157
      /* It doesn't matter which pointer.  */
158
0
      free (scn->shdr.e32);
159
160
    /* Free zdata if uncompressed, but not yet used as
161
       rawdata_base.  If it is already used it will be
162
       freed below.  */
163
4.96M
    if (scn->zdata_base != scn->rawdata_base)
164
1.81M
      {
165
1.81M
        free (scn->zdata_base);
166
1.81M
        scn->zdata_base = NULL;
167
1.81M
      }
168
169
    /* If the file has the same byte order and the
170
       architecture doesn't require overly stringent
171
       alignment the raw data buffer is the same as the
172
       one used for presenting to the caller.  */
173
4.96M
    if (scn->data_base != scn->rawdata_base)
174
6.20k
      free (scn->data_base);
175
176
    /* The section data is allocated if we couldn't mmap
177
       the file.  Or if we had to decompress.  */
178
4.96M
    if (elf->map_address == NULL
179
4.96M
        || scn->rawdata_base == scn->zdata_base
180
4.96M
        || (scn->flags & ELF_F_MALLOCED) != 0)
181
3.15M
      free (scn->rawdata_base);
182
183
    /* Free the list of data buffers for the section.
184
       We don't free the buffers themselves since this
185
       is the users job.  */
186
4.96M
    runp = scn->data_list.next;
187
4.96M
    while (runp != NULL)
188
0
      {
189
0
        Elf_Data_List *oldp = runp;
190
0
        runp = runp->next;
191
0
        if ((oldp->flags & ELF_F_MALLOCED) != 0)
192
0
          free (oldp);
193
0
      }
194
4.96M
        }
195
196
      /* Free the memory for the array.  */
197
21.4k
      Elf_ScnList *oldp = list;
198
21.4k
      list = list->next;
199
21.4k
      assert (list == NULL || oldp->cnt == oldp->max);
200
21.4k
      if (oldp != (elf->class == ELFCLASS32
201
21.4k
       || (offsetof (struct Elf, state.elf32.scns)
202
6.87k
           == offsetof (struct Elf, state.elf64.scns))
203
21.4k
       ? &elf->state.elf32.scns
204
21.4k
       : &elf->state.elf64.scns))
205
0
        free (oldp);
206
21.4k
    }
207
21.4k
  while (list != NULL);
208
21.4k
      }
209
210
      /* Free the section header.  */
211
21.4k
      if (elf->state.elf.shdr_malloced  != 0)
212
2.03k
  free (elf->class == ELFCLASS32
213
2.03k
        || (offsetof (struct Elf, state.elf32.shdr)
214
988
      == offsetof (struct Elf, state.elf64.shdr))
215
2.03k
        ? (void *) elf->state.elf32.shdr
216
2.03k
        : (void *) elf->state.elf64.shdr);
217
218
      /* Free the program header.  */
219
21.4k
      if ((elf->state.elf.phdr_flags & ELF_F_MALLOCED) != 0)
220
1.15k
  free (elf->class == ELFCLASS32
221
1.15k
        || (offsetof (struct Elf, state.elf32.phdr)
222
606
      == offsetof (struct Elf, state.elf64.phdr))
223
1.15k
        ? (void *) elf->state.elf32.phdr
224
1.15k
        : (void *) elf->state.elf64.phdr);
225
21.4k
      break;
226
227
5.60k
    default:
228
5.60k
      break;
229
199k
    }
230
231
199k
  if (elf->map_address != NULL && parent == NULL)
232
13.9k
    {
233
      /* The file was read or mapped for this descriptor.  */
234
13.9k
      if ((elf->flags & ELF_F_MALLOCED) != 0)
235
2.78k
  free (elf->map_address);
236
11.1k
      else if ((elf->flags & ELF_F_MMAPPED) != 0)
237
10.9k
  munmap (elf->map_address, elf->maximum_size);
238
13.9k
    }
239
240
199k
  rwlock_unlock (elf->lock);
241
199k
  rwlock_fini (elf->lock);
242
243
  /* Finally the descriptor itself.  */
244
199k
  free (elf);
245
246
199k
  return (parent != NULL && parent->ref_count == 0
247
199k
    ? INTUSE(elf_end) (parent) : 0);
248
199k
}
249
INTDEF(elf_end)