Subject: Re: bug#11984: 24.1; segfault while deleting a window

From: Russell Sim <[email-masked]>
Date: Sat, 21 Jul 2012 19:00:36 +1000

Chong Yidong <[email-masked]> writes:

> Russell Sim <[email-masked]> writes:
>
>> Oh crap, I just realised that you didn't add you full patch in the
>> commit.  I have re-compiled and included the extra in
>> window-absolute-pixel-edges and delete-other-windows-internal changes.
>> Unfortunately I still get the error.
>>
>> I here is an updated core
>> file. http://russellsim.org/emacs-24.3770cb4-patch.core
>
> Hmm, I'm not sure the core file loaded properly for me.  Can you trigger
> the crash with Emacs running in gdb?  Do you get the following strange
> result from printing f->output_data?
>
> (gdb) p f->output_data
> $4 = {
>   tty = 0xc2, 
>   x = 0xc2, 
>   w32 = 0xc2, 
>   ns = 0xc2, 
>   nothing = 194
> }

(gdb) p f->output_data
$1 = {tty = 0x0, x = 0x0, w32 = 0x0, ns = 0x0, nothing = 0}

Be aware that I am running in batch mode.

> Also, please provide the step-by-step recipe that you are using to run
> the tests?  If I can try to reproduce the crash myself, debugging will
> go faster.

I wish I could offer some simple recipe, I'll see if I can narrow it
down to one test case, but because this is the test runner for the whole
python-mode you need a heap of 3rd party Python stuff to get far enough
along to cause the crash.  If this is too painful, I can setup a VM with
the appropriate environment for you to access.

I'll be on IRC in the #emacs channel for a while and my handle is
arrsim, or jabber at my email address.

I have included the whole function that I am using, which is the
emacs-24 branch + your extra CHECK_LIVE_FRAME chuncks.

