Jump to page: 1 25  
Page
Thread overview
misplaced @trust?
Feb 05, 2015
Zach the Mystic
Feb 05, 2015
Zach the Mystic
Feb 05, 2015
H. S. Teoh
Feb 05, 2015
H. S. Teoh
Feb 05, 2015
Walter Bright
Feb 05, 2015
Walter Bright
Feb 05, 2015
Zach the Mystic
Feb 05, 2015
Walter Bright
Feb 08, 2015
Jacob Carlborg
Feb 05, 2015
CraigDillabaugh
Feb 05, 2015
Zach the Mystic
Feb 05, 2015
Dicebot
Feb 05, 2015
Dicebot
Feb 06, 2015
Dicebot
Feb 06, 2015
Dicebot
Feb 06, 2015
Dicebot
Feb 06, 2015
Dicebot
Feb 06, 2015
Walter Bright
Feb 06, 2015
Tobias Pankrath
Feb 06, 2015
Walter Bright
Feb 06, 2015
Walter Bright
Feb 05, 2015
Walter Bright
Feb 05, 2015
Zach the Mystic
Feb 05, 2015
H. S. Teoh
Feb 05, 2015
H. S. Teoh
Feb 05, 2015
H. S. Teoh
Feb 05, 2015
H. S. Teoh
February 05, 2015
Reading the thread in bug report https://issues.dlang.org/show_bug.cgi?id=14125 gets me thinking, perhaps @trusted is mis-designed.

At the moment, a @trusted function is the same as a @system function, but is allowed to be called from a @safe function. And that's it.

But a @trusted function may only need to be marked @trusted because of a few lines of code. So we now use this mechanism where we mark the @trusted portions with a lambda or static nested function, and call that internally, and mark the entire function @safe.

The benefit of this is, for the 90% of the code that is @safe, the compiler is used as a tool to check the @safe-ty of the function. For the 10% that isn't, we have contained it and marked it, and we can focus on that portion for scrutiny. This becomes EXTREMELY important when it comes to maintenance.

For example, if a @trusted function has some code added to it, the new code needs to be measured to see if it really is safe to call from a @safe function. This may be no easy feat.

At least with the @trusted inner function/lambda, you limit yourself to the code that has been marked as such, and you don't need to worry about the actual @safe code that is added to the function.

Or do you?... the problem with this mentality is interactions with data inside the @safe code after a @trusted function is called can still be subject to memory safety issues. An example (using static functions for clarity):

void foo() @safe
{
   static auto tmalloc(size_t x) @trusted {return (cast(int *)malloc(x * sizeof(int)))[0..x];}
   static void tfree(void[] arr) @trusted {free(arr.ptr);}

   auto mem = tmalloc(100);
   tfree(mem);
   mem[0] = 5;
}

Note that the final line in the function, setting mem[0] to 5, is the only unsafe part. it's safe to malloc, it's safe to free as long as you don't ever refer to that memory again.

But the problem with the above is that @trusted is not needed to apply to the mem[0] = 5 call. And imagine that the mem[0] = 5 function may be simply added, by another person who didn't understand the context. Marking the whole function as safe is kind of meaningless here.

Changing gears, one of the issues raised in the aforementioned bug is that a function like this really should be marked trusted in its entirety. But what does this actually mean?

When we mark a function @safe, we can assume that the compiler has checked it for us. When we mark a function @trusted, we can assume the compiler has NOT checked it for us. But how does this help? A @safe function can call a @trusted function. So there is little difference between a @safe and a @trusted function from an API point of view. I would contend that @trusted really should NEVER HAVE BEEN a function attribute. You may as well call them all @safe, there is no difference.

What I think we need to approach this correctly is that instead of marking *functions* with @trusted, we need to mark *data* and *calls* with @trusted. Once data is used inside a @trusted island, it becomes tainted with the @trusted mark. The compiler can no longer guarantee safety for that data.

