------- Comment #13 from jakub at gcc dot gnu dot org  2007-10-15 11:20 -------
To me this looks like aliasing violation in 400.perlbench (and in perl 5.8.8
too, so I'll cite the latter).

#define       IVTYPE          long            /**/
typedef IVTYPE IV;
typedef struct xpviv XPVIV;
typedef size_t STRLEN;
struct xpviv {
    char *      xpv_pv;         /* pointer to malloced string */
    STRLEN      xpv_cur;        /* length of xpv_pv as a C string */
    STRLEN      xpv_len;        /* allocated size */
    IV          xiv_iv;         /* integer value or pv offset */
};
#   define STRUCT_OFFSET(s,m)  (Size_t)(&(((s *)0)->m))
#define STATIC static
#  define pTHX_
#  define LOCK_SV_MUTEX
#  define UNLOCK_SV_MUTEX
extern IV * PL_xiv_root;

In sv.c, we have:

STATIC void
S_del_xiv(pTHX_ XPVIV *p)
{
    IV* xiv = (IV*)((char*)(p) + STRUCT_OFFSET(XPVIV, xiv_iv));
    LOCK_SV_MUTEX;
    *(IV**)xiv = PL_xiv_root;
    PL_xiv_root = xiv;
    UNLOCK_SV_MUTEX;
}

The problem is when Perl_sv_upgrade function is called, with (sv->sv_flags &
0xff) == SVt_IV, mt == SVt_PVNV, ((XPVIV*) (sv)->sv_any)->xiv_iv == 0 and
PL_xiv_root != NULL:
    IV          iv;
...
    switch (SvTYPE(sv)) {
    case SVt_NULL:
        break;
    case SVt_IV:
        iv      = SvIVX(sv);
        del_XIV(SvANY(sv));
        if (mt == SVt_NV)
            mt = SVt_PVNV;
        else if (mt < SVt_PVIV)
            mt = SVt_PVIV;
        break;
...
    switch (mt) {
    case SVt_PVNV:
        SvANY(sv) = new_XPVNV();
        SvPV_set(sv, pv);
        SvCUR_set(sv, cur);
        SvLEN_set(sv, len);
        SvIV_set(sv, iv);
        SvNV_set(sv, nv);
        break;
...

or better preprocessed:

    switch (((sv)->sv_flags & 0xff)) {
    case SVt_NULL:
 break;
    case SVt_IV:
 iv = ((XPVIV*) (sv)->sv_any)->xiv_iv;
 S_del_xiv((XPVIV*) (sv)->sv_any);
 if (mt == SVt_NV)
     mt = SVt_PVNV;
 else if (mt < SVt_PVIV)
     mt = SVt_PVIV;   
 break;
...
    switch (mt) {
...
    case SVt_PVNV:
 (sv)->sv_any = (void*)S_new_xpvnv();
 ((XPV*) (sv)->sv_any)->xpv_pv = pv; 
 ((XPV*) (sv)->sv_any)->xpv_cur = cur;
 ((XPV*) (sv)->sv_any)->xpv_len = len;
 ((XPVIV*) (sv)->sv_any)->xiv_iv = iv;
 ((XPVNV*)(sv)->sv_any)->xnv_nv = nv; 
 break;

when sv.c is compiled with -O2 -fstrict-aliasing, then the
*(IV**)xiv = PL_xiv_root; write isn't considered aliased with the
iv = ((XPVIV*) (sv)->sv_any)->xiv_iv;, because the former accesses the object
as long *, while the latter as long.  The difference between -O2
-fstrict-aliasing and -O2 -fno-strict-aliasing compiled sv.c is then that
in this call ((XPVIV*) (sv)->sv_any)->xiv_iv = iv; stores (long) PL_xiv_root
value before entering this function with -fstrict-aliasing and 0 (i.e. what
((XPVIV*) (sv)->sv_any)->xiv_iv contained on function entry) with
-fno-strict-aliasing.

It seems perl is aware of this, but doesn't care to fix it - Configure has
instead:
        case "$gccversion" in
        1*) ;;
        2.[0-8]*) ;;
        ?*)     echo " "
                echo "Checking if your compiler accepts -fno-strict-aliasing" 2
>&1
                echo 'int main(void) { return 0; }' > gcctest.c
                if $cc -O2 -fno-strict-aliasing -o gcctest gcctest.c; then
                        echo "Yes, it does." 2>&1
                        case "$ccflags" in
                        *strict-aliasing*)
                                echo "Leaving current flags $ccflags alone." 2>
&1
                                ;;
                        *) dflt="$dflt -fno-strict-aliasing" ;;
                        esac
                else
                        echo "Nope, it doesn't, but that's ok." 2>&1
                fi
                ;;
        esac

Not sure what is the best way forward with CPU2006 and GCC though (and what are
other compilers doing to pass 400.perlbench).  Is it acceptable to add
-fno-strict-aliasing just for this test?


-- 


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

Reply via email to