Coverage Report

Created: 2026-05-30 06:17

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