Jump to page: 1 2 3
Thread overview
What exactly does "@safe" mean?
Jun 01, 2013
monarch_dodra
Jun 01, 2013
Nick Sabalausky
Jun 01, 2013
monarch_dodra
Jun 01, 2013
Maxim Fomin
Jun 01, 2013
Maxim Fomin
Jun 01, 2013
Jonathan M Davis
Jun 01, 2013
Peter Alexander
Jun 01, 2013
Jonathan M Davis
Jun 01, 2013
Maxim Fomin
Jun 01, 2013
Peter Alexander
Jun 01, 2013
Jonathan M Davis
Jun 01, 2013
Piotr Szturmaj
Jun 01, 2013
Jonathan M Davis
Jun 01, 2013
Paulo Pinto
Jun 01, 2013
monarch_dodra
Jun 01, 2013
Jonathan M Davis
Jun 02, 2013
monarch_dodra
Jun 02, 2013
Jonathan M Davis
Jun 03, 2013
Jonathan M Davis
Jun 01, 2013
monarch_dodra
Jun 01, 2013
Jonathan M Davis
June 01, 2013
The way I understood it, @safe defines a list of things that are or aren't legal inside the implementation of a function. It also changes the scheme of bounds checking, in release code.

What bothers me though, is that from an interface point of view, it doesn't really mean anything (or at least, I haven't really understood anything). AFAIK: if I call something "@safe", chances of a core dump are relatively "lower", but they can still happen:
* A function that accepts a pointer as an argument can be marked safe, so all bets are off there, no, since the pointer can be dereferenced?
* Member functions for structs that have pointers, too, can be marked safe...

Or does it only mean "if you give me valid pointers, I can't core dump*"?
(*ignoring current flaws, such as escaping slices from static arrays)

The main reason about this question is that now I'm confused about @trusted: what are the conditions a developer needs to take into account before marking a function "@trusted" ?

Ditto for member functions, when they operate on pointer members. Can those be @safe?

Yeah, overall, I'm confused as to what "@safe" means from an interface point of view :(
June 01, 2013
On Sat, 01 Jun 2013 21:59:18 +0200
"monarch_dodra" <monarchdodra@gmail.com> wrote:

> The way I understood it, @safe defines a list of things that are or aren't legal inside the implementation of a function. It also changes the scheme of bounds checking, in release code.
> 
> What bothers me though, is that from an interface point of view,
> it doesn't really mean anything (or at least, I haven't really
> understood anything). AFAIK: if I call something "@safe", chances
> of a core dump are relatively "lower", but they can still happen:
> * A function that accepts a pointer as an argument can be marked
> safe, so all bets are off there, no, since the pointer can be
> dereferenced?
> * Member functions for structs that have pointers, too, can be
> marked safe...
> 
> Or does it only mean "if you give me valid pointers, I can't core
> dump*"?
> (*ignoring current flaws, such as escaping slices from static
> arrays)
> 
> The main reason about this question is that now I'm confused about @trusted: what are the conditions a developer needs to take into account before marking a function "@trusted" ?
> 
> Ditto for member functions, when they operate on pointer members. Can those be @safe?
> 
> Yeah, overall, I'm confused as to what "@safe" means from an interface point of view :(

Core dumps aren't the big problem @safe tries to avoid. The big problem is memory corruption, ie trampling memory you didn't expect to (or shouldn't be allowed to).

June 01, 2013
On Saturday, 1 June 2013 at 20:22:01 UTC, Nick Sabalausky wrote:
> On Sat, 01 Jun 2013 21:59:18 +0200
> "monarch_dodra" <monarchdodra@gmail.com> wrote:
>
>> The way I understood it, @safe defines a list of things that are or aren't legal inside the implementation of a function. It also changes the scheme of bounds checking, in release code.
>> 
>> What bothers me though, is that from an interface point of view, it doesn't really mean anything (or at least, I haven't really understood anything). AFAIK: if I call something "@safe", chances of a core dump are relatively "lower", but they can still happen:
>> * A function that accepts a pointer as an argument can be marked safe, so all bets are off there, no, since the pointer can be dereferenced?
>> * Member functions for structs that have pointers, too, can be marked safe...
>> 
>> Or does it only mean "if you give me valid pointers, I can't core dump*"?
>> (*ignoring current flaws, such as escaping slices from static arrays)
>> 
>> The main reason about this question is that now I'm confused about @trusted: what are the conditions a developer needs to take into account before marking a function "@trusted" ?
>> 
>> Ditto for member functions, when they operate on pointer members. Can those be @safe?
>> 
>> Yeah, overall, I'm confused as to what "@safe" means from an interface point of view :(
>
> Core dumps aren't the big problem @safe tries to avoid. The big problem
> is memory corruption, ie trampling memory you didn't expect to (or
> shouldn't be allowed to).

