]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/test-loaders.c
5286f020d631bff218a8346798820509e7207928
[~andy/gtk] / gdk-pixbuf / test-loaders.c
1 /* -*- Mode: C; c-basic-offset: 2; -*- */
2 /* GdkPixbuf library - test loaders
3  *
4  * Copyright (C) 2001 Søren Sandmann (sandmann@daimi.au.dk)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include <config.h>
22 #include "gdk-pixbuf.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include "test-images.h"
26 #include <time.h>
27 #include <string.h>
28
29 #define PRETEND_MEM_SIZE (16 * 1024 * 1024)
30 #define REMAINING_MEM_SIZE 5000
31
32
33 static int current_allocation = 0;
34 static int max_allocation = 0;
35
36 #define HEADER_SPACE sizeof(void*)
37
38 static gpointer
39 record_bytes (gpointer mem, gsize bytes)
40 {
41   if (mem == NULL ||
42       (current_allocation + bytes) > max_allocation)
43     {
44       if (mem)
45         free (mem);
46       
47       return NULL;
48     }
49   
50   *(void **)mem = GINT_TO_POINTER (bytes);
51
52   g_assert (GPOINTER_TO_INT (*(void**)mem) == bytes);
53   
54   g_assert (current_allocation >= 0);
55   current_allocation += bytes;
56   g_assert (current_allocation >= 0);
57   
58   g_assert ( mem == (void*) ((((char*)mem) + HEADER_SPACE) - HEADER_SPACE) );
59   return ((char*)mem) + HEADER_SPACE;
60 }
61
62 static gpointer
63 limited_try_malloc (gsize n_bytes)
64 {
65   return record_bytes (malloc (n_bytes + HEADER_SPACE), n_bytes);
66 }
67
68 static gpointer
69 limited_malloc (gsize n_bytes)
70 {
71   return limited_try_malloc (n_bytes);
72 }
73
74 static gpointer
75 limited_calloc (gsize n_blocks,
76                 gsize n_block_bytes)
77 {
78   int bytes = n_blocks * n_block_bytes + HEADER_SPACE;
79   gpointer mem = malloc (bytes);
80   memset (mem, 0, bytes);
81   return record_bytes (mem, n_blocks * n_block_bytes);
82 }
83
84 static void
85 limited_free (gpointer mem)
86 {
87   gpointer real = ((char*)mem) - HEADER_SPACE;
88
89   g_assert (current_allocation >= 0);
90   current_allocation -= GPOINTER_TO_INT (*(void**)real);
91   g_assert (current_allocation >= 0);
92   
93   free (real);
94 }
95
96 static gpointer
97 limited_try_realloc (gpointer mem,
98                      gsize    n_bytes)
99 {
100   if (mem == NULL)
101     {
102       return limited_try_malloc (n_bytes);
103     }
104   else
105     {
106       gpointer real;
107
108       g_assert (mem);
109
110       real = ((char*)mem) - HEADER_SPACE;
111       
112       g_assert (current_allocation >= 0);
113       current_allocation -= GPOINTER_TO_INT (*(void**)real);
114       g_assert (current_allocation >= 0);
115
116       return record_bytes (realloc (real, n_bytes + HEADER_SPACE), n_bytes);
117     }
118 }
119
120 static gpointer
121 limited_realloc (gpointer mem,
122                  gsize    n_bytes)
123 {
124   return limited_try_realloc (mem, n_bytes);
125 }
126
127 static GMemVTable limited_table = {
128   limited_malloc,
129   limited_realloc,
130   limited_free,
131   limited_calloc,
132   limited_try_malloc,
133   limited_try_realloc
134 };
135
136 static gboolean
137 test_loader (const guchar *bytes, gsize len, gboolean data_is_ok)
138 {
139   GdkPixbufLoader *loader;
140   GError *err = NULL;
141   gboolean did_fail = FALSE;
142   
143   loader = gdk_pixbuf_loader_new ();
144   gdk_pixbuf_loader_write (loader, bytes, len, &err);
145   if (err)
146     {
147       g_error_free (err);
148       err = NULL;
149       did_fail = TRUE;
150     }
151   gdk_pixbuf_loader_close (loader, &err);
152   if (err)
153     {
154       g_error_free (err);
155       err = NULL;
156       did_fail = TRUE;
157     }
158   g_object_unref (loader);
159   
160   if (data_is_ok == did_fail)
161     return FALSE;
162   else 
163     return TRUE;
164 }
165
166 static void
167 mem_test (const guchar *bytes, gsize len)
168 {
169   gboolean did_fail = FALSE;
170   GError *err = NULL;
171   GdkPixbufLoader *loader; 
172   GList *loaders = NULL;
173   GList *i;
174   
175   do {
176     loader = gdk_pixbuf_loader_new ();
177     gdk_pixbuf_loader_write (loader, bytes, len, &err);
178     if (err)
179       {
180         g_error_free (err);
181         err = NULL;
182         did_fail = TRUE;
183       }
184     gdk_pixbuf_loader_close (loader, NULL);
185     if (err)
186       {
187         g_error_free (err);
188         err = NULL;
189         did_fail = TRUE;
190       }
191     loaders = g_list_prepend (loaders, loader);
192   } while (!did_fail);
193   
194   for (i = loaders; i != NULL; i = i->next)
195     g_object_unref (i->data);
196   g_list_free (loaders);
197 }
198
199 void
200 assault (const gchar *header, gsize header_size, 
201          int n_images, gboolean verbose)
202 {
203   enum { N_CHARACTERS = 10000 };
204   int j;
205   for (j = 0; j < n_images; ++j)
206     {
207       GError *err = NULL;
208       int i;
209       GdkPixbufLoader *loader;
210       
211       if (verbose)
212         g_print ("'img' no: %d\n", j);
213       
214       loader = gdk_pixbuf_loader_new ();
215       
216       gdk_pixbuf_loader_write (loader, header, header_size, &err);
217       if (err)
218         {
219           g_error_free (err);
220           continue;
221         }
222       
223       for (i = 0; i < N_CHARACTERS; ++i)
224         {
225           int r = g_random_int ();
226           
227           if (verbose)
228             {
229               int j;
230               for (j = 0; j < sizeof (r); j++)
231                 g_print ("%u, ", ((guchar *)&r)[j]);
232             }
233           
234           gdk_pixbuf_loader_write (loader, (guchar *)&r, sizeof (r), &err);
235           if (err)
236             {
237               g_error_free (err);
238               err = NULL;
239               break;
240             }
241         }
242       if (verbose)
243         g_print ("\n");
244       
245       gdk_pixbuf_loader_close (loader, &err);
246       if (err)
247         {
248           g_error_free (err);
249           err = NULL;
250         }
251       
252       g_object_unref (loader);
253     }
254 }
255
256 static void
257 randomly_modify (const guchar *image, guint size, gboolean verbose)
258 {
259   int i;
260   guchar *img_copy = g_malloc (size);
261   for (i = 0; i < size; i++)
262     img_copy [i] = image[i];
263   
264   for (i = 0; i < size / 4; i++)
265     {
266       int j;
267       
268       guint index = g_random_int_range (0, size);
269       guchar byte = g_random_int_range (0, 256);
270       
271       img_copy[index] = byte;
272       
273       if (verbose)
274         {
275           g_print ("img no %d\n", i);
276           for (j = 0; j < size; j++)
277             g_print ("%u, ", img_copy[j]);
278           g_print ("\n\n");
279         }
280       
281       test_loader (img_copy, size, FALSE);
282     }
283   g_free (img_copy);
284 }
285
286 #define TEST(bytes, data_is_ok)                                 \
287 do {                                                            \
288         g_print ("%-40s", "                  " #bytes " ");     \
289         fflush (stdout);                                        \
290         if (test_loader (bytes, sizeof (bytes), data_is_ok))    \
291             g_print ("\tpassed\n");                             \
292         else                                                    \
293             g_print ("\tFAILED\n");                             \
294 } while (0)
295
296 #define LOWMEMTEST(bytes)                                       \
297 do {                                                            \
298         g_print ("%-40s", "memory            " #bytes " ");     \
299         fflush (stdout);                                        \
300         mem_test (bytes, sizeof (bytes));                       \
301         g_print ("\tpassed\n");                                 \
302 } while (0)
303
304 #define TEST_RANDOM(header, n_img, verbose)                     \
305 do {                                                            \
306         static guchar h[] = { header };                         \
307         g_print ("%-40s", "random            " #header " ");    \
308         fflush (stdout);                                        \
309         assault (h, sizeof (h), n_img, verbose);                \
310         g_print ("\tpassed\n");                                 \
311 } while (0)
312
313 #define TEST_RANDOMLY_MODIFIED(image, verbose)                  \
314 do {                                                            \
315         g_print ("%-40s", "randomly modified " #image " ");     \
316         fflush (stdout);                                        \
317         randomly_modify (image, sizeof (image), verbose);       \
318         g_print ("\tpassed\n");                                 \
319 } while (0)
320
321
322
323 static void
324 almost_exhaust_memory (void)
325 {
326   gpointer x = g_malloc (REMAINING_MEM_SIZE);
327   while (g_try_malloc (REMAINING_MEM_SIZE / 10))
328     ;
329   g_free (x);
330 }
331
332 static void
333 write_seed (int seed)
334 {
335   FILE *f;
336   /* write this so you can reproduce failed tests */
337   f = fopen ("test-loaders-seed", "w");
338   if (!f)
339     {
340       perror ("fopen");
341       exit (EXIT_FAILURE);
342     }
343   if (fprintf (f, "%d\n", seed) < 0)
344     {
345       perror ("fprintf");
346       exit (EXIT_FAILURE);
347     }
348   if (fclose (f) < 0)
349     {
350       perror ("fclose");
351       exit (EXIT_FAILURE);
352     }
353   g_print ("seed: %d\n", seed);
354 }
355
356 int
357 main (int argc, char **argv)
358 {
359   int seed;
360
361   /* Set a malloc which emulates low mem */
362   max_allocation = G_MAXINT;
363   g_mem_set_vtable (&limited_table);
364   
365   if (argc > 1)
366     seed = atoi (argv[1]);
367   else
368     {
369       seed = time (NULL);
370       write_seed (seed);
371     }
372   g_random_set_seed (seed);
373   
374   g_type_init ();
375   g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
376   
377   putenv ("GDK_PIXBUF_MODULEDIR="BUILT_MODULES_DIR);
378
379   TEST (valid_ppm_1, TRUE);
380   TEST (valid_ppm_2, TRUE);
381   TEST (valid_ppm_3, FALSE); /* image is valid, but we don't handle maxval > 255 */
382   TEST (valid_ppm_4, TRUE);
383
384   TEST (invalid_ppm_1, FALSE); /* this test fails to fail, because it's shorter than LOADER_HEADER_SIZE */
385   TEST (invalid_ppm_2, FALSE);
386   TEST (invalid_ppm_3, FALSE);
387   TEST (invalid_ppm_4, FALSE);
388   TEST (invalid_ppm_5, FALSE);
389   TEST (invalid_ppm_6, FALSE);
390   TEST (invalid_ppm_7, FALSE);
391   TEST (invalid_ppm_8, FALSE);
392
393   TEST (valid_gif_test, TRUE); 
394   TEST (gif_test_1, FALSE);   
395   TEST (gif_test_2, FALSE);   
396   TEST (gif_test_3, FALSE);   
397   TEST (gif_test_4, FALSE);   
398   
399   TEST (valid_png_test, TRUE);
400   TEST (png_test_1, FALSE);   
401   TEST (png_test_2, FALSE);
402
403
404   TEST (valid_ico_test, TRUE);
405   TEST (ico_test_1, FALSE);
406   TEST (ico_test_2, FALSE);
407
408   TEST (valid_jpeg_test, TRUE);
409   
410   TEST (valid_tiff1_test, TRUE);
411   TEST (tiff1_test_1, FALSE);
412   TEST (tiff1_test_2, FALSE);
413 #if 0
414   TEST (tiff1_test_3, FALSE); /* Segfault in TIFFReadDirectory with libtiff 3.5.5, fixed in 3.5.7 */
415 #endif
416
417   TEST (valid_tga_test, TRUE);
418   TEST (tga_test_1, FALSE);
419
420   TEST (xpm_test_1, FALSE);
421
422   TEST (wbmp_test_1, FALSE); 
423   TEST (wbmp_test_2, FALSE);
424   
425   TEST_RANDOM (GIF_HEADER, 150, FALSE);
426   TEST_RANDOM (PNG_HEADER, 1100, FALSE);
427   TEST_RANDOM (JPEG_HEADER, 800, FALSE);
428   TEST_RANDOM (TIFF1_HEADER, 150, FALSE);
429   TEST_RANDOM (TIFF2_HEADER, 150, FALSE);
430 #define PNM_HEADER 'P', '6'
431   TEST_RANDOM (PNM_HEADER, 150, FALSE);
432 #define XBM_HEADER '#', 'd', 'e', 'f', 'i', 'n', 'e', ' '  
433   TEST_RANDOM (XBM_HEADER, 150, FALSE);
434 #define BMP_HEADER 'B', 'M'  
435   TEST_RANDOM (BMP_HEADER, 150, FALSE);
436 #define XPM_HEADER '/', '*', ' ', 'X', 'P', 'M', ' ', '*', '/'
437   TEST_RANDOM (XPM_HEADER, 150, FALSE);
438
439
440   TEST_RANDOMLY_MODIFIED (valid_tiff1_test, FALSE);  
441   TEST_RANDOMLY_MODIFIED (valid_gif_test, FALSE);
442   TEST_RANDOMLY_MODIFIED (valid_png_test, FALSE);
443   TEST_RANDOMLY_MODIFIED (valid_tga_test, FALSE);
444   TEST_RANDOMLY_MODIFIED (valid_jpeg_test, FALSE);
445   TEST_RANDOMLY_MODIFIED (valid_ico_test, FALSE);
446   TEST_RANDOMLY_MODIFIED (valid_bmp_test, FALSE);
447   TEST_RANDOMLY_MODIFIED (valid_xpm_test, FALSE);
448   
449
450   /* memory tests */
451
452   /* How do the loaders behave when memory is low?
453      It depends on the state the above tests left the 
454      memory in.
455
456      - Sometimes the png loader tries to report an 
457        "out of memory", but then g_strdup_printf() calls
458        g_malloc(), which fails.
459        
460      - There are unchecked realloc()s inside libtiff, which means it
461        will never work with low memory, unless something drastic is
462        done, like allocating a lot of memory upfront and release it
463        before entering libtiff.  Also, some TIFFReadRGBAImage calls
464        returns successfully, even though they have called the error
465        handler with an 'out of memory' message.
466   */
467
468   max_allocation = PRETEND_MEM_SIZE;
469   almost_exhaust_memory ();
470
471   g_print ("Allocated %dK of %dK, %dK free during tests\n",
472            current_allocation / 1024, max_allocation / 1024,
473            (max_allocation - current_allocation) / 1024);
474   
475 #if 0
476   LOWMEMTEST (valid_tiff1_test);  
477 #endif
478   LOWMEMTEST (valid_gif_test);
479   LOWMEMTEST (valid_png_test);
480   LOWMEMTEST (valid_jpeg_test);
481   
482   return 0;
483 }