comp_method_zlib_decomp: Improve buffer growing algorithm

The old algorithm was O(N^2), causing lots and lots of reallocations
when highly compressed data was transferred.

This patch implements a simpler one that just doubles the buffer size
everytime it is exhausted. It results in O(N) complexity.

Also a smaller inflate ratio is used to calculate the initial size (x4).

Signed-off-by: Salvador <sfandino@yahoo.com>
This commit is contained in:
Salvador
2013-10-15 13:07:00 +02:00
committed by Daniel Stenberg
parent 55a8b10ad9
commit 94077f7a58

View File

@@ -226,8 +226,7 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session,
/* A short-term alloc of a full data chunk is better than a series of
reallocs */
char *out;
int out_maxlen = 8 * src_len;
int limiter = 0;
int out_maxlen = 4 * src_len;
/* If strm is null, then we have not yet been initialized. */
if (strm == NULL)
@@ -252,7 +251,7 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session,
/* Loop until it's all inflated or hit error */
for (;;) {
int status, grow_size;
int status;
size_t out_ofs;
char *newout;
@@ -274,22 +273,15 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session,
"decompression failure");
}
/* If we get here we need to grow the output buffer and try again */
out_ofs = out_maxlen - strm->avail_out;
if (strm->avail_in) {
grow_size = strm->avail_in * 8;
} else {
/* Not sure how much to grow by */
grow_size = 32;
}
out_maxlen += grow_size;
if ((out_maxlen > (int) payload_limit) && limiter++) {
if (out_maxlen >= (int) payload_limit) {
LIBSSH2_FREE(session, out);
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
"Excessive growth in decompression phase");
}
/* If we get here we need to grow the output buffer and try again */
out_ofs = out_maxlen - strm->avail_out;
out_maxlen *= 2;
newout = LIBSSH2_REALLOC(session, out, out_maxlen);
if (!newout) {
LIBSSH2_FREE(session, out);
@@ -298,7 +290,7 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session,
}
out = newout;
strm->next_out = (unsigned char *) out + out_ofs;
strm->avail_out += grow_size;
strm->avail_out = out_maxlen - out_ofs;
}
*dest = (unsigned char *) out;