Skip to content

Commit 933fd51

Browse files
committed
deflate: Better Huffman.construct errors and error handling
This brings construct error handling in line with puff.c
1 parent c4cd592 commit 933fd51

File tree

1 file changed

+33
-6
lines changed

1 file changed

+33
-6
lines changed

lib/std/compress/deflate.zig

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ const Huffman = struct {
4545

4646
min_code_len: u16,
4747

48-
fn construct(self: *Huffman, code_length: []const u16) !void {
48+
const ConstructError = error{ Oversubscribed, IncompleteSet };
49+
50+
fn construct(self: *Huffman, code_length: []const u16) ConstructError!void {
4951
for (self.count) |*val| {
5052
val.* = 0;
5153
}
@@ -70,7 +72,7 @@ const Huffman = struct {
7072
// Make sure the number of codes with this length isn't too high.
7173
left -= @as(isize, @bitCast(i16, val));
7274
if (left < 0)
73-
return error.InvalidTree;
75+
return error.Oversubscribed;
7476
}
7577

7678
// Compute the offset of the first symbol represented by a code of a
@@ -125,6 +127,9 @@ const Huffman = struct {
125127

126128
self.last_code = codes[PREFIX_LUT_BITS + 1];
127129
self.last_index = offset[PREFIX_LUT_BITS + 1] - self.count[PREFIX_LUT_BITS + 1];
130+
131+
if (left > 0)
132+
return error.IncompleteSet;
128133
}
129134
};
130135

@@ -322,7 +327,13 @@ pub fn InflateStream(comptime ReaderType: type) type {
322327
try lencode.construct(len_lengths[0..]);
323328

324329
const dist_lengths = [_]u16{5} ** MAXDCODES;
325-
try distcode.construct(dist_lengths[0..]);
330+
distcode.construct(dist_lengths[0..]) catch |err| switch (err) {
331+
// This error is expected because we only compute distance codes
332+
// 0-29, which is fine since "distance codes 30-31 will never actually
333+
// occur in the compressed data" (from section 3.2.6 of RFC1951).
334+
error.IncompleteSet => {},
335+
else => return err,
336+
};
326337
}
327338

328339
self.hlen = &lencode;
@@ -357,7 +368,7 @@ pub fn InflateStream(comptime ReaderType: type) type {
357368
lengths[val] = @intCast(u16, try self.readBits(3));
358369
}
359370

360-
try lencode.construct(lengths[0..]);
371+
lencode.construct(lengths[0..]) catch return error.InvalidTree;
361372
}
362373

363374
// Read the length/literal and distance code length tables.
@@ -406,8 +417,24 @@ pub fn InflateStream(comptime ReaderType: type) type {
406417
if (lengths[256] == 0)
407418
return error.MissingEOBCode;
408419

409-
try self.huffman_tables[0].construct(lengths[0..nlen]);
410-
try self.huffman_tables[1].construct(lengths[nlen .. nlen + ndist]);
420+
self.huffman_tables[0].construct(lengths[0..nlen]) catch |err| switch (err) {
421+
error.Oversubscribed => return error.InvalidTree,
422+
error.IncompleteSet => {
423+
// incomplete code ok only for single length 1 code
424+
if (nlen != self.huffman_tables[0].count[0] + self.huffman_tables[0].count[1]) {
425+
return error.InvalidTree;
426+
}
427+
},
428+
};
429+
self.huffman_tables[1].construct(lengths[nlen .. nlen + ndist]) catch |err| switch (err) {
430+
error.Oversubscribed => return error.InvalidTree,
431+
error.IncompleteSet => {
432+
// incomplete code ok only for single length 1 code
433+
if (ndist != self.huffman_tables[1].count[0] + self.huffman_tables[1].count[1]) {
434+
return error.InvalidTree;
435+
}
436+
},
437+
};
411438

412439
self.hlen = &self.huffman_tables[0];
413440
self.hdist = &self.huffman_tables[1];

0 commit comments

Comments
 (0)