Subject: Re: bug#18438: 24.4.50; assertion failed in bidi.c

From: Eli Zaretskii <[email-masked]>
Date: Fri, 10 Oct 2014 10:19:57 +0300

> Date: Fri, 10 Oct 2014 15:21:53 +1300
> From: [email-masked]
> Cc: Eli Zaretskii <[email-masked]>, <[email-masked]>
> 
> > Could you show the disassembly of this function in its new form?  I'd
> > like to see if the value of the bidi type being checked is loaded 
> > into
> > the same register as in the original version.
> 
> (gdb) disassemble 'bidi.c'::bidi_check_type
> Dump of assembler code for function bidi_check_type:
>     0x00000001004f9dd3 <+0>:     push   %rbp
>     0x00000001004f9dd4 <+1>:     mov    %rsp,%rbp
>     0x00000001004f9dd7 <+4>:     sub    $0x40,%rsp
>     0x00000001004f9ddb <+8>:     mov    %ecx,0x10(%rbp)
>     0x00000001004f9dde <+11>:    mov    0x55d8db(%rip),%rax
>     0x00000001004f9de5 <+18>:    movzbl (%rax),%eax
>     0x00000001004f9de8 <+21>:    xor    $0x1,%eax
>     0x00000001004f9deb <+24>:    test   %al,%al
>     0x00000001004f9ded <+26>:    je     0x1004f9e37 <bidi_check_type+100>
>     0x00000001004f9def <+28>:    cmpl   $0x17,0x10(%rbp)
>     0x00000001004f9df3 <+32>:    jbe    0x1004f9e37 

Yes, this is the same arrangement as in the original version: passed
through ECX, then stored in RBP+0x10.

Moreover, the value printed by fprintf is taken from RBP+0x10:

>     0x00000001004f9dfa <+39>:    mov    0x18(%rax),%rax
>     0x00000001004f9dfe <+43>:    movl   $0x17,0x30(%rsp)
>     0x00000001004f9e06 <+51>:    movl   $0x0,0x28(%rsp)
>     0x00000001004f9e0e <+59>:    mov    0x10(%rbp),%edx  <<<<<<<<<<<
>     0x00000001004f9e11 <+62>:    mov    %edx,0x20(%rsp)  <<<<<<<<<<<
>     0x00000001004f9e15 <+66>:    mov    $0x14c,%r9d
>     0x00000001004f9e1b <+72>:    lea    0x52edde(%rip),%r8
>     0x00000001004f9e22 <+79>:    lea    0x52eddf(%rip),%rdx
>     0x00000001004f9e29 <+86>:    mov    %rax,%rcx
>     0x00000001004f9e2c <+89>:    callq  0x1006b8080 <fprintf>

So now I'm no longer sure that my theory about some other thread
overwriting registers is valid.  But what else could cause this?
Hm... can you try the following version instead?  I expect it to force
GCC to store the value of 'type' in a 64-bit register, and use a
64-bit compare instruction for it.  Please show the resulting
disassembly, so we are sure this trick succeeded.

=== modified file 'src/bidi.c'
--- src/bidi.c	2014-04-06 15:56:01 +0000
+++ src/bidi.c	2014-10-10 07:12:01 +0000
@@ -326,7 +326,14 @@ bidi_get_type (int ch, bidi_dir_t overri
 static void
 bidi_check_type (bidi_type_t type)
 {
-  eassert (UNKNOWN_BT <= type && type <= NEUTRAL_ON);
+  volatile ptrdiff_t qtype = type;
+
+  if (!(suppress_checking || (UNKNOWN_BT <= qtype && qtype <= NEUTRAL_ON)))
+    {
+      fprintf (stderr, "\r\n%s:%d: bidi type %d is not in [%d..%d]\r\n",
+	       __FILE__, __LINE__, type, UNKNOWN_BT, NEUTRAL_ON);
+      emacs_abort ();
+    }
 }
 
 /* Given a bidi TYPE of a character, return its category.  */

> > Also, if you have the backtrace, including from all the other 
> > threads,
> > please post that.
> 
> Attached, but the emacs process died while printing the backtrace for 
> thread 2, and I have no idea why.

I do: it's because you started GDB from the src directory, where it
read the .gdbinit file, which causes the "bt" command to call a
function in the Emacs process being debugged.

To work around this, comment out (by prepending a # to every line) the
following few lines in .gdbinit:

define hookpost-backtrace
  set $bt = backtrace_top ()
  if backtrace_p ($bt)
    echo \n
    echo Lisp Backtrace:\n
    xbacktrace
  end
end

Then you will still be able to invoke "xbacktrace" by hand, but it
won't be invoked automatically by "bt".

Thanks.