Coverage Report

Created: 2025-08-24 06:28

/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
0
{
46
0
  Elf_Data_Chunk *rawchunk = (Elf_Data_Chunk *)n;
47
0
  if (rawchunk->dummy_scn.flags & ELF_F_MALLOCED)
48
0
    free (rawchunk->data.d.d_buf);
49
0
  free (rawchunk);
50
0
}
51
52
int
53
elf_end (Elf *elf)
54
22.8k
{
55
22.8k
  Elf *parent;
56
57
22.8k
  if (elf == NULL)
58
    /* This is allowed and is a no-op.  */
59
0
    return 0;
60
61
  /* Make sure we are alone.  */
62
22.8k
  rwlock_wrlock (elf->lock);
63
64
22.8k
  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
22.8k
  if (elf->kind == ELF_K_AR)
73
4
    {
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
4
      if (elf->state.ar.ar_sym != (Elf_Arsym *) -1l)
81
4
  free (elf->state.ar.ar_sym);
82
4
      elf->state.ar.ar_sym = NULL;
83
84
4
      if (elf->state.ar.children != NULL)
85
0
  {
86
0
    rwlock_unlock(elf->lock);
87
0
    return 0;
88
0
  }
89
4
    }
90
91
  /* Remove this structure from the children list.  */
92
22.8k
  parent = elf->parent;
93
22.8k
  if (parent != NULL)
94
0
    {
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
0
      rwlock_unlock (elf->lock);
101
0
      rwlock_rdlock (parent->lock);
102
0
      rwlock_wrlock (elf->lock);
103
104
0
      if (parent->state.ar.children == elf)
105
0
  parent->state.ar.children = elf->next;
106
0
      else
107
0
  {
108
0
    struct Elf *child = parent->state.ar.children;
109
110
0
    while (child->next != elf)
111
0
      child = child->next;
112
113
0
    child->next = elf->next;
114
0
  }
115
116
0
      rwlock_unlock (parent->lock);
117
0
    }
118
119
22.8k
  if (elf->kind != ELF_K_AR)
120
22.8k
    {
121
22.8k
      if (elf->state.elf.elf_ar_hdr.ar_name != NULL)
122
0
  free (elf->state.elf.elf_ar_hdr.ar_name);
123
124
22.8k
      if (elf->state.elf.elf_ar_hdr.ar_rawname != NULL)
125
0
  free (elf->state.elf.elf_ar_hdr.ar_rawname);
126
22.8k
    }
127
128
  /* This was the last activation.  Free all resources.  */
129
22.8k
  switch (elf->kind)
130
22.8k
    {
131
4
    case ELF_K_AR:
132
4
      if (elf->state.ar.long_names != NULL)
133
0
  free (elf->state.ar.long_names);
134
4
      break;
135
136
22.2k
    case ELF_K_ELF:
137
22.2k
      {
138
22.2k
  search_tree *rawchunk_tree
139
22.2k
    = (elf->class == ELFCLASS32
140
22.2k
       || (offsetof (struct Elf, state.elf32.rawchunk_tree)
141
5.52k
     == offsetof (struct Elf, state.elf64.rawchunk_tree))
142
22.2k
       ? &elf->state.elf32.rawchunk_tree
143
22.2k
       : &elf->state.elf64.rawchunk_tree);
144
145
22.2k
  eu_search_tree_fini (rawchunk_tree, free_chunk);
146
147
22.2k
  Elf_ScnList *list = (elf->class == ELFCLASS32
148
22.2k
           || (offsetof (struct Elf, state.elf32.scns)
149
5.52k
         == offsetof (struct Elf, state.elf64.scns))
150
22.2k
           ? &elf->state.elf32.scns
151
22.2k
           : &elf->state.elf64.scns);
152
153
22.2k
  do
154
22.2k
    {
155
      /* Free all separately allocated section headers.  */
156
22.2k
      size_t cnt = list->max;
157
158
5.80M
      while (cnt-- > 0)
159
5.78M
        {
160
    /* These pointers can be NULL; it's safe to use
161
       'free' since it will check for this.  */
162
5.78M
    Elf_Scn *scn = &list->data[cnt];
163
5.78M
    Elf_Data_List *runp;
164
165
5.78M
    if ((scn->shdr_flags & ELF_F_MALLOCED) != 0)
166
      /* It doesn't matter which pointer.  */
167
0
      free (scn->shdr.e32);
168
169
    /* Free zdata if uncompressed, but not yet used as
170
       rawdata_base.  If it is already used it will be
171
       freed below.  */
172
5.78M
    if (scn->zdata_base != scn->rawdata_base)
173
109k
      {
174
109k
        free (scn->zdata_base);
175
109k
        scn->zdata_base = NULL;
176
109k
      }
177
178
    /* If the file has the same byte order and the
179
       architecture doesn't require overly stringent
180
       alignment the raw data buffer is the same as the
181
       one used for presenting to the caller.  */
182
5.78M
    if (scn->data_base != scn->rawdata_base)
183
58.3k
      free (scn->data_base);
184
185
    /* The section data is allocated if we couldn't mmap
186
       the file.  Or if we had to decompress.  */
187
5.78M
    if (elf->map_address == NULL
188
5.78M
        || scn->rawdata_base == scn->zdata_base
189
5.78M
        || (scn->flags & ELF_F_MALLOCED) != 0)
190
5.78M
      free (scn->rawdata_base);
191
192
    /* Free the list of data buffers for the section.
193
       We don't free the buffers themselves since this
194
       is the users job.  */
195
5.78M
    runp = scn->data_list.next;
196
5.78M
    while (runp != NULL)
197
0
      {
198
0
        Elf_Data_List *oldp = runp;
199
0
        runp = runp->next;
200
0
        if ((oldp->flags & ELF_F_MALLOCED) != 0)
201
0
          free (oldp);
202
0
      }
203
5.78M
        }
204
205
      /* Free the memory for the array.  */
206
22.2k
      Elf_ScnList *oldp = list;
207
22.2k
      list = list->next;
208
22.2k
      assert (list == NULL || oldp->cnt == oldp->max);
209
22.2k
      if (oldp != (elf->class == ELFCLASS32
210
22.2k
       || (offsetof (struct Elf, state.elf32.scns)
211
5.52k
           == offsetof (struct Elf, state.elf64.scns))
212
22.2k
       ? &elf->state.elf32.scns
213
22.2k
       : &elf->state.elf64.scns))
214
0
        free (oldp);
215
22.2k
    }
216
22.2k
  while (list != NULL);
217
22.2k
      }
218
219
      /* Free the section header.  */
220
22.2k
      if (elf->state.elf.shdr_malloced  != 0)
221
10.0k
  free (elf->class == ELFCLASS32
222
10.0k
        || (offsetof (struct Elf, state.elf32.shdr)
223
2.08k
      == offsetof (struct Elf, state.elf64.shdr))
224
10.0k
        ? (void *) elf->state.elf32.shdr
225
10.0k
        : (void *) elf->state.elf64.shdr);
226
227
      /* Free the program header.  */
228
22.2k
      if ((elf->state.elf.phdr_flags & ELF_F_MALLOCED) != 0)
229
0
  free (elf->class == ELFCLASS32
230
0
        || (offsetof (struct Elf, state.elf32.phdr)
231
0
      == offsetof (struct Elf, state.elf64.phdr))
232
0
        ? (void *) elf->state.elf32.phdr
233
0
        : (void *) elf->state.elf64.phdr);
234
22.2k
      break;
235
236
536
    default:
237
536
      break;
238
22.8k
    }
239
240
22.8k
  if (elf->map_address != NULL && parent == NULL)
241
11.4k
    {
242
      /* The file was read or mapped for this descriptor.  */
243
11.4k
      if ((elf->flags & ELF_F_MALLOCED) != 0)
244
5.71k
  free (elf->map_address);
245
5.69k
      else if ((elf->flags & ELF_F_MMAPPED) != 0)
246
5.69k
  munmap (elf->map_address, elf->maximum_size);
247
11.4k
    }
248
249
22.8k
  rwlock_unlock (elf->lock);
250
22.8k
  rwlock_fini (elf->lock);
251
252
  /* Finally the descriptor itself.  */
253
22.8k
  free (elf);
254
255
22.8k
  return (parent != NULL && parent->ref_count == 0
256
22.8k
    ? INTUSE(elf_end) (parent) : 0);
257
22.8k
}
258
INTDEF(elf_end)