So, let's say I have:

--------
void foo(int* p) @safe
{
    *p = 0;
}
--------

I suppose that this give foo the liberty of saying "p points to someplace valid" ... "and if not, it's not my fault"?

I suppose something that is trusted then means "I will not trample your memory under any circumstance, even if I'm doing unsafe things under the hood (unless you give a pointer that is already bad)"?
June 01, 2013
On Saturday, 1 June 2013 at 19:59:19 UTC, monarch_dodra wrote:
> The way I understood it, @safe defines a list of things that are or aren't legal inside the implementation of a function. It also changes the scheme of bounds checking, in release code.

You completely get the point. Safe attribute does not guarantee safety, but blocks some practices which are supposed to be unsafe. Such characteristic raises several questions:

1) How strong are @safe commitments? I value them quite weak, because @safe function can call trusted and systems function indirectly.

2) How (un)safe are those practices which are still allowed? They are also unsafe and issue here is not trivial cases like dereferencing null.

Current type system has some holes, so any practice blocked in @safe can be achieved by employing type system holes (delegates, ref and lazy parameters). On the other hand, there is no point in using these holes - just do not make a function @safe if it cannot be. However there is still a problem of doing unintentional (especially memory) errors.

> What bothers me though, is that from an interface point of view, it doesn't really mean anything (or at least, I haven't really understood anything). AFAIK: if I call something "@safe", chances of a core dump are relatively "lower", but they can still happen:
> * A function that accepts a pointer as an argument can be marked safe, so all bets are off there, no, since the pointer can be dereferenced?
> * Member functions for structs that have pointers, too, can be marked safe...

Yes, @safe is not an interface feature (in a sense of delivering some guarantee). As it stands, it is a commitment to not to do some potentially unsafe actions. It is useful only in cases when user doesn't want do unsafe things and asks compiler for help in detecting some of them.

> Or does it only mean "if you give me valid pointers, I can't core dump*"?
> (*ignoring current flaws, such as escaping slices from static arrays)

Of course not.

> The main reason about this question is that now I'm confused about @trusted: what are the conditions a developer needs to take into account before marking a function "@trusted" ?

I think it is the same except what is listed in the spec. Nothing conceptually different.

> Ditto for member functions, when they operate on pointer members. Can those be @safe?

What do you mean?

> Yeah, overall, I'm confused as to what "@safe" means from an interface point of view :(

June 01, 2013
On Saturday, June 01, 2013 21:59:18 monarch_dodra wrote:
> The way I understood it, @safe defines a list of things that are or aren't legal inside the implementation of a function. It also changes the scheme of bounds checking, in release code.
> 
> What bothers me though, is that from an interface point of view,
> it doesn't really mean anything (or at least, I haven't really
> understood anything). AFAIK: if I call something "@safe", chances
> of a core dump are relatively "lower", but they can still happen:
> * A function that accepts a pointer as an argument can be marked
> safe, so all bets are off there, no, since the pointer can be
> dereferenced?
> * Member functions for structs that have pointers, too, can be
> marked safe...
> 
> Or does it only mean "if you give me valid pointers, I can't core
> dump*"?
> (*ignoring current flaws, such as escaping slices from static
> arrays)
> 
> The main reason about this question is that now I'm confused about @trusted: what are the conditions a developer needs to take into account before marking a function "@trusted" ?
> 
> Ditto for member functions, when they operate on pointer members. Can those be @safe?
> 
> Yeah, overall, I'm confused as to what "@safe" means from an interface point of view :(

@safe is for memory safety, meaning that @safe code cannot corrupt memory. You can get segfaults due to null pointers and the like, but you can't have code which writes passed the end of a buffer, or which uses a freed memory, or does anything else which involves writing or reading from memory which variables aren't supposed to have access to.

Assuming that there are no bugs in @safe, the one thing that can invalidate it is @trusted. With @trusted code, it is the _programmer_ who is then guaranteeing that the code is actually @safe. The code is doing something which is potentially not safe (and therefore is considered @system by the compiler) but which _could_ be safe if the code is correct, and if the programmer is marking the code as @trusted, they are then telling the compiler that they've verified that the code isn't doing anything which could corrupt memory. As long as the programmer doesn't screw that up, then any @safe code calling that @trusted function is indeed @safe, but if the programmer screwed it up, then you could still get memory corruption. However, here's really no way to get around that problem with a systems language, since most code needs to eventually call something that's @system (e.g. all I/O needs @system stuff internally). But by limiting how much code is @system or @trusted, most code is @safe with a minimal amount of code having to have been verified by an appropriately competent programmer as being @trusted.

