# HG changeset patch # User Bram Moolenaar # Date 1418846449 -3600 # Node ID 86aacd619ac0ab9b6b6519cf132367b744adf8f0 # Parent ad262c7047d9e896f567c60a08451ab89d027a9b updated for version 7.4.560 Problem: Memory leak using :wviminfo. Issue 296. Solution: Free memory when needed. (idea by Christian Brabandt) diff --git a/src/ops.c b/src/ops.c --- a/src/ops.c +++ b/src/ops.c @@ -5663,6 +5663,8 @@ read_viminfo_register(virp, force) int set_prev = FALSE; char_u *str; char_u **array = NULL; + int new_type; + colnr_T new_width; /* We only get here (hopefully) if line[0] == '"' */ str = virp->vir_line + 1; @@ -5695,21 +5697,25 @@ read_viminfo_register(virp, force) limit = 100; /* Optimized for registers containing <= 100 lines */ if (do_it) { + /* + * Build the new register in array[]. + * y_array is kept as-is until done. + * The "do_it" flag is reset when something is wrong, in which case + * array[] needs to be freed. + */ if (set_prev) y_previous = y_current; - vim_free(y_current->y_array); - array = y_current->y_array = - (char_u **)alloc((unsigned)(limit * sizeof(char_u *))); + array = (char_u **)alloc((unsigned)(limit * sizeof(char_u *))); str = skipwhite(skiptowhite(str)); if (STRNCMP(str, "CHAR", 4) == 0) - y_current->y_type = MCHAR; + new_type = MCHAR; else if (STRNCMP(str, "BLOCK", 5) == 0) - y_current->y_type = MBLOCK; + new_type = MBLOCK; else - y_current->y_type = MLINE; + new_type = MLINE; /* get the block width; if it's missing we get a zero, which is OK */ str = skipwhite(skiptowhite(str)); - y_current->y_width = getdigits(&str); + new_width = getdigits(&str); } while (!(eof = viminfo_readline(virp)) @@ -5717,40 +5723,66 @@ read_viminfo_register(virp, force) { if (do_it) { - if (size >= limit) + if (size == limit) { - y_current->y_array = (char_u **) + char_u **new_array = (char_u **) alloc((unsigned)(limit * 2 * sizeof(char_u *))); + + if (new_array == NULL) + { + do_it = FALSE; + break; + } for (i = 0; i < limit; i++) - y_current->y_array[i] = array[i]; + new_array[i] = array[i]; vim_free(array); + array = new_array; limit *= 2; - array = y_current->y_array; } str = viminfo_readstring(virp, 1, TRUE); if (str != NULL) array[size++] = str; else + /* error, don't store the result */ do_it = FALSE; } } if (do_it) { + /* free y_array[] */ + for (i = 0; i < y_current->y_size; i++) + vim_free(y_current->y_array[i]); + vim_free(y_current->y_array); + + y_current->y_type = new_type; + y_current->y_width = new_width; + y_current->y_size = size; if (size == 0) { - vim_free(array); y_current->y_array = NULL; } - else if (size < limit) + else { + /* Move the lines from array[] to y_array[]. */ y_current->y_array = (char_u **)alloc((unsigned)(size * sizeof(char_u *))); for (i = 0; i < size; i++) - y_current->y_array[i] = array[i]; - vim_free(array); + { + if (y_current->y_array == NULL) + vim_free(array[i]); + else + y_current->y_array[i] = array[i]; + } } - y_current->y_size = size; - } + } + else + { + /* Free array[] if it was filled. */ + for (i = 0; i < size; i++) + vim_free(array[i]); + } + vim_free(array); + return eof; } diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -742,6 +742,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 560, +/**/ 559, /**/ 558,