Problem:

Vim crashes with SEGV or BUS when netbeans is processing a command and
concurrently receives a socket disconnection event. This is difficult
to reproduce as timing is critical. The first two backtraces below
are the result of such a crash. In both cases, examination of the
variables 'node' and 'head', in the netbeans_parse_messages() function
show that their 'next' or 'prev' pointers are invalid.

Description:

The third backtrace is obtained after setting a breakpoint in
nb_free() and this backtrace explains the crashes:

    . a netbeans command is processed by netbeans_parse_messages()
    . this command triggers an autocommand
    . this causes ui_breakcheck() to be called and control is passed
      to the gui event loop that in turn calls netbeans_read()
    . netbeans_read() receives the disconnection event and calls
      netbeans_close()
    . netbeans_close() clears all the netbeans data structures, so
      that when control returns to netbeans_parse_messages(), this
      function is now working on invalidated (probably re-used) memory

Patch:

The attached patch to vim 7.3.047 fixes the problem by queueing the
"DETACH" netbeans message in the command queue when netbeans_read()
processes the socket disconnection. This way, the netbeans data
structures are cleared later by netbeans_parse_messages() in vim idle
loop when processing this "DETACH" command, and not anymore in the gui
event loop (or the select loop).


=======================================================================
1 - Crash in vim_free:

#11 0x00007f83e8624ab6 in free () from /lib/libc.so.6
#12 0x00000000004d443f in vim_free (x=0x18c7e00) at misc2.c:1699
#13 0x00000000005ac178 in netbeans_parse_messages () at netbeans.c:685
#14 0x00000000005a74e6 in gui_mch_wait_for_chars (wtime=3600000) at
gui_gtk_x11.c:5423
#15 0x0000000000597f16 in gui_wait_for_chars (wtime=-1) at gui.c:2718
#16 0x000000000058106a in ui_inchar (buf=0x8286f6 "", maxlen=80,
wtime=-1, tb_change_cnt=23) at ui.c:184
#17 0x0000000000499691 in inchar (buf=0x8286f6 "", maxlen=242,
wait_time=-1, tb_change_cnt=23) at getchar.c:3004
#18 0x00000000004992a0 in vgetorpeek (advance=1) at getchar.c:2780
#19 0x00000000004974ed in vgetc () at getchar.c:1559
#20 0x0000000000497a6d in safe_vgetc () at getchar.c:1764
#21 0x00000000004e40c7 in normal_cmd (oap=0x7fff51af12a0, toplevel=1)
at normal.c:654
#22 0x00000000004a6159 in main_loop (cmdwin=0, noexmode=0) at main.c:1260
#23 0x00000000004a5c39 in main (argc=1, argv=0x7fff51af1598) at main.c:965
=======================================================================
2 - Crash in off2pos:

#7  0x00000000005b1432 in off2pos (buf=0x30303005, offset=0) at netbeans.c:3778
#8  0x00000000005b151c in get_off_or_lnum (buf=0x30303005,
argp=0x7fffb66780b0) at netbeans.c:3813
#9  0x00000000005aeaca in nb_do_cmd (bufno=2, cmd=0x1d934a2 "",
func=0, cmdno=39, args=0x1d934ac "\307\177") at netbeans.c:2234
#10 0x00000000005ac4d5 in nb_parse_cmd (cmd=0x1d934a0 "") at netbeans.c:902
#11 0x00000000005ac161 in netbeans_parse_messages () at netbeans.c:680
#12 0x00000000005a74e6 in gui_mch_wait_for_chars (wtime=3600000) at
gui_gtk_x11.c:5423
#13 0x0000000000597f16 in gui_wait_for_chars (wtime=-1) at gui.c:2718
#14 0x000000000058106a in ui_inchar (buf=0x82871d "", maxlen=67,
wtime=-1, tb_change_cnt=62) at ui.c:184
#15 0x0000000000499691 in inchar (buf=0x82871d "", maxlen=203,
wait_time=-1, tb_change_cnt=62) at getchar.c:3004
#16 0x00000000004992a0 in vgetorpeek (advance=1) at getchar.c:2780
#17 0x00000000004974ed in vgetc () at getchar.c:1559
#18 0x0000000000497a6d in safe_vgetc () at getchar.c:1764
#19 0x00000000004e40c7 in normal_cmd (oap=0x7fffb6678930, toplevel=1)
at normal.c:654
#20 0x00000000004a6159 in main_loop (cmdwin=0, noexmode=0) at main.c:1260
#21 0x00000000004a5c39 in main (argc=1, argv=0x7fffb6678c28) at main.c:965
=======================================================================
3 - Backtrace while vim is stopped at a breakpoint in nb_free()

  #0  nb_free () at netbeans.c:955
  #1  0x00000000005ab5bc in netbeans_close () at netbeans.c:179
  #2  0x00000000005ac320 in netbeans_read () at netbeans.c:796
  #3  0x00000000005ac1dd in messageFromNetbeans (clientData=0x0,
