[MacPorts] #45582: grace: xmgrace crashes with SIGSYS in yosemite

MacPorts noreply at macports.org
Fri Jun 10 14:23:00 UTC 2022


#45582: grace: xmgrace crashes with SIGSYS in yosemite
--------------------------+--------------------------------
  Reporter:  gezelter@…   |      Owner:  macports-tickets@…
      Type:  defect       |     Status:  new
  Priority:  Normal       |  Milestone:
 Component:  ports        |    Version:
Resolution:               |   Keywords:
      Port:  grace t1lib  |
--------------------------+--------------------------------

Comment (by chuckcranor):

 I have figured out why grace crashes at startup (unless you compile -O1 or
 less).
 The t1lib is triggering a clang code generation bug.

 There is also a malloc buffer overflow in t1lib that causes issues on OSX.

 Here are the details from an email I posted elsewhere:

 there are two bugs in fonts/t1lib that cause grace to crash on OSX:

  1. compiler bug in some versions of clang when compiling with "-O2" ...
     this appears to have been fixed somewhere between clang-11 and
 clang-12.
     it works ok with "-O1".

  2. one case of t1lib trying to be clever and instead writing past end of
     malloc'd buffer (which the OSX malloc did not like at all).   the
 address
     sanitizer helped pinpoint this.




 For 1, the t1lib is trying to roll its own optmized memcpy() using
 this macro in lib/type1/objects.h:
 {{{
  #define  LONGCOPY(dest,source,bytes) { \
      register LONG *p1 = (LONG *)dest;  register LONG *p2 = (LONG
 *)source; \
      register int count = (bytes) / sizeof(LONG); \
      while (--count >= 0) *p1++ = *p2++; }
 }}}
 they explain (in lib/type1/objects.c) they are doing this because
 there is no standarized portable memory copy routine (e.g. memcpy()
 vs bcopy()).   maybe that was true in 1991 when this code was written,
 but i think pretty much everyone has memcpy() now?

 At any rate, some versions of "clang -O2" choke on LONGCOPY() and
 produce incorrect code.   I've got a 49 line test C program that
 reproduces the issue (see attached xalloc-test.c):
 {{{
         % clang-11 -O1 -o alloc-test xalloc-test.c
         % ./alloc-test
         Result CORRECT!
         % clang-11 -O2 -o alloc-test xalloc-test.c
         % ./alloc-test
         Result FAILED! (0 != 0x80)
         % clang-12 -O2 -o alloc-test xalloc-test.c
         % ./alloc-test
         Result CORRECT!
         %
 }}}
 I think the solution is to assume that memcpy() is going to be
 available and have LONGCOPY() use memcpy() rather than its custom
 copy.



 For 2, the issue is in lib/type1/regions.c where it allocates
 "(ymax - iy) * sizeof(pel)" bytes of extra data using malloc and
 then uses LONGCOPY() like this:

 {{{
 /*
 We must round up (ymax - iy) so we get the ceiling of the number of
 longs.  The destination must be able to hold these extra bytes because
 Allocate() makes everything it allocates be in multiples of longs.
 */
        LONGCOPY(&r[1], xvalues, (ymax - iy) * sizeof(pel) + sizeof(LONG) -
 1);
 }}}

 they've incorrectly computed the ceiling by just adding "sizeof(LONG) - 1"
 (need to mask off the low bits by "~(sizeof(LONG) - 1)").



 with those fixes in, I can run grace on all the examples
 that it installs (using the "dotest" script there) on OSX
 without grace crashing with everything compiled -O2.


 xalloc test program source:

 {{{
 #include <err.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

 struct xobject {
     int flag;
 };

 #define  LONGCOPY(dest,source,bytes) do {
 \
     long *p1 = (long *)dest;
 \
     long *p2 = (long *)source;
 \
     int count = (bytes) / sizeof(long);
 \
     while (--count >= 0)
 \
         *p1++ = *p2++;
 \
 } while(0)

 struct xobject *t1_Allocate(int size, struct xobject *xtemplate) {
     struct xobject *r;

     r = (struct xobject *) malloc(size);
     if (r == NULL) errx(1, "malloc abort");

 #if 1
     LONGCOPY(r, xtemplate, size);
 #else
     memcpy(r, xtemplate, size);
 #endif
     r->flag &= ~(0x01);
     return(r);
 }

 int main(int argc, char **argv) {
     struct xobject *xo, *xo2;

     xo = malloc(56);
     memset(xo, 0, 56);
     xo->flag = 0x80;

     xo2 = t1_Allocate(56, xo);

     if (xo2->flag == 0x80) {
         fprintf(stderr, "Result CORRECT!\n");
     } else {
         fprintf(stderr, "Result FAILED! (%#x != 0x80)\n", xo2->flag);
     }
    exit(0);
 }

 }}}

-- 
Ticket URL: <https://trac.macports.org/ticket/45582#comment:13>
MacPorts <https://www.macports.org/>
Ports system for macOS


More information about the macports-tickets mailing list