Allocator-aware @safe reference counting is still not possible
Timon Gehr
timon.gehr at gmx.ch
Mon Jan 30 23:14:57 UTC 2023
On 1/30/23 18:36, Paul Backus wrote:
>
> As far as I am aware, it is impossible to have all three of the following:
>
> 1. @safe containers.
> 2. User-supplied allocators.
> 3. No language changes.
Well, we have @system variables now, so we can have poor man's typestate
together with poor man's move semantics [1], like already proposed by
ntrel and Dukc.
Why is this scheme not workable? Isn't this exactly the kind of problem
(non-trivial memory safety invariant) we invented `@system` variables to
solve?
(With sumtype, I guess you can even move the flags to runtime (at the
cost of template bloat exponential in the number of flags) to get poor
man's dependent type state.)
[1]:
import core.stdc.stdlib;
void main(){
import std.stdio;
void foo()@safe{
auto ptr0=fancyMalloc(16);
writeln(ptr0.borrow((scope ptr){
return cast(int)ptr;
}));
fancyFree(ptr0);
}
foo();
void bar()@safe{
auto ptr0=fancyMalloc(16);
auto ptr1=ptr0.withAliasing.leak;
// ok, leaking is safe
writeln(ptr1);
}
bar();
void baz()@safe{
auto ptr0=fancyMalloc(16);
auto ptr1=ptr0.withAliasing;
// fancyFree(ptr1); // error, not isolated
}
baz();
void qux()@safe{
auto ptr0=fancyMalloc(16);
auto ptr1=ptr0.withAliasing;
// auto ptr2=ptr1.unsafeAddFlags!(PointerFlags.isolated); //
error, unsafe
// fancyFree(ptr2); // (ok)
}
qux();
void flarp()@trusted{
auto ptr0=fancyMalloc(16);
auto ptr1=ptr0.withAliasing;
auto ptr2=ptr1.unsafeAddFlags!(PointerFlags.isolated); // ok,
and we can check it is fine
fancyFree(ptr2); // (ok)
}
flarp();
void bongo()@safe{
auto ptr1=function()@trusted{
auto ptr0=malloc(16);
return
ptr0.unsafeAddFlags!(PointerFlags.mallocd|PointerFlags.isolated); // ok,
we can tell it is mallocd and isolated
}();
fancyFree(ptr1); // ok
}
bongo();
}
enum PointerFlags{
none,
mallocd=1,
isolated=2,
}
struct Pointer(T,PointerFlags flags){
private @system T* ptr;
Pointer!(T,flags&~PointerFlags.isolated) withAliasing()@trusted{
auto result=ptr;
ptr=null;
return typeof(return)(result);
}
static if(!(flags&PointerFlags.isolated)){
T* leak()@trusted{
auto result=ptr;
ptr=null;
return result;
}
}
auto borrow(R)(scope R delegate(scope T*)@safe dg)@trusted{
scope local=ptr;
ptr=null;
scope(exit) ptr=local;
return dg(local);
}
auto borrow(R)(scope R delegate(scope T*)@system dg)@system{
scope local=ptr;
ptr=null;
scope(exit) ptr=local;
return dg(ptr);
}
}
Pointer!(T,flags) unsafeAddFlags(PointerFlags flags,T)(ref T* ptr)@system{
auto result=ptr;
ptr=null;
return typeof(return)(result);
}
Pointer!(T,newFlags|oldFlags) unsafeAddFlags(PointerFlags
newFlags,T,PointerFlags oldFlags)(ref Pointer!(T,oldFlags) ptr)@system{
auto result=ptr.ptr;
ptr.ptr=null;
return unsafeAddFlags!(newFlags|oldFlags)(result);
}
Pointer!(void, PointerFlags.mallocd|PointerFlags.isolated)
fancyMalloc(size_t size)@trusted{
return typeof(return)(malloc(size));
}
void fancyFree(ref Pointer!(void,
PointerFlags.mallocd|PointerFlags.isolated) ptr)@trusted{
if(!ptr.ptr) return;
free(ptr.ptr);
ptr.ptr=null;
}
More information about the Digitalmars-d
mailing list