So how can we implement this without too much pain? I envision that we can mark lines or blocks inside a @safe function as @trusted (a @trusted block inside a @system function would be a no-op, but allowed). I also envision that any variable used inside the function is internally marked as @safe until it's used in a @trusted block, and then is marked as @trusted (again internally, no requirement to mark in syntax). If at any time during compilation a @trusted variable is used in @safe code, it's a compile error.

There may be situations in which you DO need this to work, and in those cases, I would say a cast(@safe) could get rid of that mark. For example, if you want to return the result of a @trusted call in a @safe function.

Such a change would be somewhat disruptive, but much more in line with what @trusted calls really mean.

I've left some of the details fuzzy on purpose, because I'm not a compiler writer :)

Destroy

-Steve
February 05, 2015
On Thursday, 5 February 2015 at 16:50:18 UTC, Steven Schveighoffer wrote:
> I've left some of the details fuzzy on purpose, because I'm not a compiler writer :)

So you want to spend another 8 years implementing linear typing for D:
http://en.wikipedia.org/wiki/Substructural_type_system

Or maybe give up @safe.

Or implement either a behavioural or dependent type system.

Lots of options.
Lots of theory...

Without type theory => leaky cauldron.
February 05, 2015
On Thursday, 5 February 2015 at 16:50:18 UTC, Steven Schveighoffer wrote:
> Reading the thread in bug report https://issues.dlang.org/show_bug.cgi?id=14125 gets me thinking, perhaps @trusted is mis-designed.
>
> At the moment, a @trusted function is the same as a @system function, but is allowed to be called from a @safe function. And that's it.
>
> But a @trusted function may only need to be marked @trusted because of a few lines of code. So we now use this mechanism where we mark the @trusted portions with a lambda or static nested function, and call that internally, and mark the entire function @safe.
>
> The benefit of this is, for the 90% of the code that is @safe, the compiler is used as a tool to check the @safe-ty of the function. For the 10% that isn't, we have contained it and marked it, and we can focus on that portion for scrutiny. This becomes EXTREMELY important when it comes to maintenance.
>
> For example, if a @trusted function has some code added to it, the new code needs to be measured to see if it really is safe to call from a @safe function. This may be no easy feat.
>
> At least with the @trusted inner function/lambda, you limit yourself to the code that has been marked as such, and you don't need to worry about the actual @safe code that is added to the function.
>
> Or do you?... the problem with this mentality is interactions with data inside the @safe code after a @trusted function is called can still be subject to memory safety issues. An example (using static functions for clarity):
>
> void foo() @safe
> {
>    static auto tmalloc(size_t x) @trusted {return (cast(int *)malloc(x * sizeof(int)))[0..x];}
>    static void tfree(void[] arr) @trusted {free(arr.ptr);}
>
>    auto mem = tmalloc(100);
>    tfree(mem);
>    mem[0] = 5;
> }
>
> Note that the final line in the function, setting mem[0] to 5, is the only unsafe part. it's safe to malloc, it's safe to free as long as you don't ever refer to that memory again.
>
> But the problem with the above is that @trusted is not needed to apply to the mem[0] = 5 call. And imagine that the mem[0] = 5 function may be simply added, by another person who didn't understand the context. Marking the whole function as safe is kind of meaningless here.
>
> Changing gears, one of the issues raised in the aforementioned bug is that a function like this really should be marked trusted in its entirety. But what does this actually mean?
>
> When we mark a function @safe, we can assume that the compiler has checked it for us. When we mark a function @trusted, we can assume the compiler has NOT checked it for us. But how does this help? A @safe function can call a @trusted function. So there is little difference between a @safe and a @trusted function from an API point of view. I would contend that @trusted really should NEVER HAVE BEEN a function attribute. You may as well call them all @safe, there is no difference.
>
> What I think we need to approach this correctly is that instead of marking *functions* with @trusted, we need to mark *data* and *calls* with @trusted. Once data is used inside a @trusted island, it becomes tainted with the @trusted mark. The compiler can no longer guarantee safety for that data.
>
> So how can we implement this without too much pain? I envision that we can mark lines or blocks inside a @safe function as @trusted (a @trusted block inside a @system function would be a no-op, but allowed). I also envision that any variable used inside the function is internally marked as @safe until it's used in a @trusted block, and then is marked as @trusted (again internally, no requirement to mark in syntax). If at any time during compilation a @trusted variable is used in @safe code, it's a compile error.
>
> There may be situations in which you DO need this to work, and in those cases, I would say a cast(@safe) could get rid of that mark. For example, if you want to return the result of a @trusted call in a @safe function.
>
> Such a change would be somewhat disruptive, but much more in line with what @trusted calls really mean.
>
> I've left some of the details fuzzy on purpose, because I'm not a compiler writer :)
>
> Destroy
>
> -Steve

