Skip to content

Instantly share code, notes, and snippets.

@moyix
Created March 8, 2024 05:26
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save moyix/02029770cb4f7afc2ae91a01b3929118 to your computer and use it in GitHub Desktop.
Save moyix/02029770cb4f7afc2ae91a01b3929118 to your computer and use it in GitHub Desktop.
Claude 3 writes a fuzzer

gifdec.c and gifdec.h are from this GitHub repository:

https://github.com/lecram/gifdec

gifread.c was written by me (@moyix).

gengif.py written by Claude 3 Opus. The prompt was:

(Attached files: gifread.c, gifdec.c, gifdec.h)

Given this C program, can you write a Python function that generates random gif files that fully exercise the parsing code? The function should have the signature:

# Generates a random file into `out`
def generate_random_input(out: BinaryIO):

Claude's explanation of the Python code:

This function writes random GIF data to the provided binary output stream (out). Here's a breakdown of what the function does:

  1. It generates a GIF header by writing the signature "GIF89a".
  2. It generates a Logical Screen Descriptor with random width, height, and other fields.
  3. It generates a Global Color Table with random colors.
  4. It enters a loop to generate random extensions and image blocks:
  • It randomly selects a block type: Extension Introducer, Image Separator, or Trailer.
  • If it's an Extension Introducer, it randomly selects an extension label (Plain Text, Graphic Control, Comment, or Application) and generates the corresponding extension data.
  • If it's an Image Separator, it generates an Image Descriptor with random fields and optionally a Local Color Table. It then generates random sub-blocks for the image data.
  • If it's a Trailer, it breaks the loop.
  1. The function continues generating extensions and image blocks until a Trailer is encountered.

To use this function, you can create a binary file and pass it as the out parameter:

with open('random.gif', 'wb') as f:
    generate_random_input(f)

This will create a file named "random.gif" with randomly generated GIF data that can be used to test the parsing code in the C program.

Note that the generated GIF files may not always be valid or complete, as they are generated randomly. The purpose is to provide a wide range of inputs to exercise the parsing code and potentially uncover edge cases or issues.

