Bug Summary

File:samples/clock/gifenc.c
Warning:line 222, column 18
Access to field 'key' results in a dereference of a null pointer (loaded from variable 'node')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name gifenc.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -pic-is-pie -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -fno-plt -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/clang/9.0.1 -include /home/buildbot/lwan-worker/clang-analyze/build/lwan-build-config.h -D _FILE_OFFSET_BITS=64 -D _TIME_BITS=64 -I /home/buildbot/lwan-worker/clang-analyze/build/src/lib/missing -I /usr/include/luajit-2.0 -I /usr/include/valgrind -I /home/buildbot/lwan-worker/clang-analyze/build/src/lib -internal-isystem /usr/local/include -internal-isystem /usr/lib/clang/9.0.1/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -Wno-free-nonheap-object -std=gnu99 -fdebug-compilation-dir /home/buildbot/lwan-worker/clang-analyze/build/src/samples/clock -ferror-limit 19 -fmessage-length 0 -stack-protector 2 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -faddrsig -o /home/buildbot/lwan-worker/clang-analyze/CLANG/2020-04-15-025140-3801729-1 -x c /home/buildbot/lwan-worker/clang-analyze/build/src/samples/clock/gifenc.c
1/*
2 * All of the source code and documentation for gifenc is released into the
3 * public domain and provided without warranty of any kind.
4 *
5 * Author: Marcel Rodrigues <https://github.com/lecram>
6 */
7#include "gifenc.h"
8
9#include <fcntl.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <sys/stat.h>
14#include <sys/types.h>
15#include <unistd.h>
16
17static uint8_t vga[0x30] = {
18 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0x55, 0x00,
19 0x00, 0x00, 0xAA, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
20 0x55, 0x55, 0x55, 0xFF, 0x55, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0xFF, 0x55,
21 0x55, 0x55, 0xFF, 0xFF, 0x55, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
22};
23
24#pragma GCC diagnostic ignored "-Wconversion"
25#pragma GCC diagnostic ignored "-Wsign-conversion"
26#pragma GCC diagnostic ignored "-Wpointer-sign"
27
28struct Node {
29 uint16_t key;
30 struct Node *children[];
31};
32typedef struct Node Node;
33
34static Node *new_node(uint16_t key, int degree)
35{
36 Node *node = calloc(1, sizeof(*node) + degree * sizeof(Node *));
37 if (node)
38 node->key = key;
39 return node;
40}
41
42static Node *new_trie(int degree, int *nkeys)
43{
44 Node *root = new_node(0, degree);
45 /* Create nodes for single pixels. */
46 for (*nkeys = 0; *nkeys < degree; (*nkeys)++)
47 root->children[*nkeys] = new_node(*nkeys, degree);
48 *nkeys += 2; /* skip clear code and stop code */
49 return root;
50}
51
52static void del_trie(Node *root, int degree)
53{
54 if (!root)
55 return;
56 for (int i = 0; i < degree; i++)
57 del_trie(root->children[i], degree);
58 free(root);
59}
60
61static void put_loop(ge_GIF *gif, uint16_t loop);
62
63static void write_num(struct lwan_strbuf *buf, int16_t num)
64{
65 lwan_strbuf_append_char(buf, num & 0xff);
66 lwan_strbuf_append_char(buf, num >> 8);
67}
68
69ge_GIF *ge_new_gif(struct lwan_strbuf *buf,
70 uint16_t width,
71 uint16_t height,
72 uint8_t *palette,
73 int depth,
74 int loop)
75{
76 int i, r, g, b, v;
77 ge_GIF *gif = calloc(1, sizeof(*gif) + 2 * width * height);
78
79 if (!gif)
80 goto no_gif;
81
82 gif->w = width;
83 gif->h = height;
84 gif->depth = depth > 1 ? depth : 2;
85 gif->frame = (uint8_t *)&gif[1];
86 gif->back = &gif->frame[width * height];
87 gif->buf = buf;
88
89 lwan_strbuf_append_str(buf, "GIF89a", 6);
90 write_num(buf, width);
91 write_num(buf, height);
92 lwan_strbuf_append_str(buf, (const char[]){0xF0 | (depth - 1), 0x00, 0x00},
93 3);
94
95 if (palette) {
96 lwan_strbuf_append_str(buf, palette, 3 << depth);
97 } else if (depth <= 4) {
98 lwan_strbuf_append_str(buf, vga, 3 << depth);
99 } else {
100 lwan_strbuf_append_str(buf, vga, sizeof(vga));
101
102 i = 0x10;
103 for (r = 0; r < 6; r++) {
104 for (g = 0; g < 6; g++) {
105 for (b = 0; b < 6; b++) {
106 lwan_strbuf_append_str(
107 buf, (const char[]){r * 51, g * 51, b * 51}, 3);
108 if (++i == 1 << depth)
109 goto done_gct;
110 }
111 }
112 }
113 for (i = 1; i <= 24; i++) {
114 v = i * 0xFF / 25;
115 lwan_strbuf_append_str(buf, (const char[]){v, v, v}, 3);
116 }
117 }
118
119done_gct:
120 if (loop >= 0 && loop <= 0xFFFF)
121 put_loop(gif, (uint16_t)loop);
122 return gif;
123
124no_gif:
125 return NULL((void*)0);
126}
127
128static void put_loop(ge_GIF *gif, uint16_t loop)
129{
130 lwan_strbuf_append_str(gif->buf, (const char[]){'!', 0xFF, 0x0B}, 3);
131 lwan_strbuf_append_str(gif->buf, "NETSCAPE2.0", 11);
132 lwan_strbuf_append_str(gif->buf, (const char[]){0x03, 0x01}, 2);
133 write_num(gif->buf, loop);
134 lwan_strbuf_append_char(gif->buf, '\0');
135}
136
137/* Add packed key to buffer, updating offset and partial.
138 * gif->offset holds position to put next *bit*
139 * gif->partial holds bits to include in next byte */
140static void put_key(ge_GIF *gif, uint16_t key, int key_size)
141{
142 int byte_offset, bit_offset, bits_to_write;
143
144 byte_offset = gif->offset / 8;
145 bit_offset = gif->offset % 8;
146 gif->partial |= ((uint32_t)key) << bit_offset;
147 bits_to_write = bit_offset + key_size;
148
149 while (bits_to_write >= 8) {
150 gif->buffer[byte_offset++] = gif->partial & 0xFF;
151
152 if (byte_offset == 0xFF) {
153 lwan_strbuf_append_char(gif->buf, 0xff);
154 lwan_strbuf_append_str(gif->buf, gif->buffer, 0xff);
155
156 byte_offset = 0;
157 }
158
159 gif->partial >>= 8;
160 bits_to_write -= 8;
161 }
162 gif->offset = (gif->offset + key_size) % (0xFF * 8);
163}
164
165static void end_key(ge_GIF *gif)
166{
167 int byte_offset;
168
169 byte_offset = gif->offset / 8;
170 if (gif->offset % 8)
171 gif->buffer[byte_offset++] = gif->partial & 0xFF;
172
173 lwan_strbuf_append_char(gif->buf, byte_offset);
174 lwan_strbuf_append_str(gif->buf, gif->buffer, byte_offset);
175 lwan_strbuf_append_char(gif->buf, '\0');
176
177 gif->offset = gif->partial = 0;
178}
179
180static void
181put_image(ge_GIF *gif, uint16_t w, uint16_t h, uint16_t x, uint16_t y)
182{
183 int nkeys, key_size, i, j;
184 Node *node, *child, *root;
185 int degree = 1 << gif->depth;
186
187 lwan_strbuf_append_char(gif->buf, ',');
188 write_num(gif->buf, x);
189 write_num(gif->buf, y);
190 write_num(gif->buf, w);
191 write_num(gif->buf, h);
192 lwan_strbuf_append_str(gif->buf, (const char[]){0x00, gif->depth}, 2);
193
194 root = node = new_trie(degree, &nkeys);
195 key_size = gif->depth + 1;
196 put_key(gif, degree, key_size); /* clear code */
197
198 for (i = y; i < y + h; i++) {
6
Assuming the condition is true
7
Loop condition is true. Entering loop body
17
Assuming the condition is false
18
Loop condition is false. Execution continues on line 222
199 for (j = x; j < x + w; j++) {
8
Assuming the condition is true
9
Loop condition is true. Entering loop body
15
Assuming the condition is false
16
Loop condition is false. Execution continues on line 198
200 uint8_t pixel = gif->frame[i * gif->w + j] & (degree - 1);
201 child = node->children[pixel];
202
203 if (
9.1
'child' is null
child) {
10
Taking false branch
204 node = child;
205 } else {
206 put_key(gif, node->key, key_size);
207 if (nkeys <
10.1
'nkeys' is < 4096
0x1000) {
11
Taking true branch
208 if (nkeys == (1 << key_size))
12
Assuming the condition is false
13
Taking false branch
209 key_size++;
210 node->children[pixel] = new_node(nkeys++, degree);
211 } else {
212 put_key(gif, degree, key_size); /* clear code */
213 del_trie(root, degree);
214 root = node = new_trie(degree, &nkeys);
215 key_size = gif->depth + 1;
216 }
217 node = root->children[pixel];
14
Null pointer value stored to 'node'
218 }
219 }
220 }
221
222 put_key(gif, node->key, key_size);
19
Access to field 'key' results in a dereference of a null pointer (loaded from variable 'node')
223 put_key(gif, degree + 1, key_size); /* stop code */
224 end_key(gif);
225 del_trie(root, degree);
226}
227
228static int
229get_bbox(ge_GIF *gif, uint16_t *w, uint16_t *h, uint16_t *x, uint16_t *y)
230{
231 int i, j, k;
232 int left, right, top, bottom;
233
234 left = gif->w;
235 right = 0;
236 top = gif->h;
237 bottom = 0;
238 k = 0;
239 for (i = 0; i < gif->h; i++) {
240 for (j = 0; j < gif->w; j++, k++) {
241 if (gif->frame[k] != gif->back[k]) {
242 if (j < left)
243 left = j;
244 if (j > right)
245 right = j;
246 if (i < top)
247 top = i;
248 if (i > bottom)
249 bottom = i;
250 }
251 }
252 }
253
254 if (left != gif->w && top != gif->h) {
255 *x = left;
256 *y = top;
257 *w = right - left + 1;
258 *h = bottom - top + 1;
259 return 1;
260 } else {
261 return 0;
262 }
263}
264
265static void set_delay(ge_GIF *gif, uint16_t d)
266{
267 lwan_strbuf_append_str(gif->buf, (const char[]){'!', 0xF9, 0x04, 0x04}, 4);
268 write_num(gif->buf, d);
269 lwan_strbuf_append_str(gif->buf, "\0\0", 2);
270}
271
272void ge_add_frame(ge_GIF *gif, uint16_t delay)
273{
274 uint16_t w, h, x, y;
275 uint8_t *tmp;
276
277 if (delay)
1
Assuming 'delay' is 0
2
Taking false branch
278 set_delay(gif, delay);
279 if (gif->nframes == 0) {
3
Assuming field 'nframes' is equal to 0
4
Taking true branch
280 w = gif->w;
281 h = gif->h;
282 x = y = 0;
283 } else if (!get_bbox(gif, &w, &h, &x, &y)) {
284 /* image's not changed; save one pixel just to add delay */
285 w = h = 1;
286 x = y = 0;
287 }
288 put_image(gif, w, h, x, y);
5
Calling 'put_image'
289 gif->nframes++;
290 tmp = gif->back;
291 gif->back = gif->frame;
292 gif->frame = tmp;
293}
294
295struct lwan_strbuf *ge_close_gif(ge_GIF *gif)
296{
297 struct lwan_strbuf *buf = gif->buf;
298
299 lwan_strbuf_append_char(gif->buf, ';');
300 free(gif);
301
302 return buf;
303}