http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60941

            Bug ID: 60941
           Summary: gcc 4.8.3/sparc64 miscompiles firefox javascript
                    interpreter
           Product: gcc
           Version: 4.8.3
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: martin at netbsd dot org

System: NetBSD/sparc64; NetBSD in-tree version of gcc: 
> gcc -v
Using built-in specs.
COLLECT_GCC=gcc
Target: sparc64--netbsd
Configured with: /usr/src6/tools/gcc/../../external/gpl3/gcc/dist/configure
--target=sparc64--netbsd --enable-long-long --enable-threads
--with-bugurl=http://www.NetBSD.org/Misc/send-pr.html --with-pkgversion='NetBSD
nb1 20120916' --with-system-zlib --enable-__cxa_atexit
--with-mpc-lib=/var/obj/mknative/sparc64/usr/src6/external/lgpl3/mpc/lib/libmpc
--with-mpfr-lib=/var/obj/mknative/sparc64/usr/src6/external/lgpl3/mpfr/lib/libmpfr
--with-gmp-lib=/var/obj/mknative/sparc64/usr/src6/external/lgpl3/gmp/lib/libgmp
--with-mpc-include=/usr/src6/external/lgpl3/mpc/dist/src
--with-mpfr-include=/usr/src6/external/lgpl3/mpfr/dist/src
--with-gmp-include=/usr/src6/external/lgpl3/gmp/lib/libgmp/arch/sparc64
--enable-tls --disable-multilib --disable-symvers --disable-libstdcxx-pch
--build=x86_64-unknown-netbsd6.0. --host=sparc64--netbsd
--with-sysroot=/var/obj/mknative/sparc64/usr/src6/destdir.sparc64
Thread model: posix
gcc version 4.8.3 (NetBSD nb2 20140304) 


When building a firefox 28 with gcc 4.8 and at least -O2 the javascript
interpreter misbehaves and causes firefox to crash. An example URL that
triggers this is:
https://github.com/mconf/ffmpeg/blob/master/doc/optimization.txt

The bug itself is a bit subtle - hope I get it clear:

The firefox javascript interpreter has a very special way to represent all
kinds of values in a single 64 bit value (which makes it impossible to
represent certain double NaN values and some pointer values - however, this is
all "properly" taken care of). The definition of the Value type is:

typedef union jsval_layout
{
    uint64_t asBits;
    struct {
        JSValueTag         tag : 17;
        uint64_t           payload47 : 47;
    } debugView;
    struct {
        uint32_t           padding;
        union {
            int32_t        i32;
            uint32_t       u32;
            JSWhyMagic     why;
        } payload;
    } s;
    double asDouble;
    void *asPtr;
    size_t asWord;
    uintptr_t asUIntPtr;
} JSVAL_ALIGNMENT jsval_layout;

There is a helper macro that "constructs" new Values from 32bit ints:

static inline JS_VALUE_CONSTEXPR jsval_layout
INT32_TO_JSVAL_IMPL(int32_t i32)
{
    JS_RETURN_LAYOUT_FROM_BITS(((uint64_t)(uint32_t)i32) |
JSVAL_SHIFTED_TAG_INT32);
}

and JS_RETURN_LAYOUT_FROM_BITS is (depending on ifdefs) in this case defined
as:

#  define JS_RETURN_LAYOUT_FROM_BITS(BITS) \
    return (jsval_layout) { .asBits = (BITS) }

Now ignoring a few details, the values with tag 0xfff88 in the high order bits
are int32 values, and the low order bits just contain the value.

With some printf instrumentation, right before the crash happens, the
interpreter stack looks like:

end of JSOP_INT8 top of stack: fff8800000000019
end of JSOP_URSH top of stack: fff8800000000028
end of JSOP_BITXOR top of stack: fff88000014e18ab
end of JSOP_GETLOCAL top of stack: fff88000510e527f
end of JSOP_INT8 top of stack: fff880000000001a

now you see 0x510e527f and 0x1a as the topmost values, both int32. Next a
logical shift left is done with these two.

The assembler code generated loads the args into %g2 and %g3 and does a sll:

(gdb) p/x $g3
$1 = 0x510e527f
(gdb) p/x $g2
$2 = 0x1a

   0xfffffffffe4d97e0     sll  %g3, %g2, %g2

now sll leaves the high 32 bits in undefined state, so after the sll we get
0x1443949fc000000 instead of 0xfc000000 in %g2. Unfortunately the code now ors
the correct tag bits into this and stores it directly as a 64bit value:

=> 0xfffffffffe4d97e4     ldx  [ %l7 + %o0 ], %o0 
   0xfffffffffe4d97e8     add  %g1, -8, %g3                                     
   0xfffffffffe4d97ec     or  %g2, %g4, g2                                      
   0xfffffffffe4d97f0     stx  %g3, [ %fp + 0x727 ] 

(the 0xfff88 tag bits had been precomputed in %g4 earlier). This leads to
broken jsvalue_layout data, as the result now looks like a pointer to a
javascript object to the interpreter, and when trying to call methods of that,
the crash happens.


The code in the interpreter loop (slightly unriddled a few macros) looks
correct to me:

CASE(JSOP_LSH)
    {
        int32_t i, j;
        if (!ToInt32(cx, REGS.stackHandleAt(-2), &i))
            goto error;
        if (!ToInt32(cx, REGS.stackHandleAt(-1), &j))
            goto error;
        i = i << (j & 31);
        REGS.sp--;
        REGS.sp[-1].setInt32(i);
    }
END_CASE(JSOP_LSH)  

The setInt32() function is the accessor mentioned earlier:

    void setInt32(int32_t i) {
        data = INT32_TO_JSVAL_IMPL(i);
    }

and "data" is a union jsval_layout. INT32_TO_JSVAL_IMPL is shown above.

The files this can be found in the firefox source are:

mozilla-release/js/public/Value.h (macros, inlines, unions jsval_layout)
mozilla-release/js/src/vm/Interpreter.cpp (main interpreter loop).

The critical thing should be the ((uint64_t)(uint32_t)i32 part when i32 is the
result of a "sll" - this should require an explicit extension to 64bit,
shouldn't it?

Reply via email to