Hey I like the creativity you're showing. Just to give people a concrete idea, you might show some sample code and illustrate how things work. It sure helps when I'm trying to think about things.
February 05, 2015
On 2/5/15 1:12 PM, Zach the Mystic wrote:

>
> Hey I like the creativity you're showing. Just to give people a concrete
> idea, you might show some sample code and illustrate how things work. It
> sure helps when I'm trying to think about things.

So for example:

@safe int *foo()
{
   int *x;
   int *y;
   int z;
   x = new int; // ok
   //y = &z; // not OK
   @trusted y = &z; // OK, but now y is marked as @trusted
   // return y; // not OK, cannot return @trusted pointer in @safe function
   return cast(@safe)y; // ok, we are overriding the compiler.
   // and of course return x; would be ok
}

-Steve
February 05, 2015
On Thursday, 5 February 2015 at 18:21:40 UTC, Steven Schveighoffer wrote:
> On 2/5/15 1:12 PM, Zach the Mystic wrote:
>
>>
>> Hey I like the creativity you're showing. Just to give people a concrete
>> idea, you might show some sample code and illustrate how things work. It
>> sure helps when I'm trying to think about things.
>
> So for example:
>
> @safe int *foo()
> {
>    int *x;
>    int *y;
>    int z;
>    x = new int; // ok
>    //y = &z; // not OK
>    @trusted y = &z; // OK, but now y is marked as @trusted
>    // return y; // not OK, cannot return @trusted pointer in @safe function
>    return cast(@safe)y; // ok, we are overriding the compiler.
>    // and of course return x; would be ok
> }
>
> -Steve

`cast(@safe)`...interesting. It's the most fine-tuned way of adding safety, whereas @trusting a whole function is the most blunt way.

I've been hatching a scheme for reference safety in my head which would automatically track `@trusted y = &z;` above, marking `y` with "scopedepth(1)", which would be unreturnable in @safe code.

I can anticipate the objection that giving people too much power will encourage them to abuse it... but then again, if that were true, who let them mark the whole function `@trusted` to begin with? Your proposal really pinpoints the actual code which needs to be worked on.

You're basically moving the unit of safety from the *function* to the *pointer*, which makes sense to me, since only a pointer can really be unsafe.
February 05, 2015
On Thu, Feb 05, 2015 at 11:50:18AM -0500, Steven Schveighoffer via Digitalmars-d wrote:
> Reading the thread in bug report https://issues.dlang.org/show_bug.cgi?id=14125 gets me thinking, perhaps @trusted is mis-designed.

That's the feeling I'm getting too!

Well, to be fair, I can see why it arose in its current form historically, but history is not justification for mis-design.


> At the moment, a @trusted function is the same as a @system function, but is allowed to be called from a @safe function. And that's it.
> 
> But a @trusted function may only need to be marked @trusted because of a few lines of code. So we now use this mechanism where we mark the @trusted portions with a lambda or static nested function, and call that internally, and mark the entire function @safe.

The more I think about it, the more I'm becoming convinced that @trusted is a misfeature. Basically, it's a blanket permission for a function to perform arbitrary @system operations and yet hide under the sheep's clothing of being callable from @safe code.  While that may work for trivial 4-line functions, it quickly becomes a maintenance nightmare when a large, complex function is marked @trusted.

