tech-pkg archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: odd fonts/t1lib compile mystery on osx

On Fri, Jan 04, 2019 at 05:05:34PM -0500, Chuck Cranor wrote:
>     I'm on a quest to get math/grace working on osx.   Thomas solved a 
> x11/motif problem blocking me by updating the package from 2.3.4 
> to 2.3.8 (thanks wiz!).   So motif programs now work on osx, but grace
> is still crashing...

clearly I'm on the slow boat, but I finally got there.   turns out
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" and it doesn't impact my NetBSD system (which
    has gcc instead of clang).

[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 netbsd
     malloc did not get messed up by this).   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

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 in 
/usr/pkg/grace/examples (using the "dotest" script there) on OSX
without grace crashing. 

I will attempt to fix this in pkgsrc.


#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);
    memcpy(r, xtemplate, size);
    r->flag &= ~(0x01);

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);

Home | Main Index | Thread Index | Old Index