fix(protocol): serialize float32/float64/fkVector in big-endian

The JavaScript client reads floats via readFloatBE/readDoubleBE,
which expect IEEE-754 values in big-endian byte order.
The Nim server was writing them with copyMem in native byte order,
so on little-endian machines (x86_64) the JS side deserialized
FLOAT64 values as garbage (e.g. 1.0 became 3.03865e-319).

Fix serialization by casting to int32/int64 and using bigEndian32/
bigEndian64, mirroring the existing big-endian handling for ints.
Apply the same fix to deserialization and to fkVector elements.
This commit is contained in:
2026-05-14 02:22:07 +03:00
parent a0d2ca7776
commit 8fb5dde858
+15 -6
View File
@@ -169,12 +169,14 @@ proc serializeValue*(buf: var seq[byte], val: WireValue) =
of fkFloat32: of fkFloat32:
var fl = val.float32Val var fl = val.float32Val
var bytes: array[4, byte] var bytes: array[4, byte]
copyMem(addr bytes, unsafeAddr fl, 4) var i32 = cast[int32](fl)
bigEndian32(addr bytes, unsafeAddr i32)
buf.add(bytes) buf.add(bytes)
of fkFloat64: of fkFloat64:
var fl = val.float64Val var fl = val.float64Val
var bytes: array[8, byte] var bytes: array[8, byte]
copyMem(addr bytes, unsafeAddr fl, 8) var i64 = cast[int64](fl)
bigEndian64(addr bytes, unsafeAddr i64)
buf.add(bytes) buf.add(bytes)
of fkString: buf.writeString(val.strVal) of fkString: buf.writeString(val.strVal)
of fkBytes: buf.writeBytes(val.bytesVal) of fkBytes: buf.writeBytes(val.bytesVal)
@@ -192,7 +194,8 @@ proc serializeValue*(buf: var seq[byte], val: WireValue) =
for f in val.vecVal: for f in val.vecVal:
var fl = f var fl = f
var bytes: array[4, byte] var bytes: array[4, byte]
copyMem(addr bytes, unsafeAddr fl, 4) var i32 = cast[int32](fl)
bigEndian32(addr bytes, unsafeAddr i32)
buf.add(bytes) buf.add(bytes)
of fkJson: of fkJson:
buf.writeString(val.jsonVal) buf.writeString(val.jsonVal)
@@ -227,14 +230,18 @@ proc deserializeValue*(buf: openArray[byte], pos: var int, depth: int = 0): Wire
var fl: float32 var fl: float32
var bytes: array[4, byte] var bytes: array[4, byte]
for i in 0..3: bytes[i] = buf[pos + i] for i in 0..3: bytes[i] = buf[pos + i]
copyMem(addr fl, unsafeAddr bytes, 4) var i32: int32
bigEndian32(addr i32, unsafeAddr bytes)
fl = cast[float32](i32)
pos += 4 pos += 4
result = WireValue(kind: fkFloat32, float32Val: fl) result = WireValue(kind: fkFloat32, float32Val: fl)
of fkFloat64: of fkFloat64:
var fl: float64 var fl: float64
var bytes: array[8, byte] var bytes: array[8, byte]
for i in 0..7: bytes[i] = buf[pos + i] for i in 0..7: bytes[i] = buf[pos + i]
copyMem(addr fl, unsafeAddr bytes, 8) var i64: int64
bigEndian64(addr i64, unsafeAddr bytes)
fl = cast[float64](i64)
pos += 8 pos += 8
result = WireValue(kind: fkFloat64, float64Val: fl) result = WireValue(kind: fkFloat64, float64Val: fl)
of fkString: of fkString:
@@ -270,7 +277,9 @@ proc deserializeValue*(buf: openArray[byte], pos: var int, depth: int = 0): Wire
var fl: float32 var fl: float32
var bytes: array[4, byte] var bytes: array[4, byte]
for j in 0..3: bytes[j] = buf[pos + j] for j in 0..3: bytes[j] = buf[pos + j]
copyMem(addr fl, unsafeAddr bytes, 4) var i32: int32
bigEndian32(addr i32, unsafeAddr bytes)
fl = cast[float32](i32)
pos += 4 pos += 4
vec.add(fl) vec.add(fl)
result = WireValue(kind: fkVector, vecVal: vec) result = WireValue(kind: fkVector, vecVal: vec)