Dominique Pelle wrote:

> I notice that Vim-7.2.40 (huge) crashes on start up when I
> compile it with gcc 4.3.2 with -O3 (that's the default gcc
> version from Ubuntu-8.10), but it works perfectly fine when
> compiled with -O0, -O1 or -O2.
> 
> Here is the crash:

[...]

> **7840** *** strcpy_chk: buffer overflow detected ***: program terminated
> ==7840==    at 0x4027871: VALGRIND_PRINTF_BACKTRACE (valgrind.h:3695)
> ==7840==    by 0x4027A37: __strcpy_chk (mc_replace_strmem.c:614)
> ==7840==    by 0x80817DE: call_user_func (string3.h:106)
> ==7840==    by 0x8082ED0: call_func (eval.c:8017)

[...]

> Adding some printf(), I see that Vim crashes at line 22154 in eval.c
> in the STRCPY(...):
> 
> 21153     v = &fc.fixvar[fixvar_idx++].var;
> 21154     STRCPY(v->di_key, "000");
> 21155     v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
> 
> v is declared as: 'dictitem_T  *v;' with:
> 
> struct dictitem_S
> {
>     typval_T    di_tv;          /* type and value of the variable */
>     char_u      di_flags;       /* flags (only used for variable) */
>     char_u      di_key[1];      /* key (actually longer!) */
> };
> 
> typedef struct dictitem_S dictitem_T;
> 
> 
> So copying "000" in 'char_u di_key[1]' is of course a bit special
> but it's not a bug I think, it's a classic pattern described in:
> 
> http://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/Zero-Length.html#Zero-Length
> 
> There should in practice be no corruption since:
> 
> v = &fc.fixvar[fixvar_idx++].var;
> 
> ... with fixvar defined as:
> 
>   227     struct                      /* fixed variables for arguments */
>   228     {
>   229         dictitem_T      var;            /* variable (without
> room for name) */
>   230         char_u  room[VAR_SHORT_LEN];    /* room for the name */
>   231     } fixvar[FIXVAR_CNT];
> 
> .... with FIXVAR_CNT being defined as  #define FIXVAR_CNT      12

And VAR_SHORT_LEN is 20, so there are 21 bytes available for the key
name.  A bit more if the compiler rounds off struct sizes.

> This code looks OK to me. Maybe it's a bug in gcc or maybe this
> construction is just not portable. I suspect it's a bug in gcc but
> I'm not 100% sure.
> 
> In any case, I found that gcc has an extension to the C language
> which allows to declare the di_key array without a size:
> 
> struct dictitem_S
> {
>     typval_T    di_tv;          /* type and value of the variable */
>     char_u      di_flags;       /* flags (only used for variable) */
> #ifdef __GNUC__
>     /* Declaring di_key[] instead of di_key[1] prevents crashes when
>      * compiling with gcc -O3 */
>     char_u      di_key[];       /* key (actually longer!) */
> #else
>     char_u      di_key[1];      /* key (actually longer!) */
> #endif
> };
> 
> 
> Doing that is enough to make it work with -O3, and also pacifies
> valgrind memory checker. I guess gcc then relaxes the optimization
> for di_key.

Unfortunately this solution only works for the GNU compiler, requiring
#ifdefs.

> There are other places (which I did not change yet) where
> the same problem could possibly happen.  I see at least those:
> 
> $ egrep -n "\[1\].*actually longer" *.c *.h
> eval.c:184:    char_u uf_name[1];     /* name of function (actually longer); 
> can
> memline.c:92:    PTR_EN       pb_pointer[1];  /* list of pointers to blocks
> (actually longer)
> message.c:2164:    char_u     sb_text[1];     /* text to be displayed,
> actually longer */
> misc2.c:3862:    char_u               ffv_fname[1];   /* actually longer */
> spell.c:582:    char_u        wc_word[1];         /* word, actually longer */
> spell.c:4801:    char_u       sb_data[1];     /* data, actually longer */
> spell.c:13081:    char_u      sft_word[1];    /* soundfolded word, actually 
> longer */
> tag.c:1336:   char_u  match[1];       /* actually longer */
> regexp.h:37:    char_u                program[1];             /* actually 
> longer.. */
> structs.h:414:    char_u              b_str[1];       /* contents (actually 
> longer) */
> structs.h:768:    char_u      keyword[1];     /* actually longer */
> structs.h:1101:    char_u     di_key[1];      /* key (actually longer!) */
> 
> 
> I did not fix all those other places, but if you think that the
> propose way to fix is good, I can put it in all those places.

I don't think we need the fix in all those places, as it is only
triggered by using strcpy copying into that space.

