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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
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

Pull Requests

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-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 10 21:01:27 2024 UTC