IntToHex(Value: QWord; Digits: Integer) internally casts QWord to Int64, which causes incorrect behavior for values ≥ 2^63.
Summary
IntToHex(Value: QWord; Digits: Integer) internally casts QWord to Int64, which causes incorrect behavior for values ≥ 2^63. This leads to signed interpretation and compile-time range check warnings when round-tripped into Pascal source.
System Information
Operating system: Windows / Linux Processor architecture: x86-64 Compiler version: 3.2.2 and trunk (confirmed via sysstr.inc) Device: Standard PC
Steps to reproduce
- Compile and run the following code: '''pascal uses SysUtils;
var V: QWord; begin V := $A769CDDE6CFC0000; WriteLn('As QWord: ', V); WriteLn('As Hex: ', IntToHex(V, 16)); end. '''
-
Observe that the hex output appears visually correct, but this hides a problem: the function internally casts QWord → Int64.
-
Now emit this output back into a .pas source file: '''pascal C: array[0..0] of QWord = ( $A769CDDE6CFC0000 ); '''
-
Warning: range check error while evaluating constants (-6383344641626079232 must be between 0 and 18446744073709551615)
Example Project
What is the current bug behavior?
IntToHex(Value: QWord, Digits) casts QWord to Int64, which silently corrupts unsigned values above $7FFFFFFFFFFFFFFF. The output appears hex-correct but becomes signed and causes range-check issues when reused.
What is the expected (correct) behavior?
IntToHex(QWord) should preserve the unsigned value fully and never rely on narrowing casts. Values above 2^63 should be printed as 16-digit hex without triggering signed overflow or invalid constants.
Relevant logs and/or screenshots
Example of invalid constant being produced: '''pascal C: array[0..0] of QWord = ( $A769CDDE6CFC0000 // → interpreted as -6383344641626079232 ); '''
Line with the issue
in sysstr.inc on line 917 uint64 is casted to a int64:
function IntToHex(Value: QWord; Digits: integer): string;
begin
result := IntToHex(Int64(Value), Digits); // this cast is unsafe
end;
Possible fixes
function IntToHex(Value: QWord; Digits: Integer): string;
const
HexDigits: array[0..15] of Char = '0123456789ABCDEF';
var
I: Integer;
begin
SetLength(Result, Digits);
for I := Digits downto 1 do
begin
Result[I] := HexDigits[Value and $F];
Value := Value shr 4;
end;
end;