unused1=4, unused2=GDK_INPUT_READ) at netbeans.c:719
  #4  0x00007fa5e80a6e2f in ?? () from /usr/lib/libgdk-x11-2.0.so.0
  #5  0x00007fa5e6eb27ab in g_main_context_dispatch () from
/usr/lib/libglib-2.0.so.0
  #6  0x00007fa5e6eb5f7d in ?? () from /usr/lib/libglib-2.0.so.0
  #7  0x00007fa5e6eb613b in g_main_context_iteration () from
/usr/lib/libglib-2.0.so.0
  #8  0x00000000005a7436 in gui_mch_update () at gui_gtk_x11.c:5331
  #9  0x000000000058122e in ui_breakcheck () at ui.c:364
  #10 0x00000000004d084c in line_breakcheck () at misc1.c:8518
  #11 0x000000000048ece5 in auto_next_pat (apc=0x7fffb4de0360,
stop_at_last=0) at fileio.c:9552
  #12 0x000000000048e7d8 in apply_autocmds_group
(event=EVENT_BUFWINLEAVE, fname=0xad5a30
"/home/xavier/src/pyclewn-hg-pdb/foobar.py",
      fname_io=0x8890f0 "foobar.py", force=0, group=-3, buf=0x887060,
eap=0x0) at fileio.c:9358
  #13 0x000000000048e125 in apply_autocmds (event=EVENT_BUFWINLEAVE,
fname=0x8890f0 "foobar.py", fname_io=0x8890f0 "foobar.py", force=0,
buf=0x887060)
      at fileio.c:8994
  #14 0x000000000040ede6 in close_buffer (win=0x8857e0, buf=0x887060,
action=0) at buffer.c:372
  #15 0x0000000000456ab9 in do_ecmd (fnum=0, ffname=0x9ba120
"/home/xavier/src/pyclewn-hg-pdb/(clewn)_console", sfname=0xaaa680
"(clewn)_console",
      eap=0x0, newlnum=1, flags=5, oldwin=0x8857e0) at ex_cmds.c:3398
  #16 0x00000000005ae5de in nb_do_cmd (bufno=1, cmd=0xae8fa2
"editFile", func=0, cmdno=11, args=0xae8fae "\"(clewn)_console\"") at
netbeans.c:2074
  #17 0x00000000005ac4d5 in nb_parse_cmd (cmd=0xae8fa0 "1:editFile")
at netbeans.c:902
  #18 0x00000000005ac161 in netbeans_parse_messages () at netbeans.c:680
  #19 0x00000000005a74e6 in gui_mch_wait_for_chars (wtime=3600000) at
gui_gtk_x11.c:5423
  #20 0x0000000000597f16 in gui_wait_for_chars (wtime=-1) at gui.c:2718
  #21 0x000000000058106a in ui_inchar (buf=0x8286f5 "", maxlen=81,
