Subject: Re: bug#5984: Crash displaying composed characters

From: Eli Zaretskii <[email-masked]>
Date: Tue, 20 Apr 2010 20:29:29 +0300

> Date: Tue, 20 Apr 2010 18:06:58 +0300
> From: Eli Zaretskii <[email-masked]>
> Cc: [email-masked]
> 
> > From: Juanma Barranquero <[email-masked]>
> > Date: Tue, 20 Apr 2010 15:42:16 +0200
> > Cc: 
> > 
> > Package: emacs
> > Version: 24.0.50
> > 
> > Discussed in the thread of bug#5973
> > 
> >     Juanma
> > 
> > 
> > 
> > 
> > Breakpoint 1, w32_abort () at w32fns.c:7349
> > 7349      button = MessageBox (NULL,
> > (gdb) bt
> > #0  w32_abort () at w32fns.c:7349
> > #1  0x012be7c9 in temp_set_point_both (buffer=0x34b6e00, charpos=32,
> > bytepos=33) at intervals.c:1944
> > #2  0x012772b4 in autocmp_chars (cft_element=50852182, charpos=29,
> > bytepos=29, limit=31, win=0x350b400, face=0x4e8c100, string=49838082)
> >    at composite.c:1002
> > #3  0x01278591 in composition_reseat_it (cmp_it=0x88db74, charpos=29,
> > bytepos=29, endpos=32, w=0x350b400, face=0x4e8c100, string=49838082)
> >    at composite.c:1147
> > #4  0x01069fcb in next_element_from_buffer (it=0x88d6f8) at xdisp.c:6834
> > #5  0x01066642 in get_next_display_element (it=0x88d6f8) at xdisp.c:5828
> 
> I see the same crash in Emacs 23.1.96, which means two things:
> 
>   . It has nothing to do with bidi code (phew!)
> 
>   . It is much more urgent to fix

Here's the analysis of what causes this crash:

  . The defadvice displays the value of END, the second argument to
    narrow-to-region.  When the defadvice is evaluated, Edebug
    displays the result, and attempts to interpret it as a character.

  . As the result, the following text is inserted into the " *Echo
    Area 0*" buffer, with the purpose of displaying it in the echo
    area:

           Result: 784 (#o1420, #x310, 0̐)

    The funny character before the right parenthesis is composed from
    u+0310 (COMBINING CANDRABINDU), and ASCII `0' (the digit zero).  I
    presume that some composition rule causes us to display a bare
    u+0310 composed like that.

  . Emacs then enters redisplay to display the echo area.  As part of
    redisplay, autocmp_chars is called, and it records the values of
    point in character and byte units:

         EMACS_INT pt = PT, pt_byte = PT_BYTE;

    At this point, pt is 32 and pt_byte is 33, which is consistent
    with the multibyte text we have in the buffer, as shown above.

  . Further down, autocmp_chars calls the value of
    auto-composition-function:

	  if (NILP (LGSTRING_ID (gstring)))
	    {
	      Lisp_Object args[6];

	      args[0] = Vauto_composition_function;
	      args[1] = AREF (elt, 2);
	      args[2] = pos;
	      args[3] = make_number (to);
	      args[4] = font_object;
	      args[5] = string;
	      gstring = safe_call (6, args);
	    }

  . The call to auto-composition-function loads uni-combining.el.  And
    because force-load-messages is non-nil, that displays the 2
    messages

      Loading lisp/international/uni-combining.el (source)...
      Loading lisp/international/uni-combining.el (source)...done

  . Now the " *Echo Area0*" buffer holds a totally different text,
    unbeknownst to autocmp_chars, which still passes the old values 32
    and 33 to TEMP_SET_PT_BOTH:

	  if (NILP (string))
	    TEMP_SET_PT_BOTH (pt, pt_byte);
	  return unbind_to (count, gstring);

  . temp_set_pt_both uses BUF_ZV and BUF_ZV_BYTE to validate its
    argument, but now BUF_ZV and BUF_ZV_BYTE correspond to the text
    "Loading ...", which has an entirely different length and
    contents, and the validation fails.  Therefore, temp_set_pt_both
    aborts.

One kludgy way of fixing this would be to bind force-load-messages to
nil around the call to auto-composition-function.  But that sounds too
harsh: after all, whoever sets that variable, actually wants to see
all these messages.

Another way is to force the "Loading..." messages use the second echo
area buffer.  Do we have ways to do something like that?

Ideas are welcome.