Line  | Count  | Source  | 
1  |  | #include "egif_fuzz_common.h"  | 
2  | 152k  | #define GIF_IMAGE_WIDTH 100  | 
3  |  | // This is rgb byte stream length per horizontal line = GIF_IMAGE_WIDTH * 3  | 
4  | 723  | #define GIF_IMAGE_LINE 300  | 
5  |  |  | 
6  |  | extern "C" void PrintGifError(int ErrorCode);  | 
7  |  |  | 
8  |  | int stub_output_writer(GifFileType *gifFileType, const uint8_t *buf, int len)  | 
9  | 116k  | { | 
10  | 116k  |   struct gifUserData *gud = (struct gifUserData *)gifFileType->UserData;  | 
11  |  |  | 
12  | 116k  |   if (gud == NULL || gud->gifData == NULL || len == 0)  | 
13  | 0  |     return 0;  | 
14  | 116k  |   if (gud->allocatedSize < (gud->gifLen + len))  | 
15  | 702  |   { | 
16  |  |     // Reallocate gifFileType  | 
17  | 702  |     int newSize = (gud->gifLen + len) * 2;  | 
18  | 702  |     uint8_t *oldGud = gud->gifData;  | 
19  | 702  |     gud->gifData = (uint8_t *)realloc(oldGud, newSize);  | 
20  |  |     // Assert when realloc fails.  | 
21  | 702  |     assert(gud->gifData != NULL);  | 
22  | 702  |     gud->allocatedSize = newSize;  | 
23  | 702  |   }  | 
24  | 116k  |   memcpy(gud->gifData + gud->gifLen, buf, len);  | 
25  | 116k  |   gud->gifLen += len;  | 
26  | 116k  |   return len;  | 
27  | 116k  | }  | 
28  |  |  | 
29  |  | // RGB to GIF converter  | 
30  |  | static bool rgb_to_gif(const uint8_t *data, size_t size)  | 
31  | 348  | { | 
32  |  |   // Bail if total size is not a multiple of GIF_IMAGE_LINE (see below)  | 
33  |  |   // Keep a fixed width e.g., GIF_IMAGE_WIDTH  | 
34  |  |   // size/3 = GIF_IMAGE_WIDTH * height  | 
35  |  |   // height = size/GIF_IMAGE_LINE  | 
36  |  |  | 
37  |  |   // Extract height  | 
38  | 348  |   int height = size / GIF_IMAGE_LINE;  | 
39  |  |  | 
40  |  |   // GifByteType is unsigned char (raw byte)  | 
41  |  |   // mem holds the raw RGB byte stream for the entire image  | 
42  | 348  |   GifByteType *mem = (GifByteType *)malloc(sizeof(GifByteType) * height * GIF_IMAGE_WIDTH * 3);  | 
43  | 348  |   if (!mem)  | 
44  | 0  |     return false;  | 
45  |  |  | 
46  |  |   // Copy RGB data to mem  | 
47  | 348  |   memcpy(mem, data, size);  | 
48  |  |  | 
49  | 348  |   GifByteType *red_buf = mem;  | 
50  | 348  |   GifByteType *green_buf = mem + (GIF_IMAGE_WIDTH * height);  | 
51  | 348  |   GifByteType *blue_buf = mem + (GIF_IMAGE_WIDTH * height * 2);  | 
52  |  |  | 
53  |  |   // ColorMapObject *GifMakeMapObject(int ColorCount, GifColorType *ColorMap)  | 
54  |  |   // Allocate storage for a color map object with the given number of RGB triplet slots.  | 
55  |  |   // If the second argument is non-NULL, initialize the color table portion of  | 
56  |  |   // the new map from it. Returns NULL if memory is exhausted or if the size is  | 
57  |  |   // not a power of 2 <= 256.  | 
58  |  |   // TODO: Fuzz color map size (has to be a power of 2 less than equal to 256)  | 
59  |  |   // TODO: Fuzz color table initialization  | 
60  | 348  |   int color_map_size = 256;  | 
61  | 348  |   ColorMapObject *output_color_map = GifMakeMapObject(color_map_size, NULL);  | 
62  | 348  |   if (!output_color_map)  | 
63  | 0  |   { | 
64  | 0  |     free(mem);  | 
65  | 0  |     return false;  | 
66  | 0  |   }  | 
67  |  |  | 
68  |  |   // gif output will be written to output_buf  | 
69  | 348  |   size_t out_size = sizeof(GifByteType) * GIF_IMAGE_WIDTH * height;  | 
70  | 348  |   GifByteType *output_buf = (GifByteType *)malloc(out_size);  | 
71  | 348  |   if (!output_buf)  | 
72  | 0  |   { | 
73  | 0  |     GifFreeMapObject(output_color_map);  | 
74  | 0  |     free(mem);  | 
75  | 0  |     return false;  | 
76  | 0  |   }  | 
77  |  |  | 
78  | 348  |   if (GifQuantizeBuffer(GIF_IMAGE_WIDTH, height, &color_map_size,  | 
79  | 348  |               red_buf, green_buf, blue_buf,  | 
80  | 348  |               output_buf, output_color_map->Colors) == GIF_ERROR)  | 
81  | 0  |   { | 
82  | 0  |     GifFreeMapObject(output_color_map);  | 
83  | 0  |     free(output_buf);  | 
84  | 0  |     free(mem);  | 
85  | 0  |     return false;  | 
86  | 0  |   }  | 
87  |  |  | 
88  |  |   // Now that raw RGB data has been quantized, we no longer need it.  | 
89  | 348  |   free(mem);  | 
90  |  |  | 
91  | 348  |   GifFileType *GifFile;  | 
92  | 348  |   int Error;  | 
93  |  |   // We start with 1024, but resize dynamically  | 
94  |  |   // see stub_output_writer  | 
95  | 348  |   uint8_t *gifData = (uint8_t *)malloc(1024);  | 
96  | 348  |   struct gifUserData gUData = {0, 1024, gifData}; | 
97  |  |  | 
98  |  |   /* GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc, int *ErrorCode)  | 
99  |  |    * Description:  | 
100  |  |    *  Open a new GIF file using the given userPtr (in binary mode, if under Windows).  | 
101  |  |    *  writeFunc is a function pointer that writes to output gif file.  | 
102  |  |    *  If any error occurs, NULL is returned and the ErrorCode is set.  | 
103  |  |    */  | 
104  | 348  |   GifFile = EGifOpen((void *)&gUData, stub_output_writer, &Error);  | 
105  | 348  |   if (GifFile == NULL)  | 
106  | 0  |   { | 
107  | 0  |     PrintGifError(GifFile->Error);  | 
108  | 0  |     GifFreeMapObject(output_color_map);  | 
109  | 0  |     free(output_buf);  | 
110  | 0  |     free(gUData.gifData);  | 
111  | 0  |     return false;  | 
112  | 0  |   }  | 
113  |  |  | 
114  |  |   /* void EGifSetGifVersion(GifFileType *GifFile, bool gif89)  | 
115  |  |    * Description:  | 
116  |  |    *  Set the GIF type, to GIF89 if the argument is true and GIF87 if it is false.  | 
117  |  |    *  The default type is GIF87. This function may be called after the GifFile  | 
118  |  |    *  record is allocated but before EGifPutScreenDesc().  | 
119  |  |    */  | 
120  | 348  |   EGifSetGifVersion(GifFile, false);  | 
121  |  |  | 
122  |  |   /* int EGifPutScreenDesc(GifFileType *GifFile,  | 
123  |  |      *   const int GifWidth, const GifHeight,  | 
124  |  |      *   const int GifColorRes, const int GifBackGround,  | 
125  |  |      *   ColorMapObject *GifColorMap)  | 
126  |  |      *  | 
127  |  |    *  Update the GifFile Screen parameters, in GifFile structure and in the real file.  | 
128  |  |    *  If error occurs, returns GIF_ERROR (see gif_lib.h), otherwise GIF_OK.  | 
129  |  |    *  This routine should be called immediately after the GIF file was opened.  | 
130  |  |    */  | 
131  | 348  |   if (EGifPutScreenDesc(GifFile, GIF_IMAGE_WIDTH, height, color_map_size, 0, output_color_map) == GIF_ERROR)  | 
132  | 0  |   { | 
133  | 0  |     PrintGifError(GifFile->Error);  | 
134  | 0  |     GifFreeMapObject(output_color_map);  | 
135  | 0  |     free(output_buf);  | 
136  | 0  |     EGifCloseFile(GifFile, &Error);  | 
137  | 0  |     free(gUData.gifData);  | 
138  | 0  |     return false;  | 
139  | 0  |   }  | 
140  |  |  | 
141  |  |   /* int EGifPutImageDesc(GifFileType *GifFile, const int GifLeft, const int GifTop,  | 
142  |  |    * const int GifWidth, const GifHeight, const bool GifInterlace, ColorMapObject *GifColorMap)  | 
143  |  |    * Description  | 
144  |  |    *  Update GifFile Image parameters, in GifFile structure and in the real file.  | 
145  |  |    *  if error occurs returns GIF_ERROR (see gif_lib.h), otherwise GIF_OK.  | 
146  |  |    *  This routine should be called each time a new image must be dumped to the file.  | 
147  |  |    */  | 
148  | 348  |   if (EGifPutImageDesc(GifFile, 0, 0, GIF_IMAGE_WIDTH, height, false, NULL) == GIF_ERROR)  | 
149  | 0  |   { | 
150  | 0  |     PrintGifError(GifFile->Error);  | 
151  | 0  |     GifFreeMapObject(output_color_map);  | 
152  | 0  |     free(output_buf);  | 
153  | 0  |     EGifCloseFile(GifFile, &Error);  | 
154  | 0  |     free(gUData.gifData);  | 
155  | 0  |     return false;  | 
156  | 0  |   }  | 
157  |  |  | 
158  | 348  |   GifByteType *output_bufp = output_buf;  | 
159  | 75.2k  |   for (int i = 0; i < height; i++)  | 
160  | 74.8k  |   { | 
161  |  |     /* int EGifPutLine(GifFileType *GifFile, PixelType *GifLine, int GifLineLen)  | 
162  |  |      * Description:  | 
163  |  |      *  Dumps a block of pixels out to the GIF file. The slab can be of any length.  | 
164  |  |      *  More than that, this routine may be interleaved with EGifPutPixel(),  | 
165  |  |      *  until all pixels have been sent.  | 
166  |  |      *  Returns GIF_ERROR if something went wrong, GIF_OK otherwise.  | 
167  |  |      */  | 
168  | 74.8k  |     if (EGifPutLine(GifFile, output_bufp, GIF_IMAGE_WIDTH) == GIF_ERROR)  | 
169  | 0  |     { | 
170  | 0  |       PrintGifError(GifFile->Error);  | 
171  | 0  |       GifFreeMapObject(output_color_map);  | 
172  | 0  |       free(output_buf);  | 
173  | 0  |       EGifCloseFile(GifFile, &Error);  | 
174  | 0  |       free(gUData.gifData);  | 
175  | 0  |       return false;  | 
176  | 0  |     }  | 
177  | 74.8k  |     output_bufp += GIF_IMAGE_WIDTH;  | 
178  | 74.8k  |   }  | 
179  |  |  | 
180  |  |   /* void GifFreeMapObject(ColorMapObject *Object)  | 
181  |  |    * Description  | 
182  |  |    *  Free the storage occupied by a ColorMapObject that is no longer needed.  | 
183  |  |    */  | 
184  | 348  |   GifFreeMapObject(output_color_map);  | 
185  | 348  |   free(output_buf);  | 
186  | 348  |   EGifCloseFile(GifFile, &Error);  | 
187  | 348  |   free(gUData.gifData);  | 
188  | 348  |   return true;  | 
189  | 348  | }  | 
190  |  |  | 
191  |  | int fuzz_egif(const uint8_t *Data, size_t Size)  | 
192  | 375  | { | 
193  |  |   // We treat fuzzed data as a raw RGB stream for a picture  | 
194  |  |   // with a fixed width of GIF_IMAGE_WIDTH.  | 
195  |  |   // Since we need 3 color bytes per pixel (RGB), height = size/GIF_IMAGE_LINE  | 
196  |  |   //      where GIF_IMAGE_LINE = GIF_IMAGE_WIDTH * 3  | 
197  |  |   // For integral height, we need Size to be a multiple of GIF_IMAGE_LINE  | 
198  | 375  |   if ((Size == 0) || ((Size % GIF_IMAGE_LINE) != 0))  | 
199  | 27  |     return 0;  | 
200  | 348  |   bool status = rgb_to_gif(Data, Size);  | 
201  | 348  |   return 0;  | 
202  | 375  | }  |