I read the thread over again.
Could that be a “rule of thumb” for a Julia programmer using pointers?
“to be safe, enclose dereferencing use of a pointer into memory of x in a GC.@preserve x block”.
You said clearly that pointer computation outside (before) the GC.@preserve block is safe. This is a BIG difference between Julia and other languages, e.g. Java with a GC which relocates valid java memory blocks to compactify managed Java heaps.
Sorry for another example - it is not meant as efficient code, it solely demonstrates decoupled computing and dereferencing of a pointer variable and my understanding of “memory belongs to object pd”.
Are both uses of GC.@preserved in the following code snippet correct and necessary?
mutable struct PreservedDemo
s:: String # private instance, only changed by constructor and setstring!
p:: Ptr{UInt8} # private instance, only changed by constructor and setstring!
PreservedDemo(s::String) = new(s,pointer(s))
end
# pointer computation decoupled from pointer dereferencing
function setstring!(pd::PreservedDemo,s::String)
pd.s = s
pd.p = pointer(s)
end
# protect dereferencing of pd.p which points to memory belonging (indirectly) to pd
function codeunit1(pd::PreservedDemo, i::Integer)
# boundschecks ommitted to keep example short
GC.@preserve pd unsafe_load(pd.p+(i-1))
end
# protect dereferencing of pd.p which points to memory belonging to pd.s
function codeunit2(pd::PreservedDemo, i::Integer)
# boundschecks ommitted to keep example short
s = pd.s
GC.@preserve s unsafe_load(pd.p+(i-1))
end
# Testcode
q = PreservedDemo("hello")
codeunit1(q,2) # hex 'e'
codeunit1(q,4) # hex 'l'