Skip to content

Inconsistent results from === on non-power-of-2 primitives #58434

@NHDaly

Description

@NHDaly

Here is an MRE we tracked down from our real code:

julia> primitive type ByteString18 (18 * 8) end

julia> a = reinterpret(ByteString18, ntuple(_->0x0, 18))
ByteString18(0x000000000000000000000000000000000000)

julia> (a,) === (a,)
false

julia> (a,) === (a,)
true

julia> (a,) === (a,)
false

julia> (a,) === (a,)
false

julia> (a,) === (a,)
false

julia> (a,) === (a,)
true

This is definitely wrong.
This reproduces for me on ARM Mac, x86 Linux, 1.10, and 1.12.

And it's not unique to reinterpret, it shows up with zext as well:

julia> primitive type ByteString18 (18 * 8) end

julia> a = Core.zext_int(ByteString18, 0x0)
ByteString18(0x000000000000000000000000000000000000)

julia> (a,) === (a,)  # should obviously be `true`
false

And also, it's not unique to being all 0s, it works for reinterpreting any values in there.

julia> a = reinterpret(ByteString18, ntuple(_->0xaf, 18)); C = 10000; sum(@eval ((a,) === (a,)) for _ in 1:C) / C
0.7306

So far, we've only ever seen this during constant-folding, but I'm not sure if that's 100% true or not.

Finally, as you'd expect, this issue doesn't seem to affect primitive types that have standard power-of-2 integer sizes: 1,2,4,8,16,32. But most of the rest are affected:

Image ratio of times `(a,) === (a,)` returns `true` out of 3,000 iterations, for different primitive type byte-widths.
Code to generate the above plot:
const MAX_PRIMITIVE_BYTE_STRING = 16 * 8
for BYTES in 1:MAX_PRIMITIVE_BYTE_STRING
    name = Symbol("ByteString$(BYTES)")
    BITS = BYTES * 8
    @eval begin
        primitive type $(name) $(BITS) end
    end
end

out = let iters = 3000, out = Float64[]
    for N in 1:32
        T = eval(Symbol("ByteString$(N)"))
        a = reinterpret(T, ntuple(_->0x0, N))
        push!(out, sum(@eval(($a,) === ($a,)) for _ in 1:iters) / iters)
    end
    out
end

using Plots

plot(out)
vline!([1,2,4,8,16,32])

Metadata

Metadata

Assignees

No one assigned

    Labels

    backport 1.10Change should be backported to the 1.10 releasebugIndicates an unexpected problem or unintended behaviorcompiler:llvmFor issues that relate to LLVM

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions