File: test_invalid_streams.c

package info (click to toggle)
libdeflate 1.23-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,072 kB
  • sloc: ansic: 11,716; sh: 1,388; python: 169; makefile: 31
file content (130 lines) | stat: -rw-r--r-- 3,913 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * test_invalid_streams.c
 *
 * Test that invalid DEFLATE streams are rejected with LIBDEFLATE_BAD_DATA.
 *
 * This isn't actually very important, since DEFLATE doesn't have built-in error
 * detection, so corruption of a DEFLATE stream can only be reliably detected
 * using a separate checksum anyway.  As long as the DEFLATE decompressor
 * handles all streams safely (no crashes, etc.), in practice it is fine for it
 * to automatically remap invalid streams to valid streams, instead of returning
 * an error.  Corruption detection is the responsibility of the zlib or gzip
 * layer, or the application when an external checksum is used.
 *
 * Nevertheless, to reduce surprises when people intentionally compare zlib's
 * and libdeflate's handling of invalid DEFLATE streams, libdeflate implements
 * zlib's strict behavior when decoding DEFLATE, except when it would have a
 * significant performance cost.
 */

#include "test_util.h"

static void
assert_decompression_error(const u8 *in, size_t in_nbytes)
{
	struct libdeflate_decompressor *d;
	z_stream z;
	u8 out[128];
	const size_t out_nbytes_avail = sizeof(out);
	size_t actual_out_nbytes;
	enum libdeflate_result res;

	/* libdeflate */
	d = libdeflate_alloc_decompressor();
	ASSERT(d != NULL);
	res = libdeflate_deflate_decompress(d, in, in_nbytes,
					    out, out_nbytes_avail,
					    &actual_out_nbytes);
	ASSERT(res == LIBDEFLATE_BAD_DATA);
	libdeflate_free_decompressor(d);

	/* zlib, as a control */
	memset(&z, 0, sizeof(z));
	res = inflateInit2(&z, -15);
	ASSERT(res == Z_OK);
	z.next_in = (void *)in;
	z.avail_in = in_nbytes;
	z.next_out = (void *)out;
	z.avail_out = out_nbytes_avail;
	res = inflate(&z, Z_FINISH);
	ASSERT(res == Z_DATA_ERROR);
	inflateEnd(&z);
}

/*
 * Test that DEFLATE decompression returns an error if a block header contains
 * too many encoded litlen and offset codeword lengths.
 */
static void
test_too_many_codeword_lengths(void)
{
	u8 in[128];
	struct output_bitstream os = { .next = in, .end = in + sizeof(in) };
	int i;

	ASSERT(put_bits(&os, 1, 1));	/* BFINAL: 1 */
	ASSERT(put_bits(&os, 2, 2));	/* BTYPE: DYNAMIC_HUFFMAN */

	/*
	 * Litlen code:
	 *	litlensym_255			len=1 codeword=0
	 *	litlensym_256 (end-of-block)	len=1 codeword=1
	 * Offset code:
	 *	(empty)
	 *
	 * Litlen and offset codeword lengths:
	 *	[0..254] = 0	presym_{18,18}
	 *	[255]	 = 1	presym_1
	 *	[256]	 = 1	presym_1
	 *	[257...] = 0	presym_18 [TOO MANY]
	 *
	 * Precode:
	 *	presym_1	len=1 codeword=0
	 *	presym_18	len=1 codeword=1
	 */

	ASSERT(put_bits(&os, 0, 5));	/* num_litlen_syms: 0 + 257 */
	ASSERT(put_bits(&os, 0, 5));	/* num_offset_syms: 0 + 1 */
	ASSERT(put_bits(&os, 14, 4));	/* num_explicit_precode_lens: 14 + 4 */

	/*
	 * Precode codeword lengths: order is
	 * [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]
	 */
	for (i = 0; i < 2; i++)		/* presym_{16,17}: len=0 */
		ASSERT(put_bits(&os, 0, 3));
	ASSERT(put_bits(&os, 1, 3));	/* presym_18: len=1 */
	ASSERT(put_bits(&os, 0, 3));	/* presym_0: len=0 */
	for (i = 0; i < 13; i++)	/* presym_{8,...,14}: len=0 */
		ASSERT(put_bits(&os, 0, 3));
	ASSERT(put_bits(&os, 1, 3));	/* presym_1: len=1 */

	/* Litlen and offset codeword lengths */
	ASSERT(put_bits(&os, 0x1, 1) &&	/* presym_18, 128 zeroes */
	       put_bits(&os, 117, 7));
	ASSERT(put_bits(&os, 0x1, 1) &&	/* presym_18, 127 zeroes */
	       put_bits(&os, 116, 7));
	ASSERT(put_bits(&os, 0x0, 1));	/* presym_1 */
	ASSERT(put_bits(&os, 0x0, 1));	/* presym_1 */
	ASSERT(put_bits(&os, 0x1, 1) &&	/* presym_18, 128 zeroes [TOO MANY] */
	       put_bits(&os, 117, 7));

	/* Literal */
	ASSERT(put_bits(&os, 0x0, 0));	/* litlensym_255 */

	/* End of block */
	ASSERT(put_bits(&os, 0x1, 1));	/* litlensym_256 */

	ASSERT(flush_bits(&os));

	assert_decompression_error(in, os.next - in);
}

int
tmain(int argc, tchar *argv[])
{
	begin_program(argv);

	test_too_many_codeword_lengths();
	return 0;
}