Skip to content

Commit 712c532

Browse files
committed
Merge branch 'PHP-7.1'
2 parents 758af77 + 898e439 commit 712c532

File tree

2 files changed

+70
-2
lines changed

2 files changed

+70
-2
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
--TEST--
2+
Test deflate_add() buffer issue with data that fills deflate buffer while using ZLIB_SYNC_FLUSH on ZLIB_ENCODING_RAW.
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("zlib")) {
6+
print "skip - ZLIB extension not loaded";
7+
}
8+
?>
9+
--FILE--
10+
<?php
11+
12+
/*
13+
* When using ZLIB_ENCODING_RAW, the deflated buffer should always end in 00 00 ff ff
14+
* Many streaming deflate users rely on this behaviour.
15+
* example: websocket permessage-deflate extension
16+
* (https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-28#section-7.2.1)
17+
*
18+
* Prior to fixing, the output buffer size was not being checked. According to the zlib
19+
* manual, deflate must be called again with more buffer space.
20+
*/
21+
22+
$deflateContext = deflate_init(ZLIB_ENCODING_RAW);
23+
24+
$deflated = deflate_add(
25+
$deflateContext,
26+
hex2bin("255044462d312e320a25c7ec8fa20a362030206f626a0a3c3c2f4c656e6774682037203020522f46696c746572202f466c6174654465636f64653e3e0a737472"),
27+
ZLIB_SYNC_FLUSH
28+
);
29+
30+
echo bin2hex(substr($deflated, strlen($deflated) - 4)) . "\n";
31+
32+
$deflated = deflate_add(
33+
$deflateContext,
34+
hex2bin("65616d0a789c7d53c16ed43010bde7c037f85824766a7bc6767c2ca8a00a016a1b2edcb2dbecaed1266937d98afe3d6327363794439437e3f17b6f5e242821e3"),
35+
ZLIB_SYNC_FLUSH
36+
);
37+
38+
echo bin2hex(substr($deflated, strlen($deflated) - 4)) . "\n";
39+
40+
$deflated = deflate_add(
41+
$deflateContext,
42+
hex2bin("b3be777df5525d3f90384cd58b50a9945fbb5e7c6cb8c89fca8156c688665f2de794504a81f75658a7c1d54a347d7575fb6e17ba617edffcae9c84da3aee6c9e"),
43+
ZLIB_SYNC_FLUSH
44+
);
45+
46+
echo bin2hex(substr($deflated, strlen($deflated) - 4)) . "\n";
47+
?>
48+
===DONE===
49+
--EXPECTF--
50+
0000ffff
51+
0000ffff
52+
0000ffff
53+
===DONE===

ext/zlib/zlib.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,7 +1115,7 @@ PHP_FUNCTION(deflate_add)
11151115
{
11161116
zend_string *out;
11171117
char *in_buf;
1118-
size_t in_len, out_size;
1118+
size_t in_len, out_size, buffer_used;
11191119
zval *res;
11201120
z_stream *ctx;
11211121
zend_long flush_type = Z_SYNC_FLUSH;
@@ -1157,14 +1157,29 @@ PHP_FUNCTION(deflate_add)
11571157
out_size = PHP_ZLIB_BUFFER_SIZE_GUESS(ctx->total_in + in_len);
11581158
out_size = (ctx->total_out >= out_size) ? 16 : (out_size - ctx->total_out);
11591159
out_size = (out_size < 16) ? 16 : out_size;
1160+
out_size += 64;
11601161
out = zend_string_alloc(out_size, 0);
11611162

11621163
ctx->next_in = (Bytef *) in_buf;
11631164
ctx->next_out = (Bytef *) ZSTR_VAL(out);
11641165
ctx->avail_in = in_len;
11651166
ctx->avail_out = ZSTR_LEN(out);
11661167

1167-
status = deflate(ctx, flush_type);
1168+
buffer_used = 0;
1169+
1170+
do {
1171+
if (ctx->avail_out == 0) {
1172+
/* more output buffer space needed; realloc and try again */
1173+
/* adding 64 more bytes solved every issue I have seen */
1174+
/* the + 1 is for the string terminator added below */
1175+
out = zend_string_realloc(out, ZSTR_LEN(out) + 64 + 1, 0);
1176+
ctx->avail_out = 64;
1177+
ctx->next_out = (Bytef *) ZSTR_VAL(out) + buffer_used;
1178+
}
1179+
status = deflate(ctx, flush_type);
1180+
buffer_used = ZSTR_LEN(out) - ctx->avail_out;
1181+
} while (status == Z_OK && ctx->avail_out == 0);
1182+
11681183
switch (status) {
11691184
case Z_OK:
11701185
ZSTR_LEN(out) = (char *) ctx->next_out - ZSTR_VAL(out);

0 commit comments

Comments
 (0)