mirror of
https://github.com/libssh2/libssh2.git
synced 2025-11-05 09:30:35 +03:00
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:
committed by
Daniel Stenberg
parent
55a8b10ad9
commit
94077f7a58
22
src/comp.c
22
src/comp.c
@@ -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
|
/* A short-term alloc of a full data chunk is better than a series of
|
||||||
reallocs */
|
reallocs */
|
||||||
char *out;
|
char *out;
|
||||||
int out_maxlen = 8 * src_len;
|
int out_maxlen = 4 * src_len;
|
||||||
int limiter = 0;
|
|
||||||
|
|
||||||
/* If strm is null, then we have not yet been initialized. */
|
/* If strm is null, then we have not yet been initialized. */
|
||||||
if (strm == NULL)
|
if (strm == NULL)
|
||||||
@@ -252,7 +251,7 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session,
|
|||||||
|
|
||||||
/* Loop until it's all inflated or hit error */
|
/* Loop until it's all inflated or hit error */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int status, grow_size;
|
int status;
|
||||||
size_t out_ofs;
|
size_t out_ofs;
|
||||||
char *newout;
|
char *newout;
|
||||||
|
|
||||||
@@ -274,22 +273,15 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session,
|
|||||||
"decompression failure");
|
"decompression failure");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we get here we need to grow the output buffer and try again */
|
if (out_maxlen >= (int) payload_limit) {
|
||||||
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++) {
|
|
||||||
LIBSSH2_FREE(session, out);
|
LIBSSH2_FREE(session, out);
|
||||||
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||||
"Excessive growth in decompression phase");
|
"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);
|
newout = LIBSSH2_REALLOC(session, out, out_maxlen);
|
||||||
if (!newout) {
|
if (!newout) {
|
||||||
LIBSSH2_FREE(session, out);
|
LIBSSH2_FREE(session, out);
|
||||||
@@ -298,7 +290,7 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session,
|
|||||||
}
|
}
|
||||||
out = newout;
|
out = newout;
|
||||||
strm->next_out = (unsigned char *) out + out_ofs;
|
strm->next_out = (unsigned char *) out + out_ofs;
|
||||||
strm->avail_out += grow_size;
|
strm->avail_out = out_maxlen - out_ofs;
|
||||||
}
|
}
|
||||||
|
|
||||||
*dest = (unsigned char *) out;
|
*dest = (unsigned char *) out;
|
||||||
|
|||||||
Reference in New Issue
Block a user