To: vim-dev@vim.org Subject: Patch 6.2.295 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit ------------ Patch 6.2.295 Problem: When in debug mode, receiving a message from a remote client causes a crash. Evaluating an expression causes Vim to wait for "cont" to be typed, without a prompt. (Hari Krishna Dara) Solution: Disable debugging when evaluating an expression for a client. (Michael Geddes) Don't try reading into the typehead buffer when it may have been filled in another way. Files: src/ex_getln.c, src/getchar.c, src/if_xcmdsrv.c, src/main.c, src/misc1.c, src/proto/getchar.pro, src/proto/main.pro, src/proto/os_unix.pro, src/proto/ui.pro, src/structs.h, src/os_unix.c, src/ui.c *** ../vim-6.2.294/src/ex_getln.c Tue Feb 24 15:23:58 2004 --- src/ex_getln.c Sat Feb 28 16:33:29 2004 *************** *** 1834,1840 **** p = (char_u *)line_ga.ga_data + line_ga.ga_len; /* Get one character (inchar gets a third of maxlen characters!) */ ! len = inchar(p + off, 3, -1L); if (len < 0) continue; /* end of input script reached */ /* for a special character, we need at least three characters */ --- 1834,1840 ---- p = (char_u *)line_ga.ga_data + line_ga.ga_len; /* Get one character (inchar gets a third of maxlen characters!) */ ! len = inchar(p + off, 3, -1L, 0); if (len < 0) continue; /* end of input script reached */ /* for a special character, we need at least three characters */ *** ../vim-6.2.294/src/getchar.c Tue Feb 17 21:46:46 2004 --- src/getchar.c Sun Feb 29 14:24:23 2004 *************** *** 433,439 **** * of an escape sequence. * In an xterm we get one char at a time and we have to get them all. */ ! while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L) != 0) ; typebuf.tb_off = MAXMAPLEN; typebuf.tb_len = 0; --- 433,440 ---- * of an escape sequence. * In an xterm we get one char at a time and we have to get them all. */ ! while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L, ! typebuf.tb_change_cnt) != 0) ; typebuf.tb_off = MAXMAPLEN; typebuf.tb_len = 0; *************** *** 860,866 **** /* * Initialize typebuf.tb_buf to point to typebuf_init. ! * Alloc() cannot be used here: In out-of-memory situations it would * be impossible to type anything. */ static void --- 861,867 ---- /* * Initialize typebuf.tb_buf to point to typebuf_init. ! * alloc() cannot be used here: In out-of-memory situations it would * be impossible to type anything. */ static void *************** *** 873,878 **** --- 874,880 ---- typebuf.tb_buflen = TYPELEN_INIT; typebuf.tb_len = 0; typebuf.tb_off = 0; + typebuf.tb_change_cnt = 1; } } *************** *** 910,915 **** --- 912,919 ---- int nrm; init_typebuf(); + if (++typebuf.tb_change_cnt == 0) + typebuf.tb_change_cnt = 1; addlen = (int)STRLEN(str); /* *************** *** 1013,1018 **** --- 1017,1041 ---- } /* + * Return TRUE if the typeahead buffer was changed (while waiting for a + * character to arrive). Happens when a message was received from a client. + * But check in a more generic way to avoid trouble: When "typebuf.tb_buf" + * changed it was reallocated and the old pointer can no longer be used. + * Or "typebuf.tb_off" may have been changed and we would overwrite characters + * that was just added. + */ + int + typebuf_changed(tb_change_cnt) + int tb_change_cnt; /* old value of typebuf.tb_change_cnt */ + { + return (tb_change_cnt != 0 && (typebuf.tb_change_cnt != tb_change_cnt + #ifdef FEAT_CLIENTSERVER + || received_from_client + #endif + )); + } + + /* * Return TRUE if there are no characters in the typeahead buffer that have * not been typed (result from a mapping or come from ":normal"). */ *************** *** 1106,1111 **** --- 1129,1136 ---- * typeahead buffer. */ received_from_client = FALSE; #endif + if (++typebuf.tb_change_cnt == 0) + typebuf.tb_change_cnt = 1; } /* *************** *** 1185,1190 **** --- 1210,1217 ---- typebuf.tb_maplen = 0; typebuf.tb_silent = 0; typebuf.tb_no_abbr_cnt = 0; + if (++typebuf.tb_change_cnt == 0) + typebuf.tb_change_cnt = 1; return OK; } *************** *** 1769,1777 **** if (got_int) { /* flush all input */ ! c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L); /* ! * If inchar returns TRUE (script file was active) or we * are inside a mapping, get out of insert mode. * Otherwise we behave like having gotten a CTRL-C. * As a result typing CTRL-C in insert mode will --- 1796,1805 ---- if (got_int) { /* flush all input */ ! c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L, ! typebuf.tb_change_cnt); /* ! * If inchar() returns TRUE (script file was active) or we * are inside a mapping, get out of insert mode. * Otherwise we behave like having gotten a CTRL-C. * As a result typing CTRL-C in insert mode will *************** *** 2235,2242 **** && (State & INSERT) && (p_timeout || (keylen == KL_PART_KEY && p_ttimeout)) && (c = inchar(typebuf.tb_buf + typebuf.tb_off ! + typebuf.tb_len, 3, 25L)) ! == 0) { colnr_T col = 0, vcol; char_u *ptr; --- 2263,2270 ---- && (State & INSERT) && (p_timeout || (keylen == KL_PART_KEY && p_ttimeout)) && (c = inchar(typebuf.tb_buf + typebuf.tb_off ! + typebuf.tb_len, 3, 25L, ! typebuf.tb_change_cnt)) == 0) { colnr_T col = 0, vcol; char_u *ptr; *************** *** 2466,2472 **** ? -1L : ((keylen == KL_PART_KEY && p_ttm >= 0) ? p_ttm ! : p_tm))); #ifdef FEAT_CMDL_INFO if (i != 0) --- 2494,2500 ---- ? -1L : ((keylen == KL_PART_KEY && p_ttm >= 0) ? p_ttm ! : p_tm)), typebuf.tb_change_cnt); #ifdef FEAT_CMDL_INFO if (i != 0) *************** *** 2549,2557 **** * 1. a scriptfile * 2. the keyboard * ! * As much characters as we can get (upto 'maxlen') are put in buf and * NUL terminated (buffer length must be 'maxlen' + 1). ! * Minimum for 'maxlen' is 3!!!! * * If we got an interrupt all input is read until none is available. * --- 2577,2590 ---- * 1. a scriptfile * 2. the keyboard * ! * As much characters as we can get (upto 'maxlen') are put in "buf" and * NUL terminated (buffer length must be 'maxlen' + 1). ! * Minimum for "maxlen" is 3!!!! ! * ! * "tb_change_cnt" is the value of typebuf.tb_change_cnt if "buf" points into ! * it. When typebuf.tb_change_cnt changes (e.g., when a message is received ! * from a remote client) "buf" can no longer be used. "tb_change_cnt" is 0 ! * otherwise. * * If we got an interrupt all input is read until none is available. * *************** *** 2562,2573 **** * Return the number of obtained characters. * Return -1 when end of input script reached. */ - int ! inchar(buf, maxlen, wait_time) char_u *buf; int maxlen; long wait_time; /* milli seconds */ { int len = 0; /* init for GCC */ int retesc = FALSE; /* return ESC with gotint */ --- 2595,2606 ---- * Return the number of obtained characters. * Return -1 when end of input script reached. */ int ! inchar(buf, maxlen, wait_time, tb_change_cnt) char_u *buf; int maxlen; long wait_time; /* milli seconds */ + int tb_change_cnt; { int len = 0; /* init for GCC */ int retesc = FALSE; /* return ESC with gotint */ *************** *** 2648,2654 **** for (;;) { ! len = ui_inchar(dum, DUM_LEN, 0L); if (len == 0 || (len == 1 && dum[0] == 3)) break; } --- 2681,2687 ---- for (;;) { ! len = ui_inchar(dum, DUM_LEN, 0L, 0); if (len == 0 || (len == 1 && dum[0] == 3)) break; } *************** *** 2665,2672 **** * Fill up to a third of the buffer, because each character may be * tripled below. */ ! len = ui_inchar(buf, maxlen / 3, wait_time); } return fix_input_buffer(buf, len, script_char >= 0); } --- 2698,2708 ---- * Fill up to a third of the buffer, because each character may be * tripled below. */ ! len = ui_inchar(buf, maxlen / 3, wait_time, tb_change_cnt); } + + if (typebuf_changed(tb_change_cnt)) + return 0; return fix_input_buffer(buf, len, script_char >= 0); } *** ../vim-6.2.294/src/if_xcmdsrv.c Thu Jul 24 21:52:31 2003 --- src/if_xcmdsrv.c Fri Feb 27 17:33:19 2004 *************** *** 388,396 **** { char_u *ret; ! ++emsg_skip; ! ret = eval_to_string(cmd, NULL); ! --emsg_skip; if (result != NULL) { if (ret == NULL) --- 388,394 ---- { char_u *ret; ! ret = eval_client_expr_to_string(cmd); if (result != NULL) { if (ret == NULL) *************** *** 1238,1248 **** if (asKeys) server_to_input_buf(script); else ! { ! ++emsg_skip; ! res = eval_to_string(script, NULL); ! --emsg_skip; ! } } if (resWindow != None) { --- 1236,1242 ---- if (asKeys) server_to_input_buf(script); else ! res = eval_client_expr_to_string(script); } if (resWindow != None) { *** ../vim-6.2.294/src/main.c Thu Feb 19 14:43:37 2004 --- src/main.c Fri Feb 27 17:29:56 2004 *************** *** 3094,3099 **** --- 3102,3134 ---- /* Let input_available() know we inserted text in the typeahead buffer. */ received_from_client = TRUE; } + + /* + * Evaluate an expression that the client sent to a string. + * Handles disabling error messages and disables debugging, otherwise Vim + * hangs, waiting for "cont" to be typed. + */ + char_u * + eval_client_expr_to_string(expr) + char_u *expr; + { + char_u *res; + int save_dbl = debug_break_level; + int save_ro = redir_off; + + debug_break_level = -1; + redir_off = 0; + ++emsg_skip; + + res = eval_to_string(expr, NULL); + + debug_break_level = save_dbl; + redir_off = save_ro; + --emsg_skip; + + return res; + } + /* * Make our basic server name: use the specified "arg" if given, otherwise use *** ../vim-6.2.294/src/misc1.c Sun Feb 15 13:44:45 2004 --- src/misc1.c Sat Feb 28 16:38:02 2004 *************** *** 2771,2777 **** * insert a key code into (max 5 chars plus NUL). And * fix_input_buffer() can triple the number of bytes. */ n = ui_inchar(buf + len, (CBUFLEN - 6 - len) / 3, ! len == 0 ? -1L : 100L); if (n > 0) { /* Replace zero and CSI by a special key code. */ --- 2783,2789 ---- * insert a key code into (max 5 chars plus NUL). And * fix_input_buffer() can triple the number of bytes. */ n = ui_inchar(buf + len, (CBUFLEN - 6 - len) / 3, ! len == 0 ? -1L : 100L, 0); if (n > 0) { /* Replace zero and CSI by a special key code. */ *** ../vim-6.2.294/src/proto/getchar.pro Sun Jun 1 12:26:10 2003 --- src/proto/getchar.pro Sat Feb 28 16:40:34 2004 *************** *** 21,26 **** --- 21,27 ---- int start_redo_ins __ARGS((void)); void stop_redo_ins __ARGS((void)); int ins_typebuf __ARGS((char_u *str, int noremap, int offset, int nottyped, int silent)); + int typebuf_changed __ARGS((int tb_change_cnt)); int typebuf_typed __ARGS((void)); int typebuf_maplen __ARGS((void)); void del_typebuf __ARGS((int len, int offset)); *************** *** 39,45 **** int vpeekc_any __ARGS((void)); int char_avail __ARGS((void)); void vungetc __ARGS((int c)); ! int inchar __ARGS((char_u *buf, int maxlen, long wait_time)); int fix_input_buffer __ARGS((char_u *buf, int len, int script)); int input_available __ARGS((void)); int do_map __ARGS((int maptype, char_u *arg, int mode, int abbrev)); --- 40,46 ---- int vpeekc_any __ARGS((void)); int char_avail __ARGS((void)); void vungetc __ARGS((int c)); ! int inchar __ARGS((char_u *buf, int maxlen, long wait_time, int tb_change_cnt)); int fix_input_buffer __ARGS((char_u *buf, int len, int script)); int input_available __ARGS((void)); int do_map __ARGS((int maptype, char_u *arg, int mode, int abbrev)); *** ../vim-6.2.294/src/proto/main.pro Sun Jun 1 12:26:13 2003 --- src/proto/main.pro Sat Feb 28 16:40:40 2004 *************** *** 8,13 **** --- 8,14 ---- void time_pop __ARGS((void *tp)); void time_msg __ARGS((char *msg, void *tv_start)); void server_to_input_buf __ARGS((char_u *str)); + char_u *eval_client_expr_to_string __ARGS((char_u *expr)); int toF_TyA __ARGS((int c)); int fkmap __ARGS((int c)); void conv_to_pvim __ARGS((void)); *** ../vim-6.2.294/src/proto/os_unix.pro Sun Jun 1 12:26:18 2003 --- src/proto/os_unix.pro Sat Feb 28 16:40:46 2004 *************** *** 1,6 **** /* os_unix.c */ void mch_write __ARGS((char_u *s, int len)); ! int mch_inchar __ARGS((char_u *buf, int maxlen, long wtime)); int mch_char_avail __ARGS((void)); long_u mch_total_mem __ARGS((int special)); void mch_delay __ARGS((long msec, int ignoreinput)); --- 1,6 ---- /* os_unix.c */ void mch_write __ARGS((char_u *s, int len)); ! int mch_inchar __ARGS((char_u *buf, int maxlen, long wtime, int tb_change_cnt)); int mch_char_avail __ARGS((void)); long_u mch_total_mem __ARGS((int special)); void mch_delay __ARGS((long msec, int ignoreinput)); *** ../vim-6.2.294/src/proto/ui.pro Sun Jun 1 12:26:21 2003 --- src/proto/ui.pro Sat Feb 28 16:40:50 2004 *************** *** 1,7 **** /* ui.c */ void ui_write __ARGS((char_u *s, int len)); void ui_inchar_undo __ARGS((char_u *s, int len)); ! int ui_inchar __ARGS((char_u *buf, int maxlen, long wtime)); int ui_char_avail __ARGS((void)); void ui_delay __ARGS((long msec, int ignoreinput)); void ui_suspend __ARGS((void)); --- 1,7 ---- /* ui.c */ void ui_write __ARGS((char_u *s, int len)); void ui_inchar_undo __ARGS((char_u *s, int len)); ! int ui_inchar __ARGS((char_u *buf, int maxlen, long wtime, int tb_change_cnt)); int ui_char_avail __ARGS((void)); void ui_delay __ARGS((long msec, int ignoreinput)); void ui_suspend __ARGS((void)); *** ../vim-6.2.294/src/structs.h Thu Feb 5 12:09:25 2004 --- src/structs.h Sun Feb 29 14:25:58 2004 *************** *** 776,785 **** char_u *tb_noremap; /* mapping flags for characters in tb_buf[] */ int tb_buflen; /* size of tb_buf[] */ int tb_off; /* current position in tb_buf[] */ ! int tb_len; /* number of valid chars in tb_buf[] */ ! int tb_maplen; /* nr of mapped characters in tb_buf[] */ ! int tb_silent; /* nr of silently mapped chars in tb_buf[] */ ! int tb_no_abbr_cnt; /* nr of chars without abbrev. in tb_buf[] */ } typebuf_T; /* Struct to hold the saved typeahead for save_typeahead(). */ --- 779,789 ---- char_u *tb_noremap; /* mapping flags for characters in tb_buf[] */ int tb_buflen; /* size of tb_buf[] */ int tb_off; /* current position in tb_buf[] */ ! int tb_len; /* number of valid bytes in tb_buf[] */ ! int tb_maplen; /* nr of mapped bytes in tb_buf[] */ ! int tb_silent; /* nr of silently mapped bytes in tb_buf[] */ ! int tb_no_abbr_cnt; /* nr of bytes without abbrev. in tb_buf[] */ ! int tb_change_cnt; /* nr of time tb_buf was changed; never zero */ } typebuf_T; /* Struct to hold the saved typeahead for save_typeahead(). */ *** ../vim-6.2.294/src/os_unix.c Sun Feb 1 20:06:29 2004 --- src/os_unix.c Sat Feb 28 16:38:11 2004 *************** *** 309,318 **** * If wtime == -1 wait forever for characters. */ int ! mch_inchar(buf, maxlen, wtime) char_u *buf; int maxlen; long wtime; /* don't use "time", MIPS cannot handle it */ { int len; #ifdef FEAT_AUTOCMD --- 309,319 ---- * If wtime == -1 wait forever for characters. */ int ! mch_inchar(buf, maxlen, wtime, tb_change_cnt) char_u *buf; int maxlen; long wtime; /* don't use "time", MIPS cannot handle it */ + int tb_change_cnt; { int len; #ifdef FEAT_AUTOCMD *************** *** 383,392 **** if (do_resize) /* interrupted by SIGWINCH signal */ continue; ! #ifdef FEAT_CLIENTSERVER ! if (received_from_client) ! return 0; /* Input was put directly in typeahead buffer */ ! #endif /* * For some terminals we only get one character at a time. --- 384,392 ---- if (do_resize) /* interrupted by SIGWINCH signal */ continue; ! /* If input was put directly in typeahead buffer bail out here. */ ! if (typebuf_changed(tb_change_cnt)) ! return 0; /* * For some terminals we only get one character at a time. *************** *** 3609,3615 **** len = 0; if (!(options & SHELL_EXPAND) && (ta_len > 0 ! || (len = ui_inchar(ta_buf, BUFLEN, 10L)) > 0)) { /* * For pipes: --- 3609,3616 ---- len = 0; if (!(options & SHELL_EXPAND) && (ta_len > 0 ! || (len = ui_inchar(ta_buf, BUFLEN, 10L, ! 0)) > 0)) { /* * For pipes: *** ../vim-6.2.294/src/ui.c Sun Jan 18 20:58:01 2004 --- src/ui.c Sat Feb 28 16:36:51 2004 *************** *** 105,116 **** * If "wtime" == 0 do not wait for characters. * If "wtime" == -1 wait forever for characters. * If "wtime" > 0 wait "wtime" milliseconds for a character. */ int ! ui_inchar(buf, maxlen, wtime) char_u *buf; int maxlen; long wtime; /* don't use "time", MIPS cannot handle it */ { int retval = 0; --- 105,122 ---- * If "wtime" == 0 do not wait for characters. * If "wtime" == -1 wait forever for characters. * If "wtime" > 0 wait "wtime" milliseconds for a character. + * + * "tb_change_cnt" is the value of typebuf.tb_change_cnt if "buf" points into + * it. When typebuf.tb_change_cnt changes (e.g., when a message is received + * from a remote client) "buf" can no longer be used. "tb_change_cnt" is NULL + * otherwise. */ int ! ui_inchar(buf, maxlen, wtime, tb_change_cnt) char_u *buf; int maxlen; long wtime; /* don't use "time", MIPS cannot handle it */ + int tb_change_cnt; { int retval = 0; *************** *** 143,150 **** static int count = 0; # ifndef NO_CONSOLE ! retval = mch_inchar(buf, maxlen, 10L); ! if (retval > 0) return retval; # endif if (wtime == -1 && ++count == 1000) --- 149,156 ---- static int count = 0; # ifndef NO_CONSOLE ! retval = mch_inchar(buf, maxlen, 10L, tb_change_cnt); ! if (retval > 0 || typebuf_changed(tb_change_cnt)) return retval; # endif if (wtime == -1 && ++count == 1000) *************** *** 162,168 **** #ifdef FEAT_GUI if (gui.in_use) { ! if (gui_wait_for_chars(wtime)) retval = read_from_input_buf(buf, (long)maxlen); } #endif --- 168,174 ---- #ifdef FEAT_GUI if (gui.in_use) { ! if (gui_wait_for_chars(wtime) && !typebuf_changed(tb_change_cnt)) retval = read_from_input_buf(buf, (long)maxlen); } #endif *************** *** 170,176 **** # ifdef FEAT_GUI else # endif ! retval = mch_inchar(buf, maxlen, wtime); #endif ctrl_c_interrupts = TRUE; --- 176,182 ---- # ifdef FEAT_GUI else # endif ! retval = mch_inchar(buf, maxlen, wtime, tb_change_cnt); #endif ctrl_c_interrupts = TRUE; *** ../vim-6.2.294/src/version.c Sat Feb 28 15:30:58 2004 --- src/version.c Sun Feb 29 14:42:27 2004 *************** *** 639,640 **** --- 639,642 ---- { /* Add new patch number below this line */ + /**/ + 295, /**/ -- Not too long ago, a program was something you watched on TV... /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// Sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ Project leader for A-A-P -- http://www.A-A-P.org /// \\\ Buy at Amazon and help AIDS victims -- http://ICCF.nl/click1.html ///