@safe leak fix?

Steven Schveighoffer schveiguy at yahoo.com
Fri Nov 13 06:05:55 PST 2009


On Fri, 13 Nov 2009 08:45:28 -0500, Denis Koroskin <2korden at gmail.com>  
wrote:

> On Fri, 13 Nov 2009 16:16:29 +0300, Steven Schveighoffer  
> <schveiguy at yahoo.com> wrote:
>
>> On Fri, 13 Nov 2009 07:46:02 -0500, Denis Koroskin <2korden at gmail.com>  
>> wrote:
>>
>>
>>>> Sure (with the current compiler):
>>>>
>>>> char[] foo()
>>>> {
>>>>    char buf[100];
>>>>    // fill buf
>>>>    return strstr(buf, "hi"); // no .dup, buf escapes
>>>> }
>>>>
>>>
>>> No, no, no! It's foo which is unsafe in your example, not strstr!
>>
>> OK, tell me if foo is now safe or unsafe:
>>
>> @safe char[] bar(char[] x);
>>
>> char[] foo()
>> {
>>    char buf[100];
>>    return bar(buf);
>> }
>>
>
> It is unsafe even if bar doesn't return anything (it could store  
> reference to a buf in some global variable, for example). Or accessing  
> globals is considered unsafe now?

No, it's *potentially* unsafe.  If bar is written like this:

@safe char[] bar(char[] x){ return x.dup;}

Then bar is completely safe in all contexts, and therefore foo is  
completely safe.  Merely taking the address of a stack variable does not  
make a function unsafe.

Is this unsafe?

char[] foo()
{
   char buf[100];
   return buf[0..50].dup;
}

What about this?

void foo(int a, int b)
{
   swap(a, b); // uses references to local variables, what if swap stores a  
reference to one of its args in a global?
}

You might understand that if these kinds of thing is not allowed to be  
marked as safe, you might have non-stop complaints from new users and  
critics of D about how D's "safety" features are a joke, just like Vista's  
security popups are a joke.  And then everything gets marked as @trusted  
or unmarked, and safed becomes a complete waste of time.  We need to  
choose rules that are good for safety, but which allow intuitive code to  
be written.

> It is foo's fault that pointer to a stack allocated buffer is passed and  
> returned outside of the scope. The dangerous line is buf[], which gets a  
> slice out of a static array, not return bar(...). You could as well  
> write:
>
> char[] foo()
> {
>      char buf[100];
>      return buf[]; // no more bar, but code is still dangerous
> }

The line is most of the time fuzzy whose fault it is.  This is why  
definitions of what is allowed and what is not are important.  Your  
example looks obvious, but there is code that does not look so obvious.   
Unless you know exactly the flow of the data in the functions you call,  
then you can't prove whether it's safe or not.  I hope that someday the  
compiler can prove safety even through function calls, but we are a long  
ways away from that.

-Steve



More information about the Digitalmars-d mailing list