wtime=-1, tb_change_cnt=22) at ui.c:184
  #22 0x0000000000499691 in inchar (buf=0x8286f5 "", maxlen=243,
wait_time=-1, tb_change_cnt=22) at getchar.c:3004
  #23 0x00000000004992a0 in vgetorpeek (advance=1) at getchar.c:2780
  #24 0x00000000004974ed in vgetc () at getchar.c:1559
  #25 0x0000000000497a6d in safe_vgetc () at getchar.c:1764
  #26 0x00000000004e40c7 in normal_cmd (oap=0x7fffb4de0e90,
toplevel=1) at normal.c:654
  #27 0x00000000004a6159 in main_loop (cmdwin=0, noexmode=0) at main.c:1260
  #28 0x00000000004a5c39 in main (argc=1, argv=0x7fffb4de1188) at main.c:965
=======================================================================


-- 
Xavier

Les Chemins de Lokoti: http://lokoti.alwaysdata.net

-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
diff --git a/src/netbeans.c b/src/netbeans.c
--- a/src/netbeans.c
+++ b/src/netbeans.c
@@ -136,13 +136,8 @@
 static int inAtomic = 0;
 
     static void
-netbeans_close(void)
+nb_close_socket(void)
 {
-    if (!NETBEANS_OPEN)
-	return;
-
-    netbeans_send_disconnect();
-
 #ifdef FEAT_GUI_X11
     if (inputHandler != (XtInputId)NULL)
     {
@@ -167,13 +162,23 @@
 # endif
 #endif
 
+    sock_close(nbsock);
+    nbsock = -1;
+}
+
+    static void
+netbeans_close(void)
+{
+    if (NETBEANS_OPEN)
+    {
+        netbeans_send_disconnect();
+        nb_close_socket();
+    }
+
 #ifdef FEAT_BEVAL
     bevalServers &= ~BEVAL_NETBEANS;
 #endif
 
-    sock_close(nbsock);
-    nbsock = -1;
-
     needupdate = 0;
     inAtomic = 0;
     nb_free();
@@ -632,9 +637,6 @@
     char_u	*p;
     queue_T	*node;
 
-    if (!NETBEANS_OPEN)
-	return;
-
     while (head.next != NULL && head.next != &head)
     {
 	node = head.next;
@@ -720,6 +722,8 @@
 }
 #endif
 
+#define DETACH_MSG "DETACH\n"
+
     void
 netbeans_read()
 {
@@ -790,17 +794,27 @@
 	    break;	/* did read everything that's available */
     }
 
+    /* Reading a socket disconnection (readlen == 0), or a socket error. */
     if (readlen <= 0)
     {
-	/* read error or didn't read anything */
-	netbeans_close();
-	nbdebug(("messageFromNetbeans: Error in read() from socket\n"));
+        /* Queue a "DETACH" netbeans message in the command queue in order to
+         * terminate the netbeans session later. Do not end the session here
+         * directly as we may be running in the context of a call to
+         * netbeans_parse_messages():
+         *      netbeans_parse_messages
+         *          -> autocmd triggered while processing the netbeans cmd
+         *              -> ui_breakcheck
+         *                  -> gui event loop or select loop
+         *                      -> netbeans_read()
+         */
+	save((char_u *)DETACH_MSG, strlen(DETACH_MSG));
+        nb_close_socket();
+
 	if (len < 0)
 	{
 	    nbdebug(("read from Netbeans socket\n"));
 	    PERROR(_("read from Netbeans socket"));
 	}
-	return; /* don't try to parse it */
     }
 
 #if defined(NB_HAS_GUI) && !defined(FEAT_GUI_W32)
@@ -1186,6 +1200,10 @@
 
     nbdebug(("REP %d: <none>\n", cmdno));
 
+    /* Avoid printing an annoying error message. */
+    if (!NETBEANS_OPEN)
+        return;
+
     sprintf(reply, "%d\n", cmdno);
     nb_send(reply, "nb_reply_nil");
 }

Raspunde prin e-mail lui