2548: DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
2549:        Sdelete_other_windows_internal, 0, 2, "",
2550:        doc: /* Make WINDOW fill its frame.
2551: Only the frame WINDOW is on is affected.  WINDOW may be any window and
2552: defaults to the selected one.
2553: 
2554: Optional argument ROOT, if non-nil, must specify an internal window such
2555: that WINDOW is in its window subtree.  If this is the case, replace ROOT
2556: by WINDOW and leave alone any windows not part of ROOT's subtree.
2557: 
2558: When WINDOW is live try to reduce display jumps by keeping the text
2559: previously visible in WINDOW in the same place on the frame.  Doing this
2560: depends on the value of (window-start WINDOW), so if calling this
2561: function in a program gives strange scrolling, make sure the
2562: window-start value is reasonable when this function is called.  */)
2563:      (Lisp_Object window, Lisp_Object root)
2564: {
2565:   struct window *w, *r, *s;
2566:   struct frame *f;
2567:   Lisp_Object sibling, pwindow, swindow IF_LINT (= Qnil), delta;
2568:   EMACS_INT startpos IF_LINT (= 0);
2569:   int top IF_LINT (= 0), new_top, resize_failed;
2570:   Mouse_HLInfo *hlinfo;
2571: 
2572:   w = decode_any_window (window);
2573:   CHECK_LIVE_FRAME (w->frame);
2574:   XSETWINDOW (window, w);
2575:   f = XFRAME (w->frame);
2576: 
2577:   if (NILP (root))
2578:     /* ROOT is the frame's root window.  */
2579:     {
2580:       root = FRAME_ROOT_WINDOW (f);
2581:       r = XWINDOW (root);
2582:     }
2583:   else
2584:     /* ROOT must be an ancestor of WINDOW.  */
2585:     {
2586:       r = decode_any_window (root);
2587:       CHECK_LIVE_FRAME (r->frame);
2588:       pwindow = XWINDOW (window)->parent;
2589:       while (!NILP (pwindow))
2590: 	if (EQ (pwindow, root))
2591: 	  break;
2592: 	else
2593: 	  pwindow = XWINDOW (pwindow)->parent;
2594:       if (!EQ (pwindow, root))
2595: 	error ("Specified root is not an ancestor of specified window");
2596:     }
2597: 
2598:   if (EQ (window, root))
2599:     /* A noop.  */
2600:     return Qnil;
2601:   /* I don't understand the "top > 0" part below.  If we deal with a
2602:      standalone minibuffer it would have been caught by the preceding
2603:      test.  */
2604:   else if (MINI_WINDOW_P (w)) /* && top > 0) */
2605:     error ("Can't expand minibuffer to full frame");
2606: 
2607:   if (!NILP (w->buffer))
2608:     {
2609:       startpos = marker_position (w->start);
2610:       top = WINDOW_TOP_EDGE_LINE (w)
2611: 	- FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
2612:       /* Make sure WINDOW is the frame's selected window.  */
2613:       if (!EQ (window, FRAME_SELECTED_WINDOW (f)))
2614: 	{
2615: 	  if (EQ (selected_frame, w->frame))
2616: 	    Fselect_window (window, Qnil);
2617: 	  else
2618: 	    FRAME_SELECTED_WINDOW (f) = window;
2619: 	}
2620:     }
2621:   else
2622:     {
2623:       /* See if the frame's selected window is a part of the window
2624: 	 subtree rooted at WINDOW, by finding all the selected window's
2625: 	 parents and comparing each one with WINDOW.  If it isn't we
2626: 	 need a new selected window for this frame.  */
2627:       swindow = FRAME_SELECTED_WINDOW (f);
2628:       while (1)
2629: 	{
2630: 	  pwindow = swindow;
2631: 	  while (!NILP (pwindow) && !EQ (window, pwindow))
2632: 	    pwindow = XWINDOW (pwindow)->parent;
2633: 
2634: 	  if (EQ (window, pwindow))
2635: 	    /* If WINDOW is an ancestor of SWINDOW, then SWINDOW is ok
2636: 	       as the new selected window.  */
2637: 	    break;
2638: 	  else
2639: 	    /* Else try the previous window of SWINDOW.  */
2640: 	    swindow = Fprevious_window (swindow, Qlambda, Qnil);
2641: 	}
2642: 
2643:       if (!EQ (swindow, FRAME_SELECTED_WINDOW (f)))
2644: 	{
2645: 	  if (EQ (selected_frame, w->frame))
2646: 	    Fselect_window (swindow, Qnil);
2647: 	  else
2648: 	    FRAME_SELECTED_WINDOW (f) = swindow;
2649: 	}
2650:     }
2651: 
2652:   BLOCK_INPUT;
2653:   hlinfo = MOUSE_HL_INFO (f);
2654:   /* We are going to free the glyph matrices of WINDOW, and with that
2655:      we might lose any information about glyph rows that have some of
2656:      their glyphs highlighted in mouse face.  (These rows are marked
2657:      with a non-zero mouse_face_p flag.)  If WINDOW indeed has some
2658:      glyphs highlighted in mouse face, signal to frame's up-to-date
2659:      hook that mouse highlight was overwritten, so that it will
2660:      arrange for redisplaying the highlight.  */
2661:   if (EQ (hlinfo->mouse_face_window, window))
2662:     {
2663:       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
2664:       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
2665:       hlinfo->mouse_face_window = Qnil;
2666:     }
2667:   free_window_matrices (r);
2668: 
2669:   windows_or_buffers_changed++;
2670:   Vwindow_list = Qnil;
2671:   FRAME_WINDOW_SIZES_CHANGED (f) = 1;
2672:   resize_failed = 0;
2673: 
2674:   if (NILP (w->buffer))
2675:     {
2676:       /* Resize child windows vertically.  */
2677:       XSETINT (delta, XINT (r->total_lines) - XINT (w->total_lines));
2678:       w->top_line = r->top_line;
2679:       resize_root_window (window, delta, Qnil, Qnil);
2680:       if (window_resize_check (w, 0))
2681: 	window_resize_apply (w, 0);
2682:       else
2683: 	{
2684: 	  resize_root_window (window, delta, Qnil, Qt);
2685: 	  if (window_resize_check (w, 0))
2686: 	    window_resize_apply (w, 0);
2687: 	  else
2688: 	    resize_failed = 1;
2689: 	}
2690: 
2691:       /* Resize child windows horizontally.  */
2692:       if (!resize_failed)
2693: 	{
2694: 	  w->left_col = r->left_col;
2695: 	  XSETINT (delta, XINT (r->total_cols) - XINT (w->total_cols));
2696: 	  w->left_col = r->left_col;
2697: 	  resize_root_window (window, delta, Qt, Qnil);
2698: 	  if (window_resize_check (w, 1))
2699: 	    window_resize_apply (w, 1);
2700: 	  else
2701: 	    {
2702: 	      resize_root_window (window, delta, Qt, Qt);
2703: 	      if (window_resize_check (w, 1))
2704: 		window_resize_apply (w, 1);
2705: 	      else
2706: 		resize_failed = 1;
2707: 	    }
2708: 	}
2709: 
2710:       if (resize_failed)
2711: 	/* Play safe, if we still can ...  */
2712: 	{
2713: 	  window = swindow;
2714: 	  w = XWINDOW (window);
2715: 	}
2716:     }
2717: 
2718:   /* Cleanly unlink WINDOW from window-tree.  */
2719:   if (!NILP (w->prev))
2720:     /* Get SIBLING above (on the left of) WINDOW.  */
2721:     {
2722:       sibling = w->prev;
2723:       s = XWINDOW (sibling);
2724:       s->next = w->next;
2725:       if (!NILP (s->next))
2726: 	XWINDOW (s->next)->prev = sibling;
2727:     }
2728:   else
2729:     /* Get SIBLING below (on the right of) WINDOW.  */
2730:     {
2731:       sibling = w->next;
2732:       s = XWINDOW (sibling);
2733:       s->prev = Qnil;
2734:       if (!NILP (XWINDOW (w->parent)->vchild))
2735: 	XWINDOW (w->parent)->vchild = sibling;
2736:       else
2737: 	XWINDOW (w->parent)->hchild = sibling;
2738:     }
2739: 
2740:   /* Delete ROOT and all child windows of ROOT.  */
2741:   if (!NILP (r->vchild))
2742:     {
2743:       delete_all_child_windows (r->vchild);
2744:       r->vchild = Qnil;
2745:     }
2746:   else if (!NILP (r->hchild))
2747:     {
2748:       delete_all_child_windows (r->hchild);
2749:       r->hchild = Qnil;
2750:     }
2751: 
2752:   replace_window (root, window, 1);
2753: 
2754:   /* This must become SWINDOW anyway ....... */
2755:   if (!NILP (w->buffer) && !resize_failed)
2756:     {
2757:       /* Try to minimize scrolling, by setting the window start to the
2758: 	 point will cause the text at the old window start to be at the
2759: 	 same place on the frame.  But don't try to do this if the
2760: 	 window start is outside the visible portion (as might happen
2761: 	 when the display is not current, due to typeahead).  */
2762:       new_top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
2763:       if (new_top != top
2764: 	  && startpos >= BUF_BEGV (XBUFFER (w->buffer))
2765: 	  && startpos <= BUF_ZV (XBUFFER (w->buffer)))
2766: 	{
2767: 	  struct position pos;
2768: 	  struct buffer *obuf = current_buffer;
2769: 
2770: 	  Fset_buffer (w->buffer);
2771: 	  /* This computation used to temporarily move point, but that
2772: 	     can have unwanted side effects due to text properties.  */
2773: 	  pos = *vmotion (startpos, -top, w);
2774: 
2775: 	  set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
2776: 	  w->window_end_valid = Qnil;
2777: 	  w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
2778: 				   || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
2779: 				  : Qnil);
2780: 	  /* We need to do this, so that the window-scroll-functions
2781: 	     get called.  */
2782: 	  w->optional_new_start = Qt;
2783: 
2784: 	  set_buffer_internal (obuf);
2785: 	}
2786:     }
2787: 
2788:   adjust_glyphs (f);
2789:   UNBLOCK_INPUT;
2790: 
2791:   run_window_configuration_change_hook (f);
2792: 
2793:   return Qnil;
2794: }