- Jonathan M Davis
June 01, 2013
On Saturday, 1 June 2013 at 20:31:45 UTC, monarch_dodra wrote:
> On Saturday, 1 June 2013 at 20:22:01 UTC, Nick Sabalausky wrote:
>> Core dumps aren't the big problem @safe tries to avoid. The big problem
>> is memory corruption, ie trampling memory you didn't expect to (or
>> shouldn't be allowed to).
>
> So, let's say I have:
>
> --------
> void foo(int* p) @safe
> {
>     *p = 0;
> }
> --------

I don't see how this is related to @safe. Remove the attribute, and you are in same situation.

> I suppose that this give foo the liberty of saying "p points to someplace valid" ... "and if not, it's not my fault"?

I think in D any reference or pointer may refer to anywhere.

Actually, example above is not a big deal. Example of bigger problem:

extern(C) int printf(const char*,...) @safe;

alias int T;

auto foo(lazy T i) @safe
{
   return { return i; } ;
}

auto bar() @safe
{
   T i = 4;
   return foo(i);
}

void baz() @safe
{
   double[2] i = 3.14;
}

void main() @safe
{
   auto x = bar();
   baz();
   printf("%d\n", x());
}

This may print garbage or not, it also can print constant garbage or changing, depending on compiler switches. Assume that foo, bar and baz are splitted in several modules and instead of int there is more complex data structure. This is example of memory error not prevented by @safe.
June 01, 2013
On Saturday, 1 June 2013 at 21:02:44 UTC, Jonathan M Davis wrote:
> @safe is for memory safety, meaning that @safe code cannot corrupt memory. You
> can get segfaults due to null pointers and the like, but you can't have code
> which writes passed the end of a buffer, or which uses a freed memory, or does
> anything else which involves writing or reading from memory which variables
> aren't supposed to have access to.

Not true.

void foo(int* p) @safe
{
	*p = 0;
}

void main()
{
	int[3] buf1 = [1, 2, 3];
	int[1] buf2;
	int* p = buf2.ptr;
	--p;
	foo(p);
	import std.stdio;
	writeln(buf1);
}

For me, this prints [1, 2, 0]. You could easily come up with an example which writes to freed memory.

You can argue that foo didn't "cause" this problem (the undefined behaviour from the pointer arithmetic in main did), but that's irrelevant: what guarantees do I have when I call a @safe function that I don't have with any non-@safe function?

Do @safe functions only provide guarantees when the inputs are valid, or is it the case the @safe functions are guaranteed to not *introduce* any new undefined behaviour?
June 01, 2013
On Saturday, 1 June 2013 at 21:02:44 UTC, Jonathan M Davis wrote:
> On Saturday, June 01, 2013 21:59:18 monarch_dodra wrote:
>> The way I understood it, @safe defines a list of things that are
>> or aren't legal inside the implementation of a function. It also
>> changes the scheme of bounds checking, in release code.
>> 
>> What bothers me though, is that from an interface point of view,
>> it doesn't really mean anything (or at least, I haven't really
>> understood anything). AFAIK: if I call something "@safe", chances
>> of a core dump are relatively "lower", but they can still happen:
>> * A function that accepts a pointer as an argument can be marked
>> safe, so all bets are off there, no, since the pointer can be
>> dereferenced?
>> * Member functions for structs that have pointers, too, can be
>> marked safe...
>> 
>> Or does it only mean "if you give me valid pointers, I can't core
>> dump*"?
>> (*ignoring current flaws, such as escaping slices from static
>> arrays)
>> 
>> The main reason about this question is that now I'm confused
>> about @trusted: what are the conditions a developer needs to take
>> into account before marking a function "@trusted" ?
>> 
>> Ditto for member functions, when they operate on pointer members.
>> Can those be @safe?
>> 
>> Yeah, overall, I'm confused as to what "@safe" means from an
>> interface point of view :(
>
> @safe is for memory safety, meaning that @safe code cannot corrupt memory. You
> can get segfaults due to null pointers and the like, but you can't have code
> which writes passed the end of a buffer, or which uses a freed memory, or does
> anything else which involves writing or reading from memory which variables
> aren't supposed to have access to.
>
> Assuming that there are no bugs in @safe, the one thing that can invalidate it
> is @trusted. With @trusted code, it is the _programmer_ who is then
> guaranteeing that the code is actually @safe. The code is doing something
> which is potentially not safe (and therefore is considered @system by the
> compiler) but which _could_ be safe if the code is correct, and if the
> programmer is marking the code as @trusted, they are then telling the compiler
> that they've verified that the code isn't doing anything which could corrupt
> memory. As long as the programmer doesn't screw that up, then any @safe code
> calling that @trusted function is indeed @safe, but if the programmer screwed
> it up, then you could still get memory corruption. However, here's really no
> way to get around that problem with a systems language, since most code needs
> to eventually call something that's @system (e.g. all I/O needs @system stuff
> internally). But by limiting how much code is @system or @trusted, most code
> is @safe with a minimal amount of code having to have been verified by an
> appropriately competent programmer as being @trusted.
>
> - Jonathan M Davis

