mirror of
				https://github.com/libssh2/libssh2.git
				synced 2025-11-03 22:13:11 +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