Bug Summary

File:obj-scan-build/libtrivfs/../../libtrivfs/dyn-classes.c
Location:line 105, column 11
Description:Memory is never released; potential leak of memory pointed to by 'new_aux_vec'

Annotated Source Code

1/* Dynamically allocated port classes/buckets recognized by trivfs
2
3 Copyright (C) 1997 Free Software Foundation, Inc.
4
5 Written by Miles Bader <miles@gnu.ai.mit.edu>
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21#include "priv.h"
22
23/* Auxiliary info for each vector element. */
24struct aux
25{
26 void (*free_el)();
27 unsigned refs;
28};
29
30/* Vectors of dynamically allocated port classes/buckets. */
31
32/* Protid port classes. */
33struct port_class **trivfs_dynamic_protid_port_classes = 0;
34size_t trivfs_num_dynamic_protid_port_classes = 0;
35static struct aux *dynamic_protid_port_classes_aux = 0;
36static size_t dynamic_protid_port_classes_sz = 0;
37
38/* Control port classes. */
39struct port_class **trivfs_dynamic_control_port_classes = 0;
40size_t trivfs_num_dynamic_control_port_classes = 0;
41static struct aux *dynamic_control_port_classes_aux = 0;
42static size_t dynamic_control_port_classes_sz = 0;
43
44/* Port buckets. */
45struct port_bucket **trivfs_dynamic_port_buckets = 0;
46size_t trivfs_num_dynamic_port_buckets = 0;
47static struct aux *dynamic_port_buckets_aux = 0;
48static size_t dynamic_port_buckets_sz = 0;
49
50/* Lock used to control access to all the above vectors. */
51static pthread_mutex_t dyn_lock = PTHREAD_MUTEX_INITIALIZER{ ((__pthread_spinlock_t) 0), ((__pthread_spinlock_t) 0), 0, 0
, 0, 0, 0, 0 }
;
52
53
54/* Add EL to the vector pointed to by VEC_V, which should point to a vector
55 of pointers of some type, and has a length stored in *SZ; If there's
56 already a pointer to EL in VEC_V, nothing will actually be added, but the
57 reference count for that element will be increased. *NUM is the actual
58 number of non-null elements in the vector, and will be incremented if
59 something is actually added. AUX_VEC is a pointer to a vector of struct
60 aux elements, that contains information parralleling VEC_V. FREE_EL, if
61 non-zero, should be a function that takes a single argument of the same
62 type as EL, and deallocates it; this function is called in the following
63 cases: (1) An error is encountered trying to grow one of the vectors, (2)
64 when the element is eventually freed by drop_el. */
65static error_t
66add_el (void *el, void (*free_el)(),
67 void *vec_v, struct aux **aux_vec,
68 size_t *sz, size_t *num)
69{
70 int i;
71 size_t new_sz;
72 void ***vec, **new_vec;
73 struct aux *new_aux_vec;
74
75 if (! el)
3
Taking false branch
76 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
77
78 pthread_mutex_lock (&dyn_lock);
79
80 vec = vec_v;
81
82 for (i = 0; i < *sz; i++)
4
Loop condition is false. Execution continues on line 99
83 if (! (*vec)[i])
84 {
85 (*vec)[i] = el;
86 (*aux_vec)[i].free_el = free_el;
87 (*aux_vec)[i].refs = 1;
88 (*num)++;
89 pthread_mutex_unlock (&dyn_lock);
90 return 0;
91 }
92 else if ((*vec)[i] == el)
93 {
94 (*aux_vec)[i].refs++;
95 pthread_mutex_unlock (&dyn_lock);
96 return 0;
97 }
98
99 new_sz = *sz + 4;
100 new_vec = realloc (*vec, new_sz * sizeof (void *));
101 new_aux_vec = realloc (*aux_vec, new_sz * sizeof (struct aux));
5
Memory is allocated
102
103 if (!new_vec || !new_aux_vec)
6
Assuming 'new_vec' is null
104 {
105 if (free_el)
7
Memory is never released; potential leak of memory pointed to by 'new_aux_vec'
106 (*free_el) (el);
107 /* One of the vectors might be the wrong size, but who cares. */
108 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
109 }
110
111 for (i = *sz; i < new_sz; i++)
112 new_vec[i] = 0;
113
114 new_vec[*sz] = el;
115 new_aux_vec[*sz].free_el = free_el;
116 new_aux_vec[*sz].refs = 1;
117 (*num)++;
118
119 *vec = new_vec;
120 *aux_vec = new_aux_vec;
121 *sz = new_sz;
122
123 pthread_mutex_unlock (&dyn_lock);
124
125 return 0;
126}
127
128/* Scan VEC_V, which should be a vector of SZ pointers of the same type as
129 EL, for EL; if it is found, then decrement its reference count, and if
130 that goes to zero, decrement *NUM and free EL if it had an associated free
131 routine passed to add_el. */
132static void
133drop_el (void *el, void *vec_v, struct aux *aux_vec,
134 size_t sz, size_t *num)
135{
136 int i;
137 void **vec;
138
139 if (! el)
140 return;
141
142 pthread_mutex_lock (&dyn_lock);
143
144 vec = vec_v;
145
146 for (i = 0; i < sz; i++)
147 if (vec[i] == el)
148 {
149 if (aux_vec[i].refs == 1)
150 {
151 if (aux_vec[i].free_el)
152 (*aux_vec[i].free_el) (el);
153 vec[i] = 0;
154 (*num)--;
155 }
156 else
157 aux_vec[i].refs--;
158 break;
159 }
160
161 pthread_mutex_unlock (&dyn_lock);
162}
163
164/* Add the port class *CLASS to the list of control port classes recognized
165 by trivfs; if *CLASS is 0, an attempt is made to allocate a new port
166 class, which is stored in *CLASS. */
167error_t
168trivfs_add_control_port_class (struct port_class **class)
169{
170 /* XXX Gee, there *is no* way of freeing port classes or buckets! So we
171 actually never free anything! */
172
173 if (! *class)
174 {
175 *class = ports_create_class (trivfs_clean_cntl, 0);
176 if (! *class)
177 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
178 }
179
180 return
181 add_el (*class, 0,
182 &trivfs_dynamic_control_port_classes,
183 &dynamic_control_port_classes_aux,
184 &dynamic_control_port_classes_sz,
185 &trivfs_num_dynamic_control_port_classes);
186}
187
188/* Remove the previously added dynamic control port class CLASS, freeing it
189 if it was allocated by trivfs_add_control_port_class. */
190void
191trivfs_remove_control_port_class (struct port_class *class)
192{
193 drop_el (class,
194 trivfs_dynamic_control_port_classes,
195 dynamic_control_port_classes_aux,
196 dynamic_control_port_classes_sz,
197 &trivfs_num_dynamic_control_port_classes);
198}
199
200/* Add the port class *CLASS to the list of protid port classes recognized by
201 trivfs; if *CLASS is 0, an attempt is made to allocate a new port class,
202 which is stored in *CLASS. */
203error_t
204trivfs_add_protid_port_class (struct port_class **class)
205{
206 /* XXX Gee, there *is no* way of freeing port classes or buckets! So we
207 actually never free anything! */
208
209 if (! *class)
210 {
211 *class = ports_create_class (trivfs_clean_protid, 0);
212 if (! *class)
213 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
214 }
215
216 return
217 add_el (*class, 0,
218 &trivfs_dynamic_protid_port_classes,
219 &dynamic_protid_port_classes_aux,
220 &dynamic_protid_port_classes_sz,
221 &trivfs_num_dynamic_protid_port_classes);
222}
223
224/* Remove the previously added dynamic protid port class CLASS, freeing it
225 if it was allocated by trivfs_add_protid_port_class. */
226void
227trivfs_remove_protid_port_class (struct port_class *class)
228{
229 drop_el (class,
230 trivfs_dynamic_protid_port_classes,
231 dynamic_protid_port_classes_aux,
232 dynamic_protid_port_classes_sz,
233 &trivfs_num_dynamic_protid_port_classes);
234}
235
236/* Add the port bucket *BUCKET to the list of dynamically allocated port
237 buckets; if *bucket is 0, an attempt is made to allocate a new port
238 bucket, which is then stored in *bucket. */
239error_t
240trivfs_add_port_bucket (struct port_bucket **bucket)
241{
242 /* XXX Gee, there *is no* way of freeing port bucketes or buckets! So we
243 actually never free anything! */
244
245 if (! *bucket)
1
Taking false branch
246 {
247 *bucket = ports_create_bucket ();
248 if (! *bucket)
249 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
250 }
251
252 return
253 add_el (*bucket, 0,
2
Calling 'add_el'
254 &trivfs_dynamic_port_buckets,
255 &dynamic_port_buckets_aux,
256 &dynamic_port_buckets_sz,
257 &trivfs_num_dynamic_port_buckets);
258}
259
260/* Remove the previously added dynamic port bucket BUCKET, freeing it
261 if it was allocated by trivfs_add_port_bucket. */
262void
263trivfs_remove_port_bucket (struct port_bucket *bucket)
264{
265 drop_el (bucket,
266 trivfs_dynamic_port_buckets,
267 dynamic_port_buckets_aux,
268 dynamic_port_buckets_sz,
269 &trivfs_num_dynamic_port_buckets);
270}