Consider, for example, if trustedFunction() calls helper functions helper1(), helper2(), and helper3(), that are currently marked @safe. The last review of trustedFunction() verified its safety, *keyed on the fact that helper1, helper2, and helper3 are @safe*. Now, helper1, helper2 and helper3 are not directly related to trustedFunction; they are merely general utilities that trustedFunction depends on. So people may make changes to them later on, without realizing the implications they may have on the trustworthiness of trustedFunction(). One of these changes may, inadvertently or otherwise, make helper1() @system instead of @safe. Note that with template attribute inference, this can even be an *unconscious* change. However, since helper1() is a general utility, nobody realizes that trustedFunction's manual proof of safety has been compromised. As a result, the PR gets merged, and now trustedFunction() is no longer trustworthy but is still marked @trusted.

Worse yet, it may not be helper1() directly that breaks the trustworthiness of trustedFunction(), but helper1 calls helper4 which calls helper5 that in turn calls helper6. Due to some obscure change in helper6, which used to be @safe, it now becomes @system, and because of that helper5, helper4, and helper1 all become @system. But since trustedFunction() is allowed to call @system functions without restriction, the breakage goes completely unnoticed. Even a thorough review of trustedFunction may not detect this problem, unless the reviewer recursively reviews ALL dependencies of trustedFunction.

Now, if @trusted functions are *still* under the restrictions of @safe code, except small parts explicitly marked to require human verification, then if helper1 is outside the marked section, as soon as helper6 changes in safety, trustedFunction no longer compiles. This at least provides us with some safety net in case things go wrong.

However, the problem still remains. No matter how confined those explicitly marked sections of code may be, they are still subject to the above indirect breach of trust problem. I see no real solution to this.


[...]
> At least with the @trusted inner function/lambda, you limit yourself to the code that has been marked as such, and you don't need to worry about the actual @safe code that is added to the function.

Actually, the @trusted inner function is an abuse of @trusted. They are not trustworthy AT ALL, unless, as Walter said on the bug comments, they present an API that CANNOT be made to break safety, no matter what arguments you give it. The current implementation of wrapping &ptr in a @trusted inner function that simply turns the & operator into a @safe operation, is a completely wrong solution. Consider:

	auto trustedFunc(ref int x) @safe {
		ref int trustedDeref(int* x) @trusted {
			return *x;
		}
		auto p = &x;
		trustedDeref(p) = 999;
	}

On the surface, this looks good, since the dangerous operation inside trustedFunc has been overtly marked as such, so reviewers will carefully review it to make sure it's correct... except, it *cannot* be correct, because it's assuming that its CALLER doesn't pass invalid arguments to it. Somebody could easily change the code to:

	auto trustedFunc(ref int x) @safe {
		ref int trustedDeref(int* x) @trusted {
			return *x;
		}
		int* p;		// <--- N.B.: new change, now p is null
		trustedDeref(p) = 999; // arghhh....
	}

The compiler continues to accept it blindly, even though it's now blatantly wrong.

While the *idea* of marking out specific sections of code inside a @trusted function for scrutiny is valid, the above approach is NOT the right way to go about implementing it.

Rather, what *should* have been done, is that trustedFunc should be marked @trusted, but the compiler STILL imposes @safe restrictions on the function body, except for explicitly-marked blocks inside. To use hypothetical syntax, it should look something like this:

	auto trustedFunc(ref int x) @trusted { // <-- @trusted to indicate need of review
		int *p = &x;
		@system {	// indicate that code inside this block needs manual verification
			*p = 999;
		}
		//*p = 888;	// Illegal: @system operations not allowed outside @system block
	}

IOW, the entire function is marked @trusted to indicate that it needs review, but the function body is STILL under @safe restrictions. So @trusted becomes the same as @safe, except that it permits @system blocks inside, and @system operations must be confined to these blocks.


