php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #47365 ip2long: 32bit vs. 64bit
Submitted: 2009-02-12 09:27 UTC Modified: 2009-04-28 22:31 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:0 (0.0%)
Same OS:1 (50.0%)
From: flobee at gmail dot com Assigned:
Status: Closed Package: Network related
PHP Version: 5.2.9 OS: SunOS
Private report: No CVE-ID: None
 [2009-02-12 09:27 UTC] flobee at gmail dot com
Description:
------------
ip2long seems to be buggy on 64 Bit Solaris:
Tested with: php5.2.2, php5.2.8



Reproduce code:
---------------
64bit Solaris
#php -r "echo 'x:' . ip2long('web.de') .\"\n\";"
// x:4294967295

32bit Solaris
#php -r "echo 'x:' . ip2long('web.de') .\"\n\";"
// x:false



Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-02-12 13:09 UTC] dsp@php.net
Not enough information was provided for us to be able
to handle this bug. Please re-read the instructions at
http://bugs.php.net/how-to-report.php

If you can provide more information, feel free to add it
to this bug and change the status back to "Open".

Thank you for your interest in PHP.


Which Solaris Version. Solaris 10. On Sparc or on x86?

On OpenSolaris x86 64 bit it returns false as expected:

~/> php -r "var_dump(ip2long('web.de'));"                                      
bool(false)
~/> isainfo -b                                                                 
64
~/> uname -a                                                                   
SunOS Stanford 5.11 snv_106 i86pc i386 i86pc Solaris
~/> php -v                                                                     
PHP 5.2.6 (cli) (built: Jan 28 2009 01:43:42) (DEBUG)
Copyright (c) 1997-2008 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies

 [2009-03-26 01:22 UTC] pada at hrz dot tu-chemnitz dot de
Hi,

I can confirm the bug on Solaris (not OpenSolaris) Version 10 x86_64

# isainfo -b
64
# uname -srvmpi
SunOS 5.10 Generic_118855-33 i86pc i386 i86pc

# Results with unpatched 64 Bit PHP 5.2.8:

# php5 -r "var_dump(ip2long('example.com'));"
int(4294967295) # WRONG, should be bool(false), this is not a valid IP
# php5 -r "var_dump(ip2long(\"1\x00x\"));"
int(1) # correct?
# php5 -r "var_dump(ip2long('0.1'));"
int(1) # correct?
# php5 -r "var_dump(ip2long(''));"
bool(false) # correct
# php5 -r "var_dump(ip2long('0.0.0.0'));"
int(0) # correct
# php5 -r "var_dump(ip2long('0.0.0.1'));"
int(1) # correct
# php5 -r "var_dump(ip2long('1.2.3.4'));"
int(16909060) # correct
# php5 -r "var_dump(ip2long('4.3.2.1'));"
int(67305985) # correct
# php5 -r "var_dump(ip2long('255.255.255.254'));"
int(4294967294) # correct
# php5 -r "var_dump(ip2long('255.255.255.255'));"
int(4294967295) # correct

There is a problem in PHP function ip2long() with the comparison with
INADDR_NONE on 64 bit Solaris systems, since the return value of function inet_addr is stored in an "unsigned long int" variable while struct inet_addr is only 32 bit wide.  The "RETURN_FALSE" branch will never be reached when a string like "example.com" is supplied, since the comparison of ip and INADDR_NONE evaluates to false (it should be true in case of error).

# Patch worked as expected on Debian GNU/Linux squeeze x86_64 with PHP 5.2.6:

# php5 -r "var_dump(ip2long('example.com'));"
bool(false) # correct
# php5 -r "var_dump(ip2long(\"1\x00x\"));"
int(1) # correct?
# php5 -r "var_dump(ip2long('0.1'));"
int(1) # correct?
# php5 -r "var_dump(ip2long(''));"
bool(false) # correct
# php5 -r "var_dump(ip2long('0.0.0.0'));"
int(0) # correct
# php5 -r "var_dump(ip2long('0.0.0.1'));"
int(1) # correct
# php5 -r "var_dump(ip2long('1.2.3.4'));"
int(16909060) # correct
# php5 -r "var_dump(ip2long('4.3.2.1'));"
int(67305985) # correct
# php5 -r "var_dump(ip2long('255.255.255.254'));"
int(4294967294) # correct
# php5 -r "var_dump(ip2long('255.255.255.255'));"
int(4294967295) # correct

I propose the following patch to simplify the code and fix the problem at the same time.  Will this code work on all platforms (Linux, Solaris, BSD, Windows, etc.)?  Your hints and suggestions are welcome.

-------------------- start of patch --------------------
diff -ru php-5.2.9.orig/ext/standard/basic_functions.c php-5.2.9/ext/standard/basic_functions.c
--- php-5.2.9.orig/ext/standard/basic_functions.c 2008-12-31 12:17:44.000000000 +0100
+++ php-5.2.9/ext/standard/basic_functions.c  2009-03-25 19:00:15.000000000 +0100
@@ -97,10 +97,6 @@
 # include "win32/unistd.h"
 #endif

-#ifndef INADDR_NONE
-#define INADDR_NONE ((unsigned long int) -1)
-#endif
-
 #include "zend_globals.h"
 #include "php_globals.h"
 #include "SAPI.h"
@@ -4336,7 +4332,7 @@
 PHP_FUNCTION(ip2long)
 {
  zval **str;
- unsigned long int ip;
+ struct in_addr addr;

  if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
    WRONG_PARAM_COUNT;
@@ -4344,20 +4340,11 @@

  convert_to_string_ex(str);

- if (Z_STRLEN_PP(str) == 0 || (ip = inet_addr(Z_STRVAL_PP(str))) == INADDR_NONE) {
-   /* the only special case when we should return -1 ourselves,
-    * because inet_addr() considers it wrong. We return 0xFFFFFFFF and
-    * not -1 or ~0 because of 32/64bit issues.
-    */
-   if (Z_STRLEN_PP(str) == sizeof("255.255.255.255") - 1 &&
-     !memcmp(Z_STRVAL_PP(str), "255.255.255.255", sizeof("255.255.255.255") - 1)) {
-     RETURN_LONG(0xFFFFFFFF);
-   }
-
-   RETURN_FALSE;
- }
+  if (Z_STRLEN_PP(str) == 0 || inet_pton(AF_INET, Z_STRVAL_PP(str), &addr) != 1) {
+    RETURN_FALSE;
+  }

- RETURN_LONG(ntohl(ip));
+ RETURN_LONG(ntohl(addr.s_addr));
 }
 /* }}} */

-------------------- end of patch --------------------

Kind regards,
Daniel
 [2009-04-28 22:31 UTC] iliaa@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: Thu Nov 21 09:01:32 2024 UTC