Hi
I can reproduce a bug (use of freed memory) in Vim-7.2.284
on Linux x86 as follows:
1/ Start vim with valgrind:
$ cd vim7/src
$ valgrind --leak-check=yes \
--num-callers=50 ./vim --noplugin -u NONE 2> vg.log
2/ Enter the 2 following Ex commands:
:redir @"
:reg
3/ Observe in vg.log the following errors as soon as :reg is being
executed:
==13408== Invalid read of size 1
==13408== at 0x40276F8: memmove (mc_replace_strmem.c:517)
==13408== by 0x813CDA1: str_to_reg (ops.c:6157)
==13408== by 0x813CB6F: write_reg_contents_ex (ops.c:6052)
==13408== by 0x813C9E1: write_reg_contents (ops.c:5981)
==13408== by 0x8104C0E: redir_write (message.c:3046)
==13408== by 0x8103034: msg_puts_attr_len (message.c:1803)
==13408== by 0x8102715: msg_outtrans_len_attr (message.c:1402)
==13408== by 0x810243D: msg_outtrans_len (message.c:1291)
==13408== by 0x81398A3: ex_display (ops.c:4013)
==13408== by 0x80A7548: do_one_cmd (ex_docmd.c:2627)
==13408== by 0x80A4D7F: do_cmdline (ex_docmd.c:1096)
==13408== by 0x8090CB8: call_user_func (eval.c:21292)
==13408== by 0x807CE17: call_func (eval.c:8123)
==13408== by 0x807CA5B: get_func_tv (eval.c:7969)
==13408== by 0x8078DF3: eval7 (eval.c:5021)
==13408== by 0x80786FC: eval6 (eval.c:4688)
==13408== by 0x80782E8: eval5 (eval.c:4504)
==13408== by 0x8077839: eval4 (eval.c:4199)
==13408== by 0x8077691: eval3 (eval.c:4111)
==13408== by 0x807751D: eval2 (eval.c:4040)
==13408== by 0x807734D: eval1 (eval.c:3965)
==13408== by 0x80772B4: eval0 (eval.c:3922)
==13408== by 0x8073AC5: ex_let (eval.c:1837)
==13408== by 0x80A7548: do_one_cmd (ex_docmd.c:2627)
==13408== by 0x80A4D7F: do_cmdline (ex_docmd.c:1096)
==13408== by 0x80A2FE3: do_source (ex_cmds2.c:3116)
==13408== by 0x80EA44D: source_startup_scripts (main.c:2778)
==13408== by 0x80E74DB: main (main.c:563)
==13408== Address 0x548108c is 4 bytes inside a block of size 32 free'd
==13408== at 0x4024E5A: free (vg_replace_malloc.c:323)
==13408== by 0x8116C67: vim_free (misc2.c:1639)
==13408== by 0x813CD7A: str_to_reg (ops.c:6155)
==13408== by 0x813CB6F: write_reg_contents_ex (ops.c:6052)
==13408== by 0x813C9E1: write_reg_contents (ops.c:5981)
==13408== by 0x8104C0E: redir_write (message.c:3046)
==13408== by 0x8103034: msg_puts_attr_len (message.c:1803)
==13408== by 0x8102715: msg_outtrans_len_attr (message.c:1402)
==13408== by 0x810243D: msg_outtrans_len (message.c:1291)
==13408== by 0x81398A3: ex_display (ops.c:4013)
==13408== by 0x80A7548: do_one_cmd (ex_docmd.c:2627)
==13408== by 0x80A4D7F: do_cmdline (ex_docmd.c:1096)
==13408== by 0x8090CB8: call_user_func (eval.c:21292)
==13408== by 0x807CE17: call_func (eval.c:8123)
==13408== by 0x807CA5B: get_func_tv (eval.c:7969)
==13408== by 0x8078DF3: eval7 (eval.c:5021)
==13408== by 0x80786FC: eval6 (eval.c:4688)
==13408== by 0x80782E8: eval5 (eval.c:4504)
==13408== by 0x8077839: eval4 (eval.c:4199)
==13408== by 0x8077691: eval3 (eval.c:4111)
==13408== by 0x807751D: eval2 (eval.c:4040)
==13408== by 0x807734D: eval1 (eval.c:3965)
==13408== by 0x80772B4: eval0 (eval.c:3922)
==13408== by 0x8073AC5: ex_let (eval.c:1837)
==13408== by 0x80A7548: do_one_cmd (ex_docmd.c:2627)
==13408== by 0x80A4D7F: do_cmdline (ex_docmd.c:1096)
==13408== by 0x80A2FE3: do_source (ex_cmds2.c:3116)
==13408== by 0x80EA44D: source_startup_scripts (main.c:2778)
==13408== by 0x80E74DB: main (main.c:563)
(several more errors follow after that)
The bug happens because function ex_display() is printing
all registers and while doing so, a register can be modified
if output is redirected to register (causing access to freed
memory).
Attached patch fixes it by making function ex_display()
output a copy of the register. Please review it.
I noticed this issue when trying Tony's .vimrc available at:
http://vim.wikia.com/wiki/User:Tonymec/vimrc
The bug happens in function TestForX() in his vimrc file.
Cheers
-- Dominique
--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---
Index: ops.c
===================================================================
RCS file: /cvsroot/vim/vim7/src/ops.c,v
retrieving revision 1.76
diff -c -r1.76 ops.c
*** ops.c 3 Nov 2009 15:44:21 -0000 1.76
--- ops.c 7 Nov 2009 17:13:42 -0000
***************
*** 990,995 ****
--- 990,1039 ----
}
/*
+ * Return a deep copy of register reg. Memory is dynamically allocated,
+ * use free_register() to free the copy.
+ */
+ static struct yankreg *
+ copy_register(reg)
+ struct yankreg* reg;
+ {
+ struct yankreg *copy;
+ int i;
+
+ copy = (struct yankreg *)alloc((unsigned)sizeof(struct yankreg));
+ if (copy == NULL)
+ return NULL;
+
+ *copy = *reg;
+ copy->y_array = (char_u **)alloc((unsigned)reg->y_size*sizeof(char *));
+ if (copy->y_array == NULL)
+ {
+ vim_free(copy);
+ return NULL;
+ }
+ for (i = 0; i < reg->y_size; ++i)
+ copy->y_array[i] = vim_strsave(reg->y_array[i]);
+
+ return copy;
+ }
+
+ /*
+ * Free a register previous allocated with copy_register().
+ */
+ static void
+ free_register(reg)
+ struct yankreg* reg;
+ {
+ int i;
+
+ for (i = 0; i < reg->y_size; ++i)
+ vim_free(reg->y_array[i]);
+ vim_free(reg->y_array);
+ vim_free(reg);
+ }
+
+
+ /*
* Put "reg" into register "name". Free any previous contents and "reg".
*/
void
***************
*** 3952,3957 ****
--- 3996,4002 ----
long j;
char_u *p;
struct yankreg *yb;
+ struct yankreg *copy_reg;
int name;
int attr;
char_u *arg = eap->arg;
***************
*** 3990,4025 ****
}
else
yb = &(y_regs[i]);
if (yb->y_array != NULL)
{
! msg_putchar('\n');
! msg_putchar('"');
! msg_putchar(name);
! MSG_PUTS(" ");
! n = (int)Columns - 6;
! for (j = 0; j < yb->y_size && n > 1; ++j)
! {
! if (j)
! {
! MSG_PUTS_ATTR("^J", attr);
! n -= 2;
! }
! for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0; ++p)
{
#ifdef FEAT_MBYTE
! clen = (*mb_ptr2len)(p);
#endif
! msg_outtrans_len(p, clen);
#ifdef FEAT_MBYTE
! p += clen - 1;
#endif
}
}
! if (n > 1 && yb->y_type == MLINE)
! MSG_PUTS_ATTR("^J", attr);
! out_flush(); /* show one line at a time */
}
ui_breakcheck();
}
--- 4035,4080 ----
}
else
yb = &(y_regs[i]);
+
if (yb->y_array != NULL)
{
! /* Output a copy of register yb, rather than register yb itself
! * since yb may be overwritten while outputting it in case of
! * redirection to register. */
! copy_reg = copy_register(yb);
! if (copy_reg != NULL)
! {
! msg_putchar('\n');
! msg_putchar('"');
! msg_putchar(name);
! MSG_PUTS(" ");
! n = (int)Columns - 6;
! for (j = 0; j < copy_reg->y_size && n > 1; ++j)
{
+ if (j)
+ {
+ MSG_PUTS_ATTR("^J", attr);
+ n -= 2;
+ }
+ for (p = copy_reg->y_array[j]; *p && (n -= ptr2cells(p)) >= 0; ++p)
+ {
#ifdef FEAT_MBYTE
! clen = (*mb_ptr2len)(p);
#endif
! msg_outtrans_len(p, clen);
#ifdef FEAT_MBYTE
! p += clen - 1;
#endif
+ }
}
+ if (n > 1 && copy_reg->y_type == MLINE)
+ MSG_PUTS_ATTR("^J", attr);
+ out_flush(); /* show one line at a time */
}
! free_register(copy_reg);
}
+
ui_breakcheck();
}
***************
*** 6089,6095 ****
long maxlen;
#endif
! if (y_ptr->y_array == NULL) /* NULL means emtpy register */
y_ptr->y_size = 0;
/*
--- 6144,6150 ----
long maxlen;
#endif
! if (y_ptr->y_array == NULL) /* NULL means empty register */
y_ptr->y_size = 0;
/*