php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #74748 HexDec outputs invalid conversions
Submitted: 2017-06-12 08:38 UTC Modified: 2017-06-12 09:35 UTC
From: sysop at pkx dot pw Assigned:
Status: Not a bug Package: Math related
PHP Version: Irrelevant OS: LInux Mint 18
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: sysop at pkx dot pw
New email:
PHP Version: OS:

 

 [2017-06-12 08:38 UTC] sysop at pkx dot pw
Description:
------------
---
From manual page: http://www.php.net/function.hexdec
---



Test script:
---------------
var_dump((int)hexdec(dechex(-9223372036854775805)));

var_dump((int)hexdec(dechex(-9223372036854775804)));

var_dump((int)hexdec(dechex(-9223372036854775803)));

Expected result:
----------------
int(-9223372036854775808)

int(-9223372036854775808)

int(-9223372036854775808)


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-06-12 09:35 UTC] danack@php.net
-Status: Open +Status: Not a bug
 [2017-06-12 09:35 UTC] danack@php.net
You are converting decimal to hex, which converts the number to the representation, but doesn't save the signed information.

$hexed = dechex(-9223372036854775805);
var_dump($hexed);
var_dump(dechex(PHP_INT_MAX));

//Output is 
string(16) "8000000000000003"
string(16) "7fffffffffffffff"

When PHP goes to convert back from this string, to a decimal, it interprets 0x80000000003 as an unsigned number. As that number is bigger than PHP_INT_MAX, it overflows to a floating point number, where weird things start happening, as not every int can be represented in a float above 2**53.

Perhaps you want to be using the pack and unpack functions:

http://php.net/manual/en/function.pack.php
http://php.net/manual/en/function.unpack.php 

Which shouldn't make assumptions about the signedness of numbers.
 [2017-06-12 10:10 UTC] sysop at pkx dot pw
This is clearly a bug, -9223372036854775808 is the same as the defined PHP_INT_MIN.

I need to keep the signedness of the variable, but I guess as a whole php only supports unsigned numbers.

What I mean is your correct some weirdness goes on, as the defined value is output as a integer, but the same value as a variable outputs a float, even through they're the same number.

I have try'ed to use pack with the q syntax however it outputs a invalid hexadecimal number as a whole, so thats wrong too.
 [2017-06-12 11:33 UTC] danack@php.net
> -9223372036854775808 is the same as the defined PHP_INT_MIN.

echo dechex(-9223372036854775808);
// 8000000000000000

which is the same as PHP_INT_MAX + 1. HexDec has no way of knowing which one you meant.

> I guess as a whole php only supports unsigned numbers.
No, in this very particular case PHP can't tell the difference.


> I have try'ed to use pack with the q syntax however it outputs a invalid hexadecimal number as a whole, so thats wrong too.

$packed = pack('J', -9223372036854775805);
echo bin2hex($packed) . "\n";
var_dump(unpack('Jfoo', $packed));

// Output is
8000000000000003
array(1) {
  ["foo"]=>
  int(-9223372036854775805)
}

Please feel free to report a separate bug if you can make a reproduce case.
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Fri Feb 28 03:01:27 2020 UTC