Thread overview
[Issue 9463] New: make @safe "non-escapable"
Feb 06, 2013
jfanatiker@gmx.at
Feb 06, 2013
Jesse Phillips
Feb 06, 2013
jfanatiker@gmx.at
Feb 06, 2013
Jonathan M Davis
Feb 07, 2013
jfanatiker@gmx.at
Feb 07, 2013
Jonathan M Davis
Feb 07, 2013
jfanatiker@gmx.at
Feb 07, 2013
jfanatiker@gmx.at
Feb 07, 2013
jfanatiker@gmx.at
February 06, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9463

           Summary: make @safe "non-escapable"
           Product: D
           Version: unspecified
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: jfanatiker@gmx.at


--- Comment #0 from jfanatiker@gmx.at 2013-02-06 12:50:57 PST ---
Currently the following code is valid:
@safe {
int test1() @system {
    int* p=new int;
    *p++=8;
    return 7;
}
}

So you can mark code system in an already safe section, this makes it impossible to import code into an application in a safe way. With un-escapable '@safe' the above code would be invalid and one could do for example the following:

@safe {
 mixin(import("app.cfg"));
}

for simply guaranteeing that app.cfg only contains safe code.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 06, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9463


Jesse Phillips <Jesse.K.Phillips+D@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |Jesse.K.Phillips+D@gmail.co
                   |                            |m


--- Comment #1 from Jesse Phillips <Jesse.K.Phillips+D@gmail.com> 2013-02-06 13:59:51 PST ---
Just thought I'd mention implementation shouldn't affect

@safe:

int test1() @system {
    int* p=new int;
    *p++=8;
    return 7;
}

or at minimum:

@safe:

