ID: 41118 Updated by: [EMAIL PROTECTED] Reported By: mahesh dot vemula at in dot ibm dot com -Status: Bogus +Status: Open -Bug Type: Output Control +Bug Type: Scripting Engine problem Operating System: RHEL 4 PHP Version: 5CVS-2007-04-17 (snap) New Comment:
Hi Ilia, Mahesh is one of a team in IBM who are looking at contributing new PHP tests to the PHP community to improve the coverage of the PHPT tests. This defect reports one of a number of issues that this work has so far uncovered. So as to try and avoid us rasing bogus defects all issues they uncover are first reviewed internally by myself and others. I myself reviewed this issue (and what the PHP manual says on the matter) and considered the issue raised here to be a valid defect. Interpreting a literal expressed in octal notation which is outside the range of a signed 32 bit int as a decimal integer without any warning makes no sense to me at all and certainly is not the behaviour suggested by the PHP manual: http://uk2.php.net/manual/en/language.types.integer.php It says on the subject of integers: "Integers can be specified in decimal (10-based), hexadecimal (16-based) or octal (8-based) notation, optionally preceded by a sign (- or +). If you use the octal notation, you must precede the number with a 0 (zero), to use hexadecimal notation precede the number with 0x" and "If you specify a number beyond the bounds of the integer type, it will be interpreted as a float instead. Also, if you perform an operation that results in a number beyond the bounds of the integer type, a float will be returned instead. and indeed this is what happens if an integer is specified in decimal or hexadecimal notation but not when its specified in octal so at the very least the manual needs updating to document the different behaviour for octal. However, better still would be to fix the code in some way to at least warn users this is happening. The code which is causing this bad/unexpected behaviour is in zend_scanner <ST_IN_SCRIPTING>{LNUM} { if (yyleng < MAX_LENGTH_OF_LONG - 1) { /* Won't overflow */ zendlval->value.lval = strtol(yytext, NULL, 0); } else { errno = 0; zendlval->value.lval = strtol(yytext, NULL, 0); if (errno == ERANGE) { /* Overflow */ zendlval->value.dval = zend_strtod(yytext, NULL); zendlval->type = IS_DOUBLE; return T_DNUMBER; } } zendlval->type = IS_LONG; return T_LNUMBER; } If "yytext" contains an octal value > 017777777777 (i.e decimal 2147483647 )then strtol will return with errno == ERANGE and we will call zend_strtod. Unfortunately zend_strtod does not support octal notation; just decimal and hexadecimal and as a result the number gets interpreted as decimal. To fix the behaviour to be inline with expectations zend_strtod would need to be modified to support octal. I can appreciate this may not be a straightforward change and what one that would need a fare amount of testing so as a temporary/simpler fix could the scanner code not be changed to issue a NOTICE when a integer is expressed in OCTAL that is too large to be expressed as a 32 bit signed integer. This was until a recent change in PHP 5 what happened in the case of large hexadecimal integers and indeed is what still happens on PHP6 as the fix as not yet been applied there, i.e if I run the following code on PHP6: <?php $i = 0xFFFFFFFFFFFFFFFFFFF); var_dump($i); ?> you get >php -f testmod.php PHP Notice: Hex number is too big: 0xFFFFFFFFFFFFFFFFFFF in <path to testcase> on line 7 int(2147483647) i.e a notice is issued and the number set to maximum value for a 32 bit signed integer. Using a similar technique the PHP code could easily be changed as follows: <ST_IN_SCRIPTING>{LNUM} { if (yyleng < MAX_LENGTH_OF_LONG - 1) { /* Won't overflow */ zendlval->value.lval = strtol(yytext, NULL, 0); } else { errno = 0; zendlval->value.lval = strtol(yytext, NULL, 0); //check for octal if (*yytext == '0') { zendlval->value.lval = LONG_MAX; zendlval->type = IS_LONG; zend_error(E_NOTICE,"Octal number is too big: %s", yytext); } else { zendlval->value.dval = zend_strtod(yytext, NULL); zendlval->type = IS_DOUBLE; } } zendlval->type = IS_LONG; return T_LNUMBER; } Assuming that most PHP developers test programs with error_reporting =E_ALL this would at least warn the application writer that the script is not going to behave as expected rather than just silently convert the octal numbers to decimal as the code does today. I am therefore re-eopning the defect for further consideration in light of the above. Regards Andy Wharmby IBM United Kingdom Limited Previous Comments: ------------------------------------------------------------------------ [2007-04-17 14:15:57] [EMAIL PROTECTED] Thank you for taking the time to write to us, but this is not a bug. Please double-check the documentation available at http://www.php.net/manual/ and the instructions on how to report a bug at http://bugs.php.net/how-to-report.php . ------------------------------------------------------------------------ [2007-04-17 13:28:59] mahesh dot vemula at in dot ibm dot com Description: ------------ Octal integer values which are beyond MAX_INT or MIN_INT value are not converted to respective float values as expected, instead they are treated as decimal values. Please see the example attached. Environment: Linux Kernal: Linux 2.6.9 PHP Version: PHP 5.2 (Built on Apr 17, 2007 from snaps.php.net) PHP Configure Setup: ./configure Reproduce code: --------------- <?php var_dump(017777777777); var_dump(020000000000); var_dump(020000000007); var_dump(-017777777777); var_dump(-020000000000); var_dump(-020000000007); ?> Expected result: ---------------- int(2147483647) float(2147483648) float(2147483655) int(-2147483647) int(-2147483648) float(-2147483655) Actual result: -------------- int(2147483647) float(2.0E+10) float(20000000007) int(-2147483647) float(-2.0E+10) float(-20000000007) ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=41118&edit=1