### Bug Summary

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

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