### Bug Summary

File: | builds/wireshark/wireshark/epan/tvbuff_zlib.c
Warning: | line 303, column 23 Attempt to release already released memory

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
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-22/lib/clang/22 -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/lua5.5 -isystem /usr/include/libxml2 -D CARES_NO_DEPRECATED -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-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../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=gnu17 -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 -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-06-21-100313-3595-1 -x c /builds/wireshark/wireshark/epan/tvbuff_zlib.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

1 | /* tvbuff_zlib.c
2 | *
3 | * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
4 | *
5 | * Wireshark - Network traffic analyzer
6 | * By Gerald Combs <gerald@wireshark.org>
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 |
33 | tvbuff_t *
34 | tvb_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 | tvbuff_t *uncompr_tvb = NULL((void*)0);
42 | zlib_streamp strm;
43 | Bytef *strmbuf;
44 | unsigned inits_done = 0;
45 | int wbits = MAX_WBITS15;
46 | uint8_t *next;
47 | unsigned bufsiz;
48 | unsigned inflate_passes = 0;
49 | unsigned bytes_in = tvb_captured_length_remaining(tvb, offset);
50 |
51 | if (tvb == NULL((void*)0) || comprlen <= 0) {
1 | Assuming 'tvb' is not equal to NULL | →
2 | ← | Assuming 'comprlen' is > 0 | →
3 | ← | Taking false branch | →
52 | return NULL((void*)0);
53 | }
54 |
55 | compr = (uint8_t *)tvb_memdup(NULL((void*)0), tvb, offset, comprlen);
56 | if (compr == NULL((void*)0)) {
4 | ← | Assuming 'compr' is not equal to NULL | →
5 | ← | Taking false branch | →
57 | return NULL((void*)0);
58 | }
59 |
60 | /*
61 | * Assume that the uncompressed data is at least twice as big as
62 | * the compressed size.
63 | */
64 | if (ckd_mul(&bufsiz, bytes_in, 2)__builtin_mul_overflow((bytes_in), (2), (&bufsiz))) {
6 | ← | Taking true branch | →
65 | bufsiz = TVB_Z_MAX_BUFSIZ1048576 * 10;
66 | } else {
67 | bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ)(((bufsiz) > (1048576 * 10)) ? (1048576 * 10) : (((bufsiz) < (32768)) ? (32768) : (bufsiz)));
68 | }
69 |
70 | ws_debug("bufsiz: %u bytes\n", bufsiz)do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/tvbuff_zlib.c" , 70, __func__, "bufsiz: %u bytes\n", bufsiz); } } while (0);
7 | ← | Taking true branch | →
8 | ← | Loop condition is false. Exiting loop | →
71 |
72 | next = compr;
73 |
74 | strm = g_new0(zlib_stream, 1)((zlib_stream *) g_malloc0_n ((1), sizeof (zlib_stream)));
75 | strm->next_in = next;
76 | strm->avail_in = comprlen;
77 |
78 | strmbuf = (Bytef *)g_malloc(bufsiz);
9 | ← | Memory is allocated | →
79 |
80 | err = ZLIB_PREFIX(inflateInit2)(strm, wbits)inflateInit2_((strm), (wbits), "1.3.1", (int)sizeof(z_stream) );
81 | inits_done = 1;
82 | if (err != Z_OK0) {
10 | ← | Assuming 'err' is equal to Z_OK | →
11 | ← | Taking false branch | →
83 | ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
84 | g_free(strm)(__builtin_object_size ((strm), 0) != ((size_t) - 1)) ? g_free_sized (strm, __builtin_object_size ((strm), 0)) : (g_free) (strm);
85 | wmem_free(NULL((void*)0), compr);
86 | g_free(strmbuf)(__builtin_object_size ((strmbuf), 0) != ((size_t) - 1)) ? g_free_sized (strmbuf, __builtin_object_size ((strmbuf), 0)) : (g_free) ( strmbuf);
87 | return NULL((void*)0);
88 | }
89 |
90 | while (1) {
12 | ← | Loop condition is true. Entering loop body | →
22 | ← | Loop condition is true. Entering loop body | →
91 | strm->next_out = &strmbuf[bytes_out];
92 | strm->avail_out = bufsiz;
93 |
94 | err = ZLIB_PREFIX(inflate)inflate(strm, Z_SYNC_FLUSH2);
95 |
96 | if (err == Z_OK0 || err == Z_STREAM_END1) {
13 | ← | Assuming 'err' is equal to Z_OK | →
23 | ← | Assuming 'err' is not equal to Z_OK | →
24 | ← | Assuming 'err' is not equal to Z_STREAM_END | →
25 | ← | Taking false branch | →
97 | unsigned bytes_pass = bufsiz - strm->avail_out;
98 |
99 | // This is an unsigned long, but won't overflow even
100 | // on platforms where that is 32-bit, because bufsize
101 | // is clamped, if we break when it reaches INT_MAX.
102 | if (strm->total_out > INT_MAX2147483647) {
14 | ← | Assuming field 'total_out' is <= INT_MAX | →
15 | ← | Taking false branch | →
103 | // Qt uses signed ints in various classes, so
104 | // the GUI can't really handle anything
105 | ws_debug("overflow, returning what we have")do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/tvbuff_zlib.c" , 105, __func__, "overflow, returning what we have"); } } while (0);
106 | ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
107 | g_free(strm)(__builtin_object_size ((strm), 0) != ((size_t) - 1)) ? g_free_sized (strm, __builtin_object_size ((strm), 0)) : (g_free) (strm);
108 | break;
109 | }
110 |
111 | /* Use this for a workaround for bug #6480
112 | * (https://gitlab.com/wireshark/wireshark/-/issues/6480)
113 | * When a zero length payload was compressed into 20 bytes
114 | * bytes we want to return a tvb with 0 length instead
115 | * of NULL. */
116 | ++inflate_passes;
117 |
118 | bytes_out += bytes_pass;
119 | 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", 119, __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 | →
120 |
121 | if (strm->avail_out == 0) {
19 | ← | Assuming field 'avail_out' is not equal to 0 | →
20 | ← | Taking false branch | →
122 | strmbuf = (uint8_t*)g_realloc(strmbuf, bytes_out + bufsiz);
123 | }
124 |
125 | if (err
20.1 | 'err' is not equal to Z_STREAM_END
== Z_STREAM_END1) {
21 | ← | Taking false branch | →
126 | ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
127 | g_free(strm)(__builtin_object_size ((strm), 0) != ((size_t) - 1)) ? g_free_sized (strm, __builtin_object_size ((strm), 0)) : (g_free) (strm);
128 | break;
129 | }
130 | } else if (err == Z_BUF_ERROR(-5)) {
26 | ← | Assuming the condition is false | →
131 | /*
132 | * It's possible that not enough frames were captured
133 | * to decompress this fully, so return what we've done
134 | * so far, if any.
135 | */
136 | ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
137 | g_free(strm)(__builtin_object_size ((strm), 0) != ((size_t) - 1)) ? g_free_sized (strm, __builtin_object_size ((strm), 0)) : (g_free) (strm);
138 |
139 | if (inflate_passes) {
140 | break;
141 | } else {
142 | wmem_free(NULL((void*)0), compr);
143 | return NULL((void*)0);
144 | }
145 |
146 | } else if (err == Z_DATA_ERROR(-3) && inits_done == 1
27 | ← | Assuming the condition is false | →
147 | && inflate_passes == 0 && comprlen >= 2 &&
148 | (*compr == 0x1f) && (*(compr + 1) == 0x8b)) {
149 | /*
150 | * inflate() is supposed to handle both gzip and deflate
151 | * streams automatically, but in reality it doesn't
152 | * seem to handle either (at least not within the
153 | * context of an HTTP response.) We have to try
154 | * several tweaks, depending on the type of data and
155 | * version of the library installed.
156 | */
157 |
158 | /*
159 | * Gzip file format. Skip past the header, since the
160 | * fix to make it work (setting windowBits to 31)
161 | * doesn't work with all versions of the library.
162 | */
163 | Bytef *c = compr + 2;
164 | Bytef flags = 0;
165 |
166 | /* we read two bytes already (0x1f, 0x8b) and
167 | need at least Z_DEFLATED, 1 byte flags, 4
168 | bytes MTIME, 1 byte XFL, 1 byte OS */
169 | if (comprlen < 10 || *c != Z_DEFLATED8) {
170 | ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
171 | g_free(strm)(__builtin_object_size ((strm), 0) != ((size_t) - 1)) ? g_free_sized (strm, __builtin_object_size ((strm), 0)) : (g_free) (strm);
172 | wmem_free(NULL((void*)0), compr);
173 | g_free(strmbuf)(__builtin_object_size ((strmbuf), 0) != ((size_t) - 1)) ? g_free_sized (strmbuf, __builtin_object_size ((strmbuf), 0)) : (g_free) ( strmbuf);
174 | return NULL((void*)0);
175 | }
176 |
177 | c++;
178 | flags = *c;
179 | c++;
180 |
181 | /* Skip past the MTIME (4 bytes),
182 | XFL, and OS fields (1 byte each). */
183 | c += 6;
184 |
185 | if (flags & (1 << 2)) {
186 | /* An Extra field is present. It
187 | consists of 2 bytes xsize and xsize
188 | bytes of data.
189 | Read byte-by-byte (least significant
190 | byte first) to make sure we abort
191 | cleanly when the xsize is truncated
192 | after the first byte. */
193 | uint16_t xsize = 0;
194 |
195 | if ((unsigned)(c-compr) < comprlen) {
196 | xsize += *c;
197 | c++;
198 | }
199 | if ((unsigned)(c-compr) < comprlen) {
200 | xsize += *c << 8;
201 | c++;
202 | }
203 |
204 | c += xsize;
205 | }
206 |
207 | if (flags & (1 << 3)) {
208 | /* A null terminated filename */
209 |
210 | while ((unsigned)(c - compr) < comprlen && *c != '\0') {
211 | c++;
212 | }
213 |
214 | c++;
215 | }
216 |
217 | if (flags & (1 << 4)) {
218 | /* A null terminated comment */
219 |
220 | while ((unsigned)(c - compr) < comprlen && *c != '\0') {
221 | c++;
222 | }
223 |
224 | c++;
225 | }
226 |
227 |
228 | if ((unsigned)(c - compr) > comprlen) {
229 | ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
230 | g_free(strm)(__builtin_object_size ((strm), 0) != ((size_t) - 1)) ? g_free_sized (strm, __builtin_object_size ((strm), 0)) : (g_free) (strm);
231 | wmem_free(NULL((void*)0), compr);
232 | g_free(strmbuf)(__builtin_object_size ((strmbuf), 0) != ((size_t) - 1)) ? g_free_sized (strmbuf, __builtin_object_size ((strmbuf), 0)) : (g_free) ( strmbuf);
233 | return NULL((void*)0);
234 | }
235 | /* Drop gzip header */
236 | comprlen -= (unsigned)(c - compr);
237 | next = c;
238 |
239 | ZLIB_PREFIX(inflateReset)inflateReset(strm);
240 | strm->next_in = next;
241 | strm->avail_in = comprlen;
242 |
243 | ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
244 | err = ZLIB_PREFIX(inflateInit2)(strm, wbits)inflateInit2_((strm), (wbits), "1.3.1", (int)sizeof(z_stream) );
245 | inits_done++;
246 | if (err != Z_OK0) {
247 | g_free(strm)(__builtin_object_size ((strm), 0) != ((size_t) - 1)) ? g_free_sized (strm, __builtin_object_size ((strm), 0)) : (g_free) (strm);
248 | wmem_free(NULL((void*)0), compr);
249 | g_free(strmbuf)(__builtin_object_size ((strmbuf), 0) != ((size_t) - 1)) ? g_free_sized (strmbuf, __builtin_object_size ((strmbuf), 0)) : (g_free) ( strmbuf);
250 | return NULL((void*)0);
251 | }
252 | } else if (err == Z_DATA_ERROR(-3) && inflate_passes == 0 &&
253 | inits_done <= 3) {
254 |
255 | /*
256 | * Re-init the stream with a negative
257 | * MAX_WBITS. This is necessary due to
258 | * some servers (Apache) not sending
259 | * the deflate header with the
260 | * content-encoded response.
261 | */
262 | wbits = -MAX_WBITS15;
263 |
264 | ZLIB_PREFIX(inflateReset)inflateReset(strm);
265 |
266 | strm->next_in = next;
267 | strm->avail_in = comprlen;
268 |
269 | ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
270 | strm->next_out = strmbuf;
271 | strm->avail_out = bufsiz;
272 |
273 | err = ZLIB_PREFIX(inflateInit2)(strm, wbits)inflateInit2_((strm), (wbits), "1.3.1", (int)sizeof(z_stream) );
274 |
275 | inits_done++;
276 |
277 | if (err != Z_OK0) {
278 | g_free(strm)(__builtin_object_size ((strm), 0) != ((size_t) - 1)) ? g_free_sized (strm, __builtin_object_size ((strm), 0)) : (g_free) (strm);
279 | g_free(strmbuf)(__builtin_object_size ((strmbuf), 0) != ((size_t) - 1)) ? g_free_sized (strmbuf, __builtin_object_size ((strmbuf), 0)) : (g_free) ( strmbuf);
280 | wmem_free(NULL((void*)0), compr);
281 |
282 | return NULL((void*)0);
283 | }
284 | } else {
285 | ZLIB_PREFIX(inflateEnd)inflateEnd(strm);
286 | g_free(strm)(__builtin_object_size ((strm), 0) != ((size_t) - 1)) ? g_free_sized (strm, __builtin_object_size ((strm), 0)) : (g_free) (strm);
28 | ← | Assuming the condition is false | →
29 | ← | '?' condition is false | →
287 | g_free(strmbuf)(__builtin_object_size ((strmbuf), 0) != ((size_t) - 1)) ? g_free_sized (strmbuf, __builtin_object_size ((strmbuf), 0)) : (g_free) ( strmbuf);
30 | ← | Assuming the condition is false | →
31 | ← | '?' condition is false | →
32 | ← | Memory is released | →
288 |
289 | if (!inflate_passes
32.1 | 'inflate_passes' is 1
) {
33 | ← | Taking false branch | →
290 | wmem_free(NULL((void*)0), compr);
291 | return NULL((void*)0);
292 | }
293 |
294 | break;
34 | ← | Execution continues on line 298 | →
295 | }
296 | }
297 |
298 | ws_debug("inflate() total passes: %u\n", inflate_passes)do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/tvbuff_zlib.c" , 298, __func__, "inflate() total passes: %u\n", inflate_passes ); } } while (0);
35 | ← | Taking true branch | →
36 | ← | Loop condition is false. Exiting loop | →
299 | 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" , 299, __func__, "bytes in: %u\nbytes out: %u\n\n", bytes_in , bytes_out); } } while (0);
37 | ← | Taking true branch | →
38 | ← | Loop condition is false. Exiting loop | →
300 |
301 | if (inflate_passes
38.1 | 'inflate_passes' is 1
) {
39 | ← | Taking true branch | →
302 | /* g_realloc(..., 0) is well-defined, returns NULL. */
303 | strmbuf = (uint8_t*)g_realloc(strmbuf, bytes_out);
40 | ← | Attempt to release already released memory
304 | uncompr_tvb = tvb_new_real_data(strmbuf, bytes_out, bytes_out);
305 | tvb_set_free_cb(uncompr_tvb, g_free);
306 | }
307 | wmem_free(NULL((void*)0), compr);
308 | return uncompr_tvb;
309 | }
310 | #else /* USE_ZLIB_OR_ZLIBNG */
311 | tvbuff_t *
312 | tvb_uncompress_zlib(tvbuff_t *tvb _U___attribute__((unused)), const unsigned offset _U___attribute__((unused)), unsigned comprlen _U___attribute__((unused)))
313 | {
314 | return NULL((void*)0);
315 | }
316 | #endif /* USE_ZLIB_OR_ZLIBNG */
317 |
318 | tvbuff_t *
319 | tvb_child_uncompress_zlib(tvbuff_t *parent, tvbuff_t *tvb, const unsigned offset, unsigned comprlen)
320 | {
321 | tvbuff_t *new_tvb = tvb_uncompress_zlib(tvb, offset, comprlen);
322 | if (new_tvb)
323 | tvb_set_child_real_data_tvbuff (parent, new_tvb);
324 | return new_tvb;
325 | }
326 |
327 | /*
328 | * Editor modelines - https://www.wireshark.org/tools/modelines.html
329 | *
330 | * Local variables:
331 | * c-basic-offset: 8
332 | * tab-width: 8
333 | * indent-tabs-mode: t
334 | * End:
335 | *
336 | * vi: set shiftwidth=8 tabstop=8 noexpandtab:
337 | * :indentSize=8:tabSize=8:noTabs=false:
338 | */