Ok, I think I understand your misconception now. In julia, local variables don’t have addresses. Instead they are “bindings” that refer to an object.
So, how would you do the swap?
Since local variables have no address, you must explicitly allocate the memory / slot for them, and then you pass this slot to the swap function:
a=Ref(4)
b=Ref(5)
swap(a,b)
In many cases this will boil down to the same machine-code as the C variant. In some cases it will be more like:
uint64_t* a = malloc(8);
uint64_t* b = malloc(8);
*a = 4;
*b = 5;
swap(a,b);
The reason is that the heap alloc can only be elided if a
and b
don’t escape due to the swap
call. In C it doesn’t escape on pain of UB; in Rust, there are all the complex borrowing rules to ensure that it doesn’t escape; in julia, the compiler makes a best-effort to figure out whether the references escape, and when in doubt then a heap allocation is made.
Unfortunately it is quite buggy:
julia> function foo()
v=UInt8[0x41 for i=1:801];
popfirst!(v)
vv=reshape(v, (800, 1))
vvv = reshape(vv, (800,))
s = String(vvv)
Ref(s)
end
foo (generic function with 1 method)
julia> foo()
Base.RefValue{String}(UInt8[0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 … 0x41, 0x41, 0x00, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41])
This clearly leads to a type confusion which will blow up everything.
I couldn’t see a way to finagle the confused writes in julia/src/genericmemory.c at 9a77240f6f81b9d5999d40fdf5e2b6bb84e36783 · JuliaLang/julia · GitHub into a good primitive for exploitation, though.
PS. Type confusion with jl_genericmemory_to_string · Issue #56435 · JuliaLang/julia · GitHub