Another solution is to use the trick what's done for "self" a few lines
higher:

        v = &fc.fixvar[fixvar_idx++].var;
        name = v->di_key;
        STRCPY(name, "self");

So we can do the same for "000":

    v = &fc.fixvar[fixvar_idx++].var;
    name = v->di_key;
    STRCPY(name, "000");

Can you please verify this also fixes the crash?

> I did not see this bug when using prior version of Ubuntu-8.04.1
> (can't remember which version of gcc it used)
> 
> Interestingly, compiling with -O2 -g -finline-functions also gives
> the following warning:
> 
> gcc -c -I. -Iproto -DHAVE_CONFIG_H -DFEAT_GUI_GTK
> -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include
> -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0
> -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
> -I/usr/include/pixman-1 -I/usr/include/freetype2
> -I/usr/include/libpng12     -O2 -g -finline-functions         -o
> objects/eval.o eval.c
> In function 'strcpy',
>     inlined from 'add_nr_var' at eval.c:21397,
>     inlined from 'call_user_func' at eval.c:21151:
> /usr/include/bits/string3.h:106: warning: call to
> __builtin___strcpy_chk will always overflow destination buffer
> In function 'strcpy',
>     inlined from 'add_nr_var' at eval.c:21397,
>     inlined from 'call_user_func' at eval.c:21169:
> /usr/include/bits/string3.h:106: warning: call to
> __builtin___strcpy_chk will always overflow destination buffer
> In function 'strcpy',
>     inlined from 'add_nr_var' at eval.c:21397,
>     inlined from 'call_user_func' at eval.c:21171:
> /usr/include/bits/string3.h:106: warning: call to
> __builtin___strcpy_chk will always overflow destination buffer

These all look lik add_nr_var() calls.  I'll change the strcpy() there
as well.

So this is my patch.  Let me know if this fixes it with your compiler:

*** ../vim-7.2.040/src/eval.c   Wed Nov 12 15:28:37 2008
--- src/eval.c  Sat Nov 15 12:28:32 2008
***************
*** 21150,21157 ****
      init_var_dict(&fc.l_avars, &fc.l_avars_var);
      add_nr_var(&fc.l_avars, &fc.fixvar[fixvar_idx++].var, "0",
                                (varnumber_T)(argcount - fp->uf_args.ga_len));
      v = &fc.fixvar[fixvar_idx++].var;
!     STRCPY(v->di_key, "000");
      v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
      hash_add(&fc.l_avars.dv_hashtab, DI2HIKEY(v));
      v->di_tv.v_type = VAR_LIST;
--- 21150,21160 ----
      init_var_dict(&fc.l_avars, &fc.l_avars_var);
      add_nr_var(&fc.l_avars, &fc.fixvar[fixvar_idx++].var, "0",
                                (varnumber_T)(argcount - fp->uf_args.ga_len));
+     /* Use "name" to avoid a warning from some compiler that checks the
+      * destination size. */
      v = &fc.fixvar[fixvar_idx++].var;
!     name = v->di_key;
!     STRCPY(name, "000");
      v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
      hash_add(&fc.l_avars.dv_hashtab, DI2HIKEY(v));
      v->di_tv.v_type = VAR_LIST;
***************
*** 21394,21400 ****
      char      *name;
      varnumber_T nr;
  {
!     STRCPY(v->di_key, name);
      v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
      hash_add(&dp->dv_hashtab, DI2HIKEY(v));
      v->di_tv.v_type = VAR_NUMBER;
--- 21397,21409 ----
      char      *name;
      varnumber_T nr;
  {
!     char *nname;
! 
!     /* When inlining and the compiler adds a check for the destination of
!      * strcpy() it may complain about di_key being too small.  Happens with
!      * GCC 4.3.2 with -O3.  Use an intermediate variable to avoid that. */
!     nname = v->di_key;
!     STRCPY(nname, name);
      v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
      hash_add(&dp->dv_hashtab, DI2HIKEY(v));
      v->di_tv.v_type = VAR_NUMBER;
*** ../vim-7.2.040/src/version.c        Wed Nov 12 16:04:43 2008
--- src/version.c       Wed Nov 12 16:54:35 2008
***************
*** 678,679 ****
--- 678,681 ----
  {   /* Add new patch number below this line */
+ /**/
+     41,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
257. Your "hundred-and-one" lists include well over 101 items, since you
     automatically interpret all numbers in hexadecimal notation.
     (hex 101 = decimal 257)

 /// 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
-~----------~----~----~----~------~----~------~--~---

Raspunde prin e-mail lui