Skip to content

Commit c9df067

Browse files
committed
Fix window buffer wrap-around in zstd compression/decompression
The zstd implementation had a critical buffer overflow bug when updating the window buffer. When copying data to the circular window buffer, the code did not properly handle the case where the data would wrap around the buffer boundary. For example, with a 128KB window and 65535-byte blocks, if the current position was at 100KB, a memcpy would attempt to write past the 128KB boundary, causing a heap buffer overflow. This fix properly handles circular buffer wrap-around by splitting the memcpy into two operations when necessary: - Part 1: Copy from current position to end of buffer - Part 2: Copy remaining data from start of buffer This ensures the circular buffer implementation remains within bounds and fixes the segmentation fault that occurred on Linux when compressing large files with zstd method.
1 parent 6740c82 commit c9df067

49 files changed

Lines changed: 188 additions & 20 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.DS_Store

8 KB
Binary file not shown.

debug/expected_hello.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
hello
2+

debug/hello.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hello

debug/test.zip

222 Bytes
Binary file not shown.

debug/test_deflate

33.3 KB
Binary file not shown.

debug/test_deflate.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <zlib.h>
5+
6+
int main(int argc, char *argv[]) {
7+
if (argc < 3) {
8+
printf ("Usage: %s <input_file> <output_file>\n", argv[0]);
9+
return 1;
10+
}
11+
12+
// Open the input file
13+
FILE *fin = fopen (argv[1], "rb");
14+
if (!fin) {
15+
perror ("Failed to open input file");
16+
return 1;
17+
}
18+
19+
// Get the file size
20+
fseek (fin, 0, SEEK_END);
21+
long file_size = ftell (fin);
22+
fseek (fin, 0, SEEK_SET);
23+
24+
// Read the compressed data
25+
unsigned char *compressed_data = malloc (file_size);
26+
if (fread (compressed_data, 1, file_size, fin) != file_size) {
27+
perror ("Failed to read input file");
28+
fclose (fin);
29+
free (compressed_data);
30+
return 1;
31+
}
32+
fclose (fin);
33+
34+
// Allocate output buffer (assuming output won't be more than 10x input)
35+
unsigned char *decompressed_data = malloc (file_size * 10);
36+
37+
// Set up zlib stream for decompression
38+
z_stream strm;
39+
memset (&strm, 0, sizeof (strm));
40+
strm.next_in = compressed_data;
41+
strm.avail_in = file_size;
42+
strm.next_out = decompressed_data;
43+
strm.avail_out = file_size * 10;
44+
45+
// Initialize with raw deflate format (negative window bits)
46+
if (inflateInit2 (&strm, -MAX_WBITS) != Z_OK) {
47+
fprintf (stderr, "Failed to initialize zlib\n");
48+
free (compressed_data);
49+
free (decompressed_data);
50+
return 1;
51+
}
52+
53+
// Decompress
54+
int ret = inflate (&strm, Z_FINISH);
55+
if (ret != Z_STREAM_END) {
56+
fprintf (stderr, "Decompression failed, error code: %d\n", ret);
57+
inflateEnd (&strm);
58+
free (compressed_data);
59+
free (decompressed_data);
60+
return 1;
61+
}
62+
63+
// Get the decompressed size
64+
unsigned long decompressed_size = strm.total_out;
65+
inflateEnd (&strm);
66+
67+
// Write the decompressed data to the output file
68+
FILE *fout = fopen (argv[2], "wb");
69+
if (!fout) {
70+
perror ("Failed to open output file");
71+
free (compressed_data);
72+
free (decompressed_data);
73+
return 1;
74+
}
75+
76+
if (fwrite (decompressed_data, 1, decompressed_size, fout) != decompressed_size) {
77+
perror ("Failed to write output file");
78+
fclose (fout);
79+
free (compressed_data);
80+
free (decompressed_data);
81+
return 1;
82+
}
83+
84+
fclose (fout);
85+
free (compressed_data);
86+
free (decompressed_data);
87+
88+
printf ("Decompressed %lu bytes of data\n", decompressed_size);
89+
return 0;
90+
}

debug/world.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
world

foo.zip

7.35 KB
Binary file not shown.

hello.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hello

large.bin

100 KB
Binary file not shown.

0 commit comments

Comments
 (0)