OK. But by that standard, can't (mostly) anything be trusted? What about something that writes garbage, to a memory location it was *asked* to write to? Or if wrong usage of the function can lead to an inconsistence memory state, but without "out of bounds accesses"?

For instance: "emplace!T(T* p)": This function takes the address of a T, and writes T.init over it. It does a memcopy, so it can't be @safe, but I can 100% guarantee I'm not doing anything wrong, so I'm marking it as @trusted. This should be fine, right? Or is raw memory copying alway unsafe?

Now, technically, emplace can't be called in @safe code, since it requires a pointer to begin with.

But still, if I were to give emplace an "already constructed object", it will happily clobber that object for me, leaking the destructor, and possibly putting the program in an invalid memory state.

Now, it was *my* fault for calling emplace with an already built object, but it was the (@trusted) emplace that clobbered-it.

--------
Long story short, I'm having trouble drawing the line between system and trusted functions, especially in regards to these low level operations. The same question also works for, say "move" or "uninitializedArray": both 100% guarantee bounded memory access, but both can leave you with garbage in your memory...
June 01, 2013
On Saturday, June 01, 2013 23:34:09 Peter Alexander wrote:
> On Saturday, 1 June 2013 at 21:02:44 UTC, Jonathan M Davis wrote:
> > @safe is for memory safety, meaning that @safe code cannot
> > corrupt memory. You
> > can get segfaults due to null pointers and the like, but you
> > can't have code
> > which writes passed the end of a buffer, or which uses a freed
> > memory, or does
> > anything else which involves writing or reading from memory
> > which variables
> > aren't supposed to have access to.
> 
> Not true.
> 
> void foo(int* p) @safe
> {
> 	*p = 0;
> }
> 
> void main()
> {
> 	int[3] buf1 = [1, 2, 3];
> 	int[1] buf2;
> 	int* p = buf2.ptr;
> 	--p;
> 	foo(p);
> 	import std.stdio;
> 	writeln(buf1);
> }
> 
> For me, this prints [1, 2, 0]. You could easily come up with an example which writes to freed memory.
> 
> You can argue that foo didn't "cause" this problem (the undefined behaviour from the pointer arithmetic in main did), but that's irrelevant: what guarantees do I have when I call a @safe function that I don't have with any non-@safe function?
> 
> Do @safe functions only provide guarantees when the inputs are valid, or is it the case the @safe functions are guaranteed to not *introduce* any new undefined behaviour?

They're guaranteed to not introduce any such behavior. They can't possibly make any guarantees if the caller did @system operations and passed a bad pointer to the @safe function. But if all of the functions in the call stack are @safe, and you call an @safe function, then you can't get any memory corruption unless it (or a function that it calls) calls an @trusted function which was incorrectly verified by the programmer who marked it as @trusted.

- Jonathan M Davis
June 01, 2013
Am 01.06.2013 23:34, schrieb Peter Alexander:
> On Saturday, 1 June 2013 at 21:02:44 UTC, Jonathan M Davis wrote:
>> @safe is for memory safety, meaning that @safe code cannot corrupt
>> memory. You
>> can get segfaults due to null pointers and the like, but you can't
>> have code
>> which writes passed the end of a buffer, or which uses a freed memory,
>> or does
>> anything else which involves writing or reading from memory which
>> variables
>> aren't supposed to have access to.
>
> Not true.
>
> void foo(int* p) @safe
> {
>      *p = 0;
> }
>
> void main()
> {
>      int[3] buf1 = [1, 2, 3];
>      int[1] buf2;
>      int* p = buf2.ptr;
>      --p;
>      foo(p);
>      import std.stdio;
>      writeln(buf1);
> }
>
> For me, this prints [1, 2, 0]. You could easily come up with an example
> which writes to freed memory.
>
> You can argue that foo didn't "cause" this problem (the undefined
> behaviour from the pointer arithmetic in main did), but that's
> irrelevant: what guarantees do I have when I call a @safe function that
> I don't have with any non-@safe function?
>
> Do @safe functions only provide guarantees when the inputs are valid, or
> is it the case the @safe functions are guaranteed to not *introduce* any
> new undefined behaviour?

I always assumed that the role of @safe is to behave like safe code in Ada, Modula-3, C#, Oberon family and so on.

No C like tricks are allowed and in certain scenarios one could even disallow the linkage of modules not considered safe.

For example in .NET, IIS only allows assemblies with unsafe code if configured by the administrator. Unsafe code is also forbidden for Go
packages on App Engine.

--
Paulo
« First   ‹ Prev
1 2 3