Hi 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: ================================================ $ ./vim *** buffer overflow detected ***: ./vim terminated ======= Backtrace: ========= /lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)[0xb7746558] /lib/tls/i686/cmov/libc.so.6[0xb7744680] /lib/tls/i686/cmov/libc.so.6(__strcpy_chk+0x44)[0xb7743944] ./vim[0x80817df] ./vim[0x8082ed1] ./vim[0x8089e2c] ./vim[0x8093ef1] ./vim[0x80b4438] ./vim[0x80b6b73] ./vim[0x80a6960] ./vim[0x80a7181] ./vim[0x80a3c14] ./vim[0x80a3d08] ./vim[0x80ffb7c] /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb7662685] ./vim[0x8052c41] ======= Memory map: ======== 08048000-0823d000 r-xp 00000000 08:04 879094 /tmp/vim7/src/vim 0823d000-0823e000 r--p 001f4000 08:04 879094 /tmp/vim7/src/vim 0823e000-0824b000 rw-p 001f5000 08:04 879094 /tmp/vim7/src/vim 0824b000-08253000 rw-p 0824b000 00:00 0 ... snip... b7975000-b7976000 rw-p 0003c000 08:04 2180173 /usr/lib/libgobject-2.0.so.0.1800.2 b7976000-b79a1000 r-xp 00000000 08:04 2179260 /usr/lib/libfontconfig.so.1.3.0 b79a1000-b79a2000 r--p 0002a000 08:04 2179260 /usr/lib/libfontconfig.so.1.3.0 Vim: Caught deadly signal ABRT0 08:04 2179260 /usr/lib/lib Vim: Finished. Aborted (core dumped) ================================================ Valgrind also detects the following problem (only when compiled with -O3): $ valgrind ./vim ==7840== Memcheck, a memory error detector. ==7840== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al. ==7840== Using LibVEX rev 1854, a library for dynamic binary translation. ==7840== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP. ==7840== Using valgrind-3.3.1-Debian, a dynamic binary instrumentation framework. ==7840== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al. ==7840== For more details, rerun with: -v ==7840== **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) ==7840== by 0x8089E2B: get_func_tv (eval.c:7864) ==7840== by 0x8093EF0: ex_call (eval.c:3315) ==7840== by 0x80B4437: do_one_cmd (ex_docmd.c:2621) ==7840== by 0x80B6B72: do_cmdline (ex_docmd.c:1095) ==7840== by 0x80A695F: do_source (ex_cmds2.c:3114) ==7840== by 0x80A7180: source_callback (ex_cmds2.c:2558) ==7840== by 0x80A3C13: do_in_runtimepath (ex_cmds2.c:2652) ==7840== by 0x80A3D07: source_runtime (ex_cmds2.c:2572) ==7840== ==7840== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 103 from 1) ==7840== malloc/free: in use at exit: 1,699,551 bytes in 11,588 blocks. ==7840== malloc/free: 23,010 allocs, 11,422 frees, 3,331,612 bytes allocated. ==7840== For counts of detected errors, rerun with: -v ==7840== searching for pointers to 11,588 not-freed blocks. ==7840== checked 2,085,980 bytes. ==7840== ==7840== LEAK SUMMARY: ==7840== definitely lost: 0 bytes in 0 blocks. ==7840== possibly lost: 9,198 bytes in 323 blocks. ==7840== still reachable: 1,690,353 bytes in 11,265 blocks. ==7840== suppressed: 0 bytes in 0 blocks. ==7840== Rerun with --leak-check=full to see details of leaked memory. (keep in mind that it's with -O3 so line numbers in stack trace are not accurate) Trying to narrow down further, I found that it's the -finline-functions optimization option of gcc which triggers the crash. The option is turned on with -O3 (among other optimizations). Compiling with following options is enough to trigger the crash: CFLAGS = -O2 -g -finline-functions ... whereas the following options works just fine CFLAGS = -O2 -g 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 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. 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 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 $ gcc --version gcc (Ubuntu 4.3.2-1ubuntu11) 4.3.2 Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Attached patch makes vim work with -O3. -- Dominique --~--~---------~--~----~------------~-------~--~----~ You received this message from the "vim_dev" maillist. For more information, visit http://www.vim.org/maillist.php -~----------~----~----~----~------~----~------~--~---
Index: structs.h =================================================================== RCS file: /cvsroot/vim/vim7/src/structs.h,v retrieving revision 1.81 diff -c -r1.81 structs.h *** structs.h 9 Nov 2008 12:45:25 -0000 1.81 --- structs.h 15 Nov 2008 09:55:01 -0000 *************** *** 1093,1099 **** { 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; --- 1093,1105 ---- { 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 }; typedef struct dictitem_S dictitem_T;