Subject: Re: bug#16457: 24.3.50; crash rendering Arabic Uthmani script

From: Dmitry Antipov <[email-masked]>
Date: Fri, 17 Jan 2014 11:34:11 +0400

On 01/16/2014 09:33 PM, Eli Zaretskii wrote:

> This is really strange.  First, I cannot reproduce the crash on
> MS-Windows, so the problem might be related to the shaping engine
> being used (I presume yours is libotf and libm17n).  (I tried on both
> Windows XP and on Windows 7, which have very different versions of
> Uniscribe, and they both work fine.)

Yes, with ' --without-m17n-flt' it doesn't crash.

> Specifically, cmp_it.nbytes is computed in composition_update_it as
> the sum of byte-widths of all the characters being composed:
>
>        cmp_it->width = 0;
>        for (i = cmp_it->nchars - 1; i >= 0; i--)
> 	{
> 	  c = XINT (LGSTRING_CHAR (gstring, cmp_it->from + i));
> 	  cmp_it->nbytes += CHAR_BYTES (c);
> 	  cmp_it->width += CHAR_WIDTH (c);
> 	}

I'm trying this:

=== modified file 'src/composite.c'
--- src/composite.c     2014-01-12 23:23:55 +0000
+++ src/composite.c     2014-01-17 07:16:11 +0000
@@ -24,6 +24,7 @@

  #include <config.h>

+#include <stdio.h>
  #include "lisp.h"
  #include "character.h"
  #include "buffer.h"
@@ -1410,9 +1411,16 @@
        cmp_it->nchars = LGLYPH_TO (glyph) + 1 - from;
        cmp_it->nbytes = 0;
        cmp_it->width = 0;
+
+      fprintf (stderr, "%s: from %d, nchars %d, header %p is:\n", __func__,
+              cmp_it->from, cmp_it->nchars, XPNTR (LGSTRING_HEADER (gstring)));
+      debug_print (LGSTRING_HEADER (gstring));
+
        for (i = cmp_it->nchars - 1; i >= 0; i--)
         {
           c = XINT (LGSTRING_CHAR (gstring, cmp_it->from + i));
+         fprintf (stderr, " at %d: char %d, %d bytes\n",
+                  cmp_it->from + i, c, CHAR_BYTES (c));
           cmp_it->nbytes += CHAR_BYTES (c);
           cmp_it->width += CHAR_WIDTH (c);
         }

And now seeing an illegal access beyond end of gstring header:

;; OK
composition_update_it: from 0, nchars 1, header 0x100c958 is:
[#<font-object "-unknown-PakType Naqsh-normal-normal-normal-*-13-*-*-*-*-0-iso10646-1"> 1648 1583 1616 1593 1615 1608 1606 1614]
  at 0: char 1648, 2 bytes

;; OK
composition_update_it: from 2, nchars 2, header 0x100c958 is:
[#<font-object "-unknown-PakType Naqsh-normal-normal-normal-*-13-*-*-*-*-0-iso10646-1"> 1648 1583 1616 1593 1615 1608 1606 1614]
  at 3: char 1593, 2 bytes
  at 2: char 1616, 2 bytes

;; OK
composition_update_it: from 4, nchars 2, header 0x100c958 is:
[#<font-object "-unknown-PakType Naqsh-normal-normal-normal-*-13-*-*-*-*-0-iso10646-1"> 1648 1583 1616 1593 1615 1608 1606 1614]
  at 5: char 1608, 2 bytes
  at 4: char 1615, 2 bytes

;; OK
composition_update_it: from 6, nchars 1, header 0x100c958 is:
[#<font-object "-unknown-PakType Naqsh-normal-normal-normal-*-13-*-*-*-*-0-iso10646-1"> 1648 1583 1616 1593 1615 1608 1606 1614]
  at 6: char 1606, 2 bytes

;; BAD
composition_update_it: from 7, nchars 2, header 0x100c958 is:
[#<font-object "-unknown-PakType Naqsh-normal-normal-normal-*-13-*-*-*-*-0-iso10646-1"> 1648 1583 1616 1593 1615 1608 1606 1614]
  at 8: char 2, 1 bytes
  at 7: char 1614, 2 bytes

IIUC 2 is the garbage at (presumably invalid) position 8.

> And the characters in the LGSTRING object are simply copied from the
> buffer in fill_gstring_header, when LGSTRING is created:
>
>    for (i = 0; i < len; i++)
>      {
>        int c;
>
>        if (NILP (string))
> 	FETCH_CHAR_ADVANCE_NO_CHECK (c, from, from_byte);
>        else
> 	FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string, from, from_byte);
>        ASET (header, i + 1, make_number (c));
>      }

AFAICS gstring header is correct here.

> Btw, does the problem go away if you disable cache-long-scans?

No.

Dmitry