From:             wharmby at uk dot ibm dot com
Operating system: Windows XP
PHP version:      5CVS-2007-05-16 (CVS)
PHP Bug Type:     Scripting Engine problem
Bug description:  PHP does not process hexadecimal strings in a consistent 
manner.

Description:
------------
PHP does not process hexadecimal strings in a consistent manner or
document when a hexadecimal string is evaluated as a numeric value and 
when it's not.

Whilst developing new PHPT testcase colleagues of mine have noticed
that PHP does not process hexadecimal strings in a consistent manner 
which makes it more difficult to determine what its expected and what 
is unexpected behaviour.

We have reviewed the documentation in the PHP manual on the subject at
http://www.php.net/manual/en/language.types.string.php and there is no
explicit mention here of support for hexadecimal strings but it does
contain the reference

   "For more information on this conversion, see the Unix manual page for
strtod(3). "

The MSDN description of strtod makes no reference to treatment of
hexadecimal strings but the Linux manual does. 

The following simple testcase demonstrates the inconsistency we are 
seeing and is based on a  testcase in a comment by "wilkinson98 at
hotmail dot com" on the manual back in 2005.

If we add to hexadecimal strings together the  strings are first 
converted to numbers by calling zendi_convert_scalar_to_number() which
calls  zend_bool is_numeric_string() to convert the strings which in 
turn calls the CRT function strtol() to do the conversion. In this 
case strtol() is called with a base of 10 or 16 dependent on whether 
or not the string starts with "0x" 

i.e the code in zend_bool is_numeric_string() reads:

    /* handle hex numbers */
    if (length>=2 && str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
            conv_base=16;
    }
    errno=0;
    local_lval = strtol(str, &end_ptr_long, conv_base);

So hexadecimal strings are evaluated as numerical values and the 
addition produces the expected result. Or at least it does provided 
the string does not start with any white space, e.g "   0x123". Any white
space causes a string to evaluate to 0 which again is not what 
is suggested should happen from reading the description of strtod as
suggested by the PHP manual;  strtod description says white is ignored. So
that needs clarifying too.

If we first cast the strings to "int" before adding them however, the
cast opcode handler calls convert_to_long()which calls
convert_to_long_base() with a base of 10 which in turn calls strtol()
with base 10. As a result the hexadecimal strings both evaluate to 0 
and the result is 0.  The convert_to_long() function could easily be 
changed to employ similar logic to above to set the base dependent on 
the first 2 characters of the string but as convert_to_long() is called by
a number of extension functions to convert 
passed arguments, e.g range() this means that these functions will 
also have their behaviour changed too. Whilst this would be good form the
point of view of consistency it may break existing applications. 

PHP either needs to be changed to either consistently evaluate hexadecimal
strings as numerical values when appropriate (and I 
believe casting a string to an int is a case where an hexadecimal
string should be evaluated as numerical value) or document clearly 
when a hexadecimal string will be evaluated as a numeric value and 
when it's not. 

I am raising this defect to flag the issue and get feed back on whether
the code or manual should be fixed here. I would prefer to see
the code fixed but accept that doing so may break existing applications
and so all that can be done is to document the behaviour.
Either way I am happy to work with my colleagues developing the new PHPT
testcases to determine which code or manual pages need fixing.


Reproduce code:
---------------
<?php

$a = "0x32";
$b = "0x64";

echo $a + $b, "\n";
echo (int)$a + (int)$b, "\n";

?>

Expected result:
----------------
150
150

Actual result:
--------------
150
0

-- 
Edit bug report at http://bugs.php.net/?id=41409&edit=1
-- 
Try a CVS snapshot (PHP 4.4): 
http://bugs.php.net/fix.php?id=41409&r=trysnapshot44
Try a CVS snapshot (PHP 5.2): 
http://bugs.php.net/fix.php?id=41409&r=trysnapshot52
Try a CVS snapshot (PHP 6.0): 
http://bugs.php.net/fix.php?id=41409&r=trysnapshot60
Fixed in CVS:                 http://bugs.php.net/fix.php?id=41409&r=fixedcvs
Fixed in release:             
http://bugs.php.net/fix.php?id=41409&r=alreadyfixed
Need backtrace:               http://bugs.php.net/fix.php?id=41409&r=needtrace
Need Reproduce Script:        http://bugs.php.net/fix.php?id=41409&r=needscript
Try newer version:            http://bugs.php.net/fix.php?id=41409&r=oldversion
Not developer issue:          http://bugs.php.net/fix.php?id=41409&r=support
Expected behavior:            http://bugs.php.net/fix.php?id=41409&r=notwrong
Not enough info:              
http://bugs.php.net/fix.php?id=41409&r=notenoughinfo
Submitted twice:              
http://bugs.php.net/fix.php?id=41409&r=submittedtwice
register_globals:             http://bugs.php.net/fix.php?id=41409&r=globals
PHP 3 support discontinued:   http://bugs.php.net/fix.php?id=41409&r=php3
Daylight Savings:             http://bugs.php.net/fix.php?id=41409&r=dst
IIS Stability:                http://bugs.php.net/fix.php?id=41409&r=isapi
Install GNU Sed:              http://bugs.php.net/fix.php?id=41409&r=gnused
Floating point limitations:   http://bugs.php.net/fix.php?id=41409&r=float
No Zend Extensions:           http://bugs.php.net/fix.php?id=41409&r=nozend
MySQL Configuration Error:    http://bugs.php.net/fix.php?id=41409&r=mysqlcfg

Reply via email to