> Or do you?... the problem with this mentality is interactions with data inside the @safe code after a @trusted function is called can still be subject to memory safety issues. An example (using static functions for clarity):
> 
> void foo() @safe
> {
>    static auto tmalloc(size_t x) @trusted {return (cast(int *)malloc(x *
> sizeof(int)))[0..x];}
>    static void tfree(void[] arr) @trusted {free(arr.ptr);}
> 
>    auto mem = tmalloc(100);
>    tfree(mem);
>    mem[0] = 5;
> }
> 
> Note that the final line in the function, setting mem[0] to 5, is the only unsafe part. it's safe to malloc, it's safe to free as long as you don't ever refer to that memory again.
> 
> But the problem with the above is that @trusted is not needed to apply to the mem[0] = 5 call. And imagine that the mem[0] = 5 function may be simply added, by another person who didn't understand the context. Marking the whole function as safe is kind of meaningless here.

Exactly, this is a totally wrong approach to implementing maintainable @trusted functions. The function should not be marked @safe because it is actually @trusted, not @safe. The inner functions tmalloc and tfree are mis-attributed as @trusted, when they are actually @system.


> Changing gears, one of the issues raised in the aforementioned bug is that a function like this really should be marked trusted in its entirety. But what does this actually mean?
> 
> When we mark a function @safe, we can assume that the compiler has checked it for us. When we mark a function @trusted, we can assume the compiler has NOT checked it for us. But how does this help? A @safe function can call a @trusted function. So there is little difference between a @safe and a @trusted function from an API point of view. I would contend that @trusted really should NEVER HAVE BEEN a function attribute. You may as well call them all @safe, there is no difference.

Yes, @trusted in its current incarnation is fundamentally flawed.

However, I don't agree that the entire function can be marked @safe. Otherwise, @safe code will now contain arbitrary @trusted blocks inside, and so anybody can freely escape @safe restrictions just by putting objectionable operations inside @trusted blocks. The function still needs to be marked @trusted -- to draw attention for the need of scrutiny -- *but* the function body is still confined under @safe requirements, except that now the "escape hatch" of @trusted code blocks are permitted as well.


> What I think we need to approach this correctly is that instead of marking *functions* with @trusted, we need to mark *data* and *calls* with @trusted.  Once data is used inside a @trusted island, it becomes tainted with the @trusted mark. The compiler can no longer guarantee safety for that data.
> 
> So how can we implement this without too much pain? I envision that we can mark lines or blocks inside a @safe function as @trusted (a @trusted block inside a @system function would be a no-op, but allowed).

I think it's better to keep @safe as-is, no @trusted blocks are allowed inside @safe code. Instead, change @trusted to mean "@safe by default, but now allow @trusted blocks for performing operations that must be manually verified". Any function that contains these "escape blocks" can no longer be marked @safe, because they now require manual verification.


> I also envision that any variable used inside the function is internally marked as @safe until it's used in a @trusted block, and then is marked as @trusted (again internally, no requirement to mark in syntax). If at any time during compilation a @trusted variable is used in @safe code, it's a compile error.
> 
> There may be situations in which you DO need this to work, and in those cases, I would say a cast(@safe) could get rid of that mark. For example, if you want to return the result of a @trusted call in a @safe function.
> 
> Such a change would be somewhat disruptive, but much more in line with what @trusted calls really mean.
> 
> I've left some of the details fuzzy on purpose, because I'm not a compiler writer :)
[...]

I like the idea of tainting data as @system (for lack of a better term). This increases the compiler's ability to catch mistakes, and does not require completely turning off @safe checks inside @trusted functions. I think it was a grave mistake for @trusted to completely turn off all @safe checks. @trusted functions should still be under @safe restrictions, and any unsafe operations must be explicitly marked as such before being allowed.


T

-- 
I am not young enough to know everything. -- Oscar Wilde
February 05, 2015
On 2/5/15 1:54 PM, H. S. Teoh via Digitalmars-d wrote:

> However, I don't agree that the entire function can be marked @safe.
> Otherwise, @safe code will now contain arbitrary @trusted blocks inside,
> and so anybody can freely escape @safe restrictions just by putting
> objectionable operations inside @trusted blocks. The function still
> needs to be marked @trusted -- to draw attention for the need of
> scrutiny -- *but* the function body is still confined under @safe
> requirements, except that now the "escape hatch" of @trusted code blocks
> are permitted as well.

