From:             hoesh at dorsum dot hu
Operating system: WIN
PHP version:      Irrelevant
PHP Bug Type:     Reproducible crash
Bug description:  unserilizing doubles might crash

Description:
------------
When a double value stored within the session file, the web server might
crash. It was a mystical problem for us. To solve this issue, there need
some workaround at the VAR_UNSERIALIZER.RE source code:



"d:" (iv | nv | nvexp) ";"      {

        *p = YYCURSOR;

        INIT_PZVAL(*rval);

        ZVAL_DOUBLE(*rval, atof(start + 2));

        return 1;

}



The problem is the difference in the implementation of the function
'atof'. While general C implementations looks ahead until a non digital
character found, microsoft C tries to determine the string's length with a
call to 'strlen'. This can couse the crash some times, when the accessible
memory doesn't contain '\0'. The report about the memory dump is following
in the 'Reproducible code' section. For a quick sight I placed the various
implementations of the 'atof' function within the 'Expected result'
block.



As we figured out, this issue comes up only when unserializing sessions,
not zval represented strings, as those zvals are closed with '\0'.



Reproduce code:
---------------
Here is the report from Microsoft. They thought somthings wrong with
PHP... :)



Call stack:

----------------

0c19e228 019240e2 1b0419d8 43e72508 03019af0 msvcrt!atof+0x25 (CONV:
cdecl)

[atof.c @ 57]

WARNING: Stack unwind information not available. Following frames may be

wrong.

0c19e2d4 03019b88 1b097000 0c19e3b4 43e72508 php4ts+0x940e2

03019c88 00000000 00010002 00000000 0005006d 0x3019b88



00 0c19e1f8 780167f9 msvcrt!strlen(void)+0x20 [intel\strlen.asm @ 78]

01 0c19e228 019240e2 msvcrt!atof(char * nptr = 0x1b0419d8

"1077611306196.2860107421875;a:5:{s:5:"tabid";s:5:"tab_5";s:3:"ct0";s:13:"1077612213758";s:3:"ct1";a:1:{s:13:"403b0afeae402";s:13:"1077612210164";}}s:9:"post_vars";a:0:...



Expected result:
----------------
-- MICROSOFT C IMPLEMENTATION --



double __cdecl atof(

        REG1 const char *nptr

        )

{



#ifdef _MT

        struct _flt fltstruct;      /* temporary structure */

#endif  /* _MT */



        /* scan past leading space/tab characters */



        while ( isspace((int)(unsigned char)*nptr) )

                nptr++;



        /* let _fltin routine do the rest of the work */



#ifdef _MT

        return( *(double *)&(_fltin2( &fltstruct, nptr, strlen(nptr), 0, 0
)->

        dval) );

#else  /* _MT */

        return( *(double *)&(_fltin( nptr, strlen(nptr), 0, 0 )->dval) );

#endif  /* _MT */

}



-- GENERAL C IMPLEMENTATION (may differ at some point) --



double

atof(p)

register char *p;

{

        register c;

        double fl, flexp, exp5;

        double big = 72057594037927936.;  /*2^56*/

        double ldexp();

        int nd;

        register eexp, exp, neg, negexp, bexp;



        neg = 1;

        while((c = *p++) == ' ')

                ;

        if (c == '-')

                neg = -1;

        else if (c=='+')

                ;

        else

                --p;



        exp = 0;

        fl = 0;

        nd = 0;

        while ((c = *p++), isdigit(c)) {

                if (fl<big)

                        fl = 10*fl + (c-'0');

                else

                        exp++;

                nd++;

        }



        if (c == '.') {

                while ((c = *p++), isdigit(c)) {

                        if (fl<big) {

                                fl = 10*fl + (c-'0');

                                exp--;

                        }

                nd++;

                }

        }



        negexp = 1;

        eexp = 0;

        if ((c == 'E') || (c == 'e')) {

                if ((c= *p++) == '+')

                        ;

                else if (c=='-')

                        negexp = -1;

                else

                        --p;



                while ((c = *p++), isdigit(c)) {

                        eexp = 10*eexp+(c-'0');

                }

                if (negexp<0)

                        eexp = -eexp;

                exp = exp + eexp;

        }



        negexp = 1;

        if (exp<0) {

                negexp = -1;

                exp = -exp;

        }





        if((nd+exp*negexp) < -LOGHUGE){

                fl = 0;

                exp = 0;

        }

        flexp = 1;

        exp5 = 5;

        bexp = exp;

        for (;;) {

                if (exp&01)

                        flexp *= exp5;

                exp >>= 1;

                if (exp==0)

                        break;

                exp5 *= exp5;

        }

        if (negexp<0)

                fl /= flexp;

        else

                fl *= flexp;

        fl = ldexp(fl, negexp*bexp);

        if (neg<0)

                fl = -fl;

        return(fl);

}




-- 
Edit bug report at http://bugs.php.net/?id=27458&edit=1
-- 
Try a CVS snapshot (php4):  http://bugs.php.net/fix.php?id=27458&r=trysnapshot4
Try a CVS snapshot (php5):  http://bugs.php.net/fix.php?id=27458&r=trysnapshot5
Fixed in CVS:               http://bugs.php.net/fix.php?id=27458&r=fixedcvs
Fixed in release:           http://bugs.php.net/fix.php?id=27458&r=alreadyfixed
Need backtrace:             http://bugs.php.net/fix.php?id=27458&r=needtrace
Need Reproduce Script:      http://bugs.php.net/fix.php?id=27458&r=needscript
Try newer version:          http://bugs.php.net/fix.php?id=27458&r=oldversion
Not developer issue:        http://bugs.php.net/fix.php?id=27458&r=support
Expected behavior:          http://bugs.php.net/fix.php?id=27458&r=notwrong
Not enough info:            http://bugs.php.net/fix.php?id=27458&r=notenoughinfo
Submitted twice:            http://bugs.php.net/fix.php?id=27458&r=submittedtwice
register_globals:           http://bugs.php.net/fix.php?id=27458&r=globals
PHP 3 support discontinued: http://bugs.php.net/fix.php?id=27458&r=php3
Daylight Savings:           http://bugs.php.net/fix.php?id=27458&r=dst
IIS Stability:              http://bugs.php.net/fix.php?id=27458&r=isapi
Install GNU Sed:            http://bugs.php.net/fix.php?id=27458&r=gnused
Floating point limitations: http://bugs.php.net/fix.php?id=27458&r=float

Reply via email to