Bug Summary

File:build-analysis/../src/plugins/asf/libasf/parse.c
Warning:line 122, column 6
Potential leak of memory pointed to by 'current'

Annotated Source Code

1/* libasf - An Advanced Systems Format media file parser
2 * Copyright (C) 2006-2010 Juho Vähä-Herttua
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include <stdlib.h>
20#include <string.h>
21
22#include "asf.h"
23#include "asfint.h"
24#include "byteio.h"
25#include "header.h"
26#include "guid.h"
27#include "debug.h"
28#include "parse.h"
29
30/**
31 * Read next object from buffer pointed by data. Notice that
32 * no buffer overflow checks are done! This function always
33 * expects to have 24 bytes available, which is the size of
34 * the object header (GUID + data size)
35 */
36static void
37asf_parse_read_object(asfint_object_t *obj, uint8_t *data)
38{
39 GetGUID(data, &obj->guid);
40 obj->type = asf_guid_get_type(&obj->guid);
41 obj->size = GetQWLE(data + 16);
42 obj->full_data = data;
43 obj->datalen = 0;
44 obj->data = NULL((void*)0);
45 obj->next = NULL((void*)0);
46
47 if (obj->type == GUID_UNKNOWN) {
48 debug_printf("unknown object: %x-%x-%x-%02x%02x%02x%02x%02x%02x%02x%02x, %ld bytes",
49 obj->guid.v1, obj->guid.v2, obj->guid.v3, obj->guid.v4[0],
50 obj->guid.v4[1], obj->guid.v4[2], obj->guid.v4[3], obj->guid.v4[4],
51 obj->guid.v4[5], obj->guid.v4[6], obj->guid.v4[7], (long) obj->size);
52 }
53}
54
55/**
56 * Parse header extension object. Takes a pointer to a newly allocated
57 * header extension structure, a pointer to the data buffer and the
58 * length of the data buffer as its parameters. Subobject contents are
59 * not parsed, but they are added as a linked list to the header object.
60 */
61static int
62asf_parse_headerext(asf_object_headerext_t *header, uint8_t *buf)
63{
64 uint64_t datalen;
65 uint8_t *data;
66
67 if (header->size < 46) {
58
Taking false branch
68 /* invalide size for headerext */
69 return ASF_ERROR_INVALID_OBJECT_SIZE;
70 }
71
72 /* Read reserved and datalen fields from the buffer */
73 GetGUID(buf + 24, &header->reserved1);
74 header->reserved2 = GetWLE(buf + 40);
75 header->datalen = GetDWLE(buf + 42);
76
77 if (header->datalen != header->size - 46) {
59
Taking false branch
78 /* invalid header extension data length value */
79 return ASF_ERROR_INVALID_LENGTH;
80 }
81 header->data = buf + 46;
82
83 debug_printf("parsing header extension subobjects");
84
85 datalen = header->datalen;
86 data = header->data;
87 while (datalen > 0) {
60
Assuming 'datalen' is > 0
61
Loop condition is true. Entering loop body
88 asfint_object_t *current;
89
90 if (datalen < 24) {
62
Assuming 'datalen' is >= 24
63
Taking false branch
91 /* not enough data for reading a new object */
92 break;
93 }
94
95 /* Allocate a new subobject */
96 current = malloc(sizeof(asfint_object_t));
64
Memory is allocated
97 if (!current) {
65
Assuming 'current' is non-null
66
Taking false branch
98 return ASF_ERROR_OUTOFMEM;
99 }
100
101 asf_parse_read_object(current, data);
102 if (current->size > datalen || current->size < 24) {
103 /* invalid object size */
104 break;
67
Execution continues on line 122
105 }
106 current->datalen = current->size - 24;
107 current->data = data + 24;
108
109 /* add to the list of subobjects */
110 if (!header->first) {
111 header->first = current;
112 header->last = current;
113 } else {
114 header->last->next = current;
115 header->last = current;
116 }
117
118 data += current->size;
119 datalen -= current->size;
120 }
121
122 if (datalen != 0) {
68
Potential leak of memory pointed to by 'current'
123 /* not enough data for reading the whole object */
124 return ASF_ERROR_INVALID_LENGTH;
125 }
126
127 debug_printf("header extension subobjects parsed successfully");
128
129 return header->size;
130}
131
132/**
133 * Takes an initialized asf_file_t structure file as a parameter. Allocates
134 * a new asf_object_header_t in file->header and uses the file->iostream to
135 * read all fields and subobjects into it. Finally calls the
136 * asf_parse_header_validate function to validate the values and parse the
137 * commonly used values into the asf_file_t struct itself.
138 */
139int
140asf_parse_header(asf_file_t *file)
141{
142 asf_object_header_t *header;
143 asf_iostream_t *iostream;
144 uint8_t hdata[30];
145 int tmp;
146
147 file->header = NULL((void*)0);
148 iostream = &file->iostream;
149
150 /* object minimum is 24 bytes and header needs to have
151 * the subobject count field and two reserved fields */
152 tmp = asf_byteio_read(iostream, hdata, 30);
153 if (tmp < 0) {
1
Assuming 'tmp' is >= 0
2
Taking false branch
154 /* not enough data to read the header object */
155 return tmp;
156 }
157
158 file->header = malloc(sizeof(asf_object_header_t));
159 header = file->header;
160 if (!header) {
3
Assuming 'header' is non-null
4
Taking false branch
161 return ASF_ERROR_OUTOFMEM;
162 }
163
164 /* read the object and check its size value */
165 asf_parse_read_object((asfint_object_t *) header, hdata);
166 if (header->size < 30) {
5
Assuming the condition is false
6
Taking false branch
167 /* invalid size for header object */
168 return ASF_ERROR_INVALID_OBJECT_SIZE;
169 }
170
171 /* read header object specific compulsory fields */
172 header->subobjects = GetDWLE(hdata + 24);
173 header->reserved1 = hdata[28];
174 header->reserved2 = hdata[29];
175
176 /* clear header extension object and subobject list */
177 header->ext = NULL((void*)0);
178 header->first = NULL((void*)0);
179 header->last = NULL((void*)0);
180
181 /* the header data needs to be allocated for reading */
182 header->datalen = header->size - 30;
183 header->data = malloc(header->datalen * sizeof(uint8_t));
184 if (!header->data) {
7
Assuming the condition is false
8
Taking false branch
185 return ASF_ERROR_OUTOFMEM;
186 }
187
188 tmp = asf_byteio_read(iostream, header->data, header->datalen);
189 if (tmp < 0) {
9
Assuming 'tmp' is >= 0
10
Taking false branch
190 return tmp;
191 }
192
193 if (header->subobjects > 0) {
11
Assuming the condition is true
12
Taking true branch
194 uint64_t datalen;
195 uint8_t *data;
196 int i;
197
198 debug_printf("starting to read subobjects");
199
200 /* use temporary variables for use during the read */
201 datalen = header->datalen;
202 data = header->data;
203 for (i=0; i<header->subobjects; i++) {
13
Loop condition is true. Entering loop body
24
Assuming the condition is true
25
Loop condition is true. Entering loop body
35
Assuming the condition is true
36
Loop condition is true. Entering loop body
46
Assuming the condition is true
47
Loop condition is true. Entering loop body
204 asfint_object_t *current;
205
206 if (datalen < 24) {
14
Assuming 'datalen' is >= 24
15
Taking false branch
26
Assuming 'datalen' is >= 24
27
Taking false branch
37
Assuming 'datalen' is >= 24
38
Taking false branch
48
Assuming 'datalen' is >= 24
49
Taking false branch
207 /* not enough data for reading object */
208 break;
209 }
210
211 current = malloc(sizeof(asfint_object_t));
212 if (!current) {
16
Assuming 'current' is non-null
17
Taking false branch
28
Assuming 'current' is non-null
29
Taking false branch
39
Assuming 'current' is non-null
40
Taking false branch
50
Assuming 'current' is non-null
51
Taking false branch
213 return ASF_ERROR_OUTOFMEM;
214 }
215
216 asf_parse_read_object(current, data);
217 if (current->size > datalen || current->size < 24) {
18
Assuming the condition is false
19
Taking false branch
30
Assuming the condition is false
31
Taking false branch
41
Assuming the condition is false
42
Taking false branch
52
Assuming the condition is false
53
Taking false branch
218 /* invalid object size */
219 break;
220 }
221
222 /* Check if the current subobject is a header extension
223 * object or just a normal subobject */
224 if (current->type == GUID_HEADER_EXTENSION && !header->ext) {
20
Assuming the condition is false
32
Assuming the condition is false
43
Assuming the condition is false
54
Assuming the condition is true
55
Assuming the condition is true
56
Taking true branch
225 int ret;
226 asf_object_headerext_t *headerext;
227
228 /* we handle header extension separately because it has
229 * some subobjects as well */
230 current = realloc(current, sizeof(asf_object_headerext_t));
231 headerext = (asf_object_headerext_t *) current;
232 headerext->first = NULL((void*)0);
233 headerext->last = NULL((void*)0);
234 ret = asf_parse_headerext(headerext, data);
57
Calling 'asf_parse_headerext'
235
236 if (ret < 0) {
237 /* error parsing header extension */
238 return ret;
239 }
240
241 header->ext = headerext;
242 } else {
243 if (current->type == GUID_HEADER_EXTENSION) {
21
Taking false branch
33
Taking false branch
44
Taking false branch
244 debug_printf("WARNING! Second header extension object found, ignoring it!");
245 }
246
247 current->datalen = current->size - 24;
248 current->data = data + 24;
249
250 /* add to list of subobjects */
251 if (!header->first) {
22
Assuming the condition is false
23
Taking false branch
34
Taking false branch
45
Taking false branch
252 header->first = current;
253 header->last = current;
254 } else {
255 header->last->next = current;
256 header->last = current;
257 }
258 }
259
260 data += current->size;
261 datalen -= current->size;
262 }
263
264 if (i != header->subobjects || datalen != 0) {
265 /* header data size doesn't match given subobject count */
266 return ASF_ERROR_INVALID_VALUE;
267 }
268
269 debug_printf("%d subobjects read successfully", i);
270 }
271
272 tmp = asf_parse_header_validate(file, file->header);
273 if (tmp < 0) {
274 /* header read ok but doesn't validate correctly */
275 return tmp;
276 }
277
278 debug_printf("header validated correctly");
279
280 return header->size;
281}
282
283/**
284 * Takes an initialized asf_file_t structure file as a parameter. Allocates
285 * a new asf_object_data_t in file->data and uses the file->iostream to
286 * read all its compulsory fields into it. Notice that the actual data is
287 * not read in any way, because we need to be able to work with non-seekable
288 * streams as well.
289 */
290int
291asf_parse_data(asf_file_t *file)
292{
293 asf_object_data_t *data;
294 asf_iostream_t *iostream;
295 uint8_t ddata[50];
296 int tmp;
297
298 file->data = NULL((void*)0);
299 iostream = &file->iostream;
300
301 /* object minimum is 24 bytes and data object needs to have
302 * 26 additional bytes for its internal fields */
303 tmp = asf_byteio_read(iostream, ddata, 50);
304 if (tmp < 0) {
305 return tmp;
306 }
307
308 file->data = malloc(sizeof(asf_object_data_t));
309 data = file->data;
310 if (!data) {
311 return ASF_ERROR_OUTOFMEM;
312 }
313
314 /* read the object and check its size value */
315 asf_parse_read_object((asfint_object_t *) data, ddata);
316 if (data->size < 50) {
317 /* invalid size for data object */
318 return ASF_ERROR_INVALID_OBJECT_SIZE;
319 }
320
321 /* read data object specific compulsory fields */
322 GetGUID(ddata + 24, &data->file_id);
323 data->total_data_packets = GetQWLE(ddata + 40);
324 data->reserved = GetWLE(ddata + 48);
325 data->packets_position = file->position + 50;
326
327 /* If the file_id GUID in data object doesn't match the
328 * file_id GUID in headers, the file is corrupted */
329 if (!asf_guid_equals(&data->file_id, &file->file_id)) {
330 return ASF_ERROR_INVALID_VALUE;
331 }
332
333 /* if data->total_data_packets is non-zero (not a stream) and
334 the data packets count doesn't match, return error */
335 if (data->total_data_packets &&
336 data->total_data_packets != file->data_packets_count) {
337 return ASF_ERROR_INVALID_VALUE;
338 }
339
340 return 50;
341}
342
343/**
344 * Takes an initialized asf_file_t structure file as a parameter. Allocates
345 * a new asf_object_index_t in file->index and uses the file->iostream to
346 * read all its compulsory fields into it. Notice that the actual data is
347 * not read in any way, because we need to be able to work with non-seekable
348 * streams as well.
349 */
350int
351asf_parse_index(asf_file_t *file)
352{
353 asf_object_index_t *index;
354 asf_iostream_t *iostream;
355 uint8_t idata[56];
356 uint64_t entry_data_size;
357 uint8_t *entry_data = NULL((void*)0);
358 uint32_t i;
359 int tmp;
360
361 file->index = NULL((void*)0);
362 iostream = &file->iostream;
363
364 /* read the raw data of an index header */
365 tmp = asf_byteio_read(iostream, idata, 56);
366 if (tmp < 0) {
367 return tmp;
368 }
369
370 /* allocate the index object */
371 index = malloc(sizeof(asf_object_index_t));
372 if (!index) {
373 return ASF_ERROR_OUTOFMEM;
374 }
375
376 asf_parse_read_object((asfint_object_t *) index, idata);
377 if (index->type != GUID_INDEX) {
378 tmp = index->size;
379 free(index);
380
381 /* The guid type was wrong, just return the bytes to skip */
382 return tmp;
383 }
384
385 if (index->size < 56) {
386 /* invalid size for index object */
387 free(index);
388 return ASF_ERROR_INVALID_OBJECT_SIZE;
389 }
390
391 GetGUID(idata + 24, &index->file_id);
392 index->entry_time_interval = GetQWLE(idata + 40);
393 index->max_packet_count = GetDWLE(idata + 48);
394 index->entry_count = GetDWLE(idata + 52);
395
396 if (index->entry_count * 6 + 56 > index->size) {
397 free(index);
398 return ASF_ERROR_INVALID_LENGTH;
399 }
400
401 entry_data_size = index->entry_count * 6;
402 entry_data = malloc(entry_data_size * sizeof(uint8_t));
403 if (!entry_data) {
404 free(index);
405 return ASF_ERROR_OUTOFMEM;
406 }
407 tmp = asf_byteio_read(iostream, entry_data, entry_data_size);
408 if (tmp < 0) {
409 free(index);
410 free(entry_data);
411 return tmp;
412 }
413
414 index->entries = malloc(index->entry_count * sizeof(asf_index_entry_t));
415 if (!index->entries) {
416 free(index);
417 free(entry_data);
418 return ASF_ERROR_OUTOFMEM;
419 }
420
421 for (i=0; i<index->entry_count; i++) {
422 index->entries[i].packet_index = GetDWLE(entry_data + i*6);
423 index->entries[i].packet_count = GetWLE(entry_data + i*6 + 4);
424 }
425
426 free(entry_data);
427 file->index = index;
428
429 return index->size;
430}