Let's assume @trusted means @safe code can call it, but it may have @system-like functionality in it (however it happens).

Whether it's in an internal lambda/nested static function or not, the point is, @safe code can call @trusted code. To say that @safe makes some promises above/beyond @trusted is just incorrect.

Now, if you're saying @trusted cannot be called via @safe, then I don't know what your plan is for @trusted :) If that's true, please explain.

-Steve
February 05, 2015
On Thu, Feb 05, 2015 at 06:56:02PM +0000, Zach the Mystic via Digitalmars-d wrote:
> On Thursday, 5 February 2015 at 18:21:40 UTC, Steven Schveighoffer wrote:
> >On 2/5/15 1:12 PM, Zach the Mystic wrote:
> >
> >>
> >>Hey I like the creativity you're showing. Just to give people a concrete idea, you might show some sample code and illustrate how things work. It sure helps when I'm trying to think about things.
> >
> >So for example:
> >
> >@safe int *foo()
> >{
> >   int *x;
> >   int *y;
> >   int z;
> >   x = new int; // ok
> >   //y = &z; // not OK
> >   @trusted y = &z; // OK, but now y is marked as @trusted
> >   // return y; // not OK, cannot return @trusted pointer in @safe
> >function
> >   return cast(@safe)y; // ok, we are overriding the compiler.
> >   // and of course return x; would be ok
> >}
> >
> >-Steve
> 
> `cast(@safe)`...interesting. It's the most fine-tuned way of adding safety, whereas @trusting a whole function is the most blunt way.
> 
> I've been hatching a scheme for reference safety in my head which would automatically track `@trusted y = &z;` above, marking `y` with "scopedepth(1)", which would be unreturnable in @safe code.
> 
> I can anticipate the objection that giving people too much power will encourage them to abuse it... but then again, if that were true, who let them mark the whole function `@trusted` to begin with? Your proposal really pinpoints the actual code which needs to be worked on.
> 
> You're basically moving the unit of safety from the *function* to the *pointer*, which makes sense to me, since only a pointer can really be unsafe.

I mostly like this idea, except that foo() should not be marked @safe. It should be marked @trusted because it still needs review, but the meaning of @trusted should be changed so that it still enforces @safe-ty, except that now @trusted variables are permitted. Or rather, I would call them @system variables -- they *cannot* be trusted, and must be manually verified.

@safe code should not allow any @system variables or any cast(@safe) operations, period. Otherwise, anybody can wrap unsafe operations inside their @safe function and still clothe it with the sheep's clothing of @safe, and @safe becomes a meaningless annotation.

In short, my proposal is:

- @safe should continue being @safe -- no (potentially) unsafe
  operations are allowed, period.

  Rationale: allowing @system variables in @safe code makes the function
  non-verifiable mechanically. This completely breaks the whole point of
  @safe.

- Change the meaning of @trusted (as applied to a function) to require
  @safe inside the function body, but in addition permit @system
  variables and cast(@safe).

  Rationale: the function cannot be verified mechanically to be safe,
  therefore it cannot be marked @safe. It must be marked @trusted to
  draw attention to the fact that manual review is required. However,
  this does not constitute license to perform arbitrary @system
  operations. Instead, any @system code/variable inside the @trusted
  function must be explicitly marked as such, to indicate that these
  items require special attention during review. Everything else must
  still conform to @safe requirements.

- Introduce @system variables for holding tainted values that the
  compiler cannot guarantee the safety of, as well as cast(@safe), as
  described in Steven's post. These constructs are only permitted inside
  @trusted functions. They are prohibited in @safe code, and are no-ops
  in @system code.

  Rationale: to reduce the maintainability problem, @trusted functions
  should not allow @system code by default. Rather, the scope of @system
  code/data inside a @trusted function should be restricted by requiring
  explicit marking. The compiler then helps the verification process by
  ensuring that anything not explicitly marked is still @safe.


