ref is unsafe
Zach the Mystic
reachBUTMINUSTHISzach at gOOGLYmail.com
Thu Jan 3 12:49:17 PST 2013
On Sunday, 30 December 2012 at 08:38:27 UTC, Jonathan M Davis
wrote:
> And maybe another solution which I can't think of at the moment
> would be
> better. But my point is that we currently have a _major_ hole
> in SafeD thanks
> to the combination of ref parameters and ref return types, and
> we need to find
> a solution.
>
> - Jonathan M Davis
>
>
> Related: http://d.puremagic.com/issues/show_bug.cgi?id=8838
I've thought about how I think the attributes should work if D is
forced to use them. This was the first system I came up with, but
as you'll see below, the system can be simplified by ignoring
@safe-ty altogether:
Two attributes: @saferef and @inoutref
// "@saferef" is semantically equivalent to "@safe @inoutref"
@saferef ref int fupz(ref int a)
{
somethingUnsafe(); // Error
return a; //Okay
}
// The same function won't work with just @safe
@safe ref int fuz(ref int a)
{
return a; // Error: a @safe function which returns a reference
to
// a variable deriving from one of its parameters
must be
// marked @saferef
}
// Basic rule against using it when not necessary:
// a @saferef or @inoutref function must both accept and return a
ref
@saferef int validate1(ref int a) { return a; } // Error
@inoutref ref int validate2(int a) { return a; } // Error
// @saferef's are chained by compiler enforcement:
@saferef ref int fonz(ref int a) { return a; }
@safe ref int frooz(ref int a)
{
return fonz(a); // Error: a function which returns the result
of one of
// its parameters being passed to a @saferef or
@inoutref
// function must itself be marked @saferef or
@inoutref
}
// The problem of escaping local variables:
@saferef ref int fonz(ref int a) { return a; }
ref int dollop()
{
int local;
return fonz(local); // Error: a function may not return the
result of a local variable passed to a @saferef or an @inoutref
function
}
// @inoutref may be used when you have otherwise un-safe code:
@inoutref ref int froes(ref int a)
{
/+…some unsafe code…+/
return a;
}
ref int f()
{
int local;
return froes(local); // Bug caught now even in @system code
}
// An enhancement: mark harmless parameters as @saferef
@saferef ref int twoParams(@saferef ref int a, ref int b)
{
return a; // Error: a @saferef or @inoutref function may not
return a reference derived from a parameter marked @saferef
return b; // Fine
}
// Only @saferef or @inoutref functions would be able to use
@saferef parameters:
ref int zorf(@saferef ref int a, ref int b) {} // Error
So I typed all of that out and realized that a simpler
alternative would be to ignore @safe altogether and have the
@inoutref functionality be on by default. The only attribute now
required would be @outref, which could be simplified to just
"out" so long as it appeared *before* the parameter list, since
it could be confused for an out contract if it came afterwards.
So:
"@saferef" <=> "@safe @outref" is unnecessary because all
functions are checked, not just @safe ones.
ref int lugs(ref int a)
{
return a; // Okay
}
ref int h(ref int a)
{
return lugs(a); // Okay
int local;
return lugs(local); // Error: may not return the result of a
local variable
// passed to a function which both accepts
and returns a
// ref unless that function is marked "@outref"
}
int d;
@outref ref int saml(ref int a)
{
return *(new int); // Fine
return d; // Fine
return a; // Error: a function marked "@outref" may not return
a reference
// deriving from one of its parameters
}
ref int lugs(ref int a) { return a; }
@outref ref int druh(ref int a)
{
return lugs(a); // Error: a function marked @outref may not
return the result
// of one of its parameters being passed to a
function unless
// that function is itself marked @outref
}
// Must both accept and return a reference
@outref int boops(ref int a) {} // Error
@outref ref int bop(int a) {} // Error
// Harmless parameters may be marked @trusted:
@outref ref int lit(@trusted ref int a, ref int b)
{
return a; // Passes based on the honor system
return b; // Error
}
The second system is much simpler, and it's only a little more
computationally expensive than the first, since the signature of
all functions called with local variables must be scanned for ref
output and input, not just safe ones.
More information about the Digitalmars-d
mailing list