Bug Summary

File:xcursorgen.c
Location:line 443, column 3
Description:Potential leak of memory pointed to by 'list'

Annotated Source Code

1/*
2 * xcursorgen.c
3 *
4 * Copyright (C) 2002 Manish Singh
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Manish Singh not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Manish Singh makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
16 * MANISH SINGH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL MANISH SINGH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25#include "config.h"
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <ctype.h>
31
32#include <X11/Xlib.h>
33#include <X11/Xutil.h>
34#include <X11/Xcursor/Xcursor.h>
35
36#include <png.h>
37
38struct flist
39{
40 int size;
41 int xhot, yhot;
42 int delay;
43 char *pngfile;
44 struct flist *next;
45};
46
47static void
48usage (const char *name)
49{
50 fprintf (stderr__stderrp,
51 "usage: %s [-V] [--version] [-?] [--help] [-p <dir>] [--prefix <dir>] [CONFIG [OUT]]\n%s",
52 name,
53 "Generate an Xcursor file from a series of PNG images\n"
54 "\n"
55 " -V, --version display the version number and exit\n"
56 " -?, --help display this message and exit\n"
57 " -p, --prefix <dir> find cursor images in <dir>\n"
58 "\n"
59 "With no CONFIG, or when CONFIG is -, read standard input. "
60 "Same with OUT and\n"
61 "standard output.\n");
62}
63
64static int
65read_config_file (const char *config, struct flist **list)
66{
67 FILE *fp;
68 char line[4096], pngfile[4000];
69 int size, xhot, yhot, delay;
70 struct flist *start = NULL((void*)0), *end = NULL((void*)0), *curr;
71 int count = 0;
72
73 if (strcmp (config, "-") != 0)
6
Taking false branch
74 {
75 fp = fopen (config, "r");
76 if (!fp)
77 {
78 *list = NULL((void*)0);
79 return 0;
80 }
81 }
82 else
83 fp = stdin__stdinp;
84
85 while (fgets (line, sizeof (line), fp) != NULL((void*)0))
7
Loop condition is true. Entering loop body
16
Loop condition is false. Execution continues on line 144
86 {
87 if (line[0] == '#')
8
Taking false branch
88 continue;
89
90 switch (sscanf (line, "%d %d %d %3999s %d", &size, &xhot, &yhot, pngfile, &delay))
9
Control jumps to 'case 5:' at line 95
91 {
92 case 4:
93 delay = 50;
94 break;
95 case 5:
96 break;
10
Execution continues on line 105
97 default:
98 {
99 fprintf (stderr__stderrp, "Bad config file data!\n");
100 fclose (fp);
101 return 0;
102 }
103 }
104
105 curr = malloc (sizeof (struct flist));
11
Memory is allocated
106 if (curr == NULL((void*)0))
12
Assuming 'curr' is not equal to null
13
Taking false branch
107 {
108 fprintf (stderr__stderrp, "malloc() failed\n");
109 fclose (fp);
110 return 0;
111 }
112
113 curr->size = size;
114 curr->xhot = xhot;
115 curr->yhot = yhot;
116
117 curr->delay = delay;
118
119 curr->pngfile = strdup (pngfile);
120 if (curr->pngfile == NULL((void*)0))
14
Taking false branch
121 {
122 fprintf (stderr__stderrp, "strdup() failed\n");
123 fclose (fp);
124 free(curr);
125 return 0;
126 }
127
128 curr->next = NULL((void*)0);
129
130 if (start)
15
Taking false branch
131 {
132 end->next = curr;
133 end = curr;
134 }
135 else
136 {
137 start = curr;
138 end = curr;
139 }
140
141 count++;
142 }
143
144 fclose (fp);
145
146 *list = start;
147 return count;
148}
149
150#define div_255(x)(((x) + 0x80 + (((x) + 0x80) >> 8)) >> 8) (((x) + 0x80 + (((x) + 0x80) >> 8)) >> 8)
151
152static void
153premultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
154{
155 int i;
156
157 for (i = 0; i < row_info->rowbytes; i += 4)
158 {
159 unsigned char *base = &data[i];
160 unsigned char blue = base[0];
161 unsigned char green = base[1];
162 unsigned char red = base[2];
163 unsigned char alpha = base[3];
164 XcursorPixel p;
165
166 red = div_255((unsigned)red * (unsigned)alpha)((((unsigned)red * (unsigned)alpha) + 0x80 + ((((unsigned)red
* (unsigned)alpha) + 0x80) >> 8)) >> 8)
;
167 green = div_255((unsigned)green * (unsigned)alpha)((((unsigned)green * (unsigned)alpha) + 0x80 + ((((unsigned)green
* (unsigned)alpha) + 0x80) >> 8)) >> 8)
;
168 blue = div_255((unsigned)blue * (unsigned)alpha)((((unsigned)blue * (unsigned)alpha) + 0x80 + ((((unsigned)blue
* (unsigned)alpha) + 0x80) >> 8)) >> 8)
;
169 p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
170 memcpy (base, &p, sizeof (XcursorPixel))__builtin___memcpy_chk (base, &p, sizeof (XcursorPixel), __builtin_object_size
(base, 0))
;
171 }
172}
173
174static XcursorImage *
175load_image (struct flist *list, const char *prefix)
176{
177 XcursorImage *image;
178 png_structp png;
179 png_infop info;
180 png_bytepp rows;
181 FILE *fp;
182 int i;
183 png_uint_32 width, height;
184 int depth, color, interlace;
185 char *file;
186
187 png = png_create_read_struct (PNG_LIBPNG_VER_STRING"1.5.1", NULL((void*)0), NULL((void*)0), NULL((void*)0));
188 if (png == NULL((void*)0))
189 return NULL((void*)0);
190
191 info = png_create_info_struct (png);
192 if (info == NULL((void*)0))
193 {
194 png_destroy_read_struct (&png, NULL((void*)0), NULL((void*)0));
195 return NULL((void*)0);
196 }
197
198 if (setjmp (png_jmpbuf(png)(*png_set_longjmp_fn((png), longjmp, sizeof (jmp_buf)))))
199 {
200 png_destroy_read_struct (&png, &info, NULL((void*)0));
201 return NULL((void*)0);
202 }
203
204 if (prefix)
205 {
206 file = malloc (strlen (prefix) + 1 + strlen (list->pngfile) + 1);
207 if (file == NULL((void*)0))
208 {
209 fprintf (stderr__stderrp, "malloc() failed\n");
210 png_destroy_read_struct (&png, &info, NULL((void*)0));
211 return NULL((void*)0);
212 }
213 strcpy (file, prefix)__builtin___strcpy_chk (file, prefix, __builtin_object_size (
file, 2 > 1 ? 1 : 0))
;
214 strcat (file, "/")__builtin___strcat_chk (file, "/", __builtin_object_size (file
, 2 > 1 ? 1 : 0))
;
215 strcat (file, list->pngfile)__builtin___strcat_chk (file, list->pngfile, __builtin_object_size
(file, 2 > 1 ? 1 : 0))
;
216 }
217 else
218 file = list->pngfile;
219 fp = fopen (file, "rb");
220 if (prefix)
221 free (file);
222
223 if (fp == NULL((void*)0))
224 {
225 png_destroy_read_struct (&png, &info, NULL((void*)0));
226 return NULL((void*)0);
227 }
228
229 png_init_io (png, fp);
230 png_read_info (png, info);
231 png_get_IHDR (png, info, &width, &height, &depth, &color, &interlace,
232 NULL((void*)0), NULL((void*)0));
233
234 /* TODO: More needs to be done here maybe */
235
236 if (color == PNG_COLOR_TYPE_PALETTE(2 | 1) && depth <= 8)
237 png_set_expand (png);
238
239 if (color == PNG_COLOR_TYPE_GRAY0 && depth < 8)
240 png_set_expand (png);
241
242 if (png_get_valid (png, info, PNG_INFO_tRNS0x0010))
243 png_set_expand (png);
244
245 if (depth == 16)
246 png_set_strip_16 (png);
247
248 if (depth < 8)
249 png_set_packing (png);
250
251 if (color == PNG_COLOR_TYPE_GRAY0 || color == PNG_COLOR_TYPE_GRAY_ALPHA(4))
252 png_set_gray_to_rgb (png);
253
254 if (interlace != PNG_INTERLACE_NONE0)
255 png_set_interlace_handling (png);
256
257 png_set_bgr (png);
258 png_set_filler (png, 255, PNG_FILLER_AFTER1);
259
260 png_set_read_user_transform_fn (png, premultiply_data);
261
262 png_read_update_info (png, info);
263
264 image = XcursorImageCreate (width, height);
265
266 image->size = list->size;
267 image->xhot = list->xhot;
268 image->yhot = list->yhot;
269 image->delay = list->delay;
270
271 rows = malloc (sizeof (png_bytep) * height);
272 if (rows == NULL((void*)0))
273 {
274 fclose (fp);
275 png_destroy_read_struct (&png, &info, NULL((void*)0));
276 return NULL((void*)0);
277 }
278
279 for (i = 0; i < height; i++)
280 rows[i] = (png_bytep) (image->pixels + i * width);
281
282 png_read_image (png, rows);
283 png_read_end (png, info);
284
285 free (rows);
286 fclose (fp);
287 png_destroy_read_struct (&png, &info, NULL((void*)0));
288
289 return image;
290}
291
292static int
293write_cursors (int count, struct flist *list,
294 const char *filename, const char *prefix)
295{
296 XcursorImages *cimages;
297 XcursorImage *image;
298 int i;
299 FILE *fp;
300 int ret;
301
302 if (strcmp (filename, "-") != 0)
303 {
304 fp = fopen (filename, "wb");
305 if (!fp)
306 return 1;
307 }
308 else
309 fp = stdout__stdoutp;
310
311 cimages = XcursorImagesCreate (count);
312
313 cimages->nimage = count;
314
315 for (i = 0; i < count; i++, list = list->next)
316 {
317 image = load_image (list, prefix);
318 if (image == NULL((void*)0))
319 {
320 fprintf (stderr__stderrp, "PNG error while reading %s!\n", list->pngfile);
321 fclose(fp);
322 return 1;
323 }
324
325 cimages->images[i] = image;
326 }
327
328 ret = XcursorFileSaveImages (fp, cimages);
329
330 fclose (fp);
331
332 return ret ? 0 : 1;
333}
334
335static int
336check_image (char *image)
337{
338 unsigned int width, height;
339 unsigned char *data;
340 int x_hot, y_hot;
341 unsigned char hash[XCURSOR_BITMAP_HASH_SIZE16];
342 int i;
343
344 if (XReadBitmapFileData (image, &width, &height, &data, &x_hot, &y_hot) != BitmapSuccess0)
345 {
346 fprintf (stderr__stderrp, "Can't open bitmap file \"%s\"\n", image);
347 return 1;
348 }
349 else {
350 XImage ximage = {
351 .width = width,
352 .height = height,
353 .depth = 1,
354 .bits_per_pixel = 1,
355 .xoffset = 0,
356 .format = XYPixmap1,
357 .data = (char *)data,
358 .byte_order = LSBFirst0,
359 .bitmap_unit = 8,
360 .bitmap_bit_order = LSBFirst0,
361 .bitmap_pad = 8,
362 .bytes_per_line = (width+7)/8
363 };
364 XcursorImageHash (&ximage, hash);
365 }
366 printf ("%s: ", image);
367 for (i = 0; i < XCURSOR_BITMAP_HASH_SIZE16; i++)
368 printf ("%02x", hash[i]);
369 printf ("\n");
370 return 0;
371}
372
373int
374main (int argc, char *argv[])
375{
376 struct flist *list;
377 int count;
378 const char *in = NULL((void*)0), *out = NULL((void*)0);
379 const char *prefix = NULL((void*)0);
380 int i;
381
382 for (i = 1; i < argc; i++)
1
Assuming 'i' is >= 'argc'
2
Loop condition is false. Execution continues on line 431
383 {
384 if (strcmp (argv[i], "-V") == 0 || strcmp (argv[i], "--version") == 0)
385 {
386 printf ("xcursorgen version %s\n", PACKAGE_VERSION"1.0.6");
387 return 0;
388 }
389
390 if (strcmp (argv[i], "-?") == 0 || strcmp (argv[i], "--help") == 0)
391 {
392 usage (argv[0]);
393 return 0;
394 }
395 if (strcmp (argv[i], "-image") == 0)
396 {
397 int ret = 0;
398 while (argv[++i])
399 {
400 if (check_image (argv[i]))
401 ret = i;
402 }
403 return ret;
404 }
405 if (strcmp (argv[i], "-p") == 0 || strcmp (argv[i], "--prefix") == 0)
406 {
407 i++;
408 if (argv[i] == NULL((void*)0))
409 {
410 fprintf (stderr__stderrp, "%s: %s requires an argument\n",
411 argv[0], argv[i-1]);
412 usage (argv[0]);
413 return 1;
414 }
415 prefix = argv[i];
416 continue;
417 }
418
419 if (!in)
420 in = argv[i];
421 else if (!out)
422 out = argv[i];
423 else
424 {
425 fprintf (stderr__stderrp, "%s: unexpected argument '%s'\n", argv[0], argv[i]);
426 usage (argv[0]);
427 return 1;
428 }
429 }
430
431 if (!in)
3
Taking true branch
432 in = "-";
433 if (!out)
4
Taking true branch
434 out = "-";
435
436 count = read_config_file (in, &list);
5
Calling 'read_config_file'
17
Returned allocated memory via 2nd parameter
437 if (count == 0)
18
Taking false branch
438 {
439 fprintf (stderr__stderrp, "Error reading config file!\n");
440 return 1;
441 }
442
443 return write_cursors (count, list, out, prefix);
19
Potential leak of memory pointed to by 'list'
444}