@system:
int test1() {
    int* p=new int;
    *p++=8;
    return 7;
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 06, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9463



--- Comment #2 from jfanatiker@gmx.at 2013-02-06 15:23:09 PST ---
I personally would prefer the simple consistent rule, that you can not weaken @safe, @trusted once you declared it. If you don't want the whole file @safe, then don't say so.

-> So when I look at code and at the beginning is @safe:, then I would know ok this module is safe and I can use it for my mission critical stuff.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 06, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9463


Jonathan M Davis <jmdavisProg@gmx.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jmdavisProg@gmx.com


--- Comment #3 from Jonathan M Davis <jmdavisProg@gmx.com> 2013-02-06 15:36:34 PST ---
The only difference between using : and {} with attributes is that {} has an end to its scope, whereas : only ends if it's overriden by a conflicting attribute. Differentiating between the two in terms of what they affect seems like a really bad idea to me.

I'd argue that it's up to the functions being mixed in to guarantee that they're @safe, not the code that's mixing them in. And attributes get ignored all the time if they don't apply. Relying on attributes which are applied globally with : or {} is often a bad idea precisely because dmd will happily ignore attributes that it doesn't think are applicable.

> I personally would prefer the simple consistent rule, that you can not weaken @safe, @trusted once you declared it. If you don't want the whole file @safe, then don't say so.

Except that that's always up to the function. You can't weaken @safe because it was never applied in the first place. All that attribute{} or attribute: do is mark symbols with those attributes if applicable, and it doesn't apply if there's a conflicting attribute. The same happens with access levels.

private {
public int foo() { return 42; }
}

dmd quite happily makes foo public. There generally are no special cases with attributes in D (and I can't think of _any_ at the moment). If there were, it would be required to put const on the right-hand side of a function rather than the left (due to the confusion it causes by being on the left, since it looks like it applies to the return type when it doesn't), but Walter refuses to special case attributes like that. They're all treated the same on purpose. And I think that it would be a mistake to treat @safe or @system any differently from the rest.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 07, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9463



--- Comment #4 from jfanatiker@gmx.at 2013-02-06 16:11:11 PST ---
(In reply to comment #3)
> The only difference between using : and {} with attributes is that {} has an end to its scope, whereas : only ends if it's overriden by a conflicting attribute. Differentiating between the two in terms of what they affect seems like a really bad idea to me.
> 
> I'd argue that it's up to the functions being mixed in to guarantee that they're @safe, not the code that's mixing them in. And attributes get ignored all the time if they don't apply. Relying on attributes which are applied globally with : or {} is often a bad idea precisely because dmd will happily ignore attributes that it doesn't think are applicable.

Yeah, but what if you can not trust the code you are mixing in to declare it self @safe, like in the example with the imported configuration. You could validate the code, by greping for @system and @trusted but this would be pretty unreliable, especially with mixins. So you would end up writing your own D parser.

The goal of this feature is to make D more viable for problems one would usually pick a scripting language.

> 
> > I personally would prefer the simple consistent rule, that you can not weaken @safe, @trusted once you declared it. If you don't want the whole file @safe, then don't say so.
> 
> Except that that's always up to the function. You can't weaken @safe because it was never applied in the first place. All that attribute{} or attribute: do is mark symbols with those attributes if applicable, and it doesn't apply if there's a conflicting attribute. The same happens with access levels.
> 
> private {
> public int foo() { return 42; }
> }
> 
> dmd quite happily makes foo public. There generally are no special cases with attributes in D (and I can't think of _any_ at the moment). If there were, it would be required to put const on the right-hand side of a function rather

Thanks for this good explanation. But maybe there is a good solution, simply say that @safe is not applicable if a function was previously marked @system or @trusted. (Might be a problem, because @system is the default, but this could easily be worked around by internally distinguishing between explicitly assigned @system and implicit @system).

So it bails down to the meaning of "applicable".

I just think that this would greatly enhance the usefulness of @safe code. (Easy and efficient sandboxing)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 07, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9463



--- Comment #5 from Jonathan M Davis <jmdavisProg@gmx.com> 2013-02-06 17:28:46 PST ---
> But maybe there is a good solution, simply say that @safe is not applicable if > a function was previously marked @system or @trusted

That's what it does. The function in your example is @system, so the the fact that there's an @safe block around it doesn't affect it.

> Yeah, but what if you can not trust the code you are mixing in to declare it self @safe, like in the example with the imported configuration. You could validate the code, by greping for @system and @trusted but this would be pretty unreliable, especially with mixins. So you would end up writing your own D parser.

Except that you should know what you're mixing in. And you probably shouldn't be mixing in anything that you haven't written yourself. That's just asking for it IMHO. And whether it's @safe or @trusted or whatever doesn't matter much except to the caller, and the caller protects itself by marking itself @safe. You'll then get a compilation error if a function isn't @safe like it's supposed to be. And if you're mixing in code like that as part of your API (in which case, the only way that you'd catch the problem would be unit testse), then you should probably rethink your API anyway. Mixed in code doesn't appear in the documentation.

And if your issue is with scripting, then you're not writing an API. You're writing a script. So, you have full control over your code even if you don't control the code that you're mixing in for some reason (as bad as that would be), and anything @safe calling the functions will immediately give an error for @system functions. In that case, the only ways an @system function wouldn't be caught is if it's never used (in which case it doesn't matter) or if it's called by another @system or @trusted function.

I honestly don't understand what you're doing that would require you to validate that the functions being mixed and are @safe at the point that they're mixed in. That validation will happen when they're used.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 07, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9463



--- Comment #6 from jfanatiker@gmx.at 2013-02-06 17:54:40 PST ---
> it IMHO. And whether it's @safe or @trusted or whatever doesn't matter much except to the caller, and the caller protects itself by marking itself @safe.

You are absolutely right, except for static this().

Maybe for importing stuff, pre-evaluation and rejecting things like static this() might be the way to go.

For having modules dynamically linked in, (instead of extending an application via scripts), maybe a compiler switch -safe causing the compiler only to accept safe code would be a better idea.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 07, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9463


jfanatiker@gmx.at changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |FIXED


--- Comment #7 from jfanatiker@gmx.at 2013-02-06 18:31:43 PST ---
Thanks Jonathan!

By simply mixing in the code in a safe function like this:

@safe void parseConfig() {
  mixin(import("app.cfg"));
}

you have all guarantees you need.

For extending an application in a safe way, a compiler switch '-safe' would be the better way. It would be simpler to implement and completely backwards compatible.

Closing this issue.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 07, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9463



--- Comment #8 from jfanatiker@gmx.at 2013-02-07 01:44:05 PST ---
Sadly, this compiles:

@safe int test2() {
    class Test {
        @system static this()  {
            int *p=new int;
            *p++=8;
        }
    }
    return 10;
}

So no silver bullet either, but smart filtering of source code, disallowing mixin and static this, should do the trick.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------