php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #41118 PHP does not handle overflow of octal integers
Submitted: 2007-04-17 13:28 UTC Modified: 2007-04-22 21:33 UTC
From: mahesh dot vemula at in dot ibm dot com Assigned: tony2001 (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 5CVS-2007-04-17 (snap) OS: RHEL 4
Private report: No CVE-ID: None
 [2007-04-17 13:28 UTC] 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)


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-04-17 14:15 UTC] iliaa@php.net
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-19 10:26 UTC] wharmby@php.net
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
 [2007-04-19 10:58 UTC] tony2001@php.net
Ilia doesn't do MFB, so HEAD still contains outdated (and wrong) code.
I have a patch for this and I'm working on it atm.
 [2007-04-19 11:25 UTC] tony2001@php.net
Fixed in HEAD.
Waiting for Ilia's confirmation on MFH.
 [2007-04-19 12:16 UTC] wharmby at uk dot ibm dot com
Many thanks Tony that looks great.
 [2007-04-22 21:33 UTC] tony2001@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 09:01:28 2024 UTC