import random
import struct
def generate_random_input(out):
# Generate Header
out.write(b'GIF89a')
# Generate Logical Screen Descriptor
width = random.randint(1, 65535)
height = random.randint(1, 65535)
out.write(struct.pack('<HH', width, height))
packed_field = random.randint(0, 255) | 0x80 # Set Global Color Table flag
out.write(struct.pack('B', packed_field))
out.write(struct.pack('B', random.randint(0, 255))) # Background Color Index
out.write(struct.pack('B', random.randint(0, 255))) # Pixel Aspect Ratio
# Generate Global Color Table
gct_size = 1 << ((packed_field & 0x07) + 1)
for _ in range(gct_size):
r, g, b = random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
out.write(struct.pack('BBB', r, g, b))
# Generate Extensions and Image Blocks
while True:
block_type = random.choice([0x21, 0x2C, 0x3B]) # Extension Introducer, Image Separator, or Trailer
out.write(struct.pack('B', block_type))
if block_type == 0x21: # Extension Introducer
extension_label = random.choice([0x01, 0xF9, 0xFE, 0xFF]) # Plain Text, Graphic Control, Comment, or Application
out.write(struct.pack('B', extension_label))
if extension_label == 0x01: # Plain Text Extension
out.write(struct.pack('B', 12)) # Block Size
out.write(struct.pack('<HHHH', random.randint(0, width), random.randint(0, height),
random.randint(0, width), random.randint(0, height)))
out.write(struct.pack('BB', random.randint(0, 255), random.randint(0, 255)))
out.write(struct.pack('BB', random.randint(0, 255), random.randint(0, 255)))
out.write(struct.pack('B', 0)) # Block Terminator
elif extension_label == 0xF9: # Graphic Control Extension
out.write(struct.pack('B', 4)) # Block Size
packed_gce_field = random.randint(0, 255)
out.write(struct.pack('B', packed_gce_field))
out.write(struct.pack('<H', random.randint(0, 65535))) # Delay Time
out.write(struct.pack('B', random.randint(0, 255))) # Transparent Color Index
out.write(struct.pack('B', 0)) # Block Terminator
elif extension_label == 0xFE: # Comment Extension
out.write(struct.pack('B', random.randint(1, 255)))
out.write(b'\x00') # Block Terminator
elif extension_label == 0xFF: # Application Extension
out.write(struct.pack('B', 11)) # Block Size
out.write(b'NETSCAPE2.0')
out.write(struct.pack('B', 3)) # Block Size
out.write(b'\x01')
out.write(struct.pack('<H', random.randint(0, 65535))) # Loop Count
out.write(b'\x00') # Block Terminator
elif block_type == 0x2C: # Image Descriptor
out.write(struct.pack('<HHHH', random.randint(0, width), random.randint(0, height),
random.randint(1, width), random.randint(1, height)))
packed_idesc_field = random.randint(0, 255)
out.write(struct.pack('B', packed_idesc_field))
if packed_idesc_field & 0x80: # Local Color Table Flag
lct_size = 1 << ((packed_idesc_field & 0x07) + 1)
for _ in range(lct_size):
r, g, b = random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
out.write(struct.pack('BBB', r, g, b))
# Image Data
lzw_min_code_size = random.randint(2, 8)
out.write(struct.pack('B', lzw_min_code_size))
# Generate random sub-blocks
while True:
sub_block_size = random.randint(1, 255)
out.write(struct.pack('B', sub_block_size))
for _ in range(sub_block_size):
out.write(struct.pack('B', random.randint(0, 255)))
if random.random() < 0.1:
break
out.write(b'\x00') # Block Terminator
else: # Trailer
break
import sys
for f in sys.argv[1:]:
with open(f,'wb') as of:
generate_random_input(of)
print(f)
#include "gifdec.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define MAX(A, B) ((A) > (B) ? (A) : (B))
typedef struct Entry {
uint16_t length;
uint16_t prefix;
uint8_t suffix;
} Entry;
typedef struct Table {
int bulk;
int nentries;
Entry *entries;
} Table;
static uint16_t
read_num(int fd)
{
uint8_t bytes[2];
read(fd, bytes, 2);
return bytes[0] + (((uint16_t) bytes[1]) << 8);
}
gd_GIF *
gd_open_gif(const char *fname)
{
int fd;
uint8_t sigver[3];
uint16_t width, height, depth;
uint8_t fdsz, bgidx, aspect;
int i;
uint8_t *bgcolor;
int gct_sz;
gd_GIF *gif;
fd = open(fname, O_RDONLY);
if (fd == -1) return NULL;
#ifdef _WIN32
setmode(fd, O_BINARY);
#endif
/* Header */
read(fd, sigver, 3);
if (memcmp(sigver, "GIF", 3) != 0) {
fprintf(stderr, "invalid signature\n");
goto fail;
}
/* Version */
read(fd, sigver, 3);
if (memcmp(sigver, "89a", 3) != 0) {
fprintf(stderr, "invalid version\n");
goto fail;
}
/* Width x Height */
width = read_num(fd);
height = read_num(fd);
/* FDSZ */
read(fd, &fdsz, 1);
/* Presence of GCT */
if (!(fdsz & 0x80)) {
fprintf(stderr, "no global color table\n");
goto fail;
}
/* Color Space's Depth */
depth = ((fdsz >> 4) & 7) + 1;
/* Ignore Sort Flag. */
/* GCT Size */
gct_sz = 1 << ((fdsz & 0x07) + 1);
/* Background Color Index */
read(fd, &bgidx, 1);
/* Aspect Ratio */
read(fd, &aspect, 1);
/* Create gd_GIF Structure. */
gif = calloc(1, sizeof(*gif));
if (!gif) goto fail;
gif->fd = fd;
gif->width = width;
gif->height = height;
gif->depth = depth;
/* Read GCT */
gif->gct.size = gct_sz;
read(fd, gif->gct.colors, 3 * gif->gct.size);
gif->palette = &gif->gct;
gif->bgindex = bgidx;
gif->frame = calloc(4, width * height);
if (!gif->frame) {
free(gif);
goto fail;
}
gif->canvas = &gif->frame[width * height];
if (gif->bgindex)
memset(gif->frame, gif->bgindex, gif->width * gif->height);
bgcolor = &gif->palette->colors[gif->bgindex*3];
if (bgcolor[0] || bgcolor[1] || bgcolor [2])
for (i = 0; i < gif->width * gif->height; i++)
memcpy(&gif->canvas[i*3], bgcolor, 3);
gif->anim_start = lseek(fd, 0, SEEK_CUR);
goto ok;
fail:
close(fd);
return 0;
ok:
return gif;
}
static void
discard_sub_blocks(gd_GIF *gif)
{
uint8_t size;
do {
read(gif->fd, &size, 1);
lseek(gif->fd, size, SEEK_CUR);
} while (size);
}
static void
read_plain_text_ext(gd_GIF *gif)
{
if (gif->plain_text) {
uint16_t tx, ty, tw, th;
uint8_t cw, ch, fg, bg;
off_t sub_block;
lseek(gif->fd, 1, SEEK_CUR); /* block size = 12 */
tx = read_num(gif->fd);
ty = read_num(gif->fd);
tw = read_num(gif->fd);
th = read_num(gif->fd);
read(gif->fd, &cw, 1);
read(gif->fd, &ch, 1);
read(gif->fd, &fg, 1);
read(gif->fd, &bg, 1);
sub_block = lseek(gif->fd, 0, SEEK_CUR);
gif->plain_text(gif, tx, ty, tw, th, cw, ch, fg, bg);
lseek(gif->fd, sub_block, SEEK_SET);
} else {
/* Discard plain text metadata. */
lseek(gif->fd, 13, SEEK_CUR);
}
/* Discard plain text sub-blocks. */
discard_sub_blocks(gif);
}
static void
read_graphic_control_ext(gd_GIF *gif)
{
uint8_t rdit;
/* Discard block size (always 0x04). */
lseek(gif->fd, 1, SEEK_CUR);
read(gif->fd, &rdit, 1);
gif->gce.disposal = (rdit >> 2) & 3;
gif->gce.input = rdit & 2;
gif->gce.transparency = rdit & 1;
gif->gce.delay = read_num(gif->fd);
read(gif->fd, &gif->gce.tindex, 1);
/* Skip block terminator. */
lseek(gif->fd, 1, SEEK_CUR);
}
static void
read_comment_ext(gd_GIF *gif)
{
if (gif->comment) {
off_t sub_block = lseek(gif->fd, 0, SEEK_CUR);
gif->comment(gif);
lseek(gif->fd, sub_block, SEEK_SET);
}
/* Discard comment sub-blocks. */
discard_sub_blocks(gif);
}
static void
read_application_ext(gd_GIF *gif)
{
char app_id[8];
char app_auth_code[3];
/* Discard block size (always 0x0B). */
lseek(gif->fd, 1, SEEK_CUR);
/* Application Identifier. */
read(gif->fd, app_id, 8);
/* Application Authentication Code. */
read(gif->fd, app_auth_code, 3);
if (!strncmp(app_id, "NETSCAPE", sizeof(app_id))) {
/* Discard block size (0x03) and constant byte (0x01). */
lseek(gif->fd, 2, SEEK_CUR);
gif->loop_count = read_num(gif->fd);
/* Skip block terminator. */
lseek(gif->fd, 1, SEEK_CUR);
} else if (gif->application) {
off_t sub_block = lseek(gif->fd, 0, SEEK_CUR);
gif->application(gif, app_id, app_auth_code);
lseek(gif->fd, sub_block, SEEK_SET);
discard_sub_blocks(gif);
} else {
discard_sub_blocks(gif);
}
}
static void
read_ext(gd_GIF *gif)
{
uint8_t label;
read(gif->fd, &label, 1);
switch (label) {
case 0x01:
read_plain_text_ext(gif);
break;
case 0xF9:
read_graphic_control_ext(gif);
break;
case 0xFE:
read_comment_ext(gif);
break;
case 0xFF:
read_application_ext(gif);
break;
default:
fprintf(stderr, "unknown extension: %02X\n", label);
}
}
static Table *
new_table(int key_size)
{
int key;
int init_bulk = MAX(1 << (key_size + 1), 0x100);
Table *table = malloc(sizeof(*table) + sizeof(Entry) * init_bulk);
if (table) {
table->bulk = init_bulk;
table->nentries = (1 << key_size) + 2;
table->entries = (Entry *) &table[1];
for (key = 0; key < (1 << key_size); key++)
table->entries[key] = (Entry) {1, 0xFFF, key};
}
return table;
}
/* Add table entry. Return value:
* 0 on success
* +1 if key size must be incremented after this addition
* -1 if could not realloc table */
static int
add_entry(Table **tablep, uint16_t length, uint16_t prefix, uint8_t suffix)
{
Table *table = *tablep;
if (table->nentries == table->bulk) {
table->bulk *= 2;
table = realloc(table, sizeof(*table) + sizeof(Entry) * table->bulk);
if (!table) return -1;
table->entries = (Entry *) &table[1];
*tablep = table;
}
table->entries[table->nentries] = (Entry) {length, prefix, suffix};
table->nentries++;
if ((table->nentries & (table->nentries - 1)) == 0)
return 1;
return 0;
}
static uint16_t
get_key(gd_GIF *gif, int key_size, uint8_t *sub_len, uint8_t *shift, uint8_t *byte)
{
int bits_read;
int rpad;
int frag_size;
uint16_t key;
key = 0;
for (bits_read = 0; bits_read < key_size; bits_read += frag_size) {
rpad = (*shift + bits_read) % 8;
if (rpad == 0) {
/* Update byte. */
if (*sub_len == 0) {
read(gif->fd, sub_len, 1); /* Must be nonzero! */
if (*sub_len == 0)
return 0x1000;
}
read(gif->fd, byte, 1);
(*sub_len)--;
}
frag_size = MIN(key_size - bits_read, 8 - rpad);
key |= ((uint16_t) ((*byte) >> rpad)) << bits_read;
}
/* Clear extra bits to the left. */
key &= (1 << key_size) - 1;
*shift = (*shift + key_size) % 8;
return key;
}
/* Compute output index of y-th input line, in frame of height h. */
static int
interlaced_line_index(int h, int y)
{
int p; /* number of lines in current pass */
p = (h - 1) / 8 + 1;
if (y < p) /* pass 1 */
return y * 8;
y -= p;
p = (h - 5) / 8 + 1;
if (y < p) /* pass 2 */
return y * 8 + 4;
y -= p;
p = (h - 3) / 4 + 1;
if (y < p) /* pass 3 */
return y * 4 + 2;
y -= p;
/* pass 4 */
return y * 2 + 1;
}
/* Decompress image pixels.
* Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
static int
read_image_data(gd_GIF *gif, int interlace)
{
uint8_t sub_len, shift, byte;
int init_key_size, key_size, table_is_full;
int frm_off, frm_size, str_len, i, p, x, y;
uint16_t key, clear, stop;
int ret;
Table *table;
Entry entry;
off_t start, end;
read(gif->fd, &byte, 1);
key_size = (int) byte;
if (key_size < 2 || key_size > 8)
return -1;
start = lseek(gif->fd, 0, SEEK_CUR);
discard_sub_blocks(gif);
end = lseek(gif->fd, 0, SEEK_CUR);
lseek(gif->fd, start, SEEK_SET);
clear = 1 << key_size;
stop = clear + 1;
table = new_table(key_size);
key_size++;
init_key_size = key_size;
sub_len = shift = 0;
key = get_key(gif, key_size, &sub_len, &shift, &byte); /* clear code */
frm_off = 0;
ret = 0;
frm_size = gif->fw*gif->fh;
while (frm_off < frm_size) {
if (key == clear) {
key_size = init_key_size;
table->nentries = (1 << (key_size - 1)) + 2;
table_is_full = 0;
} else if (!table_is_full) {
ret = add_entry(&table, str_len + 1, key, entry.suffix);
if (ret == -1) {
free(table);
return -1;
}
if (table->nentries == 0x1000) {
ret = 0;
table_is_full = 1;
}
}
key = get_key(gif, key_size, &sub_len, &shift, &byte);
if (key == clear) continue;
if (key == stop || key == 0x1000) break;
if (ret == 1) key_size++;
entry = table->entries[key];
str_len = entry.length;
for (i = 0; i < str_len; i++) {
p = frm_off + entry.length - 1;
x = p % gif->fw;
y = p / gif->fw;
if (interlace)
y = interlaced_line_index((int) gif->fh, y);
gif->frame[(gif->fy + y) * gif->width + gif->fx + x] = entry.suffix;
if (entry.prefix == 0xFFF)
break;
else
entry = table->entries[entry.prefix];
}
frm_off += str_len;
if (key < table->nentries - 1 && !table_is_full)
table->entries[table->nentries - 1].suffix = entry.suffix;
}
free(table);
if (key == stop)
read(gif->fd, &sub_len, 1); /* Must be zero! */
lseek(gif->fd, end, SEEK_SET);
return 0;
}
/* Read image.
* Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
static int
read_image(gd_GIF *gif)
{
uint8_t fisrz;
int interlace;
/* Image Descriptor. */
gif->fx = read_num(gif->fd);
gif->fy = read_num(gif->fd);
if (gif->fx >= gif->width || gif->fy >= gif->height)
return -1;
gif->fw = read_num(gif->fd);
gif->fh = read_num(gif->fd);
gif->fw = MIN(gif->fw, gif->width - gif->fx);
gif->fh = MIN(gif->fh, gif->height - gif->fy);
read(gif->fd, &fisrz, 1);
interlace = fisrz & 0x40;
/* Ignore Sort Flag. */
/* Local Color Table? */
if (fisrz & 0x80) {
/* Read LCT */
gif->lct.size = 1 << ((fisrz & 0x07) + 1);
read(gif->fd, gif->lct.colors, 3 * gif->lct.size);
gif->palette = &gif->lct;
} else
gif->palette = &gif->gct;
/* Image Data. */
return read_image_data(gif, interlace);
}
static void
render_frame_rect(gd_GIF *gif, uint8_t *buffer)
{
int i, j, k;
uint8_t index, *color;
i = gif->fy * gif->width + gif->fx;
for (j = 0; j < gif->fh; j++) {
for (k = 0; k < gif->fw; k++) {
index = gif->frame[(gif->fy + j) * gif->width + gif->fx + k];
color = &gif->palette->colors[index*3];
if (!gif->gce.transparency || index != gif->gce.tindex)
memcpy(&buffer[(i+k)*3], color, 3);
}
i += gif->width;
}
}
static void
dispose(gd_GIF *gif)
{
int i, j, k;
uint8_t *bgcolor;
switch (gif->gce.disposal) {
case 2: /* Restore to background color. */
bgcolor = &gif->palette->colors[gif->bgindex*3];
i = gif->fy * gif->width + gif->fx;
for (j = 0; j < gif->fh; j++) {
for (k = 0; k < gif->fw; k++)
memcpy(&gif->canvas[(i+k)*3], bgcolor, 3);
i += gif->width;
}
break;
case 3: /* Restore to previous, i.e., don't update canvas.*/
break;
default:
/* Add frame non-transparent pixels to canvas. */
render_frame_rect(gif, gif->canvas);
}
}
/* Return 1 if got a frame; 0 if got GIF trailer; -1 if error. */
int
gd_get_frame(gd_GIF *gif)
{
char sep;
dispose(gif);
read(gif->fd, &sep, 1);
while (sep != ',') {
if (sep == ';')
return 0;
if (sep == '!')
read_ext(gif);
else return -1;
read(gif->fd, &sep, 1);
}
if (read_image(gif) == -1)
return -1;
return 1;
}
void
gd_render_frame(gd_GIF *gif, uint8_t *buffer)
{
memcpy(buffer, gif->canvas, gif->width * gif->height * 3);
render_frame_rect(gif, buffer);
}
int
gd_is_bgcolor(gd_GIF *gif, uint8_t color[3])
{
return !memcmp(&gif->palette->colors[gif->bgindex*3], color, 3);
}
void
gd_rewind(gd_GIF *gif)
{
lseek(gif->fd, gif->anim_start, SEEK_SET);
}
void
gd_close_gif(gd_GIF *gif)
{
close(gif->fd);
free(gif->frame);
free(gif);
}
#ifndef GIFDEC_H
#define GIFDEC_H
#include <stdint.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct gd_Palette {
int size;
uint8_t colors[0x100 * 3];
} gd_Palette;
typedef struct gd_GCE {
uint16_t delay;
uint8_t tindex;
uint8_t disposal;
int input;
int transparency;
} gd_GCE;
typedef struct gd_GIF {
int fd;
off_t anim_start;
uint16_t width, height;
uint16_t depth;
uint16_t loop_count;
gd_GCE gce;
gd_Palette *palette;
gd_Palette lct, gct;
void (*plain_text)(
struct gd_GIF *gif, uint16_t tx, uint16_t ty,
uint16_t tw, uint16_t th, uint8_t cw, uint8_t ch,
uint8_t fg, uint8_t bg
);
void (*comment)(struct gd_GIF *gif);
void (*application)(struct gd_GIF *gif, char id[8], char auth[3]);
uint16_t fx, fy, fw, fh;
uint8_t bgindex;
uint8_t *canvas, *frame;
} gd_GIF;
gd_GIF *gd_open_gif(const char *fname);
int gd_get_frame(gd_GIF *gif);
void gd_render_frame(gd_GIF *gif, uint8_t *buffer);
int gd_is_bgcolor(gd_GIF *gif, uint8_t color[3]);
void gd_rewind(gd_GIF *gif);
void gd_close_gif(gd_GIF *gif);
#ifdef __cplusplus
}
#endif
#endif /* GIFDEC_H */
/* gifdec example -- simple GIF player using SDL2
* compiling:
* cc `pkg-config --cflags --libs sdl2` -o example gifdec.c example.c
* executing:
* ./example animation.gif
* */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <unistd.h>
#include "gifdec.h"
#ifdef GCOV
void __gcov_dump();
void gc_handler(int signum) {
__gcov_dump();
exit(1);
}
#endif
void handle_plain_text(
struct gd_GIF *gif, uint16_t tx, uint16_t ty,
uint16_t tw, uint16_t th, uint8_t cw, uint8_t ch,
uint8_t fg, uint8_t bg
) {
printf("plain_text_ext tx=%u ty=%u tw=%u th=%u cw=%u ch=%u fg=%u bg=%u\ntext: ",
tx,ty,tw,th,cw,ch,fg,bg);
unsigned char c;
while (read(gif->fd, &c, 1)) {
if (c == 0) break;
write(1,&c,1);
}
printf("\n");
}
void handle_comment(struct gd_GIF *gif) {
printf("comment: ");
unsigned char c;
while (read(gif->fd, &c, 1)) {
if (c == 0) break;
write(1,&c,1);
}
printf("\n");
}
int
main(int argc, char *argv[])
{
gd_GIF *gif;
char title[32] = {0};
uint8_t *color, *frame;
void *addr;
int i, j;
uint32_t pixel;
int ret, paused, quit;
uint32_t t0, t1, delay, delta;
#ifdef GCOV
for (int sig = 1; sig <= SIGRTMAX; ++sig) {
signal(sig, gc_handler);
}
#endif
if (argc != 2) {
fprintf(stderr, "usage:\n %s gif-file\n", argv[0]);
return 1;
}
gif = gd_open_gif(argv[1]);
if (!gif) {
fprintf(stderr, "Could not open %s\n", argv[1]);
return 1;
}
frame = malloc(gif->width * gif->height * 3);
if (!frame) {
fprintf(stderr, "Could not allocate frame\n");
return 1;
}
gif->plain_text = handle_plain_text;
gif->comment = handle_comment;
snprintf(title, sizeof(title) - 1, "GIF %dx%d %d colors",
gif->width, gif->height, gif->palette->size);
color = &gif->gct.colors[gif->bgindex * 3];
int num_bgcolors = 0;
int loopcount = 1;
while (loopcount) {
ret = gd_get_frame(gif);
if (ret == -1)
break;
gd_render_frame(gif, frame);
color = frame;
for (i = 0; i < gif->height; i++) {
for (j = 0; j < gif->width; j++) {
if (!gd_is_bgcolor(gif, color)) {
num_bgcolors++;
}
color += 3;
}
}
if (ret == 0) {
loopcount--;
gd_rewind(gif);
}
}
free(frame);
gd_close_gif(gif);
return 0;
}
all: gifread gifread.asan gifread.ubsan gifread.coverage
gifread: gifdec.c gifread.c gifdec.h
$(CC) $(CFLAGS) -o $@ gifdec.c gifread.c $(LDFLAGS)
gifread.asan: gifdec.c gifread.c gifdec.h
$(CC) $(CFLAGS) -g -fsanitize=address -o $@ gifdec.c gifread.c $(LDFLAGS)
gifread.ubsan: gifdec.c gifread.c gifdec.h
$(CC) $(CFLAGS) -g -fsanitize=undefined -o $@ gifdec.c gifread.c $(LDFLAGS)
gifread.coverage: gifdec.c gifread.c gifdec.h
$(CC) $(CFLAGS) -g --coverage -o $@ gifdec.c gifread.c $(LDFLAGS)
clean:
rm -f gifread gifread.asan gifread.ubsan gifread.coverage *.gcno *.gcda
.PHONY: all clean
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment