Coverage Report

Created: 2026-02-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cgif/fuzz/cgif_rgb_fuzzer.c
Line
Count
Source
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
76.0k
static int readdata(ByteStream* pStream, void* pDest, size_t size) {
15
76.0k
  if((pStream->curPos + size) <= pStream->numBytes) {
16
22.9k
    memcpy(pDest, &pStream->pData[pStream->curPos], size);
17
22.9k
    pStream->curPos += size;
18
22.9k
    return 0;
19
22.9k
  }
20
  // error: out of bounds
21
53.1k
  pStream->curPos = pStream->numBytes; // mark stream as out of sync
22
53.1k
  return -1;
23
76.0k
}
24
25
1.16k
static int read_gifconfig(ByteStream* pStream, CGIFrgb_Config* pDest) {
26
1.16k
  int r;
27
28
1.16k
  memset(pDest, 0, sizeof(CGIFrgb_Config));
29
  // width     : U16
30
  // height    : U16
31
  // attrFlags : U32
32
  // genFlags  : U32
33
  // numLoops  : U16
34
1.16k
  r  = readdata(pStream, &pDest->width,                   2);
35
1.16k
  r |= readdata(pStream, &pDest->height,                  2);
36
1.16k
  r |= readdata(pStream, &pDest->attrFlags,               4);
37
1.16k
  r |= readdata(pStream, &pDest->genFlags,                4);
38
1.16k
  r |= readdata(pStream, &pDest->numLoops,                2);
39
1.16k
  return (r ? 0 : 1);
40
1.16k
}
41
42
16.9k
static int read_frameconfig(ByteStream* pStream, CGIFrgb_FrameConfig* pDest, size_t sizeImageData) {
43
16.9k
  int r;
44
16.9k
  uint8_t fmtChan = 0;
45
46
16.9k
  memset(pDest, 0, sizeof(CGIFrgb_FrameConfig));
47
  // attrFlags  : U16
48
  // genFlags   : U16
49
  // delay      : U16
50
  // fmtChan    : U8
51
  // pImageData : U8[sizeImageData]
52
16.9k
  r  = readdata(pStream, &pDest->attrFlags,              2);
53
16.9k
  r |= readdata(pStream, &pDest->genFlags,               2);
54
16.9k
  r |= readdata(pStream, &pDest->delay,                  2);
55
16.9k
  r |= readdata(pStream, &fmtChan,                       1);
56
16.9k
  if(fmtChan != CGIF_CHAN_FMT_RGB && fmtChan != CGIF_CHAN_FMT_RGBA) {
57
14.4k
    return -1; // invalid fmtChan
58
14.4k
  }
59
2.51k
  pDest->fmtChan = (cgif_chan_fmt)fmtChan;
60
2.51k
  pDest->pImageData = (uint8_t*)malloc(sizeImageData * pDest->fmtChan);
61
2.51k
  if(pDest->pImageData == NULL) return 0; // malloc failed
62
2.51k
  r |= readdata(pStream, pDest->pImageData, sizeImageData * pDest->fmtChan);
63
2.51k
  if(r) {
64
69
    free(pDest->pImageData);
65
69
  }
66
2.51k
  return (r ? 0 : 1);
67
2.51k
}
68
69
62.0k
static int writecb(void* pContext, const uint8_t* pData, size_t size) {
70
62.0k
  (void)pContext;
71
62.0k
  (void)pData;
72
62.0k
  (void)size;
73
  // eat input
74
62.0k
  return 0;
75
62.0k
}
76
77
1.16k
static int processInput(ByteStream* pStream) {
78
1.16k
  CGIFrgb_Config      gconfig;
79
1.16k
  CGIFrgb_FrameConfig fconfig;
80
1.16k
  CGIFrgb*            pGIF;
81
1.16k
  size_t              sizeImageData;
82
1.16k
  int                 r;
83
1.16k
  int                 numFrames;
84
85
1.16k
  r = read_gifconfig(pStream, &gconfig);
86
1.16k
  if(!r) {
87
12
    return -1;
88
12
  }
89
1.15k
  sizeImageData = (uint32_t)gconfig.width * (uint32_t)gconfig.height;
90
  // limit dimensions of GIF to be created
91
1.15k
  if(sizeImageData > (100 * 100)) {
92
23
    return -1;
93
23
  }
94
1.12k
  gconfig.pWriteFn = writecb; // discard output
95
1.12k
  pGIF             = cgif_rgb_newgif(&gconfig);
96
1.12k
  if(pGIF == NULL) {
97
18
    return -1;
98
18
  }
99
1.11k
  r = read_frameconfig(pStream, &fconfig, sizeImageData);
100
1.11k
  numFrames = 1;
101
16.9k
  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.04k
      break;
107
1.04k
    }
108
15.8k
    numFrames++;
109
15.8k
    r = read_frameconfig(pStream, &fconfig, sizeImageData);
110
15.8k
  }
111
1.11k
  r = cgif_rgb_close(pGIF);
112
1.11k
  return r;
113
1.12k
}
114
115
#ifdef __cplusplus
116
extern "C"
117
#endif
118
5.15k
int LLVMFuzzerTestOneInput(const uint8_t* pData, size_t numBytes) {
119
5.15k
  ByteStream input = { pData, numBytes, 0 };
120
5.15k
  processInput(&input);
121
5.15k
  return 0;
122
5.15k
}