# Getting around the strict aliasing rule in Julia

**URL:** <https://discourse.julialang.org/t/getting-around-the-strict-aliasing-rule-in-julia/130140>\
**Category:** Performance\
**Created:** [June 23, 2025, 6:58pm UTC](https://discourse.julialang.org/t/getting-around-the-strict-aliasing-rule-in-julia/130140 "2025-06-23T18:58:58Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![nhz2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhz2/32/44428_2.png) [@nhz2](https://discourse.julialang.org/u/nhz2)\
**Post date:** [June 23, 2025, 6:58pm UTC](https://discourse.julialang.org/t/getting-around-the-strict-aliasing-rule-in-julia/130140/1 "2025-06-23T18:58:58Z")

</div>

I am trying to better understand Julia’s equivalent of the strict aliasing rule from C.

As background I would like to implement various decoding algorithms in Julia. Looking at the [LZ4](https://github.com/lz4/lz4) C code, they are careful to use [`memcpy`](https://github.com/lz4/lz4/blob/2bc386d57cd9c36780366acead0054fd49dcd36b/lib/lz4.c#L402-L405) and [casting to `unsigned char *`](https://github.com/lz4/lz4/blob/2bc386d57cd9c36780366acead0054fd49dcd36b/lib/lz4.c#L446-L447) when loading or storing to pointers.

From a discussion on slack, Julia’s version of the strict aliasing rule is much stricter than C’s so these methods are not effective in Julia.

The worry is the following simplified example of loading data into a vector may break in some future version of Julia.

```julia
function unsafe_foo!(dst::Ptr{UInt8}, n::Int64)
    for i in 0:n-1
        unsafe_store!(dst + i, 0x01)
    end
end

dst = zeros(UInt64, 4)
dst .= 2
dst_cconv = Base.cconvert(Ptr{UInt8}, reinterpret(UInt8, dst))
GC.@preserve dst_cconv begin
    dst_p = Base.unsafe_convert(Ptr{UInt8}, dst_cconv)
    unsafe_foo!(dst_p, Int64(length(dst)*8))
end

display(dst[1])
# 0x0101010101010101

```

Since `unsafe_foo!` is storing using `Ptr{UInt8}`, but `dst` is a `Vector{UInt64}`, my understand of the strict aliasing rule is that the compiler may reorder the `dst .= 2` to after the call to `unsafe_foo!`: transforming the program to.

```julia
dst = zeros(UInt64, 4)
dst_cconv = Base.cconvert(Ptr{UInt8}, reinterpret(UInt8, dst))
GC.@preserve dst_cconv begin
    dst_p = Base.unsafe_convert(Ptr{UInt8}, dst_cconv)
    unsafe_foo!(dst_p, Int64(length(dst)*8))
end

dst .= 2
display(dst[1])
# 0x0000000000000002

```

Which is obviously not the intended result.

Comments in [Get rid of reinterpret in its current form · Issue #22849 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/22849#issuecomment-315888698) seem to imply that `@noinline` can be used as a “TBAA” barrier, but I’m not sure why that would work. Even if the function is not inline can’t the compiler still analyse how it is writing to memory?

My current idea is to use `ccall` on a global function pointer:

```julia
unsafe_foo!_fp = @cfunction(unsafe_foo!, Cvoid, (Ptr{UInt8}, Int64))
@noinline function indirect_unsafe_foo!(dst::Ptr{UInt8}, n::Int64)
    @ccall $unsafe_foo!_fp(dst::Ptr{UInt8}, n::Int64)::Cvoid
end

```

Am I misunderstanding how the strict aliasing rule applies to Julia code, and there is a less overkill way to solve this?

Should I just document that pointers from reinterpreted arrays should never be passed to `unsafe_foo!`?

---

<div class="post-metadata">

**Author:** ![nhz2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhz2/32/44428_2.png) [@nhz2](https://discourse.julialang.org/u/nhz2)\
**Post date:** [June 30, 2025, 6:09pm UTC](https://discourse.julialang.org/t/getting-around-the-strict-aliasing-rule-in-julia/130140/2 "2025-06-30T18:09:19Z")

</div>

I misunderstood how the strict aliasing rule works in Julia. The example I had doesn’t break Julia’s aliasing rules because using `unsafe_load` and `unsafe_store!` is equivalent to loading and storing with [`memcpy` type punning](https://github.com/lz4/lz4/blob/2bc386d57cd9c36780366acead0054fd49dcd36b/lib/lz4.c#L402-L405) in C.

The strict aliasing rule would be an issue if the example instead used `unsafe_wrap` to write to the pointer in `unsafe_foo!`
