Coverage Report

Created: 2025-11-09 06:34

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
24.6k
{
55
24.6k
  Elf *parent;
56
57
24.6k
  if (elf == NULL)
58
    /* This is allowed and is a no-op.  */
59
0
    return 0;
60
61
  /* Make sure we are alone.  */
62
24.6k
  rwlock_wrlock (elf->lock);
63
64
24.6k
  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
24.6k
  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
24.6k
  parent = elf->parent;
93
24.6k
  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
24.6k
  if (elf->elf_ar_hdr.ar_name != NULL)
120
0
    free (elf->elf_ar_hdr.ar_name);
121
122
24.6k
  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
24.6k
  switch (elf->kind)
127
24.6k
    {
128
4
    case ELF_K_AR:
129
4
      if (elf->state.ar.long_names != NULL)
130
0
  free (elf->state.ar.long_names);
131
4
      break;
132
133
24.1k
    case ELF_K_ELF:
134
24.1k
      {
135
24.1k
  search_tree *rawchunk_tree
136
24.1k
    = (elf->class == ELFCLASS32
137
5.63k
       || (offsetof (struct Elf, state.elf32.rawchunk_tree)
138
5.63k
     == offsetof (struct Elf, state.elf64.rawchunk_tree))
139
24.1k
       ? &elf->state.elf32.rawchunk_tree
140
24.1k
       : &elf->state.elf64.rawchunk_tree);
141
142
24.1k
  eu_search_tree_fini (rawchunk_tree, free_chunk);
143
144
24.1k
  Elf_ScnList *list = (elf->class == ELFCLASS32
145
5.63k
           || (offsetof (struct Elf, state.elf32.scns)
146
5.63k
         == offsetof (struct Elf, state.elf64.scns))
147
24.1k
           ? &elf->state.elf32.scns
148
24.1k
           : &elf->state.elf64.scns);
149
150
24.1k
  do
151
24.1k
    {
152
      /* Free all separately allocated section headers.  */
153
24.1k
      size_t cnt = list->max;
154
155
5.64M
      while (cnt-- > 0)
156
5.61M
        {
157
    /* These pointers can be NULL; it's safe to use
158
       'free' since it will check for this.  */
159
5.61M
    Elf_Scn *scn = &list->data[cnt];
160
5.61M
    Elf_Data_List *runp;
161
162
5.61M
    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
5.61M
    if (scn->zdata_base != scn->rawdata_base)
170
101k
      {
171
101k
        free (scn->zdata_base);
172
101k
        scn->zdata_base = NULL;
173
101k
      }
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
5.61M
    if (scn->data_base != scn->rawdata_base)
180
57.1k
      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
5.61M
    if (elf->map_address == NULL
185
2.80M
        || scn->rawdata_base == scn->zdata_base
186
0
        || (scn->flags & ELF_F_MALLOCED) != 0)
187
5.61M
      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
5.61M
    runp = scn->data_list.next;
193
5.61M
    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
5.61M
        }
201
202
      /* Free the memory for the array.  */
203
24.1k
      Elf_ScnList *oldp = list;
204
24.1k
      list = list->next;
205
24.1k
      assert (list == NULL || oldp->cnt == oldp->max);
206
24.1k
      if (oldp != (elf->class == ELFCLASS32
207
5.63k
       || (offsetof (struct Elf, state.elf32.scns)
208
5.63k
           == offsetof (struct Elf, state.elf64.scns))
209
24.1k
       ? &elf->state.elf32.scns
210
24.1k
       : &elf->state.elf64.scns))
211
0
        free (oldp);
212
24.1k
    }
213
24.1k
  while (list != NULL);
214
24.1k
      }
215
216
      /* Free the section header.  */
217
24.1k
      if (elf->state.elf.shdr_malloced  != 0)
218
11.0k
  free (elf->class == ELFCLASS32
219
2.13k
        || (offsetof (struct Elf, state.elf32.shdr)
220
2.13k
      == offsetof (struct Elf, state.elf64.shdr))
221
11.0k
        ? (void *) elf->state.elf32.shdr
222
11.0k
        : (void *) elf->state.elf64.shdr);
223
224
      /* Free the program header.  */
225
24.1k
      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
24.1k
      break;
232
233
510
    default:
234
510
      break;
235
24.6k
    }
236
237
24.6k
  if (elf->map_address != NULL && parent == NULL)
238
12.2k
    {
239
      /* The file was read or mapped for this descriptor.  */
240
12.2k
      if ((elf->flags & ELF_F_MALLOCED) != 0)
241
6.15k
  free (elf->map_address);
242
6.13k
      else if ((elf->flags & ELF_F_MMAPPED) != 0)
243
6.13k
  munmap (elf->map_address, elf->maximum_size);
244
12.2k
    }
245
246
24.6k
  rwlock_unlock (elf->lock);
247
24.6k
  rwlock_fini (elf->lock);
248
249
  /* Finally the descriptor itself.  */
250
24.6k
  free (elf);
251
252
24.6k
  return (parent != NULL && parent->ref_count == 0
253
24.6k
    ? INTUSE(elf_end) (parent) : 0);
254
24.6k
}
255
INTDEF(elf_end)