Coverage Report

Created: 2025-11-06 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
62
{
55
62
  Elf *parent;
56
57
62
  if (elf == NULL)
58
    /* This is allowed and is a no-op.  */
59
0
    return 0;
60
61
  /* Make sure we are alone.  */
62
62
  rwlock_wrlock (elf->lock);
63
64
62
  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
62
  if (elf->kind == ELF_K_AR)
73
1
    {
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
1
      if (elf->state.ar.ar_sym != (Elf_Arsym *) -1l)
81
1
  free (elf->state.ar.ar_sym);
82
1
      elf->state.ar.ar_sym = NULL;
83
84
1
      if (elf->state.ar.children != NULL)
85
0
  {
86
0
    rwlock_unlock(elf->lock);
87
0
    return 0;
88
0
  }
89
1
    }
90
91
  /* Remove this structure from the children list.  */
92
62
  parent = elf->parent;
93
62
  if (parent != NULL)
94
1
    {
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
1
      rwlock_unlock (elf->lock);
101
1
      rwlock_rdlock (parent->lock);
102
1
      rwlock_wrlock (elf->lock);
103
104
1
      if (parent->state.ar.children == elf)
105
1
  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
1
      rwlock_unlock (parent->lock);
117
1
    }
118
119
62
  if (elf->elf_ar_hdr.ar_name != NULL)
120
1
    free (elf->elf_ar_hdr.ar_name);
121
122
62
  if (elf->elf_ar_hdr.ar_rawname != NULL)
123
1
    free (elf->elf_ar_hdr.ar_rawname);
124
125
  /* This was the last activation.  Free all resources.  */
126
62
  switch (elf->kind)
127
62
    {
128
1
    case ELF_K_AR:
129
1
      if (elf->state.ar.long_names != NULL)
130
0
  free (elf->state.ar.long_names);
131
1
      break;
132
133
16
    case ELF_K_ELF:
134
16
      {
135
16
  search_tree *rawchunk_tree
136
16
    = (elf->class == ELFCLASS32
137
9
       || (offsetof (struct Elf, state.elf32.rawchunk_tree)
138
9
     == offsetof (struct Elf, state.elf64.rawchunk_tree))
139
16
       ? &elf->state.elf32.rawchunk_tree
140
16
       : &elf->state.elf64.rawchunk_tree);
141
142
16
  eu_search_tree_fini (rawchunk_tree, free_chunk);
143
144
16
  Elf_ScnList *list = (elf->class == ELFCLASS32
145
9
           || (offsetof (struct Elf, state.elf32.scns)
146
9
         == offsetof (struct Elf, state.elf64.scns))
147
16
           ? &elf->state.elf32.scns
148
16
           : &elf->state.elf64.scns);
149
150
16
  do
151
16
    {
152
      /* Free all separately allocated section headers.  */
153
16
      size_t cnt = list->max;
154
155
41.2k
      while (cnt-- > 0)
156
41.2k
        {
157
    /* These pointers can be NULL; it's safe to use
158
       'free' since it will check for this.  */
159
41.2k
    Elf_Scn *scn = &list->data[cnt];
160
41.2k
    Elf_Data_List *runp;
161
162
41.2k
    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
41.2k
    if (scn->zdata_base != scn->rawdata_base)
170
14
      {
171
14
        free (scn->zdata_base);
172
14
        scn->zdata_base = NULL;
173
14
      }
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
41.2k
    if (scn->data_base != scn->rawdata_base)
180
4
      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
41.2k
    if (elf->map_address == NULL
185
41.2k
        || scn->rawdata_base == scn->zdata_base
186
14
        || (scn->flags & ELF_F_MALLOCED) != 0)
187
41.1k
      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
41.2k
    runp = scn->data_list.next;
193
41.2k
    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
41.2k
        }
201
202
      /* Free the memory for the array.  */
203
16
      Elf_ScnList *oldp = list;
204
16
      list = list->next;
205
16
      assert (list == NULL || oldp->cnt == oldp->max);
206
16
      if (oldp != (elf->class == ELFCLASS32
207
9
       || (offsetof (struct Elf, state.elf32.scns)
208
9
           == offsetof (struct Elf, state.elf64.scns))
209
16
       ? &elf->state.elf32.scns
210
16
       : &elf->state.elf64.scns))
211
0
        free (oldp);
212
16
    }
213
16
  while (list != NULL);
214
16
      }
215
216
      /* Free the section header.  */
217
16
      if (elf->state.elf.shdr_malloced  != 0)
218
3
  free (elf->class == ELFCLASS32
219
2
        || (offsetof (struct Elf, state.elf32.shdr)
220
2
      == offsetof (struct Elf, state.elf64.shdr))
221
3
        ? (void *) elf->state.elf32.shdr
222
3
        : (void *) elf->state.elf64.shdr);
223
224
      /* Free the program header.  */
225
16
      if ((elf->state.elf.phdr_flags & ELF_F_MALLOCED) != 0)
226
3
  free (elf->class == ELFCLASS32
227
2
        || (offsetof (struct Elf, state.elf32.phdr)
228
2
      == offsetof (struct Elf, state.elf64.phdr))
229
3
        ? (void *) elf->state.elf32.phdr
230
3
        : (void *) elf->state.elf64.phdr);
231
16
      break;
232
233
45
    default:
234
45
      break;
235
62
    }
236
237
62
  if (elf->map_address != NULL && parent == NULL)
238
61
    {
239
      /* The file was read or mapped for this descriptor.  */
240
61
      if ((elf->flags & ELF_F_MALLOCED) != 0)
241
20
  free (elf->map_address);
242
41
      else if ((elf->flags & ELF_F_MMAPPED) != 0)
243
36
  munmap (elf->map_address, elf->maximum_size);
244
61
    }
245
246
62
  rwlock_unlock (elf->lock);
247
62
  rwlock_fini (elf->lock);
248
249
  /* Finally the descriptor itself.  */
250
62
  free (elf);
251
252
62
  return (parent != NULL && parent->ref_count == 0
253
62
    ? INTUSE(elf_end) (parent) : 0);
254
62
}
255
INTDEF(elf_end)