Describe the bug

The results of Lua cmsgpack are dependent on the host platform.

To reproduce

eval "return cmsgpack.pack(cmsgpack.unpack('\\211\\127\\255\\255\\255\\255\\255\\255\\255'))" 0

This binary string is a msgpack encoded 64bit signed integer - specifically 9223372036854775807 The first byte is 0xd3 which denotes this format.

Running this command on Redis 7.0.8 / OSX (Apple Silicon M2 - OSX 13.1):

"\xcf\x7f\xff\xff\xff\xff\xff\xff\xff"

This is the 64bit unsigned encoding of the same number (so 'fine')

Running this command on Redis 7.0.8 / Linux (Ubuntu 22.04.2 LTS):

"\xca_\x00\x00\x00"

This is a float32 encoding of roughly the right value.

Expected behavior

Actually unsure, what is the correct behaviour, as Lua 5.1 doesn't support 64-bit integers I am somewhat surprised by the OSX response being lossless - but at the same time i'm surprised at the float32-float64 conversion that occurred in the Linux variant.

My expected result is more that both OSen should have identical output.

Additional information

I personally favour the route of an accurate-as-possible int64/float64 result.

Comment From: sundb

Because the precision of double is not consistent across platforms, IS_INT64_EQUIVALENT is inconsistent in determining whether 9223372036854775807 is int64. so cmsgpack.pack will pack 9223372036854775807 as int64(\xcf\x7f\xff\xff\xff\xff\xff\xff\xff) or double(\xca_\x00\x00\x0)

simple test

#include <stdio.h>
#include <stdint.h>

int main() {
    double d = 9223372036854775807;
    printf("%d\n", (int64_t)d == d);
}

# output
ubuntu: 0
mac: 1

Comment From: nicknotfun

Suspected that would be the case, it does suggest a better approach however might be available? I'd have expected 'same in same out' for Redis x-platform.

Comment From: sundb

@nicknotfun i don't know how to do that. just like the following INCRBYFLOAT command example that also shows different results on different platforms.

> INCRBYFLOAT key 9223372036854775807

# mac
"9223372036854775808"

# ubuntu
"9223372036854775807"

The ways I can think of are: 1) treat 9223372036854775807 as a string. 2) upgrade the version of lua to 5.3

Comment From: nicknotfun

In the case of msgpack it arguably should just only ever encode as the most precise it can, e.g. something like:

<=32bit, integer = i32 <=53bit, integer = i64 f32 if lossless, otherwise f64

Nothing guarantees the precise representation of the 53+bit numbers ; and without this it means you cannot reliably communicate with Redis-Lua. The incrbyfloat example I think is distinct as it's solely on Redis to decide; but msgpack is a data interchange format, and round-tripping is an important property for it to have for communication

Comment From: sundb

@nicknotfun In lua(5.3) there is support for storing number in a similar way to what you said, when the number can be stored to int64, it will be `lua_integer(int64_t), otherwise lua_Number(double). but in lua(<5.3) all the numbers are always stored as lua_Number, so precision problem is unavoidable.

Comment From: nicknotfun

I agree lua 5.3 is better, but under 5.1 I think it should prefer consistency.