Line | Count | Source (jump to first uncovered line) |
1 | | #include "egif_fuzz_common.h" |
2 | 151k | #define GIF_IMAGE_WIDTH 100 |
3 | | // This is rgb byte stream length per horizontal line = GIF_IMAGE_WIDTH * 3 |
4 | 728 | #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 | 117k | { |
10 | 117k | struct gifUserData *gud = (struct gifUserData *)gifFileType->UserData; |
11 | | |
12 | 117k | if (gud == NULL || gud->gifData == NULL || len == 0) |
13 | 0 | return 0; |
14 | 117k | if (gud->allocatedSize < (gud->gifLen + len)) |
15 | 705 | { |
16 | | // Reallocate gifFileType |
17 | 705 | int newSize = (gud->gifLen + len) * 2; |
18 | 705 | uint8_t *oldGud = gud->gifData; |
19 | 705 | gud->gifData = (uint8_t *)realloc(oldGud, newSize); |
20 | | // Assert when realloc fails. |
21 | 705 | assert(gud->gifData != NULL); |
22 | 705 | gud->allocatedSize = newSize; |
23 | 705 | } |
24 | 117k | memcpy(gud->gifData + gud->gifLen, buf, len); |
25 | 117k | gud->gifLen += len; |
26 | 117k | return len; |
27 | 117k | } |
28 | | |
29 | | // RGB to GIF converter |
30 | | static bool rgb_to_gif(const uint8_t *data, size_t size) |
31 | 350 | { |
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 | 350 | 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 | 350 | GifByteType *mem = (GifByteType *)malloc(sizeof(GifByteType) * height * GIF_IMAGE_WIDTH * 3); |
43 | 350 | if (!mem) |
44 | 0 | return false; |
45 | | |
46 | | // Copy RGB data to mem |
47 | 350 | memcpy(mem, data, size); |
48 | | |
49 | 350 | GifByteType *red_buf = mem; |
50 | 350 | GifByteType *green_buf = mem + (GIF_IMAGE_WIDTH * height); |
51 | 350 | 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 | 350 | int color_map_size = 256; |
61 | 350 | ColorMapObject *output_color_map = GifMakeMapObject(color_map_size, NULL); |
62 | 350 | 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 | 350 | size_t out_size = sizeof(GifByteType) * GIF_IMAGE_WIDTH * height; |
70 | 350 | GifByteType *output_buf = (GifByteType *)malloc(out_size); |
71 | 350 | if (!output_buf) |
72 | 0 | { |
73 | 0 | GifFreeMapObject(output_color_map); |
74 | 0 | free(mem); |
75 | 0 | return false; |
76 | 0 | } |
77 | | |
78 | 350 | if (GifQuantizeBuffer(GIF_IMAGE_WIDTH, height, &color_map_size, |
79 | 350 | red_buf, green_buf, blue_buf, |
80 | 350 | 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 | 350 | free(mem); |
90 | | |
91 | 350 | GifFileType *GifFile; |
92 | 350 | int Error; |
93 | | // We start with 1024, but resize dynamically |
94 | | // see stub_output_writer |
95 | 350 | uint8_t *gifData = (uint8_t *)malloc(1024); |
96 | 350 | 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 | 350 | GifFile = EGifOpen((void *)&gUData, stub_output_writer, &Error); |
105 | 350 | 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 | 350 | 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 | 350 | 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 | 350 | 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 | 350 | GifByteType *output_bufp = output_buf; |
159 | 74.7k | for (int i = 0; i < height; i++) |
160 | 74.4k | { |
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.4k | 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.4k | output_bufp += GIF_IMAGE_WIDTH; |
178 | 74.4k | } |
179 | | |
180 | | /* void GifFreeMapObject(ColorMapObject *Object) |
181 | | * Description |
182 | | * Free the storage occupied by a ColorMapObject that is no longer needed. |
183 | | */ |
184 | 350 | GifFreeMapObject(output_color_map); |
185 | 350 | free(output_buf); |
186 | 350 | EGifCloseFile(GifFile, &Error); |
187 | 350 | free(gUData.gifData); |
188 | 350 | return true; |
189 | 350 | } |
190 | | |
191 | | int fuzz_egif(const uint8_t *Data, size_t Size) |
192 | 378 | { |
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 | 378 | if ((Size == 0) || ((Size % GIF_IMAGE_LINE) != 0)) |
199 | 28 | return 0; |
200 | 350 | bool status = rgb_to_gif(Data, Size); |
201 | 350 | return 0; |
202 | 378 | } |