Dominique Pelle wrote:
> >> Testing autocommands, I see that Vim-7.2.107 (and older)
> >> is using memory already freed when doing silly autocommands
> >> such as:
> >>
> >> $ touch foobar
> >> $ valgrind ./vim -u NONE -c 'au! BufReadPre * cd /tmp' \
> >> -c 'e foobar' 2> vg.log
> >>
> >> In vg.log, I then see the following error:
> >>
> >> ==15058== Syscall param open(filename) points to unaddressable byte(s)
> >> ==15058== at 0x40007D2: (within /lib/ld-2.8.90.so)
> >> ==15058== by 0x805365E: open_buffer (buffer.c:130)
> >> ==15058== by 0x8098548: do_ecmd (ex_cmds.c:3655)
> >> ==15058== by 0x80AE8E9: do_exedit (ex_docmd.c:7557)
> >> ==15058== by 0x80AE560: ex_edit (ex_docmd.c:7452)
> >> ==15058== by 0x80A6FE7: do_one_cmd (ex_docmd.c:2622)
> >> ==15058== by 0x80A4867: do_cmdline (ex_docmd.c:1096)
> >> ==15058== by 0x80A3F00: do_cmdline_cmd (ex_docmd.c:702)
> >> ==15058== by 0x80E8A07: exe_commands (main.c:2693)
> >> ==15058== by 0x80E63A7: main (main.c:874)
> >> ==15058== Address 0x54312d4 is 4 bytes inside a block of size 11 free'd
> >> ==15058== at 0x4024E5A: free (vg_replace_malloc.c:323)
> >> ==15058== by 0x8114D5D: vim_free (misc2.c:1631)
> >> ==15058== by 0x80C97DF: shorten_fnames (fileio.c:5715)
> >> ==15058== by 0x80AF1A9: ex_cd (ex_docmd.c:7942)
> >> ==15058== by 0x80A6FE7: do_one_cmd (ex_docmd.c:2622)
> >> ==15058== by 0x80A4867: do_cmdline (ex_docmd.c:1096)
> >> ==15058== by 0x80CD35A: apply_autocmds_group (fileio.c:8853)
> >> ==15058== by 0x80CCD9B: apply_autocmds_exarg (fileio.c:8481)
> >> ==15058== by 0x80C2246: readfile (fileio.c:723)
> >> ==15058== by 0x805365E: open_buffer (buffer.c:130)
> >> ==15058== by 0x8098548: do_ecmd (ex_cmds.c:3655)
> >> ==15058== by 0x80AE8E9: do_exedit (ex_docmd.c:7557)
>
> [...snip...]
>
> >
> > Thanks. It's in the todo list.
>
>
> I found another case of an autocommand which also causes
> to use freed memory and the proposed patch in my previous
> email did not help to fix it. Here is how to reproduce it:
>
> # Open a file foobar in vim to create swap file .foobar.swp
> $ vim foobar
>
> # In another terminal...
> $ vim -u NONE
> :au! SwapExists * cd /tmp
> :e foobar
>
> ... and valgrind complains about use of freed memory:
>
> ==17226== Syscall param open(filename) points to unaddressable byte(s)
> ==17226== at 0x40007D2: (within /lib/ld-2.8.90.so)
> ==17226== by 0x805365E: open_buffer (buffer.c:130)
> ==17226== by 0x8098548: do_ecmd (ex_cmds.c:3655)
> ==17226== by 0x80AE8E9: do_exedit (ex_docmd.c:7557)
> ==17226== by 0x80AE560: ex_edit (ex_docmd.c:7452)
> ==17226== by 0x80A6FE7: do_one_cmd (ex_docmd.c:2622)
> ==17226== by 0x80A4867: do_cmdline (ex_docmd.c:1096)
> ==17226== by 0x812A4BC: nv_colon (normal.c:5233)
> ==17226== by 0x8123B40: normal_cmd (normal.c:1200)
> ==17226== by 0x80E6969: main_loop (main.c:1180)
> ==17226== by 0x80E64B6: main (main.c:939)
> ==17226== Address 0x543644c is 4 bytes inside a block of size 11 free'd
> ==17226== at 0x4024E5A: free (vg_replace_malloc.c:323)
> ==17226== by 0x8114D5D: vim_free (misc2.c:1631)
> ==17226== by 0x80C97DF: shorten_fnames (fileio.c:5715)
> ==17226== by 0x80AF1A9: ex_cd (ex_docmd.c:7942)
> ==17226== by 0x80A6FE7: do_one_cmd (ex_docmd.c:2622)
> ==17226== by 0x80A4867: do_cmdline (ex_docmd.c:1096)
> ==17226== by 0x80CD35A: apply_autocmds_group (fileio.c:8853)
> ==17226== by 0x80CCD5D: apply_autocmds (fileio.c:8464)
> ==17226== by 0x80FA022: do_swapexists (memline.c:3770)
> ==17226== by 0x80FA93D: findswapname (memline.c:4130)
> ==17226== by 0x80F4A88: ml_open_file (memline.c:553)
> ==17226== by 0x80F4BAE: check_need_swap (memline.c:605)
> ==17226== by 0x80C206F: readfile (fileio.c:670)
> ==17226== by 0x805365E: open_buffer (buffer.c:130)
> ==17226== by 0x8098548: do_ecmd (ex_cmds.c:3655)
> ==17226== by 0x80AE8E9: do_exedit (ex_docmd.c:7557)
> ==17226== by 0x80AE560: ex_edit (ex_docmd.c:7452)
> ==17226== by 0x80A6FE7: do_one_cmd (ex_docmd.c:2622)
> ==17226== by 0x80A4867: do_cmdline (ex_docmd.c:1096)
> ==17226== by 0x812A4BC: nv_colon (normal.c:5233)
> ==17226== by 0x8123B40: normal_cmd (normal.c:1200)
> ==17226== by 0x80E6969: main_loop (main.c:1180)
> ==17226== by 0x80E64B6: main (main.c:939)
>
> The problem happens here because readfile() in fileio.c
> calls check_need_swap(newfile); at line fileio.c:670 and
> this function can trigger an autocommand (SwapExists)
> which can potentially free or realloc curbuf->b_fname
> or curbuf->b_ffname.
>
> If parameters fname or sfname of readfile() are aliased to
> curbuf->b_fname or curbuf->b_ffname, then readfile() may
> read free memory after the autocommand has been executed.
>
> The new attached patch fixes this new problem and also fixes
> the 2 errors described in previous email. I'm not sure how
> clean the fix is. Please review it. At least it should help to
> understand what the problem is.
Thanks for the patch. I thought of catching the problem at the cause,
by disallowing the autocommands to do something that will cause trouble.
However, it's very difficult to catch all situations.
So I think we can do both: disallow autocommands to do things that are
clearly wrong, and give an error if we notice side effects. That should
be safe.
Please have a look at the patch below. There might still be other
autocommands that cause trouble. If you see one, please report.
*** ../vim-7.2.127/src/ex_getln.c Fri Nov 28 10:59:57 2008
--- src/ex_getln.c Sun Mar 1 00:13:15 2009
***************
*** 2000,2007 ****
#if defined(FEAT_AUTOCMD) || defined(PROTO)
/*
! * Check if "curbuf_lock" is set and return TRUE when it is and give an error
! * message.
*/
int
curbuf_locked()
--- 2000,2007 ----
#if defined(FEAT_AUTOCMD) || defined(PROTO)
/*
! * Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is
! * and give an error message.
*/
int
curbuf_locked()
***************
*** 2011,2016 ****
--- 2011,2031 ----
EMSG(_("E788: Not allowed to edit another buffer now"));
return TRUE;
}
+ return allbuf_locked();
+ }
+
+ /*
+ * Check if "allbuf_lock" is set and return TRUE when it is and give an error
+ * message.
+ */
+ int
+ allbuf_locked()
+ {
+ if (allbuf_lock > 0)
+ {
+ EMSG(_("E811: Not allowed to change buffer information now"));
+ return TRUE;
+ }
return FALSE;
}
#endif
*** ../vim-7.2.127/src/globals.h Tue Jan 6 16:13:42 2009
--- src/globals.h Sun Mar 1 00:02:42 2009
***************
*** 616,621 ****
--- 616,626 ----
EXTERN int curbuf_lock INIT(= 0);
/* non-zero when the current buffer can't be
* changed. Used for FileChangedRO. */
+ EXTERN int allbuf_lock INIT(= 0);
+ /* non-zero when no buffer name can be
+ * changed, no buffer can be deleted and
+ * current directory can't be changed.
+ * Used for SwapExists et al. */
#endif
#ifdef FEAT_EVAL
# define HAVE_SANDBOX
*** ../vim-7.2.127/src/fileio.c Wed Dec 31 16:20:54 2008
--- src/fileio.c Sun Mar 1 02:11:09 2009
***************
*** 69,75 ****
static int au_find_group __ARGS((char_u *name));
# define AUGROUP_DEFAULT -1 /* default autocmd group */
! # define AUGROUP_ERROR -2 /* errornouse autocmd group */
# define AUGROUP_ALL -3 /* all autocmd groups */
#endif
--- 69,75 ----
static int au_find_group __ARGS((char_u *name));
# define AUGROUP_DEFAULT -1 /* default autocmd group */
! # define AUGROUP_ERROR -2 /* erroneous autocmd group */
# define AUGROUP_ALL -3 /* all autocmd groups */
#endif
***************
*** 295,300 ****
--- 295,313 ----
int conv_restlen = 0; /* nr of bytes in conv_rest[] */
#endif
+ #ifdef FEAT_AUTOCMD
+ /* Remember the initial values of curbuf, curbuf->b_ffname and
+ * curbuf->b_fname to detect whether they are altered as a result of
+ * executing nasaty autocommands. Also check if "fname" and "sfname"
+ * point to one of these values. */
+ buf_T *old_curbuf = curbuf;
+ char_u *old_b_ffname = curbuf->b_ffname;
+ char_u *old_b_fname = curbuf->b_fname;
+ int using_b_ffname = (fname == curbuf->b_ffname)
+ || (sfname == curbuf->b_ffname);
+ int using_b_fname = (fname == curbuf->b_fname)
+ || (sfname == curbuf->b_fname);
+ #endif
write_no_eol_lnum = 0; /* in case it was set by the previous read */
/*
***************
*** 668,673 ****
--- 681,697 ----
#endif
{
check_need_swap(newfile);
+ #ifdef FEAT_AUTOCMD
+ if (!read_stdin && (curbuf != old_curbuf
+ || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
+ || (using_b_fname && (old_b_fname != curbuf->b_fname))))
+ {
+ EMSG(_("E812: Autocommands changed buffer or buffer name"));
+ if (!read_buffer)
+ close(fd);
+ return FAIL;
+ }
+ #endif
#ifdef UNIX
/* Set swap file protection bits after creating it. */
if (swap_mode > 0 && curbuf->b_ml.ml_mfp->mf_fname != NULL)
***************
*** 698,704 ****
{
int m = msg_scroll;
int n = msg_scrolled;
- buf_T *old_curbuf = curbuf;
/*
* The file must be closed again, the autocommands may want to change
--- 722,727 ----
***************
*** 740,747 ****
--- 763,775 ----
/*
* Don't allow the autocommands to change the current buffer.
* Try to re-open the file.
+ *
+ * Don't allow the autocommands to change the buffer name either
+ * (cd for example) if it invalidates fname or sfname.
*/
if (!read_stdin && (curbuf != old_curbuf
+ || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
+ || (using_b_fname && (old_b_fname != curbuf->b_fname))
|| (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) < 0))
{
--no_wait_return;
***************
*** 6320,6326 ****
if (!stuff_empty() || global_busy || !typebuf_typed()
#ifdef FEAT_AUTOCMD
! || autocmd_busy || curbuf_lock > 0
#endif
)
need_check_timestamps = TRUE; /* check later */
--- 6348,6354 ----
if (!stuff_empty() || global_busy || !typebuf_typed()
#ifdef FEAT_AUTOCMD
! || autocmd_busy || curbuf_lock > 0 || allbuf_lock > 0
#endif
)
need_check_timestamps = TRUE; /* check later */
***************
*** 6522,6529 ****
--- 6550,6559 ----
set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
# endif
+ ++allbuf_lock;
n = apply_autocmds(EVENT_FILECHANGEDSHELL,
buf->b_fname, buf->b_fname, FALSE, buf);
+ --allbuf_lock;
busy = FALSE;
if (n)
{
*** ../vim-7.2.127/src/proto/ex_getln.pro Fri Nov 28 10:59:57 2008
--- src/proto/ex_getln.pro Sun Mar 1 00:27:12 2009
***************
*** 4,9 ****
--- 4,10 ----
int text_locked __ARGS((void));
void text_locked_msg __ARGS((void));
int curbuf_locked __ARGS((void));
+ int allbuf_locked __ARGS((void));
char_u *getexline __ARGS((int c, void *dummy, int indent));
char_u *getexmodeline __ARGS((int promptc, void *dummy, int indent));
int cmdline_overstrike __ARGS((void));
--
Amazing but true: If all the salmon caught in Canada in one year were laid
end to end across the Sahara Desert, the smell would be absolutely awful.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ download, build and distribute -- http://www.A-A-P.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---