T

-- 
Nobody is perfect.  I am Nobody. -- pepoluan, GKC forum
February 05, 2015
On Thu, Feb 05, 2015 at 02:11:32PM -0500, Steven Schveighoffer via Digitalmars-d wrote:
> On 2/5/15 1:54 PM, H. S. Teoh via Digitalmars-d wrote:
> 
> >However, I don't agree that the entire function can be marked @safe. Otherwise, @safe code will now contain arbitrary @trusted blocks inside, and so anybody can freely escape @safe restrictions just by putting objectionable operations inside @trusted blocks. The function still needs to be marked @trusted -- to draw attention for the need of scrutiny -- *but* the function body is still confined under @safe requirements, except that now the "escape hatch" of @trusted code blocks are permitted as well.
> 
> Let's assume @trusted means @safe code can call it, but it may have @system-like functionality in it (however it happens).
> 
> Whether it's in an internal lambda/nested static function or not, the point is, @safe code can call @trusted code. To say that @safe makes some promises above/beyond @trusted is just incorrect.

No, @safe means the compiler can mechanically verify that it is safe, under the assumption that any @trusted function called from @safe code has been manually verified. @trusted means the compiler was not able to mechanically verify the whole function, but it has been manually verified to be safe.

If you allow @system variables in @safe code, then you're essentially make @safe the same thing as @trusted, which means the compiler cannot verify *anything*, so it's making the problem worse, as now you have to manually verify *all* @safe code instead of just the @trusted portions.


> Now, if you're saying @trusted cannot be called via @safe, then I don't know what your plan is for @trusted :) If that's true, please explain.
[...]

The idea is that while we would like the compiler to mechanically verify *everything*, in practice there are some things that the compiler simply cannot verify. Since those remaining things require human effort to verify and humans are prone to errors, we would like to limit the scope of those things by confining them inside @trusted functions, which, ideally, would be few in number and limited in scope. Everything else should be relegated to @safe functions, where we *require* completely automated verification by the compiler.

As it turns out, even within these @trusted functions, we humans could use some help, therefore we'd like the compiler to help us verify as much of these functions as it can for us, and then we can manually check the remaining bits that cannot be mechanically verified. To this end, your idea of tainting data is a valuable tool: by limiting @system-ness to explicitly marked variables, we increase the scope of automatic verification even inside @trusted functions, so that the compiler can help us catch some things that we may have missed when we manually check the code.

If we allow these @system variables inside @safe code, then we have defeated the purpose of having @trusted functions in the first place, because now the scope of functions that require manual inspection expands to *all* @safe functions, which increases the maintainability problem rather than reduce it.

Likewise, in the current implementation @trusted is a wholesale license to perform arbitrary @system operations, which increases the difficulty of manually verifying @trusted functions. (In fact, it's disastrous, since you cannot guarantee that a code change in some remote function won't change the trustworthiness of a verified @trusted function.) Requiring potentially-unsafe data being explicitly marked @system allows us to continue to impose @safe restrictions on everything else, thereby reducing the scope of the remote-code-change problem to overtly marked places where we can focus our scrutiny.


T

-- 
Doubtless it is a good thing to have an open mind, but a truly open mind should be open at both ends, like the food-pipe, with the capacity for excretion as well as absorption. -- Northrop Frye
February 05, 2015
On 2/5/15 11:17 AM, H. S. Teoh via Digitalmars-d wrote:
> In short, my proposal is:

Tainted variables are an interesting topic, but quite distinct from the notion of separating safe code from unsafe code.

As much as I was shocked about the use of @trusted/@safe/@system in std.file, std.array and sadly possibly in other places, I found no evidence that the feature is misdesigned. I continue to consider it a simple, sound, and very effective method of building and interfacing robust code. An excellent engineering solution that offers a lot of power at a modest cost.

I do not support this proposal to change the semantics of @trusted/@safe/@system. A separate tainted data proposal might be of interest for loosely related topics.


Andrei

« First   ‹ Prev
1 2 3 4 5