Jump to content

sh17

Members
  • Content Count

    51
  • Joined

  • Last visited

  • Days Won

    1

sh17 last won the day on November 15 2020

sh17 had the most liked content!

Community Reputation

26 Excellent

Technical Information

  • Delphi-Version
    Delphi 10.4 Sydney

Recent Profile Visitors

2643 profile views
  1. no effect for procedure ResetFPU; const MXCSR_DEF_LIKE_FPC = $1900; var MXCSR : Cardinal; begin asm fninit fwait end; Set8087CW(Default8087CW); MXCSR := MXCSR_DEF_LIKE_FPC; asm ldmxcsr [MXCSR] end; end;
  2. Delphi ================ FPU DUMP ================= Tag: initialization Control Word (CW) : 0x037F Status Word (SW) : 0x0000 MXCSR : 0x00001F80 MXCSR_MASK : 0x0000FFFF Control decoding: Exception masks: IM=1 DM=1 ZM=1 OM=1 UM=1 PM=1 Precision: 64 (extended) Rounding: Nearest Infinity control bit: 0 Status decoding: Exceptions: Invalid=0 Denorm=0 ZeroDiv=0 Overflow=0 Underflow=0 Precision=0 C0=0 C1=0 C2=0 Top=0 C3=0 Busy=0 FSTENV-tag word (raw): 0xFFFF FXSAVE header (first 64 bytes): 7F 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 1F 00 00 FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ST registers (raw 10 bytes each, MSB->LSB): ST0: 00000000000000000000 ST1: 00000000000000000000 ST2: 00000000000000000000 ST3: 00000000000000000000 ST4: 00000000000000000000 ST5: 00000000000000000000 ST6: 00000000000000000000 ST7: 00000000000000000000 XMM registers (16 bytes each): XMM0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 XMM1: 48 00 3A 00 6D 00 6D 00 00 00 00 00 00 00 00 00 XMM2: 64 00 64 00 2C 00 20 00 64 00 2F 00 20 00 4D 00 XMM3: 4D 00 4D 00 4D 00 20 00 79 00 79 00 79 00 79 00 XMM4: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 XMM5: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 XMM6: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 XMM7: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =========================================== FPC ================ FPU DUMP ================= Tag: initialization Control Word (CW) : 0x1372 Status Word (SW) : 0x0000 MXCSR : 0x00001900 MXCSR_MASK : 0x0000FFFF Control decoding: Exception masks: IM=0 DM=1 ZM=0 OM=0 UM=1 PM=1 Precision: 64 (extended) Rounding: Nearest Infinity control bit: 1 Status decoding: Exceptions: Invalid=0 Denorm=0 ZeroDiv=0 Overflow=0 Underflow=0 Precision=0 C0=0 C1=0 C2=0 Top=0 C3=0 Busy=0 FSTENV-tag word (raw): 0xFFFF FXSAVE header (first 64 bytes): 7F 13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 19 00 00 FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ST registers (raw 10 bytes each, MSB->LSB): ST0: 00000000000000000000 ST1: 00000000000000000000 ST2: 00000000000000000000 ST3: 00000000000000000000 ST4: 00000000000000000000 ST5: 00000000000000000000 ST6: 0000000000000080FF3F ST7: 0020F25D970CB78DFF3F XMM registers (16 bytes each): XMM0: 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA XMM1: 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA XMM2: 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA XMM3: 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA XMM4: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 XMM5: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 XMM6: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 XMM7: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ===========================================
  3. Here the win32 asm code. No RTL bug? Delphi does this correctly, only Prism emulates FILD QWORD incorrectly.
  4. Analysis The issue appears specific to Delphi Win32’s code generation for UInt64 → Double conversion. All other compilers (MSVC, FPC, .NET) work correctly under the same emulation environment. The most likely cause is that Delphi uses a particular x86 instruction sequence (possibly an FPU FILD qword ptr or RTL helper) that is mishandled by the Prism emulator. Since the same instruction works correctly on native x86/x64 systems, the failure is likely due to incomplete or incorrect instruction emulation combined with Delphi’s specific calling/stack behavior. Workaround for me function U64ToDouble(u: UInt64): Double; const TWO32: Double = 4294967296.0; var hi, lo: Cardinal; begin hi := Cardinal(u shr 32); lo := Cardinal(u); Result := hi * TWO32 + lo; end;
  5. .NET x86 ok using System; using System.Runtime.InteropServices; namespace PrismU64Bug { class Program { // Referenzkonvertierung via Windows-API (OLEAUT32): [DllImport("oleaut32.dll", CallingConvention = CallingConvention.StdCall)] private static extern int VarR8FromUI8(ulong u, out double r); static void Print(string name, double v) { // "R" = Round-trip Format, zeigt auch 0.0 vs 5.0 sauber Console.WriteLine($"{name} = {v:R}"); } static double U64ToDoubleNoCast(ulong u) { // Sichere Konvertierung ohne direkten UInt64->double Cast: const double TWO32 = 4294967296.0; // 2^32 uint lo = (uint)(u & 0xFFFFFFFF); uint hi = (uint)(u >> 32); return (double)hi * TWO32 + (double)lo; } static void BasicTests() { ulong u = 5UL; // 1) Direkter Cast double d1 = (double)u; // Erwartet: 5.0 // 2) Division UInt64/Double double d2 = (double)5UL / 10.0; // Erwartet: 0.5 // 3) JSON-ähnlicher Fall: 5 + (5 / 10) double val = 5.0 + (double)5UL / 10.0; // Erwartet: 5.5 Print("u->double", d1); Print("5/10.0 ", d2); Print("JSON-like ", val); } static void VariantForms() { double d; d = 1.0 * (double)5UL; Print("1.0 * (ulong)5", d); // 5.0 d = (double)5UL; d = d / 10.0; Print("(ulong->double)/10.0", d); // 0.5 d = (double)5UL; d = d * 0.1; Print("(ulong->double)*0.1", d); // 0.5 // großer Wert ulong big = 1UL << 60; // 2^60 d = (double)big; Print("2^60 as double", d); // ~1.152921504606847e18 } static void OleAutRef() { int hr = VarR8FromUI8(5UL, out double r); Console.WriteLine($"VarR8FromUI8 hr=0x{hr:X8}, r={r:R}"); } static void SafeWorkarounds() { ulong u = 5UL; double safeCast = U64ToDoubleNoCast(u); Print("U64ToDoubleNoCast(5)", safeCast); // 5.0 double safeDiv = U64ToDoubleNoCast(u) / 10.0; Print("U64ToDoubleNoCast(5)/10.0", safeDiv); // 0.5 } static void Main() { Console.WriteLine("--- .NET Framework 4.8 x86 FP Emulation Test ---"); Console.WriteLine("Environment: " + (Environment.Is64BitProcess ? "64-bit process" : "32-bit process")); Console.WriteLine(); BasicTests(); VariantForms(); OleAutRef(); SafeWorkarounds(); Console.WriteLine(); Console.WriteLine("Press <Enter> to exit."); Console.ReadLine(); } } } --- .NET Framework 4.8 x86 FP Emulation Test --- Environment: 32-bit process u->double = 5 5/10.0 = 0,5 JSON-like = 5,5 1.0 * (ulong)5 = 5 (ulong->double)/10.0 = 0,5 (ulong->double)*0.1 = 0,5 2^60 as double = 1,152921504606847E+18 VarR8FromUI8 hr=0x00000000, r=5 U64ToDoubleNoCast(5) = 5 U64ToDoubleNoCast(5)/10.0 = 0,5 Press <Enter> to exit.
  6. MSVC OK #include <stdio.h> #include <stdint.h> int main(void){ uint64_t u = 5ULL; double d1 = (double)u; // UInt64 -> double double d2 = (double)5ULL / 10.0; // Division printf("u->double = %.17g\n", d1); printf("5/10.0 = %.17g\n", d2); return 0; } D:\fpc\c>"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x86\cl" /TC /O2 /arch:SSE2 test.c Microsoft (R) C/C++-Optimierungscompiler Version 19.44.35219 für x86 Copyright (C) Microsoft Corporation. Alle Rechte vorbehalten. test.c Microsoft (R) Incremental Linker Version 14.44.35219.0 Copyright (C) Microsoft Corporation. All rights reserved. /out:test.exe test.obj D:\fpc\c>test u->double = 5 5/10.0 = 0.5 D:\fpc\c>"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x86\cl" /TC /O2 /arch:IA32 test.c Microsoft (R) C/C++-Optimierungscompiler Version 19.44.35219 für x86 Copyright (C) Microsoft Corporation. Alle Rechte vorbehalten. test.c Microsoft (R) Incremental Linker Version 14.44.35219.0 Copyright (C) Microsoft Corporation. All rights reserved. /out:test.exe test.obj D:\fpc\c>test u->double = 5 5/10.0 = 0.5
  7. The same test in Delphi program Project2; {$APPTYPE CONSOLE} uses System.SysUtils; type ULONGLONG = UInt64; function VarR8FromUI8(u: ULONGLONG; out r: Double): Longint; stdcall; external 'oleaut32.dll' name 'VarR8FromUI8'; procedure PrintLine(const Name: string; const V: Double); begin // 17 signifikante Stellen, um Rundungs-/Null-Fehler zu sehen Writeln(Format('%s = %.17g', [Name, V])); end; procedure RunBasicTests; var u : UInt64; d1 : Double; d2 : Double; val : Double; begin u := 5; d1 := u; // Implizite UInt64->Double Konvertierung d2 := UInt64(5) / 10.0; // Division UInt64 / Double val := 5.0 + UInt64(5) / 10.0; // JSON-ähnlich: "5.5" PrintLine('u->double', d1); // erwartet 5 PrintLine('5/10.0 ', d2); // erwartet 0.5 PrintLine('JSON-like', val); // erwartet 5.5 end; procedure RunVariantForms; var d: Double; begin d := 1.0 * UInt64(5); PrintLine('1.0 * UInt64(5)', d); // erwartet 5 d := UInt64(5); d := d / 10.0; PrintLine('(UInt64->Double) / 10.0', d); // erwartet 0.5 d := UInt64(5); d := d * 0.1; PrintLine('(UInt64->Double) * 0.1', d); // erwartet 0.5 d := UInt64(1) shl 60; // 2^60 PrintLine('2^60 as double', d); // ~1.152921504606847e18 end; procedure RunOleAut32Ref; var hr: Longint; r : Double; begin r := -1.0; hr := VarR8FromUI8(5, r); Writeln(Format('VarR8FromUI8 hr=0x%8.8x, r=%.17g', [hr, r])); end; begin Writeln('--- Delphi Win32 Emulation Test ---'); RunBasicTests; RunVariantForms; RunOleAut32Ref; Writeln('Press <Enter> to exit.'); Readln; end. Output --- Delphi Win32 Emulation Test --- u->double = 0 <---- not ok 5/10.0 = 0,5 JSON-like = 5,5 1.0 * UInt64(5) = 5 (UInt64->Double) / 10.0 = 0,5 (UInt64->Double) * 0.1 = 0,5 2^60 as double = 1,152921504606847E018 VarR8FromUI8 hr=0x00000000, r=5 Press <Enter> to exit. --- Delphi Win64 Emulation Test --- u->double = 5 <---- ok 5/10.0 = 0,5 JSON-like = 5,5 1.0 * UInt64(5) = 5 (UInt64->Double) / 10.0 = 0,5 (UInt64->Double) * 0.1 = 0,5 2^60 as double = 1,152921504606847E018 VarR8FromUI8 hr=0x00000000, r=5 Press <Enter> to exit.
  8. I ran a second test with FPC, which didn't have this problem under x86 and Windows ARM 64. There seems to be a bug in the x86 emulation. program project1; {$apptype console} uses SysUtils; type ULONGLONG = UInt64; {$ifdef MSWINDOWS} // Optionaler Referenztest über WinAPI/OLEAUT32 (um Compiler-Codegen zu umgehen) function VarR8FromUI8(u: ULONGLONG; out r: Double): Longint; stdcall; external 'oleaut32.dll' name 'VarR8FromUI8'; {$endif} procedure PrintLine(const Name: string; const V: Double); begin // 17 signifikante Stellen, um Rundungs-/Null-Fehler klar zu sehen Writeln(Format('%s = %.17g', [Name, V])); end; procedure RunBasicTests; var u : UInt64; d1, d2, val : Double; begin u := 5; d1 := u; // Implizite UInt64->Double Konvertierung d2 := UInt64(5) / 10.0; // Division UInt64 / Double val := 5.0 + UInt64(5) / 10.0; // JSON-ähnlicher Fall: "5.5" PrintLine('u->double', d1); // erwartet 5 PrintLine('5/10.0 ', d2); // erwartet 0.5 PrintLine('JSON-like', val); // erwartet 5.5 end; procedure RunVariantForms; var d : Double; begin // alternative Schreibweisen zum Eingrenzen d := 1.0 * UInt64(5); PrintLine('1.0 * UInt64(5)', d); // erwartet 5 d := UInt64(5); d := d / 10.0; PrintLine('(UInt64->Double) / 10.0', d); // erwartet 0.5 d := UInt64(5); d := d * 0.1; PrintLine('(UInt64->Double) * 0.1', d); // erwartet 0.5 // großer Wert d := UInt64(1) shl 60; // 2^60 PrintLine('2^60 as double', d); // ~1.152921504606847e18 end; procedure RunOleAut32Ref; {$ifdef MSWINDOWS} var hr : Longint; r : Double; begin r := -1.0; hr := VarR8FromUI8(5, r); Writeln(Format('VarR8FromUI8 hr=0x%8.8x, r=%.17g', [hr, r])); end; {$else} begin Writeln('OLEAUT32 test skipped (non-Windows).'); end; {$endif} begin Writeln('--- FreePascal x86 FP Emulation Test ---'); RunBasicTests; RunVariantForms; RunOleAut32Ref; end. Output Projekt kompilieren, OS: win32, CPU: i386, Ziel: D:\fpc\project1.exe: Erfolg --- FreePascal x86 FP Emulation Test --- u->double = 5 <----- ok 5/10.0 = 0,5 JSON-like = 5,5 1.0 * UInt64(5) = 5 (UInt64->Double) / 10.0 = 0,5 (UInt64->Double) * 0.1 = 0,5 2^60 as double = 1,152921504606847E18 VarR8FromUI8 hr=0x00000000, r=5
  9. Okay, I wouldn't claim that. I worded that somewhat incorrectly. Hence my question: can anyone else confirm this, perhaps using a different toolchain? I'll try to replicate it myself. But maybe others are more knowledgeable about it.
  10. Hi, I think I've found a bug here, could someone confirm this? I noticed this during JSON processing in the Delphi DMVC framework. The error must therefore lie within Delphi itself. ### Bug Summary **Severity:** Critical **Platform:** Windows 11 ARM64 **Affected Configuration:** Delphi 13 32-bit (x86) applications running under x86-on-ARM64 emulation **Delphi Versions:** All versions with 32-bit compiler **Component:** Runtime Library (RTL) - Floating Point Operations ### Problem Description When running 32-bit Delphi applications on Windows ARM64 through the x86 emulation layer (Prism), critical floating-point conversion and arithmetic operations fail silently, producing incorrect results. ### Discovered Issues #### 1. **UInt64 to Double Implicit Conversion Failure** ```pascal var lValue: UInt64; lDouble: Double; begin lValue := 5; lDouble := lValue; // Expected: 5.0, Actual: 0.0 end; ``` **Impact:** Any implicit conversion from UInt64 to Double produces zero. #### 2. **UInt64 / Double Division Failure** ```pascal var lResult: Double; begin lResult := UInt64(5) / 10.0; // Expected: 0.5, Actual: 0.0 end; ``` **Impact:** Division operations between UInt64 and Double types produce zero. ### Real-World Impact This bug severely affects JSON parsing libraries (e.g., JsonDataObjects) where decimal numbers are parsed: - JSON: `{"amount": 5.5}` → Parsed as: `5.0` (decimal part lost) - JSON: `{"value": 6.6}` → Parsed as: `6.0` (decimal part lost) The parsing process: 1. Integer part `5` is parsed correctly 2. Decimal part `.5` is read as UInt64 value `5` 3. Division `5 / 10.0` should give `0.5` but returns `0.0` 4. Result: `5.0 + 0.0 = 5.0` instead of `5.5` ### Affected Components - **JsonDataObjects.pas** - JSON parsing (decimal numbers) - **MVCFramework.Serializer.JsonDataObjects.pas** - Object deserialization - Any code using UInt64 arithmetic with floating-point numbers ### Root Cause Analysis The bug appears to be in the **x86 emulation layer (Prism)** on Windows ARM64, specifically in: - FPU (Floating Point Unit) emulation - Type conversion routines for 64-bit integers to doubles - Mixed-type arithmetic operations The same code works correctly on: - Native x86/x64 Windows systems - Delphi 64-bit applications on Windows ARM64 ### Workaround Solution **Manual digit-by-digit conversion** bypasses the faulty RTL conversion: ```pascal {$IFNDEF CPUX64} // 32-bit ARM64 emulation fix var lDecimalPart: UInt64; lDivisor: Double; lDecimalValue: Double; i: UInt64; begin lDecimalPart := ParseUInt64(F, P); // e.g., 5 lDivisor := Power10[P - F]; // e.g., 10.0 // Manual conversion: Build Double by adding 1.0 repeatedly lDecimalValue := 0.0; for i := 1 to lDecimalPart do lDecimalValue := lDecimalValue + 1.0; // 1.0 + 1.0 + 1.0 + 1.0 + 1.0 = 5.0 lDecimalValue := lDecimalValue / lDivisor; // 5.0 / 10.0 = 0.5 Value := Value + lDecimalValue; end; {$ELSE} // 64-bit: Use direct conversion (works correctly) Value := Value + ParseUInt64(F, P) / Power10[P - F]; {$ENDIF} ``` ### Additional Mitigations Applied 1. **Disabled x86 ASM code** for 32-bit to avoid assembly-level issues 2. **Forced 8-byte alignment** for Double fields in variant records 3. **Safe memory operations** using `Move()` instead of direct assignment for Doubles 4. **Direct Currency conversion** to avoid Double→Currency conversion issues ### Reproduction Steps 1. Install Windows 11 ARM64 (e.g., on Snapdragon X Elite/Plus) 2. Compile a Delphi application as **Win32** (not Win64) 3. Execute code: ```pascal var lJson: TJsonObject; begin lJson := TJsonObject.Parse('{"test": 5.5}'); ShowMessage(FloatToStr(lJson['test'].FloatValue)); // Shows: 5 (incorrect) lJson.Free; end; ``` ### Expected Behavior Display: `5.5` ### Actual Behavior Display: `5` or `5.0` (decimal part lost) ### System Information - **OS:** Windows 11 ARM64 (24H2 or later) - **Processor:** Qualcomm Snapdragon X Elite/Plus (ARM64) - **Emulation Layer:** Prism (x86-on-ARM64) - **Delphi Version:** Any version with Win32 compiler - **Application Type:** Win32 (x86) ### Recommendations 1. **For Developers:** - Avoid UInt64/Double arithmetic in 32-bit applications targeting ARM64 - Use the workaround code provided above - Consider compiling as Win64 instead of Win32 for ARM64 systems 2. **For Embarcadero:** - Investigate RTL floating-point operations under ARM64 emulation - Provide updated RTL with ARM64 emulation compatibility - Document this limitation in release notes ### Files Modified - `JsonDataObjects.pas` (lines ~7300-7330, ~7860-7880) - `MVCFramework.Serializer.JsonDataObjects.pas` (line ~1593)
  11. sh17

    Any delphi components for VNC or RemoteDesktop?

    spawn451/Remote-Desktop-Streamer-Delphi: A lightweight remote desktop streaming and control solution built entirely in Delphi
  12. sh17

    Why Aren't You Using SQLite?

    i use only sqlite in my server application. All user access it over a REST-Api. So 30 Users are no problem.
×