Bug Summary

File:builds/wireshark/wireshark/epan/tvbuff_zlib.c
Warning:line 319, column 15
Potential leak of memory pointed to by 'uncompr'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name tvbuff_zlib.c -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 -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan -isystem /builds/wireshark/wireshark/build/epan -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /usr/include/lua5.4 -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -D epan_EXPORTS -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2026-04-10-100350-3642-1 -x c /builds/wireshark/wireshark/epan/tvbuff_zlib.c
1/* tvbuff_zlib.c
2 *
3 * Copyright (c) 2000 by Gilbert Ramirez <[email protected]>
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <[email protected]>
7 * Copyright 1998 Gerald Combs
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12#include <config.h>
13#define WS_LOG_DOMAIN"Epan" LOG_DOMAIN_EPAN"Epan"
14
15#include <glib.h>
16
17#include <string.h>
18#include <wsutil/glib-compat.h>
19#include <wsutil/zlib_compat.h>
20
21#include "tvbuff.h"
22#include <wsutil/wslog.h>
23
24#ifdef USE_ZLIB_OR_ZLIBNG
25/*
26 * Uncompresses a zlib compressed packet inside a message of tvb at offset with
27 * length comprlen. Returns an uncompressed tvbuffer if uncompression
28 * succeeded or NULL if uncompression failed.
29 */
30#define TVB_Z_MIN_BUFSIZ32768 32768
31#define TVB_Z_MAX_BUFSIZ1048576 * 10 1048576 * 10
32
33tvbuff_t *
34tvb_uncompress_zlib(tvbuff_t *tvb, const unsigned offset, unsigned comprlen)
35{
36 int err;
37 /* bytes_out is an unsigned because tvb_new_real_data does not accept
38 * more than an unsigned. */
39 unsigned bytes_out = 0;
40 uint8_t *compr;
41 uint8_t *uncompr = NULL((void*)0);
42 tvbuff_t *uncompr_tvb = NULL((void*)0);
43 zlib_streamp strm;
44 Bytef *strmbuf;
45 unsigned inits_done = 0;
46 int wbits = MAX_WBITS15;
47 uint8_t *next;
48 unsigned bufsiz;
49 unsigned inflate_passes = 0;
50 unsigned bytes_in = tvb_captured_length_remaining(tvb, offset);
51
52 if (tvb == NULL((void*)0) || comprlen <= 0) {
1
Assuming 'tvb' is not equal to NULL
2
Assuming 'comprlen' is > 0
3
Taking false branch
53 return NULL((void*)0);
54 }
55
56 compr = (uint8_t *)tvb_memdup(NULL((void*)0), tvb, offset, comprlen);
57 if (compr == NULL((void*)0)) {
4
Assuming 'compr' is not equal to NULL
5
Taking false branch
58 return NULL((void*)0);
59 }
60
61 /*
62 * Assume that the uncompressed data is at least twice as big as
63 * the compressed size.
64 */
65 if (ckd_mul(&bufsiz, bytes_in, 2)__builtin_mul_overflow((bytes_in), (2), (&bufsiz))) {
6
Taking true branch
66 bufsiz = TVB_Z_MAX_BUFSIZ1048576 * 10;
67 } else {
68 bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ)(((bufsiz) > (1048576 * 10)) ? (1048576 * 10) : (((bufsiz)
< (32768)) ? (32768) : (bufsiz)))
;
69 }
70
71 ws_debug("bufsiz: %u bytes\n", bufsiz)do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/tvbuff_zlib.c"
, 71, __func__, "bufsiz: %u bytes\n", bufsiz); } } while (0)
;
7
Taking true branch
8
Loop condition is false. Exiting loop
72
73 next = compr;
74
75 strm = g_new0(zlib_stream, 1)((zlib_stream *) g_malloc0_n ((1), sizeof (zlib_stream)));
76 strm->next_in = next;
77 strm->avail_in = comprlen;
78
79 strmbuf = (Bytef *)g_malloc0(bufsiz);
80 strm->next_out = strmbuf;
81 strm->avail_out = bufsiz;
82
83 err = ZLIB_PREFIX(inflateInit2)(strm, wbits)inflateInit2_((strm), (wbits), "1.3", (int)sizeof(z_stream));
84 inits_done = 1;
85 if (err != Z_OK0) {
9
Assuming 'err' is equal to Z_OK
10
Taking false branch
86 ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
87 g_free(strm);
88 wmem_free(NULL((void*)0), compr);
89 g_free(strmbuf);
90 return NULL((void*)0);
91 }
92
93 while (1) {
11
Loop condition is true. Entering loop body
20
Loop condition is true. Entering loop body
94 memset(strmbuf, '\0', bufsiz);
95 strm->next_out = strmbuf;
96 strm->avail_out = bufsiz;
97
98 err = ZLIB_PREFIX(inflate)inflate(strm, Z_SYNC_FLUSH2);
99
100 if (err == Z_OK0 || err == Z_STREAM_END1) {
12
Assuming 'err' is equal to Z_OK
21
Assuming 'err' is not equal to Z_OK
22
Assuming 'err' is equal to Z_STREAM_END
23
Taking true branch
101 unsigned bytes_pass = bufsiz - strm->avail_out;
102
103 // This is an unsigned long, but won't overflow even
104 // on platforms where that is 32-bit, because bufsize
105 // is clamped, if we break when it reaches INT_MAX.
106 if (strm->total_out > INT_MAX2147483647) {
13
Assuming field 'total_out' is <= INT_MAX
14
Taking false branch
24
Assuming field 'total_out' is <= INT_MAX
25
Taking false branch
107 // Qt uses signed ints in various classes, so
108 // the GUI can't really handle anything
109 ws_debug("overflow, returning what we have")do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/tvbuff_zlib.c"
, 109, __func__, "overflow, returning what we have"); } } while
(0)
;
110 ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
111 g_free(strm);
112 g_free(strmbuf);
113 break;
114 }
115
116 ++inflate_passes;
117
118 if (uncompr
14.1
'uncompr' is equal to NULL
== NULL((void*)0)
) {
26
Assuming 'uncompr' is not equal to NULL
27
Taking false branch
119 /*
120 * This is ugly workaround for bug #6480
121 * (https://gitlab.com/wireshark/wireshark/-/issues/6480)
122 *
123 * g_memdup2(..., 0) returns NULL (g_malloc(0) also)
124 * when uncompr is NULL logic below doesn't create tvb
125 * which is later interpreted as decompression failed.
126 */
127 uncompr = (uint8_t *)((bytes_pass || err != Z_STREAM_END1) ?
15
Assuming 'bytes_pass' is not equal to 0
128 g_memdup2(strmbuf, bytes_pass) :
129 g_strdup("")g_strdup_inline (""));
130 } else {
131 uncompr = (uint8_t *)g_realloc(uncompr, bytes_out + bytes_pass);
28
Memory is allocated
132 memcpy(uncompr + bytes_out, strmbuf, bytes_pass);
133 }
134
135 bytes_out += bytes_pass;
136 ws_assert(bytes_out == strm->total_out)do { if ((1) && !(bytes_out == strm->total_out)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/tvbuff_zlib.c", 136, __func__
, "assertion failed: %s", "bytes_out == strm->total_out");
} while (0)
;
16
Assuming 'bytes_out' is equal to field 'total_out'
17
Taking false branch
18
Loop condition is false. Exiting loop
29
Assuming 'bytes_out' is equal to field 'total_out'
30
Taking false branch
31
Loop condition is false. Exiting loop
137
138 if (err
18.1
'err' is not equal to Z_STREAM_END
31.1
'err' is equal to Z_STREAM_END
== Z_STREAM_END1) {
19
Taking false branch
32
Taking true branch
139 ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
140 g_free(strm);
141 g_free(strmbuf);
142 break;
33
Execution continues on line 315
143 }
144 } else if (err == Z_BUF_ERROR(-5)) {
145 /*
146 * It's possible that not enough frames were captured
147 * to decompress this fully, so return what we've done
148 * so far, if any.
149 */
150 ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
151 g_free(strm);
152 g_free(strmbuf);
153
154 if (uncompr != NULL((void*)0)) {
155 break;
156 } else {
157 wmem_free(NULL((void*)0), compr);
158 return NULL((void*)0);
159 }
160
161 } else if (err == Z_DATA_ERROR(-3) && inits_done == 1
162 && uncompr == NULL((void*)0) && comprlen >= 2 &&
163 (*compr == 0x1f) && (*(compr + 1) == 0x8b)) {
164 /*
165 * inflate() is supposed to handle both gzip and deflate
166 * streams automatically, but in reality it doesn't
167 * seem to handle either (at least not within the
168 * context of an HTTP response.) We have to try
169 * several tweaks, depending on the type of data and
170 * version of the library installed.
171 */
172
173 /*
174 * Gzip file format. Skip past the header, since the
175 * fix to make it work (setting windowBits to 31)
176 * doesn't work with all versions of the library.
177 */
178 Bytef *c = compr + 2;
179 Bytef flags = 0;
180
181 /* we read two bytes already (0x1f, 0x8b) and
182 need at least Z_DEFLATED, 1 byte flags, 4
183 bytes MTIME, 1 byte XFL, 1 byte OS */
184 if (comprlen < 10 || *c != Z_DEFLATED8) {
185 ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
186 g_free(strm);
187 wmem_free(NULL((void*)0), compr);
188 g_free(strmbuf);
189 return NULL((void*)0);
190 }
191
192 c++;
193 flags = *c;
194 c++;
195
196 /* Skip past the MTIME (4 bytes),
197 XFL, and OS fields (1 byte each). */
198 c += 6;
199
200 if (flags & (1 << 2)) {
201 /* An Extra field is present. It
202 consists of 2 bytes xsize and xsize
203 bytes of data.
204 Read byte-by-byte (least significant
205 byte first) to make sure we abort
206 cleanly when the xsize is truncated
207 after the first byte. */
208 uint16_t xsize = 0;
209
210 if ((unsigned)(c-compr) < comprlen) {
211 xsize += *c;
212 c++;
213 }
214 if ((unsigned)(c-compr) < comprlen) {
215 xsize += *c << 8;
216 c++;
217 }
218
219 c += xsize;
220 }
221
222 if (flags & (1 << 3)) {
223 /* A null terminated filename */
224
225 while ((unsigned)(c - compr) < comprlen && *c != '\0') {
226 c++;
227 }
228
229 c++;
230 }
231
232 if (flags & (1 << 4)) {
233 /* A null terminated comment */
234
235 while ((unsigned)(c - compr) < comprlen && *c != '\0') {
236 c++;
237 }
238
239 c++;
240 }
241
242
243 if ((unsigned)(c - compr) > comprlen) {
244 ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
245 g_free(strm);
246 wmem_free(NULL((void*)0), compr);
247 g_free(strmbuf);
248 return NULL((void*)0);
249 }
250 /* Drop gzip header */
251 comprlen -= (unsigned)(c - compr);
252 next = c;
253
254 ZLIB_PREFIX(inflateReset)inflateReset(strm);
255 strm->next_in = next;
256 strm->avail_in = comprlen;
257
258 ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
259 err = ZLIB_PREFIX(inflateInit2)(strm, wbits)inflateInit2_((strm), (wbits), "1.3", (int)sizeof(z_stream));
260 inits_done++;
261 if (err != Z_OK0) {
262 g_free(strm);
263 wmem_free(NULL((void*)0), compr);
264 g_free(strmbuf);
265 return NULL((void*)0);
266 }
267 } else if (err == Z_DATA_ERROR(-3) && uncompr == NULL((void*)0) &&
268 inits_done <= 3) {
269
270 /*
271 * Re-init the stream with a negative
272 * MAX_WBITS. This is necessary due to
273 * some servers (Apache) not sending
274 * the deflate header with the
275 * content-encoded response.
276 */
277 wbits = -MAX_WBITS15;
278
279 ZLIB_PREFIX(inflateReset)inflateReset(strm);
280
281 strm->next_in = next;
282 strm->avail_in = comprlen;
283
284 ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
285 memset(strmbuf, '\0', bufsiz);
286 strm->next_out = strmbuf;
287 strm->avail_out = bufsiz;
288
289 err = ZLIB_PREFIX(inflateInit2)(strm, wbits)inflateInit2_((strm), (wbits), "1.3", (int)sizeof(z_stream));
290
291 inits_done++;
292
293 if (err != Z_OK0) {
294 g_free(strm);
295 g_free(strmbuf);
296 wmem_free(NULL((void*)0), compr);
297 g_free(uncompr);
298
299 return NULL((void*)0);
300 }
301 } else {
302 ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
303 g_free(strm);
304 g_free(strmbuf);
305
306 if (uncompr == NULL((void*)0)) {
307 wmem_free(NULL((void*)0), compr);
308 return NULL((void*)0);
309 }
310
311 break;
312 }
313 }
314
315 ws_debug("inflate() total passes: %u\n", inflate_passes)do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/tvbuff_zlib.c"
, 315, __func__, "inflate() total passes: %u\n", inflate_passes
); } } while (0)
;
34
Taking true branch
35
Loop condition is false. Exiting loop
316 ws_debug("bytes in: %u\nbytes out: %u\n\n", bytes_in, bytes_out)do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/tvbuff_zlib.c"
, 316, __func__, "bytes in: %u\nbytes out: %u\n\n", bytes_in
, bytes_out); } } while (0)
;
36
Taking true branch
37
Loop condition is false. Exiting loop
317
318 if (uncompr
37.1
'uncompr' is not equal to NULL
!= NULL((void*)0)) {
38
Taking true branch
319 uncompr_tvb = tvb_new_real_data(uncompr, bytes_out, bytes_out);
39
Potential leak of memory pointed to by 'uncompr'
320 tvb_set_free_cb(uncompr_tvb, g_free);
321 }
322 wmem_free(NULL((void*)0), compr);
323 return uncompr_tvb;
324}
325#else /* USE_ZLIB_OR_ZLIBNG */
326tvbuff_t *
327tvb_uncompress_zlib(tvbuff_t *tvb _U___attribute__((unused)), const unsigned offset _U___attribute__((unused)), unsigned comprlen _U___attribute__((unused)))
328{
329 return NULL((void*)0);
330}
331#endif /* USE_ZLIB_OR_ZLIBNG */
332
333tvbuff_t *
334tvb_child_uncompress_zlib(tvbuff_t *parent, tvbuff_t *tvb, const unsigned offset, unsigned comprlen)
335{
336 tvbuff_t *new_tvb = tvb_uncompress_zlib(tvb, offset, comprlen);
337 if (new_tvb)
338 tvb_set_child_real_data_tvbuff (parent, new_tvb);
339 return new_tvb;
340}
341
342tvbuff_t *
343tvb_uncompress(tvbuff_t *tvb, const unsigned offset, unsigned comprlen)
344{
345 return tvb_uncompress_zlib(tvb, offset, comprlen);
346}
347
348tvbuff_t *
349tvb_child_uncompress(tvbuff_t *parent, tvbuff_t *tvb, const unsigned offset, unsigned comprlen)
350{
351 return tvb_child_uncompress_zlib(parent, tvb, offset, comprlen);
352}
353
354/*
355 * Editor modelines - https://www.wireshark.org/tools/modelines.html
356 *
357 * Local variables:
358 * c-basic-offset: 8
359 * tab-width: 8
360 * indent-tabs-mode: t
361 * End:
362 *
363 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
364 * :indentSize=8:tabSize=8:noTabs=false:
365 */