Coverage Report

Created: 2025-09-04 07:02

/src/cgif/fuzz/cgif_rgb_fuzzer.c
Line
Count
Source (jump to first uncovered line)
1
#include <cgif.h>
2
3
#include <stddef.h>
4
#include <stdint.h>
5
#include <stdlib.h>
6
#include <string.h>
7
8
typedef struct {
9
  const uint8_t* pData;
10
  size_t         numBytes;
11
  size_t         curPos;
12
} ByteStream;
13
14
75.8k
static int readdata(ByteStream* pStream, void* pDest, size_t size) {
15
75.8k
  if((pStream->curPos + size) <= pStream->numBytes) {
16
23.2k
    memcpy(pDest, &pStream->pData[pStream->curPos], size);
17
23.2k
    pStream->curPos += size;
18
23.2k
    return 0;
19
23.2k
  }
20
  // error: out of bounds
21
52.5k
  pStream->curPos = pStream->numBytes; // mark stream as out of sync
22
52.5k
  return -1;
23
75.8k
}
24
25
1.15k
static int read_gifconfig(ByteStream* pStream, CGIFrgb_Config* pDest) {
26
1.15k
  int r;
27
28
1.15k
  memset(pDest, 0, sizeof(CGIFrgb_Config));
29
  // width     : U16
30
  // height    : U16
31
  // attrFlags : U32
32
  // genFlags  : U32
33
  // numLoops  : U16
34
1.15k
  r  = readdata(pStream, &pDest->width,                   2);
35
1.15k
  r |= readdata(pStream, &pDest->height,                  2);
36
1.15k
  r |= readdata(pStream, &pDest->attrFlags,               4);
37
1.15k
  r |= readdata(pStream, &pDest->genFlags,                4);
38
1.15k
  r |= readdata(pStream, &pDest->numLoops,                2);
39
1.15k
  return (r ? 0 : 1);
40
1.15k
}
41
42
16.8k
static int read_frameconfig(ByteStream* pStream, CGIFrgb_FrameConfig* pDest, size_t sizeImageData) {
43
16.8k
  int r;
44
16.8k
  uint8_t fmtChan = 0;
45
46
16.8k
  memset(pDest, 0, sizeof(CGIFrgb_FrameConfig));
47
  // attrFlags  : U16
48
  // genFlags   : U16
49
  // delay      : U16
50
  // fmtChan    : U8
51
  // pImageData : U8[sizeImageData]
52
16.8k
  r  = readdata(pStream, &pDest->attrFlags,              2);
53
16.8k
  r |= readdata(pStream, &pDest->genFlags,               2);
54
16.8k
  r |= readdata(pStream, &pDest->delay,                  2);
55
16.8k
  r |= readdata(pStream, &fmtChan,                       1);
56
16.8k
  if(fmtChan != CGIF_CHAN_FMT_RGB && fmtChan != CGIF_CHAN_FMT_RGBA) {
57
14.4k
    return -1; // invalid fmtChan
58
14.4k
  }
59
2.44k
  pDest->fmtChan = (cgif_chan_fmt)fmtChan;
60
2.44k
  pDest->pImageData = (uint8_t*)malloc(sizeImageData * pDest->fmtChan);
61
2.44k
  if(pDest->pImageData == NULL) return 0; // malloc failed
62
2.44k
  r |= readdata(pStream, pDest->pImageData, sizeImageData * pDest->fmtChan);
63
2.44k
  if(r) {
64
69
    free(pDest->pImageData);
65
69
  }
66
2.44k
  return (r ? 0 : 1);
67
2.44k
}
68
69
58.5k
static int writecb(void* pContext, const uint8_t* pData, size_t size) {
70
58.5k
  (void)pContext;
71
58.5k
  (void)pData;
72
58.5k
  (void)size;
73
  // eat input
74
58.5k
  return 0;
75
58.5k
}
76
77
1.15k
static int processInput(ByteStream* pStream) {
78
1.15k
  CGIFrgb_Config      gconfig;
79
1.15k
  CGIFrgb_FrameConfig fconfig;
80
1.15k
  CGIFrgb*            pGIF;
81
1.15k
  size_t              sizeImageData;
82
1.15k
  int                 r;
83
1.15k
  int                 numFrames;
84
85
1.15k
  r = read_gifconfig(pStream, &gconfig);
86
1.15k
  if(!r) {
87
12
    return -1;
88
12
  }
89
1.14k
  sizeImageData = (uint32_t)gconfig.width * (uint32_t)gconfig.height;
90
  // limit dimensions of GIF to be created
91
1.14k
  if(sizeImageData > (100 * 100)) {
92
24
    return -1;
93
24
  }
94
1.12k
  gconfig.pWriteFn = writecb; // discard output
95
1.12k
  pGIF             = cgif_rgb_newgif(&gconfig);
96
1.12k
  if(pGIF == NULL) {
97
14
    return -1;
98
14
  }
99
1.10k
  r = read_frameconfig(pStream, &fconfig, sizeImageData);
100
1.10k
  numFrames = 1;
101
16.8k
  while(r) {
102
16.8k
    cgif_rgb_addframe(pGIF, &fconfig);
103
16.8k
    free(fconfig.pImageData);
104
16.8k
    if(numFrames >= 16) {
105
      // limit number of frames to avoid timeouts: 16 should be more than enough
106
1.03k
      break;
107
1.03k
    }
108
15.7k
    numFrames++;
109
15.7k
    r = read_frameconfig(pStream, &fconfig, sizeImageData);
110
15.7k
  }
111
1.10k
  r = cgif_rgb_close(pGIF);
112
1.10k
  return r;
113
1.12k
}
114
115
#ifdef __cplusplus
116
extern "C"
117
#endif
118
5.00k
int LLVMFuzzerTestOneInput(const uint8_t* pData, size_t numBytes) {
119
5.00k
  ByteStream input = { pData, numBytes, 0 };
120
5.00k
  processInput(&input);
121
5.00k
  return 0;
122
5.00k
}