digitalmars.D - trust is an encapsulation method, not an escape
- Walter Bright (42/42) Feb 05 2015 Consider the following code excerpted from std.array.join:
- Dicebot (4/4) Feb 05 2015 The fact that @trusted is contained in small block doesn't mean
- Andrei Alexandrescu (3/6) Feb 05 2015 As Steve and others have shown, unsafe code under the disguise of
- Dicebot (5/15) Feb 05 2015 Steve has shown exactly the opposite, proving quite some of my
- Dicebot (5/9) Feb 05 2015 I believe that was also the reasoning behind H.S.Teoh proposal
- H. S. Teoh via Digitalmars-d (119/129) Feb 05 2015 This whole discussion has been very tiring and frustrating, because we
- Andrei Alexandrescu (4/6) Feb 05 2015 Before we get into this - do you have evidence of the maintenance
- Andrei Alexandrescu (32/60) Feb 05 2015 There remains the issue - is the messy @trusted code a net negative or
- Walter Bright (3/4) Feb 05 2015 The goo link is disabled for violating goo's terms of service, whatever ...
- Andrei Alexandrescu (3/9) Feb 05 2015 http://forum.dlang.org/thread/mb070a$1ok1$1@digitalmars.com#post-mailman...
- Walter Bright (10/20) Feb 05 2015 Thank you. Essentially, the proposal attaches safe/trusted/system to var...
- Zach the Mystic (2/5) Feb 05 2015 Link?
- Walter Bright (9/14) Feb 05 2015 "A non-unsafe function using unsafe internally should be implemented to ...
- Brad Roberts via Digitalmars-d (21/30) Feb 05 2015 I figured that someone would have already objected to part of this, but
- Walter Bright (2/5) Feb 05 2015 This is correct. Thanks for catching it.
- Walter Bright (10/13) Feb 05 2015 I did a review of all uses of @trusted in std.array:
- Dicebot (7/22) Feb 05 2015 Yes, that was intended and not accidental. Again, we were dealing
- Walter Bright (9/13) Feb 05 2015 I'm sorry I haven't been able to convince you. I don't have any more arg...
- Andrei Alexandrescu (2/20) Feb 05 2015 I second this. -- Andrei
- H. S. Teoh via Digitalmars-d (43/56) Feb 05 2015 You are still not getting the point we've been trying to make since the
- Andrei Alexandrescu (6/9) Feb 05 2015 Again, could you please collect past evidence of such? According to you
- Zach the Mystic (3/14) Feb 05 2015 Evidence does wonders for any argument!
- Dicebot (11/25) Feb 05 2015 This is not about convincing but about showing the example
- Walter Bright (50/52) Feb 05 2015 Let's start with std.array.uninitializedArray():
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (9/16) Feb 05 2015 It might have done so if it ensured that T was a proper value
- Walter Bright (5/18) Feb 05 2015 Good point. Then a constraint can be added to the function signature tha...
- weaselcat (3/27) Feb 05 2015 What's the "D way" of checking if a parameter is a reftype,
- Walter Bright (2/3) Feb 05 2015 http://dlang.org/phobos/std_traits.html
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (9/12) Feb 06 2015 Yes, if you remember to add it. The ideal would be to have the
- Kagamin (2/7) Feb 06 2015 Should be enforce: assert doesn't guard against malicious usage.
- Walter Bright (3/10) Feb 06 2015 Cue my endless attempts to explain the difference between input errors a...
- Vladimir Panteleev (7/20) Feb 06 2015 So which one is it?
- Walter Bright (2/6) Feb 06 2015 http://www.digitalmars.com/d/archives/digitalmars/D/Program_logic_bugs_v...
- Kagamin (5/14) Feb 06 2015 Do you want to say, that safe code can still corrupt memory if
- Vladimir Panteleev (10/19) Feb 06 2015 That doesn't answer my question.
- Andrei Alexandrescu (4/24) Feb 06 2015 Could you all please grant me this wish - let's not get into that vortex...
- Vladimir Panteleev (5/26) Feb 06 2015 What is the problem? Sorry if my post sounded confrontational,
- Andrei Alexandrescu (3/23) Feb 06 2015 I was joking - whenever Walter gets into the assert vs. enforce
- Walter Bright (12/14) Feb 06 2015 It means that you, the programmer, have to decide whether it is environm...
- Vladimir Panteleev (11/14) Feb 06 2015 OK, this is nothing new, but still doesn't answer my question.
- Walter Bright (3/7) Feb 06 2015 You wrote "is clearly a program bug". Therefore use assert(). It's as si...
- Vladimir Panteleev (4/14) Feb 07 2015 OK, thank you. A few years ago you were recommending something
- Tobias Pankrath (46/59) Feb 06 2015 I agree with you, that this should be an assert, but then it
- Tobias Pankrath (1/3) Feb 06 2015 Calling function, forward in the example.
- Kagamin (5/18) Feb 06 2015 A little offtop: if this function is compiled in release mode and
- Walter Bright (3/20) Feb 06 2015 Sigh. Please visit your nearest Catholic school and ask one of the nuns ...
- Kagamin (7/20) Feb 06 2015 Well, ok, not enforce:
- Martin Krejcirik (12/12) Feb 06 2015 If I understand it correctly, Walter is against adding trusted
- Andrei Alexandrescu (3/6) Feb 06 2015 That would be sensible - perhaps the best step forward following this
- John Colvin (21/29) Feb 06 2015 It feels inelegant, but it might be the best way out of a bad
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (5/20) Feb 06 2015 global_datastructure.push(p)
- Andrei Alexandrescu (4/7) Feb 06 2015 That's the natural direction - the default assumption is weak, and you
- Tobias Pankrath (18/37) Feb 06 2015 Some observations.
- Zach the Mystic (5/35) Feb 06 2015 It's been suggested that '@system' be used to mark the blocks in
- David Nadlinger (24/28) Feb 06 2015 This is precisely equivalent to just making the function @safe
- Zach the Mystic (22/50) Feb 06 2015 No it's not. Forcing @trusted functions, with @system blocks
- Walter Bright (9/12) Feb 06 2015 That is correct. @trusted is a statement about the implementation of a f...
- Zach the Mystic (3/18) Feb 06 2015 Please see this post:
- Walter Bright (6/8) Feb 06 2015 Right. It just inverted the interface problem, the problem remains. So, ...
- David Nadlinger (8/16) Feb 06 2015 This still does not solve the template inference problem though,
- Tobias Pankrath (5/12) Feb 06 2015 Don't understand. If that matters, the code shouldn't be marked
- David Nadlinger (39/54) Feb 06 2015 Let's say you have a template function that accepts a range. For
- Zach the Mystic (8/21) Feb 06 2015 I'm trying to promote suggesting '@system' blocks instead of
- Atila Neves (9/16) Feb 06 2015 That might be better than using @safe inside @trusted:
- Zach the Mystic (12/28) Feb 06 2015 Exactly. I think this addresses the concerns. If I read Walter's
- Zach the Mystic (2/25) Feb 06 2015 If this is a real solution, it's kind of exciting! :-)
- Steven Schveighoffer (4/19) Feb 06 2015 BTW, this is H.S. Teoh's suggestion too, and I like it better than mine
- Tobias Pankrath (9/24) Feb 06 2015 Using current semantics we must not mark foo @trusted, if r.front
- David Nadlinger (9/38) Feb 06 2015 Yes.
- Zach the Mystic (9/15) Feb 06 2015 That seems obvious to me too. Isn't the whole purpose of having
- Andrei Alexandrescu (4/18) Feb 06 2015 @trusted functions are @system.
- David Nadlinger (14/26) Feb 06 2015 See my reply to Tobias [1]. This seems to be the crux of our
- Andrei Alexandrescu (2/12) Feb 06 2015 It's clear. I just don't think it's a good point. -- Andrei
- David Nadlinger (5/6) Feb 06 2015 I'm not making a point; I'm posing a problem. What is your
- Andrei Alexandrescu (2/5) Feb 06 2015 I think the problem is overstated. -- Andrei
- H. S. Teoh via Digitalmars-d (8/15) Feb 06 2015 This is precisely why I have lost all interest in @safe. It's clear that
- Andrei Alexandrescu (4/16) Feb 06 2015 I've asked repeatedly for evidence of the "problematic situation", and
- Zach the Mystic (10/21) Feb 06 2015 The best evidence I have it that everyone who actually worked on
- Andrei Alexandrescu (2/4) Feb 06 2015 I see more like two. -- Andrei
- Walter Bright (11/15) Feb 06 2015 You asked:
- Zach the Mystic (20/40) Feb 06 2015 No, at least three of us, Steven, H.S. Teoh and myself have
- Zach the Mystic (3/16) Feb 06 2015 Also, to be clear, any @system block inside a @safe function is
- weaselcat (2/21) Feb 06 2015 this sounds interesting, is anyone going to make a DIP for it?
- Andrei Alexandrescu (62/83) Feb 06 2015 Consider the previous code:
- Zach the Mystic (6/66) Feb 06 2015 Oh I see. There are three posts, in the latter two of which the
- Steven Schveighoffer (6/35) Feb 07 2015 Please understand, Nobody is saying "let's replace incorrect code with
- Zach the Mystic (63/90) Feb 06 2015 First of all, these little @trusted functions are made obsolete
- Zach the Mystic (3/5) Feb 06 2015 ...mechanically replaced, I mean, of course.
- Zach the Mystic (7/13) Feb 06 2015 I didn't rewrite this because I didn't see the trustedXXX
- Zach the Mystic (2/25) Feb 07 2015 It was Teoh's idea. Maybe he should have the honors?
- Walter Bright (5/20) Feb 06 2015 I suspect that such a feature would simply lull people into a false sens...
- David Nadlinger (12/16) Feb 06 2015 How is adding @system to some operations *in addition to* adding
- Walter Bright (15/29) Feb 06 2015 I've said that the usage of those functions was not actually buggy, what...
- H. S. Teoh via Digitalmars-d (17/22) Feb 06 2015 [...]
- Walter Bright (5/16) Feb 06 2015 When the interface to an @system function is changed, all uses of that f...
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (13/30) Feb 07 2015 So what you should ask for is a way to "sign" @trusted with a
- Steven Schveighoffer (10/22) Feb 09 2015 This problem isn't solved by the proposal, however. If you are calling a...
- Zach the Mystic (7/20) Feb 06 2015 You do realize that our proposal *tightens* security, with no
- Zach the Mystic (13/27) Feb 07 2015 I'm also not saying phobos was written perfectly to begin with. I
- Zach the Mystic (3/9) Feb 06 2015 Even a call to a @system function inside a @trusted function must
- Steven Schveighoffer (17/35) Feb 06 2015 I think your strawman is overstated. The "doomsday" is the current
- Andrei Alexandrescu (8/24) Feb 06 2015 I see that just as: code in poor style made its way in Phobos. It
- Walter Bright (6/10) Feb 06 2015 In this thread at 8:20PM last night, Dicebot asked me:
- Steven Schveighoffer (12/23) Feb 09 2015 In the case you bring up, maintenance is easy -- the code is incorrect,
- David Nadlinger (26/27) Feb 07 2015 I think there could hardly be a more persuasive argument that
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (14/19) Feb 07 2015 This is an incredibly poor argument. The fact that there is no
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (13/13) Feb 07 2015 And I'll add this:
- Andrei Alexandrescu (5/29) Feb 07 2015 Nice, thanks for this work. One good guideline here is to almost always
- Tobias Pankrath (3/8) Feb 07 2015 And making this work in functions that already marked @trusted
- Walter Bright (6/18) Feb 06 2015 The problem is, again:
- Steven Schveighoffer (77/120) Feb 06 2015 First, I want to say that I didn't want to cause a huge rift between D
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (19/24) Feb 06 2015 Actually, I think this argument goes against what you are arguing
- Steven Schveighoffer (28/49) Feb 06 2015 That is kind of the point behind H.S. Teoh's idea that @trusted code
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (23/38) Feb 06 2015 But that would break if you want to call a @safe function with a
- Steven Schveighoffer (32/59) Feb 06 2015 The whole point of marking a function trusted instead of a block is that...
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (53/71) Feb 06 2015 Ok, I also prefer that @trusted only apply to whole functions. I
- Steven Schveighoffer (7/19) Feb 06 2015 In the proposal, @trusted code is actually considered the same as @safe,...
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (16/18) Feb 06 2015 But that can't work:
- Steven Schveighoffer (9/25) Feb 07 2015 The idea is that @trusted code still has to be reviewed for memory
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (14/20) Feb 07 2015 This is the wrong way to do it and this is a tooling issue, not a
- Steven Schveighoffer (12/17) Feb 09 2015 No.
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (6/23) Feb 09 2015 That's a nice migration path, btw. First, warn about @trusted
- Steven Schveighoffer (4/27) Feb 09 2015 Yes, that solves the problem of breaking code with this... Nice idea.
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (11/20) Feb 09 2015 The compiler should only verify what is needed for the type
- Meta (4/6) Feb 06 2015 That seems like a good idea and in the spirit of what the goal
- Steven Schveighoffer (4/9) Feb 07 2015 Yes. The big question is, is it worth it? I would say yes, since
- Wyatt (21/22) Feb 06 2015 This quote from Ola, here? That basically describes my job
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (18/26) Feb 06 2015 I don't get this. If:
- Wyatt (28/39) Feb 06 2015 This really won't happen unless statically enforced because
- Tobias Pankrath (3/19) Feb 06 2015 At least I expect the amount of @trusted in phobos to be much
- Andrei Alexandrescu (4/6) Feb 06 2015 Exactly. There's a bunch of low-level interfaces in Phobos and also some...
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (20/46) Feb 06 2015 It isn't that hard for typical library code that is required to
- Walter Bright (6/9) Feb 06 2015 Rust has "unsafe" blocks with specific instructions that it cannot be ve...
- Meta (5/10) Feb 06 2015 Rust guarantees, though, that all code outside of unsafe
- Walter Bright (5/14) Feb 06 2015 Rust guarantees no such thing, because it is explicitly up to the Rust
- Paulo Pinto (15/40) Feb 06 2015 Exactly the reason why I never liked C and C++ only makes it
- Walter Bright (6/9) Feb 06 2015 You are correct in how @trusted is currently (mis)used in Phobos. We aim...
- =?UTF-8?Q?Tobias=20M=C3=BCller?= (5/16) Feb 06 2015 I'd go even further:
- Walter Bright (15/22) Feb 06 2015 This is the crux of the problem - failing to define a safe interface to ...
- Atila Neves (19/67) Feb 06 2015 FWIW, and now that I think I understand how @trusted is supposed
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (20/22) Feb 06 2015 Of course it can work out. You need a formalized process and a
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (2/2) Feb 06 2015 6. @trusted code should be self contained so that changes in
- ponce (7/31) Feb 07 2015 If I understand correctly, your rule o be a trusted function is:
- ponce (3/9) Feb 07 2015 I see know it was already addressed:
Consider the following code excerpted from std.array.join: static U trustedCast(U, V)(V v) trusted { return cast(U) v; } return trustedCast!RetType(result); This is because the compiler would complain that the following line would not be safe: return cast(RetType)(result); The rationale is "I know it's safe, so I'll create an trusted wrapper to eliminate the error." What comes next is "that's cumbersome. How about a better syntax:" trusted { return cast(RetType)(result); } ? It's the rationale behind "unsafe" blocks that appear in other languages. It seems like a perfectly reasonable request. The trouble with it is, what if the cast is converting from an integer to a pointer? That could lead to memory corruption. The code allows a potentially memory corrupting operation to be inserted into code that is otherwise safe. The only way to deal with it is to then manually review everything about 'RetType' and 'result' to prove to oneself that it is not converting random bit patterns into pointers. In other words, one is manually reviewing safe code for memory corruption errors. This is an abject failure of safe, trusted, and system. The solution is to regard trusted as a means of encapsulating unsafe operations, not escaping them. Encapsulating them means that the interface from the trusted code is such that it is usable from safe code without having to manually review the safe code for memory safety. For example (also from std.array): static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); } I don't have to review callers of trustedMemory() because it encapsulates an unsafe operation (memcpy) with a safe interface. The reason trusted applies only to functions, and not to blocks of code, is that functions are the construct in D that provides an interface. Arbitrary blocks of code do not have a structured interface. Adding trusted { code } support will encourage incorrect uses like the opening example. The existence of trusted blocks will require review of every line of code in the function that encloses it, and transitively every function that calls it! Adding trusted as a function attribute, on the other hand, only requires review of the function's interface to determine if it is acceptable to use in safe code. Safety review of its callers is unnecessary.
Feb 05 2015
The fact that trusted is contained in small block doesn't mean rest of safe function doesn't need to be reviewed. Only difference is "review all manually" vs "review all manually with some help of compiler".
Feb 05 2015
On 2/5/15 3:43 PM, Dicebot wrote:The fact that trusted is contained in small block doesn't mean rest of safe function doesn't need to be reviewed. Only difference is "review all manually" vs "review all manually with some help of compiler".As Steve and others have shown, unsafe code under the disguise of trusted affects everything. You are fostering an illusion. -- Andrei
Feb 05 2015
On Thursday, 5 February 2015 at 23:49:05 UTC, Andrei Alexandrescu wrote:On 2/5/15 3:43 PM, Dicebot wrote:Steve has shown exactly the opposite, proving quite some of my points ;) But it is not uncommon to see what one wants to see in identical piece of information.The fact that trusted is contained in small block doesn't mean rest of safe function doesn't need to be reviewed. Only difference is "review all manually" vs "review all manually with some help of compiler".As Steve and others have shown, unsafe code under the disguise of trusted affects everything. You are fostering an illusion. -- Andrei
Feb 05 2015
On Thursday, 5 February 2015 at 23:43:19 UTC, Dicebot wrote:The fact that trusted is contained in small block doesn't mean rest of safe function doesn't need to be reviewed. Only difference is "review all manually" vs "review all manually with some help of compiler".I believe that was also the reasoning behind H.S.Teoh proposal for refining trusted semantics - to keep help from compiler but mark functions as trusted to make it clear that it still needs to be reviewed in total.
Feb 05 2015
On Thu, Feb 05, 2015 at 11:50:05PM +0000, Dicebot via Digitalmars-d wrote:On Thursday, 5 February 2015 at 23:43:19 UTC, Dicebot wrote:This whole discussion has been very tiring and frustrating, because we keep talking past each other. The reason we keep talking past each other is because we keep conflating several distinct, though related, issues. 1) I think we all basically agree that std.file is a mess and some solution is needed to fix this mess. I don't think anyone is actually advocating *for* the code that's currently in std.file right now. So can we pretty please agree that this is a given, and stop using it to beat each other over the head? 2) I think we also all basically agree that the *intent* of trusted is to be an encapsulation mechanism, or to present a safe API, or however you want to describe it. I.e., if a function is marked safe, then it must be impossible to cause it to do something unsafe by passing it the wrong arguments. Whatever it does under the hood should not have any observable unsafe effect on the outside world. I'm pretty sure everyone also agrees with this; I don't think anyone is advocating that we should changee this intent. So can we please also take this as a given, and stop repeating it at each other as if we don't all already know it? This leaves the core of the contention, which is that safe/ trusted, as currently implemented, presents maintenance difficulties. Walter & Andrei don't seem to be convinced that this is a problem, but the evidence is right before us. We Phobos committers did not deliberately set out to sabotage trusted by introducing blatant abuses of it just for fun (see (1) and (2) above). The current ugly (and arguably totally wrong) hacks are a symptom of the underlying maintenance difficulty that the current system presents. It is a desperate attempt to contain a maintenance problem that's growing out of hand. You probably don't believe me, but let's assume that we all agree on (1) and (2), and let's suppose that everything is implemented the way Walter & Andrei envision it. That is, no ugly hacks like what's currently in std.file, and trusted is only ever used on functions that present a safe API. What maintenance issues might there be? There are at least the following (and probably more): - First, let's get one thing straight: the body of a function is rarely only written once and never touched again later. In the real world, function bodies tend to be written piecemeal -- you write an initial implementation, then refine it, then commit it, then somebody comes along later and fixes a bug, somebody else implements an enhancement, etc.. I.e., code is in a constant flux of changes. Especially in a public project like Phobos, these changes are pouring in everyday from all manner of contributors of varying levels of competence. No single person can possibly keep up with every code change that gets merged. Now, with this fact as background, let's consider: - The body of a trusted function is completely unrestricted, and can contain any manner of system operation. The compiler doesn't give you any help in ensuring there aren't careless mistakes that slipped in. Any unsafe operation you can imagine can be freely thrown into such a function, and the compiler will happily accept it and allow safe code to freely call it. - The fact that the compiler does zero verification of the body of a trusted function, should already be a sign of deficiency, since the responsibility of checking correctness of the *entire* function body now falls upon fallible human beings. How sure are we that even the initial review was foolproof? At the very least, one would hope that the compiler could give us some help where it can, and leave the parts it cannot to a few isolated places where human inspection can be more focused on. - Now, couple this with the volume of changes pouring into Phobos constantly, which means that inadvertent mistakes will creep into the code, either in the function body directly, or indirectly into any of the functions that the trusted function calls. Some of these mistakes may break the trusted promise of the function, but currently there is NO WARNING for this. How confident are we that changes to the function after the initial review did not break the trusted promise? - The currently recommended approach is to thoroughly review all changes to trusted functions before merging. Given that just today, somebody merged a PR that has no unittests for verifying the correctness of a bugfix and preventing regressions, how likely is it that changes to trusted function will be thoroughly reviewed for all possible implications before merging? - Not to mention, this is a direct change to a function, that is immediately visible from the function itself. We haven't considered yet the implications of changes to helper functions called by trusted functions, which may have safety implications on previously-verified trusted functions. If a direct change passes review without a proper accompanying unittest, how much less will changes to functions *indirectly* called by trusted functions cause reviewers to inspect the trusted function that calls them? Sure, we *could* institute a draconian policy that we must keep track of every change to every function that might be called by a trusted function, and review all those trusted callers everytime any one of these functions change. That would ensure the promise of trusted is not broken. That would also ensure that nobody will maintain Phobos, because the burden of such a review requirement is far too onerous to be practical. So basically, once a function is marked trusted, we basically have to accept its safety based on faith and hope. Since reviewing the entire call tree of the function is impractical, we just need to have faith that whoever reviewed the initial version of the function 5 months ago did his job correctly, and we hope that nothing has changed since that may have broken the safety of the function. External safe callers of the function simply take its safety on faith, because it presents a safe API, and there's no reason whatsoever to doubt whether or not it is truly safe. In any case, since the compiler happily accepts safe code calling trusted code, and we can't live our lives in fear that perhaps a recent PR has introduced a change that broke the safety promise of said trusted code, we just have to take it on faith that the trusted code is, in fact, safe. Meanwhile, the changes continue to pour in, and the compiler doesn't even check the most basic safe-ty concerns in the body of the trusted function. When a change touches something that causes a previously safe operation in said function body to become system, the compiler happily accepts it without any warning or indication whatsoever that perhaps there is some kind of mistake, a previously safe primitive has now become un- safe, and we'd better re-review the trusted function to ensure that no new safety holes have been introduced. But surely, this isn't a problem at all, since we reviewed this trusted function 5 months ago, and nothing could possibly have gone wrong in the interim, -- we believe. (After all, our reviewers are doing their jobs properly, right? That is, the onerous obligation to review not only changes to trusted functions, but every change to every function that occurs in the downstream call tree of every trusted function. In a *volunteer* project, where people only work on what interests them. Yes, this just fills me with confidence that there's absolutely nothing wrong with trusted. What do you mean, the emperor has no clothes?) T -- Государство делает вид, что платит нам зарплату, а мы делаем вид, что работаем.The fact that trusted is contained in small block doesn't mean rest of safe function doesn't need to be reviewed. Only difference is "review all manually" vs "review all manually with some help of compiler".I believe that was also the reasoning behind H.S.Teoh proposal for refining trusted semantics - to keep help from compiler but mark functions as trusted to make it clear that it still needs to be reviewed in total.
Feb 05 2015
On 2/5/15 5:23 PM, H. S. Teoh via Digitalmars-d wrote:It is a desperate attempt to contain a maintenance problem that's growing out of hand.Before we get into this - do you have evidence of the maintenance problem that's growing out of hand? E.g. bugs in std.file that were fixed etc. Thanks. -- Andrei
Feb 05 2015
On 2/5/15 5:23 PM, H. S. Teoh via Digitalmars-d wrote:This whole discussion has been very tiring and frustrating, because we keep talking past each other. The reason we keep talking past each other is because we keep conflating several distinct, though related, issues.Bummer about that. Let's see.1) I think we all basically agree that std.file is a mess and some solution is needed to fix this mess. I don't think anyone is actually advocating *for* the code that's currently in std.file right now. So can we pretty please agree that this is a given, and stop using it to beat each other over the head?There remains the issue - is the messy trusted code a net negative or not? If so, why did it pass review? That would be an interesting case study for improving our review process. I find it difficult to reckon that that code got into a Phobos release.2) I think we also all basically agree that the *intent* of trusted is to be an encapsulation mechanism, or to present a safe API, or however you want to describe it. I.e., if a function is marked safe, then it must be impossible to cause it to do something unsafe by passing it the wrong arguments. Whatever it does under the hood should not have any observable unsafe effect on the outside world. I'm pretty sure everyone also agrees with this; I don't think anyone is advocating that we should changee this intent. So can we please also take this as a given, and stop repeating it at each other as if we don't all already know it?Yah.This leaves the core of the contention, which is that safe/ trusted, as currently implemented, presents maintenance difficulties.I think these difficulties have not been demonstrated.Walter & Andrei don't seem to be convinced that this is a problem, but the evidence is right before us.Pray tell.We Phobos committers did not deliberately set out to sabotage trusted by introducing blatant abuses of it just for fun (see (1) and (2) above). The current ugly (and arguably totally wrong) hacks are a symptom of the underlying maintenance difficulty that the current system presents. It is a desperate attempt to contain a maintenance problem that's growing out of hand.Could you please show the numerous bugs and subsequent commits fixing them that you are alluding to? I'll stop quoting here. My understanding of your core argument is as follows: "Currently there is no safety verification for trusted functions, and it would be nice if there were more." I'm totally on board with this. It would definitely be nice to have more verification. That said: (1) I am not convinced this is a problem as large as you want it to be. I find most of your arguments to appeal to unsubstantiated hyperbole. (2) I don't think the proposal you sketched at http://goo.gl/JWqafx is good. Now, there must be a way to convey this to you without personally offending you: I think your proposal is not good. I don't buy it. It's poorly motivated, poorly argued, it's very incomplete, it complicates the language without visible benefit, it's just not what I'd think we should be doing. If you have a better proposal, please let's have it. To be honest I don't think a reasonable amount of work on http://goo.gl/JWqafx will make it better. How can I say "after carefully learning about your points and proposal I think we should do as Walter and I say and not as you say" without insulting you? Andrei
Feb 05 2015
On 2/5/2015 6:26 PM, Andrei Alexandrescu wrote:(2) I don't think the proposal you sketched at http://goo.gl/JWqafx is good.The goo link is disabled for violating goo's terms of service, whatever that means. What's the real url?
Feb 05 2015
On 2/5/15 6:52 PM, Walter Bright wrote:On 2/5/2015 6:26 PM, Andrei Alexandrescu wrote:http://forum.dlang.org/thread/mb070a$1ok1$1 digitalmars.com#post-mailman.6039.1423163991.9932.digitalmars-d:40puremagic.com Andrei(2) I don't think the proposal you sketched at http://goo.gl/JWqafx is good.The goo link is disabled for violating goo's terms of service, whatever that means. What's the real url?
Feb 05 2015
On 2/5/2015 7:00 PM, Andrei Alexandrescu wrote:On 2/5/15 6:52 PM, Walter Bright wrote:Thank you. Essentially, the proposal attaches safe/trusted/system to variables. I don't believe this works. Safety/unsafety can often be the emergent combination of state of many otherwise 'safe' variables. In any case, it lacks any demonstration of how it would address the problems in std.array. I.e. how could it insure that the code that initializes the array in std.array.join() initializes every element? (That loop is in the 'safe' section!) I don't see how any proposal can work unless it specifies a safe interface to an unsafe section of code. (I read a Rust tutorial that rather bluntly pointed this out as well.)On 2/5/2015 6:26 PM, Andrei Alexandrescu wrote:http://forum.dlang.org/thread/mb070a$1ok1$1 digitalmars.com#post-mailman.6039.1423163991.9932.digitalmars-d:40puremagic.com(2) I don't think the proposal you sketched at http://goo.gl/JWqafx is good.The goo link is disabled for violating goo's terms of service, whatever that means. What's the real url?
Feb 05 2015
On Friday, 6 February 2015 at 03:14:59 UTC, Walter Bright wrote:I don't see how any proposal can work unless it specifies a safe interface to an unsafe section of code. (I read a Rust tutorial that rather bluntly pointed this out as well.)Link?
Feb 05 2015
On 2/5/2015 7:39 PM, Zach the Mystic wrote:On Friday, 6 February 2015 at 03:14:59 UTC, Walter Bright wrote:"A non-unsafe function using unsafe internally should be implemented to be safe to call; that is, there is no circumstance or set of arguments that can make the function violate any invariants. If there are such circumstances, it should be marked unsafe." "However, this is not the case, unsafe is just an implementation detail; if a safe function uses unsafe internally, it just means the author has been forced to step around the type system, but still exposes a safe interface." http://huonw.github.io/blog/2014/07/what-does-rusts-unsafe-mean/I don't see how any proposal can work unless it specifies a safe interface to an unsafe section of code. (I read a Rust tutorial that rather bluntly pointed this out as well.)Link?
Feb 05 2015
I figured that someone would have already objected to part of this, but the definition is stronger than I believe is intended for D: On 2/5/2015 5:23 PM, H. S. Teoh via Digitalmars-d wrote:2) I think we also all basically agree that the *intent* of trusted is to be an encapsulation mechanism, or to present a safe API, or however you want to describe it. I.e., if a function is marked safe, then it must be impossible to cause it to do something unsafe by passing it the wrong arguments. Whatever it does under the hood should not have any observable unsafe effect on the outside world. I'm pretty sure everyone also agrees with this; I don't think anyone is advocating that we should changee this intent. So can we please also take this as a given, and stop repeating it at each other as if we don't all already know it?Specifically, the 'impossible to cause it to do something unsafe by passing it the wrong arguments' part. For example, this is valid safe code: safe void setToZero(ubyte[] foo) { foo[] = 0; } How about now: void bar() { ubyte[] a; a.ptr = 0; // arbitrary value as long as NOT from an allocator a.len = 1; setToZero(a); } safe code is memory safe when passed good inputs. safe code does not have to detect or prevent garbage input from causing harm. The promises of trusted aren't stronger than that either.
Feb 05 2015
On 2/5/2015 8:30 PM, Brad Roberts via Digitalmars-d wrote:safe code is memory safe when passed good inputs. safe code does not have to detect or prevent garbage input from causing harm. The promises of trusted aren't stronger than that either.This is correct. Thanks for catching it.
Feb 05 2015
On 2/5/2015 3:43 PM, Dicebot wrote:The fact that trusted is contained in small block doesn't mean rest of safe function doesn't need to be reviewed. Only difference is "review all manually" vs "review all manually with some help of compiler".I did a review of all uses of trusted in std.array: https://issues.dlang.org/show_bug.cgi?id=14127 About 90% of them resulted in the injection of unsafe code into safe functions, requiring a safety review of those allegedly mechanically checkable functions. This is an abject failure of the technique of using trusted as an escape than as encapsulation. By definition, if an trusted function presents itself with a safe interface, the calling code does not have to be reviewed. And reviewing the interface is a heluva lot easier than the whole rest of the code.
Feb 05 2015
On Friday, 6 February 2015 at 00:04:26 UTC, Walter Bright wrote:On 2/5/2015 3:43 PM, Dicebot wrote:Yes, that was intended and not accidental. Again, we were dealing with limited set of faulty tools. Things got inevitably hacky.The fact that trusted is contained in small block doesn't mean rest of safe function doesn't need to be reviewed. Only difference is "review all manually" vs "review all manually with some help of compiler".I did a review of all uses of trusted in std.array: https://issues.dlang.org/show_bug.cgi?id=14127 About 90% of them resulted in the injection of unsafe code into safe functions, requiring a safety review of those allegedly mechanically checkable functions.By definition, if an trusted function presents itself with a safe interface, the calling code does not have to be reviewed. And reviewing the interface is a heluva lot easier than the whole rest of the code.I know this definition. It have tried it in practice and concluded as being absolutely useless. There is no way I am going to return back to this broken concept - better to ignore safe completely as misfeature if you insist on doing things that way.
Feb 05 2015
On 2/5/2015 4:13 PM, Dicebot wrote:I know this definition. It have tried it in practice and concluded as being absolutely useless. There is no way I am going to return back to this broken concept - better to ignore safe completely as misfeature if you insist on doing things that way.I'm sorry I haven't been able to convince you. I don't have any more arguments other than just repeating myself. Moving forward, I must insist that use of trusted in such a way as to make its surrounding context not mechanically checkable is no longer acceptable in Phobos. If need be, I will rewrite std.array myself to address this. But D is a systems programming language, not a B&D language, and anyone will be free to ignore safe and continue to use the other benefits of D, or use safe in a way that conforms to their own formulation of best practices.
Feb 05 2015
On 2/5/15 5:12 PM, Walter Bright wrote:On 2/5/2015 4:13 PM, Dicebot wrote:I second this. -- AndreiI know this definition. It have tried it in practice and concluded as being absolutely useless. There is no way I am going to return back to this broken concept - better to ignore safe completely as misfeature if you insist on doing things that way.I'm sorry I haven't been able to convince you. I don't have any more arguments other than just repeating myself. Moving forward, I must insist that use of trusted in such a way as to make its surrounding context not mechanically checkable is no longer acceptable in Phobos. If need be, I will rewrite std.array myself to address this. But D is a systems programming language, not a B&D language, and anyone will be free to ignore safe and continue to use the other benefits of D, or use safe in a way that conforms to their own formulation of best practices.
Feb 05 2015
On Thu, Feb 05, 2015 at 05:12:16PM -0800, Walter Bright via Digitalmars-d wrote:On 2/5/2015 4:13 PM, Dicebot wrote:You are still not getting the point we've been trying to make since the beginning of this tiresome interminable thread. WE AGREE WITH YOU THAT trusted IS MEANT TO BE USED IN THE WAY YOU DESCRIBED!! WE AGREE THAT std.file NEEDS TO BE FIXED! I hope that gets the point across. We are not arguing *for* the ugly hacks currently in std.file, std.array, and wherever else. What we're trying to tell you, is that even if we were to rewrite everything the way you prescribe, it will *still* present the same maintenance issues we have brought up, because of the way trusted is implemented. The way it gives free rein to use whatever system operations you fancy, with no warnings whatsoever issued when you did something that's blatantly wrong. The way it puts a stamp of safe-ty approval on what's essentially a system function after the initial review, and is never revoked thereafter. The way changes to trusted functions are never mechanically checked for basic safe sanity. The way a call to a previously safe function from inside a trusted function does not trigger any warning when the callee now becomes system. We are NOT asking you to justify the current state of std.file and std.array, as you seem to believe we're asking for. Please stop fixating on that, it's not helping this discussion at all. What we're asking for is for the compiler to give us the tools to make Phobos maintenance more tenable. Like performing safe checks inside trusted functions where possible. Requiring explicit markup for operations that the compiler thinks are unsafe, but we know otherwise, so that when somebody comes along later and introduces more of these operations, the compiler will issue warnings that prompt reviewers to carefully inspect what has changed. Some kind of mechanism for controlling what kind of changes can be accepted in a trusted function. The current state of std.file/std.array/whatever is just a symptom. The real disease is that we need some way of coping with the maintenance issues introduced by trusted. If those issues continue to be neglected, then other symptoms will just show up elsewhere, even if you rewrite std.file and std.array now. Until the real issue is addressed, you will just be playing whack-a-mole on every apparent "abuse" of trusted that crops up. It will never end until the real issues are addressed.I know this definition. It have tried it in practice and concluded as being absolutely useless. There is no way I am going to return back to this broken concept - better to ignore safe completely as misfeature if you insist on doing things that way.I'm sorry I haven't been able to convince you. I don't have any more arguments other than just repeating myself. Moving forward, I must insist that use of trusted in such a way as to make its surrounding context not mechanically checkable is no longer acceptable in Phobos.If need be, I will rewrite std.array myself to address this.Please do. Maybe you will understand more where we're coming from if you see it for yourself. Obviously our words mean little to you. And while you're at it, try reviewing a few Phobos PR's related to std.array as well, and observe for yourself the maintenance issues that arise. T -- "The whole problem with the world is that fools and fanatics are always so certain of themselves, but wiser people so full of doubts." -- Bertrand Russell. "How come he didn't put 'I think' at the end of it?" -- Anonymous
Feb 05 2015
On 2/5/15 5:53 PM, H. S. Teoh via Digitalmars-d wrote:And while you're at it, try reviewing a few Phobos PR's related to std.array as well, and observe for yourself the maintenance issues that arise.Again, could you please collect past evidence of such? According to you there must be many cases in which there was insufficient safety checking that was hiding bugs etc. Evidence would do wonders for your argument. Andrei
Feb 05 2015
On Friday, 6 February 2015 at 02:06:29 UTC, Andrei Alexandrescu wrote:On 2/5/15 5:53 PM, H. S. Teoh via Digitalmars-d wrote:Evidence does wonders for any argument!And while you're at it, try reviewing a few Phobos PR's related to std.array as well, and observe for yourself the maintenance issues that arise.Again, could you please collect past evidence of such? According to you there must be many cases in which there was insufficient safety checking that was hiding bugs etc. Evidence would do wonders for your argument. Andrei
Feb 05 2015
On Friday, 6 February 2015 at 01:12:18 UTC, Walter Bright wrote:On 2/5/2015 4:13 PM, Dicebot wrote:This is not about convincing but about showing the example yourself. My disagreement is not theoretical - I trust you to be much better in actual language design. But trusting alone won't make a difference if I have no idea how use it in practice (after trying and failing). I am not even sure how you can show the example though, to be honest - implied issues are about maintaining code and not just writing it.I know this definition. It have tried it in practice and concluded as being absolutely useless. There is no way I am going to return back to this broken concept - better to ignore safe completely as misfeature if you insist on doing things that way.I'm sorry I haven't been able to convince you. I don't have any more arguments other than just repeating myself.But D is a systems programming language, not a B&D language, and anyone will be free to ignore safe and continue to use the other benefits of D, or use safe in a way that conforms to their own formulation of best practices.It always feel awkward to ignore what was supposed to be a major selling point for a language :(
Feb 05 2015
On 2/5/2015 8:20 PM, Dicebot wrote:I am not even sure how you can show the example though, to be honest - implied issues are about maintaining code and not just writing it.Let's start with std.array.uninitializedArray(): auto uninitializedArray(T, I...)(I sizes) nothrow trusted Note how it says it is 'trusted'. Yet it can be used to create an uninitialized array of pointers! There is no freakin' way this function should pass muster. Worse, multiple modules use it: array.d: return uninitializedArray!(Unqual!E[])(n); array.d:auto uninitializedArray(T, I...)(I sizes) nothrow trusted array.d: double[] arr = uninitializedArray!(double[])(100); array.d: double[][] matrix = uninitializedArray!(double[][])(42, 31); array.d: auto s1 = uninitializedArray!(int[])(); array.d: return uninitializedArray!(T[])(n); array.d: auto result = uninitializedArray!(RetTypeElement[])(length); array.d: auto result = uninitializedArray!(RetTypeElement[])(length); array.d: auto result = uninitializedArray!(RetTypeElement[])(length); file.d: import std.array : uninitializedArray; file.d: auto buf = uninitializedArray!(ubyte[])(size); file.d: void[] result = uninitializedArray!(ubyte[])(initialAlloc); numeric.d: import std.array : uninitializedArray; numeric.d: auto memSpace = uninitializedArray!(lookup_t[])(2 * size); numeric.d: ret = uninitializedArray!(Complex!F[])(range.length); numeric.d: ret = uninitializedArray!(Complex!F[])(range.length); parallelism.d: auto buf = uninitializedArray!(MapType!(Args[0], functions)[])(len); parallelism.d: temp = uninitializedArray!Temp(workUnitSize); parallelism.d: temp = uninitializedArray!Temp(workUnitSize); stdio.d: import std.array : appender, uninitializedArray; stdio.d: buf = uninitializedArray!(char[])(i); stdio.d: buf = uninitializedArray!(char[])(i); stdio.d: import std.array : appender, uninitializedArray; utf.d: import std.array : uninitializedArray; utf.d: auto copy = uninitializedArray!(Unqual!OutChar[])(str.length + 1); So I already know there are serious problems. Looking closer, I see there's another function: auto minimallyInitializedArray(T, I...)(I sizes) nothrow trusted which initializes everything to 0, pointers and all. I agree this one can be trusted. The difference between their implementations is a parameter they pass to arrayAllocImpl(), which says whether to 0 it or not. But really, it's only pointer types (and types composed of pointers) that make it system code. Since uninitializedArray() is a template, we can have two implementations for it that are statically selected based on the element type. One is system, when E is a type that contains a pointer. The other is trusted, when E is not a pointer. That solves that problem without great effort. Upstream of uninitializedArray(), the only problem then is when it is called to generate an uninitialized array of pointers. In order to make the call safe, the caller must then ensure that the array gets initialized with safe values. And that code should be properly marked as trusted, and not before. I.e. start at the bottom, and work up until you find the right place to make it trusted. Rinse, repeat. I am not seeing where the problem with doing this is.
Feb 05 2015
On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); } I don't have to review callers of trustedMemory() because it encapsulates an unsafe operation (memcpy) with a safe interface.It might have done so if it ensured that T was a proper value type, but unfortunately D's type system is not strong enough. What happens if T is a unique_ptr style reference? Ouch, two unique references to the same object. Ouch, memory unsafe. safe is a leaky cauldron and will continue to be so until you provide a proof of language constructs and how they interact. The only sane way to do that is to do the proof over a simplified virtual machine and map all language constructs to it.
Feb 05 2015
On 2/5/2015 9:00 PM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:Good point. Then a constraint can be added to the function signature that T is copyable. D's type system is strong enough for that.static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); } I don't have to review callers of trustedMemory() because it encapsulates an unsafe operation (memcpy) with a safe interface.It might have done so if it ensured that T was a proper value type, but unfortunately D's type system is not strong enough. What happens if T is a unique_ptr style reference? Ouch, two unique references to the same object. Ouch, memory unsafe.
Feb 05 2015
On Friday, 6 February 2015 at 05:32:48 UTC, Walter Bright wrote:On 2/5/2015 9:00 PM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:What's the "D way" of checking if a parameter is a reftype, valuetype, etc?On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:Good point. Then a constraint can be added to the function signature that T is copyable. D's type system is strong enough for that.static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); } I don't have to review callers of trustedMemory() because it encapsulates an unsafe operation (memcpy) with a safe interface.It might have done so if it ensured that T was a proper value type, but unfortunately D's type system is not strong enough. What happens if T is a unique_ptr style reference? Ouch, two unique references to the same object. Ouch, memory unsafe.
Feb 05 2015
On 2/5/2015 9:55 PM, weaselcat wrote:What's the "D way" of checking if a parameter is a reftype, valuetype, etc?http://dlang.org/phobos/std_traits.html
Feb 05 2015
On Friday, 6 February 2015 at 05:32:48 UTC, Walter Bright wrote:Good point. Then a constraint can be added to the function signature that T is copyable. D's type system is strong enough for that.Yes, if you remember to add it. The ideal would be to have the default constrained to proper value-types. D inherits some of C's weaker typing properties by trying to stay Cish to the programmer. The fact that so many messages has been posted to this thread before someone caught it is testament to the burden put upon reviewers with " trusted". After all, in debate-like threads like this people will look with higher scrutiny at posted code than in an average review...
Feb 06 2015
On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); }Should be enforce: assert doesn't guard against malicious usage.
Feb 06 2015
On 2/6/2015 12:31 AM, Kagamin wrote:On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:Cue my endless attempts to explain the difference between input errors and logic errors :-(static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); }Should be enforce: assert doesn't guard against malicious usage.
Feb 06 2015
On Friday, 6 February 2015 at 08:58:05 UTC, Walter Bright wrote:On 2/6/2015 12:31 AM, Kagamin wrote:So which one is it? On one hand, it is clearly a logic error - passing arrays of different length is clearly a program bug. On the other hand, this is a library function, and as you said, we can't know how it's going to be used - so the check has to be unconditional.On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:Cue my endless attempts to explain the difference between input errors and logic errors :-(static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); }Should be enforce: assert doesn't guard against malicious usage.
Feb 06 2015
On 2/6/2015 1:01 AM, Vladimir Panteleev wrote:On Friday, 6 February 2015 at 08:58:05 UTC, Walter Bright wrote:http://www.digitalmars.com/d/archives/digitalmars/D/Program_logic_bugs_vs_input_environmental_errors_244143.htmlCue my endless attempts to explain the difference between input errors and logic errors :-(So which one is it?
Feb 06 2015
On Friday, 6 February 2015 at 10:28:38 UTC, Walter Bright wrote:On 2/6/2015 1:01 AM, Vladimir Panteleev wrote:Do you want to say, that safe code can still corrupt memory if it's crafted by a malevolent programmer or if it doesn't perform additional domain-specific logic checks of otherwise memory-safe data?On Friday, 6 February 2015 at 08:58:05 UTC, Walter Bright wrote:http://www.digitalmars.com/d/archives/digitalmars/D/Program_logic_bugs_vs_input_environmental_errors_244143.htmlCue my endless attempts to explain the difference between input errors and logic errors :-(So which one is it?
Feb 06 2015
On Friday, 6 February 2015 at 10:28:38 UTC, Walter Bright wrote:On 2/6/2015 1:01 AM, Vladimir Panteleev wrote:That doesn't answer my question. A few years ago, I recall, you were arguing that for functions which are or may be exported to a DLL, thus all Phobos functions, it is impossible to predict how the functions will be used. Thus, you argued, the functions' input has to be validated, even if invalid parameters can only be passed to the function as a result of a program bug, and never user input. So, to repeat my question: which one is it? Have you changed your mind, or are there exceptions to the rules in the post you quoted?On Friday, 6 February 2015 at 08:58:05 UTC, Walter Bright wrote:http://www.digitalmars.com/d/archives/digitalmars/D/Program_logic_bugs_vs_input_environmental_errors_244143.htmlCue my endless attempts to explain the difference between input errors and logic errors :-(So which one is it?
Feb 06 2015
On 2/6/15 5:13 AM, Vladimir Panteleev wrote:On Friday, 6 February 2015 at 10:28:38 UTC, Walter Bright wrote:Could you all please grant me this wish - let's not get into that vortex again? It renders everyone involved unproductive for days on end. Thanks. -- AndreiOn 2/6/2015 1:01 AM, Vladimir Panteleev wrote:That doesn't answer my question. A few years ago, I recall, you were arguing that for functions which are or may be exported to a DLL, thus all Phobos functions, it is impossible to predict how the functions will be used. Thus, you argued, the functions' input has to be validated, even if invalid parameters can only be passed to the function as a result of a program bug, and never user input. So, to repeat my question: which one is it? Have you changed your mind, or are there exceptions to the rules in the post you quoted?On Friday, 6 February 2015 at 08:58:05 UTC, Walter Bright wrote:http://www.digitalmars.com/d/archives/digitalmars/D/Program_logic_bugs_vs_input_environmental_errors_244143.htmlCue my endless attempts to explain the difference between input errors and logic errors :-(So which one is it?
Feb 06 2015
On Friday, 6 February 2015 at 16:19:00 UTC, Andrei Alexandrescu wrote:On 2/6/15 5:13 AM, Vladimir Panteleev wrote:What is the problem? Sorry if my post sounded confrontational, but I wasn't going to argue - I just want to understand the language designers' current position on this topic.That doesn't answer my question. A few years ago, I recall, you were arguing that for functions which are or may be exported to a DLL, thus all Phobos functions, it is impossible to predict how the functions will be used. Thus, you argued, the functions' input has to be validated, even if invalid parameters can only be passed to the function as a result of a program bug, and never user input. So, to repeat my question: which one is it? Have you changed your mind, or are there exceptions to the rules in the post you quoted?Could you all please grant me this wish - let's not get into that vortex again? It renders everyone involved unproductive for days on end. Thanks. -- Andrei
Feb 06 2015
On 2/6/15 9:41 AM, Vladimir Panteleev wrote:On Friday, 6 February 2015 at 16:19:00 UTC, Andrei Alexandrescu wrote:I was joking - whenever Walter gets into the assert vs. enforce distinction, the world economy is decreasing by 1%. -- AndreiOn 2/6/15 5:13 AM, Vladimir Panteleev wrote:What is the problem? Sorry if my post sounded confrontational, but I wasn't going to argue - I just want to understand the language designers' current position on this topic.That doesn't answer my question. A few years ago, I recall, you were arguing that for functions which are or may be exported to a DLL, thus all Phobos functions, it is impossible to predict how the functions will be used. Thus, you argued, the functions' input has to be validated, even if invalid parameters can only be passed to the function as a result of a program bug, and never user input. So, to repeat my question: which one is it? Have you changed your mind, or are there exceptions to the rules in the post you quoted?Could you all please grant me this wish - let's not get into that vortex again? It renders everyone involved unproductive for days on end. Thanks. -- Andrei
Feb 06 2015
On 2/6/2015 5:13 AM, Vladimir Panteleev wrote:So, to repeat my question: which one is it? Have you changed your mind, or are there exceptions to the rules in the post you quoted?It means that you, the programmer, have to decide whether it is environmental input validation or a logic error in your code. Follow the rules: 1. exceptions are not for debugging the logic of your program 2. do not use exceptions to recover from logic bugs in your program I have pontificated on this at GREAT length in multiple threads in this n.g. If it is still a mystery to you or anyone else, I give up. Keep in mind the levels of expertise: newbie: follow the rules because you're told they're the right thing to do master: follow the rules because you understand they're the right thing to do guru: transcend the rules because you know when they don't apply
Feb 06 2015
On Friday, 6 February 2015 at 21:08:21 UTC, Walter Bright wrote:1. exceptions are not for debugging the logic of your program 2. do not use exceptions to recover from logic bugs in your programOK, this is nothing new, but still doesn't answer my question. Would you say that the correct thing to do, then, would be an unconditional check that throws an Error? Such as, `if (!...) throw new Error(...)`, or `enforce!Error(...)`? I recall there is a bug report on Bugzilla that Phobos contracts are removed in release (default) builds of the library, when ideally contracts of public functions should stay but inner asserts should be removed in optimized code. That would allow using them for validating parameters without resorting to explicitly-unconditional checks.
Feb 06 2015
On 2/6/2015 9:49 PM, Vladimir Panteleev wrote:On Friday, 6 February 2015 at 21:08:21 UTC, Walter Bright wrote:You wrote "is clearly a program bug". Therefore use assert(). It's as simple as that.1. exceptions are not for debugging the logic of your program 2. do not use exceptions to recover from logic bugs in your programOK, this is nothing new, but still doesn't answer my question.
Feb 06 2015
On Saturday, 7 February 2015 at 06:20:16 UTC, Walter Bright wrote:On 2/6/2015 9:49 PM, Vladimir Panteleev wrote:OK, thank you. A few years ago you were recommending something else for this situation. We were in disagreement then, and I agree with your current opinion.On Friday, 6 February 2015 at 21:08:21 UTC, Walter Bright wrote:You wrote "is clearly a program bug". Therefore use assert(). It's as simple as that.1. exceptions are not for debugging the logic of your program 2. do not use exceptions to recover from logic bugs in your programOK, this is nothing new, but still doesn't answer my question.
Feb 07 2015
On Friday, 6 February 2015 at 08:58:05 UTC, Walter Bright wrote:On 2/6/2015 12:31 AM, Kagamin wrote:I agree with you, that this should be an assert, but then it cannot be trusted. A trusted function should provide it's guarantee for all input that can be crafted in safe code. This is why this void bar() { ubyte[] a; a.ptr = 0; // arbitrary value as long as NOT from an allocator a.len = 1; setToZero(a); } is not a valid counter-example and that memcpy cannot be trusted. It has no safe interface. Back to topic. Since trusted must provide a safe interface, I don't think it makes much sense to attach trusted to smaller code blocks than functions. That might not be true for the opposite: safe blocks where the compiler turns the safety check back on. This prevents that a trusted/ safe function becoming system breaks the trusted guarantee of called functions. void bar(void* argument) trusted { ... } void forward() trusted { // REVIEW: forwards arguments to bar, which is trusted, so we can // trust forward as well void* p = malloc(...); bar(arguments); free(p); } Changing bar to system is a breaking change and currently a silent one. This is a maintenance problem I see as well. Solution: void forward() trusted { void* p = malloc(...); // safe is bar is safe, so turn compiler checks on again. safe { bar(p); } free(p); } Introducing an error in an trusted function is _not_ an maintenance horror. While your safe-ty guarantee is out of the window, it can be catched my reviewing one function: the one where the error is introduced in. Making a trusted function system forces us to review all trusted functions calling the now system function.On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:Cue my endless attempts to explain the difference between input errors and logic errors :-(static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); }Should be enforce: assert doesn't guard against malicious usage.
Feb 06 2015
This prevents that a trusted/ safe function becoming system breaks the trusted guarantee of called functions.Calling function, forward in the example.
Feb 06 2015
On Friday, 6 February 2015 at 08:58:05 UTC, Walter Bright wrote:On 2/6/2015 12:31 AM, Kagamin wrote:A little offtop: if this function is compiled in release mode and compiler assumes assert holds, it's free to use dest.length instead of src.length and if at runtime dest is longer than src, this will create heartbleed-like bug in safe code.On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:Cue my endless attempts to explain the difference between input errors and logic errors :-(static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); }Should be enforce: assert doesn't guard against malicious usage.
Feb 06 2015
On 2/6/2015 4:17 AM, Kagamin wrote:On Friday, 6 February 2015 at 08:58:05 UTC, Walter Bright wrote:Sigh. Please visit your nearest Catholic school and ask one of the nuns to thwack your knuckles with a ruler!On 2/6/2015 12:31 AM, Kagamin wrote:A little offtop: if this function is compiled in release mode and compiler assumes assert holds, it's free to use dest.length instead of src.length and if at runtime dest is longer than src, this will create heartbleed-like bug in safe code.On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:Cue my endless attempts to explain the difference between input errors and logic errors :-(static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); }Should be enforce: assert doesn't guard against malicious usage.
Feb 06 2015
On Friday, 6 February 2015 at 08:58:05 UTC, Walter Bright wrote:On 2/6/2015 12:31 AM, Kagamin wrote:Well, ok, not enforce: static void trustedMemcopy(T[] dest, T[] src) trusted { if(src.length != dest.length)assert(false); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); }On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:Cue my endless attempts to explain the difference between input errors and logic errors :-(static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); }Should be enforce: assert doesn't guard against malicious usage.
Feb 06 2015
If I understand it correctly, Walter is against adding trusted blocks (trusted {...}) into safe functions. But what about having safe blocks in trusted functions ? int somefunc() trusted { int a = systemfunc(); int b; safe { b = safefunc(); // calling systemfunc() not allowed; } return a + b; }
Feb 06 2015
On 2/6/15 3:57 AM, Martin Krejcirik wrote:If I understand it correctly, Walter is against adding trusted blocks (trusted {...}) into safe functions. But what about having safe blocks in trusted functions ?That would be sensible - perhaps the best step forward following this long discussion. -- Andrei
Feb 06 2015
On Friday, 6 February 2015 at 16:11:31 UTC, Andrei Alexandrescu wrote:On 2/6/15 3:57 AM, Martin Krejcirik wrote:It feels inelegant, but it might be the best way out of a bad situation. I can instantly see this happening: void foo() trusted { safe { //loads of code } //a few lines of system code, only safe due to context in the safe blocks safe { \\loads of code } } Is that what we want? I can't see why not, but it feels off somehow... Effectively you've got trusted blocks in an trusted function, just inverted.If I understand it correctly, Walter is against adding trusted blocks (trusted {...}) into safe functions. But what about having safe blocks in trusted functions ?That would be sensible - perhaps the best step forward following this long discussion. -- Andrei
Feb 06 2015
On Friday, 6 February 2015 at 16:19:26 UTC, John Colvin wrote:I can instantly see this happening: void foo() trusted {auto p = malloc(…)safe {global_datastructure.push(p)//loads of code }free(p)//a few lines of system code, only safe due to context in the safe blocks safe { \\loads of code } } Is that what we want?Nope.
Feb 06 2015
On 2/6/15 8:19 AM, John Colvin wrote:Is that what we want? I can't see why not, but it feels off somehow... Effectively you've got trusted blocks in an trusted function, just inverted.That's the natural direction - the default assumption is weak, and you have the option to temporarily strengthen it. That said I'm not jazzed about the whole thing. What we have is the right balance. -- Andrei
Feb 06 2015
On Friday, 6 February 2015 at 16:19:26 UTC, John Colvin wrote:It feels inelegant, but it might be the best way out of a bad situation. I can instantly see this happening: void foo() trusted { safe { //loads of code } //a few lines of system code, only safe due to context in the safe blocks safe { \\loads of code } } Is that what we want? I can't see why not, but it feels off somehow... Effectively you've got trusted blocks in an trusted function, just inverted.Some observations. 1. You cannot corrupt memory in the first safe block. That's a plus. 2. It solves the "my- safe-function-turned- system-behind-my-back"-problem 3. It solves the problems the current trusted-abuse in std.file tried to solve And most importantly: If that function can be made trusted, there probably is a function bar, so that void bar() { .. } trusted void foo() safe { safe {} bar(); safe {} }
Feb 06 2015
On Friday, 6 February 2015 at 16:19:26 UTC, John Colvin wrote:On Friday, 6 February 2015 at 16:11:31 UTC, Andrei Alexandrescu wrote:It's been suggested that ' system' be used to mark the blocks in question. The point would be to emphasize the dangerousness of the operation. The function is still trusted, but inside, the system code is marked as such.On 2/6/15 3:57 AM, Martin Krejcirik wrote:It feels inelegant, but it might be the best way out of a bad situation. I can instantly see this happening: void foo() trusted { safe { //loads of code } //a few lines of system code, only safe due to context in the safe blocks safe { \\loads of code } } Is that what we want? I can't see why not, but it feels off somehow... Effectively you've got trusted blocks in an trusted function, just inverted.If I understand it correctly, Walter is against adding trusted blocks (trusted {...}) into safe functions. But what about having safe blocks in trusted functions ?That would be sensible - perhaps the best step forward following this long discussion. -- Andrei
Feb 06 2015
On Friday, 6 February 2015 at 17:13:09 UTC, Zach the Mystic wrote:It's been suggested that ' system' be used to mark the blocks in question. The point would be to emphasize the dangerousness of the operation. The function is still trusted, but inside, the system code is marked as such.This is precisely equivalent to just making the function safe and using trusted blocks inside (which is incidentally my preferred approach, and similar to what parts of Phobos try to emulate). As I argued almost three years ago in my " trusted considered harmful" post, trusted doesn't differ in meaning from safe for API clients. Both mean that you can call the function from safe code, nothing more, nothing less. I hope we agree on that. You might argue that having trusted in the function declaration serves as an indicator that the implementation requires extra careful review. However, there will *still* be a trusted keyword sitting in the source code and staring at your face even with trusted blocks. And if you don't have the source code for a function you call to begin with, all bets are off anyway (i.e. you need to trust its author) as safe functions may always internally call trusted ones. If the leadership feels that your proposal is to be preferred because it keeps trusted in the function signature (as he correctly remarked, the safety of trusted blocks might depend on surrounding safe code), then so be it. However, it makes an implementation detail part of the API (see " trusted considered harmful"), and furthermore is not backwards-compatible. David
Feb 06 2015
On Friday, 6 February 2015 at 18:58:27 UTC, David Nadlinger wrote:On Friday, 6 February 2015 at 17:13:09 UTC, Zach the Mystic wrote:No it's not. Forcing trusted functions, with system blocks inside builds a redundancy into the system. Now someone from outside the can read the signature and know there might be a problem, and someone inside can find everywhere that problem could possibly have arisen from. The difference is you now have two signals instead of one - one in the function header, and the other(s) in the code itself.It's been suggested that ' system' be used to mark the blocks in question. The point would be to emphasize the dangerousness of the operation. The function is still trusted, but inside, the system code is marked as such.This is precisely equivalent to just making the function safe and using trusted blocks inside (which is incidentally my preferred approach, and similar to what parts of Phobos try to emulate).As I argued almost three years ago in my " trusted considered harmful" post, trusted doesn't differ in meaning from safe for API clients. Both mean that you can call the function from safe code, nothing more, nothing less. I hope we agree on that.I know. This was recently pointed out again by Steven Schveighoffer, and it's a great insight.You might argue that having trusted in the function declaration serves as an indicator that the implementation requires extra careful review. However, there will *still* be a trusted keyword sitting in the source code and staring at your face even with trusted blocks. And if you don't have the source code for a function you call to begin with, all bets are off anyway (i.e. you need to trust its author) as safe functions may always internally call trusted ones.It is a redundancy, yes, but one people might actually *appreciate*. People around here take memory safety very seriously, and probably with good reason!If the leadership feels that your proposal is to be preferred because it keeps trusted in the function signature (as he correctly remarked, the safety of trusted blocks might depend on surrounding safe code), then so be it. However, it makes an implementation detail part of the API (see " trusted considered harmful"), and furthermore is not backwards-compatible.It's not backward-compatible, but it's not hard to fix at all. You get an error, and you enclose your unsafe code in a system block. And the quality of your code improves at the same time. The only reason the implementation detail, trusted, was made part of the API was precisely because memory safety is taken extremely seriously by the language designers. There's no other reason I can think of, but for some reason, I can appreciate the thought. Also, I want to find a real solution and I doubt anyone is suggesting getting rid of trusted at this point.
Feb 06 2015
On 2/6/2015 10:58 AM, David Nadlinger wrote:trusted doesn't differ in meaning from safe for API clients. Both mean that you can call the function from safe code, nothing more, nothing less. I hope we agree on that.That is correct. trusted is a statement about the implementation of a function, not its interface. This suggests that trusted should apply to blocks of code, not function declarations. Pedantically, I think that would be correct. But as we've seen in usage, this seductively makes for easy incorrect usage of trusted. Pragmatically, the language should make it harder to write incorrect code. Hence, I view it as the best compromise to make trusted also apply only at the function level.
Feb 06 2015
On Friday, 6 February 2015 at 21:33:01 UTC, Walter Bright wrote:On 2/6/2015 10:58 AM, David Nadlinger wrote:Please see this post: http://forum.dlang.org/post/riphxcqazksykafumzcg forum.dlang.orgtrusted doesn't differ in meaning from safe for API clients. Both mean that you can call the function from safe code, nothing more, nothing less. I hope we agree on that.That is correct. trusted is a statement about the implementation of a function, not its interface. This suggests that trusted should apply to blocks of code, not function declarations. Pedantically, I think that would be correct. But as we've seen in usage, this seductively makes for easy incorrect usage of trusted. Pragmatically, the language should make it harder to write incorrect code. Hence, I view it as the best compromise to make trusted also apply only at the function level.
Feb 06 2015
On 2/6/2015 8:19 AM, John Colvin wrote:Is that what we want? I can't see why not, but it feels off somehow... Effectively you've got trusted blocks in an trusted function, just inverted.Right. It just inverted the interface problem, the problem remains. So, no for this idea. Another way to say it: safe => trusted must go through a safe interface trusted => safe must go through a safe interface
Feb 06 2015
On Friday, 6 February 2015 at 16:11:31 UTC, Andrei Alexandrescu wrote:On 2/6/15 3:57 AM, Martin Krejcirik wrote:This still does not solve the template inference problem though, unless you make it a "non- trusted" block instead of requiring safe-ty. And then you'd end up with the—at least to my eyes—rather absurd situation that a template function that is marked trusted might actually end up being system. DavidIf I understand it correctly, Walter is against adding trusted blocks (trusted {...}) into safe functions. But what about having safe blocks in trusted functions ?That would be sensible - perhaps the best step forward following this long discussion. -- Andrei
Feb 06 2015
On Friday, 6 February 2015 at 16:40:10 UTC, David Nadlinger wrote:This still does not solve the template inference problem though, unless you make it a "non- trusted" block instead of requiring safe-ty.Don't understand. If that matters, the code shouldn't be marked trusted in the first place.And then you'd end up with the—at least to my eyes—rather absurd situation that a template function that is marked trusted might actually end up being system. DavidHow?
Feb 06 2015
On Friday, 6 February 2015 at 16:50:51 UTC, Tobias Pankrath wrote:On Friday, 6 February 2015 at 16:40:10 UTC, David Nadlinger wrote:Let's say you have a template function that accepts a range. For performance, you want to do some of the processing in a way that is system, but can be verified to be correct for all inputs in this specific case. In other words, that piece of code can be rightfully trusted. However, marking the whole function as trusted would be a mistake, as the primitives of the range that is your input data might be system. Using trusted blocks (which is what is currently emulated by the nested functions/lambdas), you can just mark your unsafe code as trusted and let the compiler figure out the safety of the whole function. safe blocks wouldn't work for this, as you'd inadvertently require the user-supplied input range to have safe/ trusted primitives.This still does not solve the template inference problem though, unless you make it a "non- trusted" block instead of requiring safe-ty.Don't understand. If that matters, the code shouldn't be marked trusted in the first place.I was referring to a hypothetical "untrusted" block that might be used something like this: --- void foo(Range)(Range r) trusted { // ... untrusted { r.front; } // Your manually checked code. untrusted { r.popFront; } // … } --- This seems incredibly backwards. Not only is it confusing to read, it also encourages bugs where operations mistakenly end up being trusted by forgetting to mark, say, an added call to r.empty as untrusted. On the other hand, it is much more unlikely that you accidentally add a new trusted block. It seems obvious that explicitly whitelisting a small number of potentially dangerous but safe operations is much less error-prone approach than disabling compiler checks for everything and then having to remember to blacklist all unverified external dependencies. DavidAnd then you'd end up with the—at least to my eyes—rather absurd situation that a template function that is marked trusted might actually end up being system. DavidHow?
Feb 06 2015
On Friday, 6 February 2015 at 17:12:40 UTC, David Nadlinger wrote:Let's say you have a template function that accepts a range. For performance, you want to do some of the processing in a way that is system, but can be verified to be correct for all inputs in this specific case. In other words, that piece of code can be rightfully trusted. However, marking the whole function as trusted would be a mistake, as the primitives of the range that is your input data might be system. Using trusted blocks (which is what is currently emulated by the nested functions/lambdas), you can just mark your unsafe code as trusted and let the compiler figure out the safety of the whole function. safe blocks wouldn't work for this, as you'd inadvertently require the user-supplied input range to have safe/ trusted primitives.I'm trying to promote suggesting ' system' blocks instead of ' trusted'. ' trusted' functions, but ' system' blocks - which can only go in trusted functions ( system block in system functions are redundant). It's the same semantics, but it might win the day because the intent is to isolate the system code, while still presenting a trusted interface, as seems so important to the leadership.
Feb 06 2015
I'm trying to promote suggesting ' system' blocks instead of ' trusted'. ' trusted' functions, but ' system' blocks - which can only go in trusted functions ( system block in system functions are redundant). It's the same semantics, but it might win the day because the intent is to isolate the system code, while still presenting a trusted interface, as seems so important to the leadership.That might be better than using safe inside trusted: trusted void myfunc() { //implicitly safe ... system { //wouldn't compile otherwise. auto ptr = cast(ubyte*)4; } //implicitly safe again }
Feb 06 2015
On Friday, 6 February 2015 at 17:36:27 UTC, Atila Neves wrote:Exactly. I think this addresses the concerns. If I read Walter's OP correctly, it's precisely the use of the word ' trusted' that he opposes, unless it's built into an interface like a function signature. Also, a system block could be one statement long, if I'm not mistaken, in which case the above could look like: trusted void myfunc() { //implicitly safe ... system auto ptr = cast(ubyte*)4; //implicitly safe again }I'm trying to promote suggesting ' system' blocks instead of ' trusted'. ' trusted' functions, but ' system' blocks - which can only go in trusted functions ( system block in system functions are redundant). It's the same semantics, but it might win the day because the intent is to isolate the system code, while still presenting a trusted interface, as seems so important to the leadership.That might be better than using safe inside trusted: trusted void myfunc() { //implicitly safe ... system { //wouldn't compile otherwise. auto ptr = cast(ubyte*)4; } //implicitly safe again }
Feb 06 2015
On Friday, 6 February 2015 at 18:30:03 UTC, Zach the Mystic wrote:If this is a real solution, it's kind of exciting! :-)That might be better than using safe inside trusted: trusted void myfunc() { //implicitly safe ... system { //wouldn't compile otherwise. auto ptr = cast(ubyte*)4; } //implicitly safe again }Exactly. I think this addresses the concerns. If I read Walter's OP correctly, it's precisely the use of the word ' trusted' that he opposes, unless it's built into an interface like a function signature. Also, a system block could be one statement long, if I'm not mistaken, in which case the above could look like: trusted void myfunc() { //implicitly safe ... system auto ptr = cast(ubyte*)4; //implicitly safe again }
Feb 06 2015
On 2/6/15 12:36 PM, Atila Neves wrote:BTW, this is H.S. Teoh's suggestion too, and I like it better than mine after much thought. -SteveI'm trying to promote suggesting ' system' blocks instead of ' trusted'. ' trusted' functions, but ' system' blocks - which can only go in trusted functions ( system block in system functions are redundant). It's the same semantics, but it might win the day because the intent is to isolate the system code, while still presenting a trusted interface, as seems so important to the leadership.That might be better than using safe inside trusted: trusted void myfunc() { //implicitly safe .... system { //wouldn't compile otherwise. auto ptr = cast(ubyte*)4; } //implicitly safe again }
Feb 06 2015
I was referring to a hypothetical "untrusted" block that might be used something like this: --- void foo(Range)(Range r) trusted { // ... untrusted { r.front; } // Your manually checked code. untrusted { r.popFront; } // … } ---Using current semantics we must not mark foo trusted, if r.front and r.popFront aren't. Using the proposed safe-blocks (are those untrusted blocks the same?) we could guarantee that, by wrapping the use of r.front and r.popFront in safe-blocks. This is limiting because now we cannot provide an foo marked system for all system ranges without boiler plate or duplicating the function. Correct?
Feb 06 2015
On Friday, 6 February 2015 at 17:50:05 UTC, Tobias Pankrath wrote:Yes. The "untrusted" blocks were an ad-hoc invention to show how safe blocks could be modified to actually work in this case (for template functions, don't require safe, but mark the function system if the contents are unsafe), but that this modification results in a much less desirable design than just straight up having trusted blocks. DavidI was referring to a hypothetical "untrusted" block that might be used something like this: --- void foo(Range)(Range r) trusted { // ... untrusted { r.front; } // Your manually checked code. untrusted { r.popFront; } // … } ---Using current semantics we must not mark foo trusted, if r.front and r.popFront aren't. Using the proposed safe-blocks (are those untrusted blocks the same?) we could guarantee that, by wrapping the use of r.front and r.popFront in safe-blocks. This is limiting because now we cannot provide an foo marked system for all system ranges without boiler plate or duplicating the function. Correct?
Feb 06 2015
On Friday, 6 February 2015 at 17:12:40 UTC, David Nadlinger wrote:It seems obvious that explicitly whitelisting a small number of potentially dangerous but safe operations is much less error-prone approach than disabling compiler checks for everything and then having to remember to blacklist all unverified external dependencies. DavidThat seems obvious to me too. Isn't the whole purpose of having ' trusted' in the first place to direct a programmer who's having memory safety problems to the potential sources those problems? But why have this and then stop at the function level? Why not force the programmer to tag precisely those portions of his code which cause him to tag his function trusted to begin with? Why help him get to the function, and then leave him hanging out to dry once inside the function?
Feb 06 2015
On 2/6/15 8:40 AM, David Nadlinger wrote:On Friday, 6 February 2015 at 16:11:31 UTC, Andrei Alexandrescu wrote:What is that?On 2/6/15 3:57 AM, Martin Krejcirik wrote:This still does not solve the template inference problemIf I understand it correctly, Walter is against adding trusted blocks (trusted {...}) into safe functions. But what about having safe blocks in trusted functions ?That would be sensible - perhaps the best step forward following this long discussion. -- Andreithough, unless you make it a "non- trusted" block instead of requiring safe-ty. And then you'd end up with the—at least to my eyes—rather absurd situation that a template function that is marked trusted might actually end up being system.trusted functions are system. Andrei
Feb 06 2015
On Friday, 6 February 2015 at 17:16:19 UTC, Andrei Alexandrescu wrote:On 2/6/15 8:40 AM, David Nadlinger wrote:See my reply to Tobias [1]. This seems to be the crux of our disagreement and/or misunderstanding, and is precisely the reason why I recommended you to try your hand at rewriting some of the std.array range algorithms yourself in the Bugzilla discussion. Let me know if the explanation in said post is not clear enough.This still does not solve the template inference problemWhat is that?I meant " system" as in the part of the function type/API contract, not concerning the implementation. That is, a template function that is marked trusted might not be able to be called from safe code. David [1] http://forum.dlang.org/post/fwiivepmjfvqbxgagcrm forum.dlang.orgthough, unless you make it a "non- trusted" block instead of requiring safe-ty. And then you'd end up with the—at least to my eyes—rather absurd situation that a template function that is marked trusted might actually end up being system.trusted functions are system.
Feb 06 2015
On 2/6/15 9:28 AM, David Nadlinger wrote:On Friday, 6 February 2015 at 17:16:19 UTC, Andrei Alexandrescu wrote:It's clear. I just don't think it's a good point. -- AndreiOn 2/6/15 8:40 AM, David Nadlinger wrote:See my reply to Tobias [1]. This seems to be the crux of our disagreement and/or misunderstanding, and is precisely the reason why I recommended you to try your hand at rewriting some of the std.array range algorithms yourself in the Bugzilla discussion. Let me know if the explanation in said post is not clear enough.This still does not solve the template inference problemWhat is that?
Feb 06 2015
On Friday, 6 February 2015 at 18:39:28 UTC, Andrei Alexandrescu wrote:It's clear. I just don't think it's a good point. -- AndreiI'm not making a point; I'm posing a problem. What is your solution? David
Feb 06 2015
On 2/6/15 10:42 AM, David Nadlinger wrote:On Friday, 6 February 2015 at 18:39:28 UTC, Andrei Alexandrescu wrote:I think the problem is overstated. -- AndreiIt's clear. I just don't think it's a good point. -- AndreiI'm not making a point; I'm posing a problem. What is your solution?
Feb 06 2015
On Fri, Feb 06, 2015 at 10:52:45AM -0800, Andrei Alexandrescu via Digitalmars-d wrote:On 2/6/15 10:42 AM, David Nadlinger wrote:This is precisely why I have lost all interest in safe. It's clear that the present problematic situation will continue to hold, and the decision makers are not interested to address it. I am not going to waste any more time and energy on this topic. T -- Question authority. Don't ask why, just do it.On Friday, 6 February 2015 at 18:39:28 UTC, Andrei Alexandrescu wrote:I think the problem is overstated. -- AndreiIt's clear. I just don't think it's a good point. -- AndreiI'm not making a point; I'm posing a problem. What is your solution?
Feb 06 2015
On 2/6/15 11:11 AM, H. S. Teoh via Digitalmars-d wrote:On Fri, Feb 06, 2015 at 10:52:45AM -0800, Andrei Alexandrescu via Digitalmars-d wrote:I've asked repeatedly for evidence of the "problematic situation", and all I got was doomsday predictions "maintenance nightmare!". If you have such, please show it. If not, thanks for a good course of action. -- AndreiOn 2/6/15 10:42 AM, David Nadlinger wrote:This is precisely why I have lost all interest in safe. It's clear that the present problematic situation will continue to hold, and the decision makers are not interested to address it. I am not going to waste any more time and energy on this topic.On Friday, 6 February 2015 at 18:39:28 UTC, Andrei Alexandrescu wrote:I think the problem is overstated. -- AndreiIt's clear. I just don't think it's a good point. -- AndreiI'm not making a point; I'm posing a problem. What is your solution?
Feb 06 2015
On Friday, 6 February 2015 at 19:16:13 UTC, Andrei Alexandrescu wrote:The best evidence I have it that everyone who actually worked on the phobos code you disapprove of says it's a problem. Argumentum ad populem, I know, but it calls for close scrutiny, to say the least. My attitude is not based on evidence. It's based on just thinking about the problem: http://forum.dlang.org/post/eeglnychgudcffpjcdvy forum.dlang.org I really can't answer this question.This is precisely why I have lost all interest in safe. It's clear that the present problematic situation will continue to hold, and the decision makers are not interested to address it. I am not going to waste any more time and energy on this topic.I've asked repeatedly for evidence of the "problematic situation", and all I got was doomsday predictions "maintenance nightmare!". If you have such, please show it. If not, thanks for a good course of action. -- Andrei
Feb 06 2015
On 2/6/15 11:29 AM, Zach the Mystic wrote:The best evidence I have it that everyone who actually worked on the phobos code you disapprove of says it's a problem.I see more like two. -- Andrei
Feb 06 2015
On 2/6/2015 11:29 AM, Zach the Mystic wrote:My attitude is not based on evidence. It's based on just thinking about the problem: http://forum.dlang.org/post/eeglnychgudcffpjcdvy forum.dlang.org I really can't answer this question.You asked: "Why not force the programmer to tag precisely those portions of his code which cause him to tag his function trusted to begin with?" That question has been asked and answered repeatedly. The answer is that trusted is not only to TAG unsafe code, but must provide a SAFE INTERFACE to it. trusted { ... unsafe code ... } provides no indication of what the interface to the unsafe code is. Addressing only the TAG aspect is insufficient.
Feb 06 2015
On Friday, 6 February 2015 at 21:56:40 UTC, Walter Bright wrote:On 2/6/2015 11:29 AM, Zach the Mystic wrote:No, at least three of us, Steven, H.S. Teoh and myself have confirmed that we've moved beyond requesting trusted blocks. We are no longer requesting them. We are requesting * system* blocks, which can only appear in trusted and system functions. Any unsafe code appearing in a trusted function which is not inside a system block is an error. We've changed the name, but I think it will make a world of difference regarding how you will look at it. Marking ' system' code inside a trusted function is exactly what is requested. Your message about ' trusted' being only acceptable as an interface has been heard. There will be no trusted blocks, only system blocks, which are the exact same thing, except they can only appear in trusted and system functions. This solution appeals to me greatly. It pinpoints precisely where unsafe code can generate; it catches unintended safety violations in all trusted code outside system blocks, as requested by many people so far; it makes systems programming highly visible, with redundancy at the function signature and at the unsafe code itself. I really think it's spot on!My attitude is not based on evidence. It's based on just thinking about the problem: http://forum.dlang.org/post/eeglnychgudcffpjcdvy forum.dlang.org I really can't answer this question.You asked: "Why not force the programmer to tag precisely those portions of his code which cause him to tag his function trusted to begin with?" That question has been asked and answered repeatedly. The answer is that trusted is not only to TAG unsafe code, but must provide a SAFE INTERFACE to it. trusted { ... unsafe code ... } provides no indication of what the interface to the unsafe code is. Addressing only the TAG aspect is insufficient.
Feb 06 2015
On Friday, 6 February 2015 at 23:02:54 UTC, Zach the Mystic wrote:No, at least three of us, Steven, H.S. Teoh and myself have confirmed that we've moved beyond requesting trusted blocks. We are no longer requesting them. We are requesting * system* blocks, which can only appear in trusted and system functions. Any unsafe code appearing in a trusted function which is not inside a system block is an error. We've changed the name, but I think it will make a world of difference regarding how you will look at it. Marking ' system' code inside a trusted function is exactly what is requested. Your message about ' trusted' being only acceptable as an interface has been heard. There will be no trusted blocks, only system blocks, which are the exact same thing, except they can only appear in trusted and system functions.Also, to be clear, any system block inside a safe function is an automatic error.
Feb 06 2015
On Friday, 6 February 2015 at 23:02:54 UTC, Zach the Mystic wrote:No, at least three of us, Steven, H.S. Teoh and myself have confirmed that we've moved beyond requesting trusted blocks. We are no longer requesting them. We are requesting * system* blocks, which can only appear in trusted and system functions. Any unsafe code appearing in a trusted function which is not inside a system block is an error. We've changed the name, but I think it will make a world of difference regarding how you will look at it. Marking ' system' code inside a trusted function is exactly what is requested. Your message about ' trusted' being only acceptable as an interface has been heard. There will be no trusted blocks, only system blocks, which are the exact same thing, except they can only appear in trusted and system functions. This solution appeals to me greatly. It pinpoints precisely where unsafe code can generate; it catches unintended safety violations in all trusted code outside system blocks, as requested by many people so far; it makes systems programming highly visible, with redundancy at the function signature and at the unsafe code itself. I really think it's spot on!this sounds interesting, is anyone going to make a DIP for it?
Feb 06 2015
On 2/6/15 3:21 PM, weaselcat wrote:On Friday, 6 February 2015 at 23:02:54 UTC, Zach the Mystic wrote:Consider the previous code: https://github.com/D-Programming-Language/phobos/blob/accb351b96bb04a6890bb7df018749337e55eccc/std/file.d#L194 that got replaced with: https://github.com/D-Programming-Language/phobos/blob/master/std/file.d#L194 With the system proposal we're looking at something like: version (Posix) void[] read(in char[] name, size_t upTo = size_t.max) trusted { import core.memory; // A few internal configuration parameters { enum size_t minInitialAlloc = 1024 * 4, maxInitialAlloc = size_t.max / 2, sizeIncrement = 1024 * 16, maxSlackMemoryAllowed = 1024; // } system { immutable fd = core.sys.posix.fcntl.open(name.tempCString(), core.sys.posix.fcntl.O_RDONLY); } cenforce(fd != -1, name); scope(exit) core.sys.posix.unistd.close(fd); stat_t statbuf = void; system { cenforce(trustedFstat(fd, trustedRef(statbuf)) == 0, name); } immutable initialAlloc = to!size_t(statbuf.st_size ? min(statbuf.st_size + 1, maxInitialAlloc) : minInitialAlloc); void[] result = uninitializedArray!(ubyte[])(initialAlloc); scope(failure) delete result; size_t size = 0; for (;;) { system { immutable actual = core.sys.posix.unistd.read(fd, result.ptr + size), min(result.length, upTo) - size); } cenforce(actual != -1, name); if (actual == 0) break; size += actual; if (size < result.length) continue; immutable newAlloc = size + sizeIncrement; system { result = GC.realloc(result.ptr, newAlloc, GC.BlkAttr.NO_SCAN)[0 .. newAlloc]; } system { return result.length - size >= maxSlackMemoryAllowed ? GC.realloc(result.ptr, size, GC.BlkAttr.NO_SCAN)[0 .. size] : result[0 .. size]; } } We want to move D forward, folks. This is not it. AndreiNo, at least three of us, Steven, H.S. Teoh and myself have confirmed that we've moved beyond requesting trusted blocks. We are no longer requesting them. We are requesting * system* blocks, which can only appear in trusted and system functions. Any unsafe code appearing in a trusted function which is not inside a system block is an error. We've changed the name, but I think it will make a world of difference regarding how you will look at it. Marking ' system' code inside a trusted function is exactly what is requested. Your message about ' trusted' being only acceptable as an interface has been heard. There will be no trusted blocks, only system blocks, which are the exact same thing, except they can only appear in trusted and system functions. This solution appeals to me greatly. It pinpoints precisely where unsafe code can generate; it catches unintended safety violations in all trusted code outside system blocks, as requested by many people so far; it makes systems programming highly visible, with redundancy at the function signature and at the unsafe code itself. I really think it's spot on!this sounds interesting, is anyone going to make a DIP for it?
Feb 06 2015
On Saturday, 7 February 2015 at 01:43:01 UTC, Andrei Alexandrescu wrote:With the system proposal we're looking at something like: version (Posix) void[] read(in char[] name, size_t upTo = size_t.max) trusted { import core.memory; // A few internal configuration parameters { enum size_t minInitialAlloc = 1024 * 4, maxInitialAlloc = size_t.max / 2, sizeIncrement = 1024 * 16, maxSlackMemoryAllowed = 1024; // } system { immutable fd = core.sys.posix.fcntl.open(name.tempCString(), core.sys.posix.fcntl.O_RDONLY); } cenforce(fd != -1, name); scope(exit) core.sys.posix.unistd.close(fd); stat_t statbuf = void; system { cenforce(trustedFstat(fd, trustedRef(statbuf)) == 0, name); } immutable initialAlloc = to!size_t(statbuf.st_size ? min(statbuf.st_size + 1, maxInitialAlloc) : minInitialAlloc); void[] result = uninitializedArray!(ubyte[])(initialAlloc); scope(failure) delete result; size_t size = 0; for (;;) { system { immutable actual = core.sys.posix.unistd.read(fd, result.ptr + size), min(result.length, upTo) - size); } cenforce(actual != -1, name); if (actual == 0) break; size += actual; if (size < result.length) continue; immutable newAlloc = size + sizeIncrement; system { result = GC.realloc(result.ptr, newAlloc, GC.BlkAttr.NO_SCAN)[0 .. newAlloc]; } system { return result.length - size >= maxSlackMemoryAllowed ? GC.realloc(result.ptr, size, GC.BlkAttr.NO_SCAN)[0 .. size] : result[0 .. size]; } } We want to move D forward, folks. This is not it. AndreiOh I see. There are three posts, in the latter two of which the little trusted functions are already removed. I had thought they were all identical, but you obviously realized the little functions should be removed.
Feb 06 2015
On 2/6/15 8:43 PM, Andrei Alexandrescu wrote:On 2/6/15 3:21 PM, weaselcat wrote:Please understand, Nobody is saying "let's replace incorrect code with the same incorrect code with different tags!" The idea is to properly identify which code needs more scrutiny, and keep the mechanical checking of safe where we can. -SteveOn Friday, 6 February 2015 at 23:02:54 UTC, Zach the Mystic wrote:Consider the previous code: https://github.com/D-Programming-Language/phobos/blob/accb351b96bb04a6890bb7df018749337e55eccc/std/file.d#L194 that got replaced with: https://github.com/D-Programming-Language/phobos/blob/master/std/file.d#L194 With the system proposal we're looking at something like:No, at least three of us, Steven, H.S. Teoh and myself have confirmed that we've moved beyond requesting trusted blocks. We are no longer requesting them. We are requesting * system* blocks, which can only appear in trusted and system functions. Any unsafe code appearing in a trusted function which is not inside a system block is an error. We've changed the name, but I think it will make a world of difference regarding how you will look at it. Marking ' system' code inside a trusted function is exactly what is requested. Your message about ' trusted' being only acceptable as an interface has been heard. There will be no trusted blocks, only system blocks, which are the exact same thing, except they can only appear in trusted and system functions. This solution appeals to me greatly. It pinpoints precisely where unsafe code can generate; it catches unintended safety violations in all trusted code outside system blocks, as requested by many people so far; it makes systems programming highly visible, with redundancy at the function signature and at the unsafe code itself. I really think it's spot on!this sounds interesting, is anyone going to make a DIP for it?
Feb 07 2015
On Saturday, 7 February 2015 at 01:41:19 UTC, Andrei Alexandrescu wrote:Consider the previous code: [...] static trustedRead(int fildes, void* buf, size_t nbyte) trusted { return core.sys.posix.unistd.read(fildes, buf, nbyte); } static trustedRealloc(void* p, size_t sz, uint ba = 0, const TypeInfo ti = null) trusted { return GC.realloc(p, sz, ba, ti); } static trustedPtrAdd(void[] buf, size_t s) trusted { return buf.ptr+s; } static trustedPtrSlicing(void* ptr, size_t lb, size_t ub) trusted { return ptr[lb..ub]; }First of all, these little trusted functions are made obsolete by the new system. They should certainly be omitted.system { immutable fd = core.sys.posix.fcntl.open(name.tempCString(), core.sys.posix.fcntl.O_RDONLY); }Next, you have to realize that system blocks are like 'try' blocks: You don't need brackets if there's only one statement in them. Here's how I would rewrite what you have written using the new method: version (Posix) void[] read(in char[] name, size_t upTo = size_t.max) trusted { import core.memory; // A few internal configuration parameters { enum size_t minInitialAlloc = 1024 * 4, maxInitialAlloc = size_t.max / 2, sizeIncrement = 1024 * 16, maxSlackMemoryAllowed = 1024; // } system immutable fd = core.sys.posix.fcntl.open(name.tempCString(), core.sys.posix.fcntl.O_RDONLY); cenforce(fd != -1, name); scope(exit) core.sys.posix.unistd.close(fd); stat_t statbuf = void; system cenforce(trustedFstat(fd, trustedRef(statbuf)) == 0, name); immutable initialAlloc = to!size_t(statbuf.st_size ? min(statbuf.st_size + 1, maxInitialAlloc) : minInitialAlloc); void[] result = uninitializedArray!(ubyte[])(initialAlloc); scope(failure) delete result; size_t size = 0; for (;;) { system immutable actual = core.sys.posix.unistd.read(fd, result.ptr + size, min(result.length, upTo) - size); cenforce(actual != -1, name); if (actual == 0) break; size += actual; if (size < result.length) continue; immutable newAlloc = size + sizeIncrement; system result = GC.realloc( result.ptr, newAlloc, GC.BlkAttr.NO_SCAN)[0 .. newAlloc]; } system return result.length - size >= maxSlackMemoryAllowed ? GC.realloc(result.ptr, size, GC.BlkAttr.NO_SCAN)[0..size] : result[0 .. size]; } Note that I just mechanically your system blocks with the better form. I didn't arrange for them to be elegant. There's nothing wrong with encapsulating a trusted sequence in a system block with brackets, to aid future reviewers in identifying subsequent code thought to be affected by the system statements. Also, few functions will have their system blocks more or less evenly distributed throughout like the above function does. The new proposal will never let you add an unsafe operation without your knowing it. It's definitely the way forward.
Feb 06 2015
On Saturday, 7 February 2015 at 05:35:51 UTC, Zach the Mystic wrote:Note that I just mechanically your system blocks with the better form....mechanically replaced, I mean, of course.
Feb 06 2015
On Saturday, 7 February 2015 at 05:35:51 UTC, Zach the Mystic wrote:Here's how I would rewrite what you have written using the new method: ... stat_t statbuf = void; system cenforce(trustedFstat(fd, trustedRef(statbuf)) == 0, name);I didn't rewrite this because I didn't see the trustedXXX functions they referred to, but the basic rewrite would be: system cenforce(fstat(fd, reff(statbuf) == 0), name); In other words, just copy the system code directly without going through trusted.
Feb 06 2015
On Friday, 6 February 2015 at 23:21:50 UTC, weaselcat wrote:On Friday, 6 February 2015 at 23:02:54 UTC, Zach the Mystic wrote:It was Teoh's idea. Maybe he should have the honors?No, at least three of us, Steven, H.S. Teoh and myself have confirmed that we've moved beyond requesting trusted blocks. We are no longer requesting them. We are requesting * system* blocks, which can only appear in trusted and system functions. Any unsafe code appearing in a trusted function which is not inside a system block is an error. We've changed the name, but I think it will make a world of difference regarding how you will look at it. Marking ' system' code inside a trusted function is exactly what is requested. Your message about ' trusted' being only acceptable as an interface has been heard. There will be no trusted blocks, only system blocks, which are the exact same thing, except they can only appear in trusted and system functions. This solution appeals to me greatly. It pinpoints precisely where unsafe code can generate; it catches unintended safety violations in all trusted code outside system blocks, as requested by many people so far; it makes systems programming highly visible, with redundancy at the function signature and at the unsafe code itself. I really think it's spot on!this sounds interesting, is anyone going to make a DIP for it?
Feb 07 2015
On 2/6/2015 3:02 PM, Zach the Mystic wrote:No, at least three of us, Steven, H.S. Teoh and myself have confirmed that we've moved beyond requesting trusted blocks. We are no longer requesting them. We are requesting * system* blocks, which can only appear in trusted and system functions. Any unsafe code appearing in a trusted function which is not inside a system block is an error. We've changed the name, but I think it will make a world of difference regarding how you will look at it. Marking ' system' code inside a trusted function is exactly what is requested. Your message about ' trusted' being only acceptable as an interface has been heard. There will be no trusted blocks, only system blocks, which are the exact same thing, except they can only appear in trusted and system functions. This solution appeals to me greatly. It pinpoints precisely where unsafe code can generate; it catches unintended safety violations in all trusted code outside system blocks, as requested by many people so far; it makes systems programming highly visible, with redundancy at the function signature and at the unsafe code itself. I really think it's spot on!I suspect that such a feature would simply lull people into a false sense of security in that merely tagging an unsafe cast with system and the compiler accepting it is good enough. My evidence for this is how trusted was used in Phobos.
Feb 06 2015
On Friday, 6 February 2015 at 23:25:02 UTC, Walter Bright wrote:I suspect that such a feature would simply lull people into a false sense of security in that merely tagging an unsafe cast with system and the compiler accepting it is good enough. My evidence for this is how trusted was used in Phobos.How is adding system to some operations *in addition to* adding trusted to the function declaration more likely to lull people into a false sense of security than just adding trusted right now? Let me also point out that the cases where the system block equivalent is used right now (like in std.file, or the trustedXyz functions in std.array) are NOT the ones that actually have safety bugs in them (such as std.array.uninitializedArray or std.uuid.randomUUID). The two latter examples were actually written in your preferred style. David
Feb 06 2015
On 2/6/2015 3:34 PM, David Nadlinger wrote:On Friday, 6 February 2015 at 23:25:02 UTC, Walter Bright wrote:I've said that the usage of those functions was not actually buggy, what was wrong about them was that they required review of the surrounding supposedly safe context. I.e. they produced a false sense of safety. I fear the system blocks, even if only allowed in trusted functions, would produce a similar illusion of safety. I agree with Andrei in that I do not believe that reviewing a trusted function, line by line, for safety is necessarily some sort of maintenance nightmare. If it is, then a refactoring should be considered to encapsulate the unsafe code in a smaller, simpler manner. I.e. let's make an effort to use trusted correctly, and then see where we stand. Scott Meyer's excellent article (a classic): http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197 describes this most eloquently. (Just substitute "private members" with "trusted code".)I suspect that such a feature would simply lull people into a false sense of security in that merely tagging an unsafe cast with system and the compiler accepting it is good enough. My evidence for this is how trusted was used in Phobos.How is adding system to some operations *in addition to* adding trusted to the function declaration more likely to lull people into a false sense of security than just adding trusted right now? Let me also point out that the cases where the system block equivalent is used right now (like in std.file, or the trustedXyz functions in std.array) are NOT the ones that actually have safety bugs in them (such as std.array.uninitializedArray or std.uuid.randomUUID). The two latter examples were actually written in your preferred style.
Feb 06 2015
On Fri, Feb 06, 2015 at 04:04:48PM -0800, Walter Bright via Digitalmars-d wrote: [...]I agree with Andrei in that I do not believe that reviewing a trusted function, line by line, for safety is necessarily some sort of maintenance nightmare. If it is, then a refactoring should be considered to encapsulate the unsafe code in a smaller, simpler manner.[...] This does not take into the account the fact that a trusted function may call other, non- trusted, functions. When one of those other functions changes, the trusted function necessarily needs to be reviewed again. However, under the current implementation, this is not done because when the other, non- trusted, function is modified, nobody thinks to re-review the trusted function. They may not even be in the same module. There is no mechanism in place to raise a warning flag when a trusted function's dependencies are modified. Thus, the proof of safety of the trusted function has been invalidated, but trust continues to be conferred upon it. T -- Let's call it an accidental feature. -- Larry Wall
Feb 06 2015
On 2/6/2015 4:29 PM, H. S. Teoh via Digitalmars-d wrote:This does not take into the account the fact that a trusted function may call other, non- trusted, functions. When one of those other functions changes, the trusted function necessarily needs to be reviewed again.That's correct.However, under the current implementation, this is not done because when the other, non- trusted, function is modified, nobody thinks to re-review the trusted function. They may not even be in the same module. There is no mechanism in place to raise a warning flag when a trusted function's dependencies are modified. Thus, the proof of safety of the trusted function has been invalidated, but trust continues to be conferred upon it.When the interface to an system function is changed, all uses of that function have to be reviewed, whether one thinks of it or not. This is part of the review process. Having system blocks does not alter that.
Feb 06 2015
On Saturday, 7 February 2015 at 00:31:41 UTC, H. S. Teoh wrote:This does not take into the account the fact that a trusted function may call other, non- trusted, functions. When one of those other functions changes, the trusted function necessarily needs to be reviewed again. However, under the current implementation, this is not done because when the other, non- trusted, function is modified, nobody thinks to re-review the trusted function. They may not even be in the same module. There is no mechanism in place to raise a warning flag when a trusted function's dependencies are modified. Thus, the proof of safety of the trusted function has been invalidated, but trust continues to be conferred upon it.So what you should ask for is a way to "sign" trusted with a timestamp that indicates when it was last proven to be safe, e.g.: trusted("2015-01-01T12:30:12z") Then ask for a fine grained dependency tracking tool that can extract changes from git. Such a dependency tracking tool could be a nice stepping stone for faster compilation (sub-file-level recompilation). So there is synergies in this. The proposal to confuse trusted/ safe with requiring system within trusted it not a language issue. It is a process issue and can be done with lint-like tooling. Keep trusted/ safe/ system simple. Enough convoluted semantics in D already.
Feb 07 2015
On 2/6/15 7:29 PM, H. S. Teoh via Digitalmars-d wrote:On Fri, Feb 06, 2015 at 04:04:48PM -0800, Walter Bright via Digitalmars-d wrote: [...]This problem isn't solved by the proposal, however. If you are calling a system function inside a trusted function, and you've marked it as system, then changing the system function does not affect the call. However, if you changed a safe function into a system function, then a call inside a trusted function would have to now be annotated. It's important to note that our proposal will not fix cases where something subtle happens inside a system block. What it DOES do is limit this effect to the system block instead of the whole function. -SteveI agree with Andrei in that I do not believe that reviewing a trusted function, line by line, for safety is necessarily some sort of maintenance nightmare. If it is, then a refactoring should be considered to encapsulate the unsafe code in a smaller, simpler manner.[...] This does not take into the account the fact that a trusted function may call other, non- trusted, functions. When one of those other functions changes, the trusted function necessarily needs to be reviewed again.
Feb 09 2015
On Friday, 6 February 2015 at 23:25:02 UTC, Walter Bright wrote:You do realize that our proposal *tightens* security, with no loosening at all? No code which currently fails to compile will start compiling with this proposal. This is literally a breaking change which does nothing but cause errors in existing code - for the explicit purpose of making all code safer, which it will do, possibly dramatically.This solution appeals to me greatly. It pinpoints precisely where unsafe code can generate; it catches unintended safety violations in all trusted code outside system blocks, as requested by many people so far; it makes systems programming highly visible, with redundancy at the function signature and at the unsafe code itself. I really think it's spot on!I suspect that such a feature would simply lull people into a false sense of security in that merely tagging an unsafe cast with system and the compiler accepting it is good enough. My evidence for this is how trusted was used in Phobos.
Feb 06 2015
On Friday, 6 February 2015 at 23:25:02 UTC, Walter Bright wrote:On 2/6/2015 3:02 PM, Zach the Mystic wrote:I'm also not saying phobos was written perfectly to begin with. I think that this whole system blocks suggestion came up in a slightly different context than did your original discontent with std.file and std.array. I'm not sure you're ever going to stop careless programmers from getting their bad code to compile. But I think that's a different issue from giving good, careful programmers the tools they need. Right now, trusted functions are the only tool they have to help people figure out where the unsafe code is, but it's not enough. Nested trusted functions, and trusted lambas are clearly being added as a workaround for not being able to "un trust" large portions of code intended to be safe.This solution appeals to me greatly. It pinpoints precisely where unsafe code can generate; it catches unintended safety violations in all trusted code outside system blocks, as requested by many people so far; it makes systems programming highly visible, with redundancy at the function signature and at the unsafe code itself. I really think it's spot on!I suspect that such a feature would simply lull people into a false sense of security in that merely tagging an unsafe cast with system and the compiler accepting it is good enough. My evidence for this is how trusted was used in Phobos.
Feb 07 2015
On Friday, 6 February 2015 at 23:02:54 UTC, Zach the Mystic wrote:This solution appeals to me greatly. It pinpoints precisely where unsafe code can generate; it catches unintended safety violations in all trusted code outside system blocks, as requested by many people so far; it makes systems programming highly visible, with redundancy at the function signature and at the unsafe code itself. I really think it's spot on!Even a call to a system function inside a trusted function must occur inside a system block. It's that strict.
Feb 06 2015
On 2/6/15 2:16 PM, Andrei Alexandrescu wrote:On 2/6/15 11:11 AM, H. S. Teoh via Digitalmars-d wrote:I think your strawman is overstated. The "doomsday" is the current situation to which you and Walter have objected. If you think having "better discipline" in reviews is going to fix it, I guess we will have to wait and see what the evidence eventually does show. There isn't evidence that either solution has worked, because neither has been employed yet. Logically, it makes sense to me that we should adjust how trusted operates to prevent preventable problems that you have identified. But we can just keep the status quo and rely on manual process improvements instead. It's not terribly important to fix it right now, we can try your way first, I don't see how adjusting the meaning of trusted in the future would be any more disruptive than it would be now. If this is how it is to be, can we get some guidelines as to what should and should not pass review for trusted? -SteveOn Fri, Feb 06, 2015 at 10:52:45AM -0800, Andrei Alexandrescu via Digitalmars-d wrote:I've asked repeatedly for evidence of the "problematic situation", and all I got was doomsday predictions "maintenance nightmare!". If you have such, please show it. If not, thanks for a good course of action. -- AndreiOn 2/6/15 10:42 AM, David Nadlinger wrote:This is precisely why I have lost all interest in safe. It's clear that the present problematic situation will continue to hold, and the decision makers are not interested to address it. I am not going to waste any more time and energy on this topic.On Friday, 6 February 2015 at 18:39:28 UTC, Andrei Alexandrescu wrote:I think the problem is overstated. -- AndreiIt's clear. I just don't think it's a good point. -- AndreiI'm not making a point; I'm posing a problem. What is your solution?
Feb 06 2015
On 2/6/15 11:53 AM, Steven Schveighoffer wrote:I think your strawman is overstated. The "doomsday" is the current situation to which you and Walter have objected.I see that just as: code in poor style made its way in Phobos. It doesn't improve anything (e.g. didn't find bugs in std.file.read) and is just a net negative resulting from the corrupted use of a feature. There's no completely automated protection against poor style.If you think having "better discipline" in reviews is going to fix it, I guess we will have to wait and see what the evidence eventually does show. There isn't evidence that either solution has worked, because neither has been employed yet. Logically, it makes sense to me that we should adjust how trusted operates to prevent preventable problems that you have identified. But we can just keep the status quo and rely on manual process improvements instead. It's not terribly important to fix it right now, we can try your way first, I don't see how adjusting the meaning of trusted in the future would be any more disruptive than it would be now. If this is how it is to be, can we get some guidelines as to what should and should not pass review for trusted?Wise words. Walter has a PR on docs, you may want to review it: https://github.com/D-Programming-Language/dlang.org/pull/890 Andrei
Feb 06 2015
On 2/6/2015 11:11 AM, H. S. Teoh via Digitalmars-d wrote:This is precisely why I have lost all interest in safe. It's clear that the present problematic situation will continue to hold, and the decision makers are not interested to address it. I am not going to waste any more time and energy on this topic.In this thread at 8:20PM last night, Dicebot asked me: "I am not even sure how you can show the example though, to be honest - implied issues are about maintaining code and not just writing it." And I replied with a specific example of how to fix one aspect of std.array. There have been no replies. What else can I do to address it?
Feb 06 2015
On 2/6/15 4:48 PM, Walter Bright wrote:On 2/6/2015 11:11 AM, H. S. Teoh via Digitalmars-d wrote:In the case you bring up, maintenance is easy -- the code is incorrect, it needs to be fixed/rewritten. No solution ever implemented or proposed can stop this from happening. The case being discussed by Dicebot, and most of us, involves a case where an entire trusted function is PROPERLY implemented, yet someone adds incorrect code to it. The compiler does not complain. Note that if the requested solution was implemented, each of these calls should be individual cases to inspect. I don't think anyone disagrees that uninitializedArray shouldn't be a public trusted function. But individual cases of it CAN be properly safe. -SteveThis is precisely why I have lost all interest in safe. It's clear that the present problematic situation will continue to hold, and the decision makers are not interested to address it. I am not going to waste any more time and energy on this topic.In this thread at 8:20PM last night, Dicebot asked me: "I am not even sure how you can show the example though, to be honest - implied issues are about maintaining code and not just writing it." And I replied with a specific example of how to fix one aspect of std.array. There have been no replies. What else can I do to address it?
Feb 09 2015
On Friday, 6 February 2015 at 18:52:45 UTC, Andrei Alexandrescu wrote:I think the problem is overstated. -- AndreiI think there could hardly be a more persuasive argument that this belief is wrong than Walter himself just having made the mistake several times, and not even immediately realizing what is wrong: https://github.com/D-Programming-Language/phobos/pull/2966 [1] Sorry for singling out this one example here. While it is particularly demonstrative, I am certainly not intending to put Walter in a bad light. It's simply hard to get that stuff right, as templates can make it hard to accurately determine the complete public interface of a function. As pointed out in the PR, here are some more examples for this class of bugs from Phobos code, also written and reviewed by top D coders: https://issues.dlang.org/show_bug.cgi?id=14135 https://issues.dlang.org/show_bug.cgi?id=14136 https://issues.dlang.org/show_bug.cgi?id=14137 https://issues.dlang.org/show_bug.cgi?id=14138 Neither of those issues would have been prevented by your new guidelines; the code in question is already written in that way. Quite to the contrary, consequent application of minimal trusted blocks or even the workaround you reject so strongly would have prevented all of the bugs except for 14138. David [1] The diff in question, for when the PR is fixed: https://github.com/klickverbot/phobos/commit/db647f62cb5279ae42ad98665cd60cdcdb9b3dd5
Feb 07 2015
On Saturday, 7 February 2015 at 12:40:26 UTC, David Nadlinger wrote:Neither of those issues would have been prevented by your new guidelines; the code in question is already written in that way. Quite to the contrary, consequent application of minimal trusted blocks or even the workaround you reject so strongly would have prevented all of the bugs except for 14138.This is an incredibly poor argument. The fact that there is no documentation for why the functions are trusted and why they have to be trusted is testament to a flawed process. If you insist on relying on half-assed flawed verification you only catch those instances where it should not have been trusted in the first place, and which would have been caught at an early stage with a decent process, but you will keep missing out on the hard to detect cases. You will run into much more difficult problems if you don't do something about the safety review process. Fix the weak typing rather than making the language more convoluted, the latter compounds the problem in the long run.
Feb 07 2015
And I'll add this: Please do not turn the compiler into a inadequate verification tool. The compiler should do what it can do well, but what it cannot do it should not do at all and leave to an external verification tool. trusted basically tells the compiler "this is beyond your capability so we left it to someone else". Third parties should be able to provide incrementally improved verification tools, for various purposes, without mandating language or compiler changes. So what you want from the language is simple clean semantics and reasonable best practice annotations for verification that can be extended based on the needs in a particular environment.
Feb 07 2015
On 2/7/15 4:40 AM, David Nadlinger wrote:On Friday, 6 February 2015 at 18:52:45 UTC, Andrei Alexandrescu wrote:Nice, thanks for this work. One good guideline here is to almost always let generic code rely on deduction instead of ascribing safety attributes to it. AndreiI think the problem is overstated. -- AndreiI think there could hardly be a more persuasive argument that this belief is wrong than Walter himself just having made the mistake several times, and not even immediately realizing what is wrong: https://github.com/D-Programming-Language/phobos/pull/2966 [1] Sorry for singling out this one example here. While it is particularly demonstrative, I am certainly not intending to put Walter in a bad light. It's simply hard to get that stuff right, as templates can make it hard to accurately determine the complete public interface of a function. As pointed out in the PR, here are some more examples for this class of bugs from Phobos code, also written and reviewed by top D coders: https://issues.dlang.org/show_bug.cgi?id=14135 https://issues.dlang.org/show_bug.cgi?id=14136 https://issues.dlang.org/show_bug.cgi?id=14137 https://issues.dlang.org/show_bug.cgi?id=14138 Neither of those issues would have been prevented by your new guidelines; the code in question is already written in that way. Quite to the contrary, consequent application of minimal trusted blocks or even the workaround you reject so strongly would have prevented all of the bugs except for 14138. David [1] The diff in question, for when the PR is fixed: https://github.com/klickverbot/phobos/commit/db647f62cb5279ae42ad98665cd60cdcdb9b3dd5
Feb 07 2015
And making this work in functions that already marked trusted and need to be, but should have some parts inferred is the hole point of this thread and the trusted-misuse in phobos.https://github.com/klickverbot/phobos/commit/db647f62cb5279ae42ad98665cd60cdcdb9b3dd5Nice, thanks for this work. One good guideline here is to almost always let generic code rely on deduction instead of ascribing safety attributes to it. Andrei
Feb 07 2015
On 2/6/2015 3:57 AM, Martin Krejcirik wrote:If I understand it correctly, Walter is against adding trusted blocks (trusted {...}) into safe functions. But what about having safe blocks in trusted functions ? int somefunc() trusted { int a = systemfunc(); int b; safe { b = safefunc(); // calling systemfunc() not allowed; } return a + b; }The problem is, again: trusted code must have a safe interface and with code blocks, there is no interface specified to them other than examining EVERY line of code in it. The way interfaces are specified in D is to use functions.
Feb 06 2015
First, I want to say that I didn't want to cause a huge rift between D developers with this, I didn't think this was such a drastic issue, just a possible idea. But here we are. I hope we can mend this, and move forward. But on to the discussion. On 2/5/15 6:39 PM, Walter Bright wrote:Consider the following code excerpted from std.array.join: static U trustedCast(U, V)(V v) trusted { return cast(U) v; } return trustedCast!RetType(result); This is because the compiler would complain that the following line would not be safe: return cast(RetType)(result); The rationale is "I know it's safe, so I'll create an trusted wrapper to eliminate the error." What comes next is "that's cumbersome. How about a better syntax:" trusted { return cast(RetType)(result); }No. This was NEVER THE ARGUMENT. Now, let me explain why the latter is BETTER. It's better because I know where it is used. It's used in one place, and I can squash it right there saying "No, you can't do this in this one place." Instead of reviewing an API in ALL POSSBILE CONTEXTS (which if trustedCast is a public API, would be a lot), I have to review one call in ONE CONTEXT. The former is WORSE because it can be used in 100 places. Now I have to go through and fix ALL THOSE FUNCTIONS that use it, because its interface was exposed to the whole of phobos. The problem, as we have said many times, is maintenance. Sure, in both cases they never should have shown up in the first place. But there they are, and we now have to fix them. All of them. And let's also talk about long term maintenance. Any time a trusted function is amended or tweaked, we have to reconsider all the contexts. If you mark a single line as trusted, then additional lines to the same function would not need as much scrutiny, especially if you warn when trusted tainted data is touched.The trouble with it is, what if the cast is converting from an integer to a pointer? That could lead to memory corruption. The code allows a potentially memory corrupting operation to be inserted into code that is otherwise safe.And so, you reject that code in both cases, except in the case where you don't define a callable API, you don't have to worry about any other code or contexts. This has to be the worst example to explain your point.The only way to deal with it is to then manually review everything about 'RetType' and 'result' to prove to oneself that it is not converting random bit patterns into pointers. In other words, one is manually reviewing safe code for memory corruption errors.trusted code is not safe code. You are reviewing that one line in its current context, not the whole function to see where it is called in various contexts.The solution is to regard trusted as a means of encapsulating unsafe operations, not escaping them. Encapsulating them means that the interface from the trusted code is such that it is usable from safe code without having to manually review the safe code for memory safety. For example (also from std.array): static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); } I don't have to review callers of trustedMemory() because it encapsulates an unsafe operation (memcpy) with a safe interface.Sure. But let's consider it's called in one place: trustedMemcopy(array[pos..pos+to_insert], tmp); What if that became: assert(tmp.length == to_insert); // same as src.length == dest.length trusted memcpy(array.ptr + pos, tmp.ptr, tmp.length); What is missing here is, make sure the type of array and tmp is the same. All one has to do is review the function to see that. You could put in a static assert if you wish: static assert(is(typeof(array) == typeof(tmp))); If there are multiple places that it's called from, sure we can encapsulate that in a function: static void trustedMemcopy(T[] dest, T[] src) { assert(src.length == dest.length); trusted memcpy(dest.ptr, src.ptr, src.length * T.sizeof); } There is very little difference here. Except if I add code to my version of trustedMemcopy that is system, I have to properly mark that too, and that should imply greater scrutiny. I fail to see why making extra unintended system calls inside a "trusted" function shouldn't require extra marking. Consider if this is a github review, and the context for the new lines is missing (i.e. you don't see that the new line is inside a trusted function because github doesn't give you that line).The reason trusted applies only to functions, and not to blocks of code, is that functions are the construct in D that provides an interface. Arbitrary blocks of code do not have a structured interface. Adding trusted { code } support will encourage incorrect uses like the opening example. The existence of trusted blocks will require review of every line of code in the function that encloses it, and transitively every function that calls it!This is like opposite land! You don't have to review every function that calls a safe function with trusted escapes any more than you have to review every function that calls a trusted function! That is the point of having the attribute on the function call. However, if trusted is improperly placed on a function, then I have to break every function that calls it if it now becomes system. While the same would be for a safe function that has incorrectly escaped trusted calls, the temptation to make those small calls into a nice neat public API without context is not there. Having trusted as a function attribute *encourages* bad encapsulation of unsafe calls WITHOUT CONTEXT. This is so easy to do with templates.Adding trusted as a function attribute, on the other hand, only requires review of the function's interface to determine if it is acceptable to use in safe code. Safety review of its callers is unnecessary.I see zero difference between a trusted function and a safe function with trusted escapes. You have to review both with the same scrutiny. Except less so for the one with escapes because you only have to scrutinize the trusted calls. You know, I'm surprised you have rejected H.S. Teoh's proposal because it seems like you are stuck on the concept that nobody should have to review safe code for memory problems. Perhaps marking functions trusted and then having escapes with system is a better way of looking at it, because you do have to review that code for memory problems. The bottom line of my reasoning is that code changes over time, by different people. Context is forgotten. It's much better to have the compiler verify you know what you are doing when working with trusted than it is to just allow anyone to inject code anywhere. -Steve
Feb 06 2015
On Friday, 6 February 2015 at 13:28:59 UTC, Steven Schveighoffer wrote:The bottom line of my reasoning is that code changes over time, by different people. Context is forgotten. It's much better to have the compiler verify you know what you are doing when working with trusted than it is to just allow anyone to inject code anywhere.Actually, I think this argument goes against what you are arguing for. Anything within a trusted section has a big warning sign attached to it that says "cannot modify this without detailed review". But the compiler cannot verify that a safe function with local trusted blocks are actually safe, so it only buys you a false sense of security. It is also much easier to bring a large trusted block to safety than a small one, e.g. to have one big trusted chunk that does: 1. obtain resource 2. process resource 3. copy resource 4. free resource 5. return copy The problem is the process around trusted given that there will be no sound verification system in D. Maybe it should have been called " manually_proven_safe" instead, to discourage use...
Feb 06 2015
On 2/6/15 8:42 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:On Friday, 6 February 2015 at 13:28:59 UTC, Steven Schveighoffer wrote:That is kind of the point behind H.S. Teoh's idea that trusted code should be default safe with system escapes instead of today where it's default system. If nothing else, it has discouraged the use of trusted to mark code for extra scrutiny. I'm coming to agree with him. Having a function marked safe doesn't tell you whether there are trusted blocks, and any trusted blocks (despite the idea of having the compiler tell you when data was generated/touched by trusted code) can bring into suspect the whole function. So marking a function safe, and having it mean "this function has NO TRUSTED OR SYSTEM CODE in it whatsoever, is probably the right move, regardless of any other changes. In fact, I would propose that it should be an error for safe functions to have any non-static functions inside them (i.e. any place where the aliasing of safe data is implicit). This is a departure from my previous position, but I think it still fits if we allow trusted to mean what H.S. Teoh's proposal means.The bottom line of my reasoning is that code changes over time, by different people. Context is forgotten. It's much better to have the compiler verify you know what you are doing when working with trusted than it is to just allow anyone to inject code anywhere.Actually, I think this argument goes against what you are arguing for. Anything within a trusted section has a big warning sign attached to it that says "cannot modify this without detailed review". But the compiler cannot verify that a safe function with local trusted blocks are actually safe, so it only buys you a false sense of security.It is also much easier to bring a large trusted block to safety than a small one, e.g. to have one big trusted chunk that does: 1. obtain resource 2. process resource 3. copy resource 4. free resource 5. return copy The problem is the process around trusted given that there will be no sound verification system in D.What we really want is: 1. A way to say "this function needs extra scrutiny" 2. Mechanical verification as MUCH AS POSSIBLE, and especially for changes to said function. Yes, we can do 2 manually if necessary. But having a compiler that never misses on pointing out certain bad things is so much better than not having it.Maybe it should have been called " manually_proven_safe" instead, to discourage use...assume_safe would probably be the right moniker since that's what we use elsewhere. But it's water under the bridge now... -Steve
Feb 06 2015
On Friday, 6 February 2015 at 15:10:18 UTC, Steven Schveighoffer wrote:into suspect the whole function. So marking a function safe, and having it mean "this function has NO TRUSTED OR SYSTEM CODE in it whatsoever, is probably the right move, regardless of any other changes.But that would break if you want to call a safe function with a trusted function reference as a parameter? Or did I misunderstand what you meant here? And... what happens if you bring in a new architecture that requires trusted implementation of a library function that is safe on other architectures?1. A way to say "this function needs extra scrutiny" 2. Mechanical verification as MUCH AS POSSIBLE, and especially for changes to said function. Yes, we can do 2 manually if necessary. But having a compiler that never misses on pointing out certain bad things is so much better than not having it.I am not sure if it is worth the trouble. If you are gonna conduct a semi formal proof, then you should not have a mechanical sleeping pillow that makes you sloppy. ;-) Also if you do safety reviews they should be separate from the functional review and only focus on safety. Maybe it would be interesting to have an annotation for notprovenyet, so that you could have regular reviews during development and then scan the source code for trusted functions that need a safety review before you a release is permitted? That way you don't have to do the safety review for every single mutation of the trusted function.Yeah, it was merely the psychological effect that one might hestitate to actually type in "I have proven this" without thinking twice about it. "I trust this code" is an easy claim... ;-)Maybe it should have been called " manually_proven_safe" instead, to discourage use...assume_safe would probably be the right moniker since that's what we use elsewhere. But it's water under the bridge now...
Feb 06 2015
On 2/6/15 10:36 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:On Friday, 6 February 2015 at 15:10:18 UTC, Steven Schveighoffer wrote:The whole point of marking a function trusted instead of a block is that you have to follow the rules of function calling to get into that block, and your separate function only has access to variables you give it. My point was that if you have trusted escapes inside a function, whether it's marked safe or not, you still have to review the whole function. If the compiler disallowed this outright, then you don't have that issue. Separating the trusted code from the safe code via an API barrier has merits when it comes to code review. Now, trusted static nested functions that stand on their own are fine, they are no different than public ones, just not public. trusted static nested functions that are ONLY OK when called in certain ways, that is where we run into issues. At that point, you have to make a choice -- add (somewhat unnecessary) machinery to make sure the function is always called in a safe way, or expand the scope of the trusted portion, possibly even to the whole safe function. I see the point now that making sure safe functions don't have escapes has the advantage of not requiring *as much* review as a system or trusted function. I am leaning so much towards H.S. Teoh's solution of making trusted safe by default, and allowing escapes into system code. That seems like the right abstraction.into suspect the whole function. So marking a function safe, and having it mean "this function has NO TRUSTED OR SYSTEM CODE in it whatsoever, is probably the right move, regardless of any other changes.But that would break if you want to call a safe function with a trusted function reference as a parameter? Or did I misunderstand what you meant here?And... what happens if you bring in a new architecture that requires trusted implementation of a library function that is safe on other architectures?Then you create a trusted wrapper around that API, ensuring when called from safe code it can't corrupt memory.I see what you mean, but there are also really dumb things that people miss that a compiler won't. Having a mechanical set of eyes in addition to human eyes is still more eyes ;)1. A way to say "this function needs extra scrutiny" 2. Mechanical verification as MUCH AS POSSIBLE, and especially for changes to said function. Yes, we can do 2 manually if necessary. But having a compiler that never misses on pointing out certain bad things is so much better than not having it.I am not sure if it is worth the trouble. If you are gonna conduct a semi formal proof, then you should not have a mechanical sleeping pillow that makes you sloppy. ;-)Also if you do safety reviews they should be separate from the functional review and only focus on safety. Maybe it would be interesting to have an annotation for notprovenyet, so that you could have regular reviews during development and then scan the source code for trusted functions that need a safety review before you a release is permitted? That way you don't have to do the safety review for every single mutation of the trusted function.The way reviews are done isn't anything the language can require. Certainly we can provide guidelines, and we can require such review processes for phobos and druntime. -Steve
Feb 06 2015
On Friday, 6 February 2015 at 18:51:34 UTC, Steven Schveighoffer wrote:My point was that if you have trusted escapes inside a function, whether it's marked safe or not, you still have to review the whole function. If the compiler disallowed this outright, then you don't have that issue.Ok, I also prefer that trusted only apply to whole functions. I don't agree with the argument, but let's leave it at that ;-).Separating the trusted code from the safe code via an API barrier has merits when it comes to code review.Yes. And I actually don't think trusted functions in Phobos should contain version() or other forms for conditional compilation since that makes it much harder to reason about.I see the point now that making sure safe functions don't have escapes has the advantage of not requiring *as much* review as a system or trusted function. I am leaning so much towards H.S. Teoh's solution of making trusted safe by default, and allowing escapes into system code. That seems like the right abstraction.Just to make sure that I got this right: I don't really understand why you need to escape to system from trusted. Isn't trusted the same as system but with a seal that says that it has been manually verified to be memory safe? system simply allows the same internal semantics as trusted but with no such declared guarantee to the caller? Except that in system you could potentially switch the stacks and do other unsafe operations that are not brought back to normal before leaving the system context... In trusted you are required to restore the context to normal before returning. So in the type system you only have safe and system, trusted is just safe with flexible manual verification rather than the limited automated verification DMD is capable of. Thus you only need to export safe vs system for separate compilation...? Isn't that how it is supposed to work already?I see what you mean, but there are also really dumb things that people miss that a compiler won't. Having a mechanical set of eyes in addition to human eyes is still more eyes ;)Well, if you can come up with something sound. The way I see it, trusted functions are allowed to create a new context on entry as long as it restores the previous context before exiting. This essentially means that what is safe before entering trusted no longer can be guaranteed to be safe. The floating point unit might work differently and result in memory unsafe operations etc etc. So calling safe from trusted means that you are calling safe as if it was system. And therefore safe code called from trusted has to be proven correct just like system code called from trusted.The way reviews are done isn't anything the language can require. Certainly we can provide guidelines, and we can require such review processes for phobos and druntime.Yes, in Phobos you need to impose additional stricter guarantees in order to support the formal review process and ensure that the formal review cannot be broken without a new review taking place. And yes, that is a process requirement, not a language requirement. A different process might impose other requirements... I think you will have to define such a process though, because I don't think there is a solution for fully automated verification for D without going for a much more complex type system and mechanics (which I actually think is out of reach unless everything is designed around it). Fortunately with 3 reviewers you can do quite well if the proof is available and they work independently without sharing results before everyone is done. If each reviewer has a 10% chance of failure then you end up with only 0.1% chance of all of them failing... So it is possible to get decent results with a formal process in place. Complicated trusted code (hard to prove safe) should be rejected and unnecessary trusted code should be fixed in the compiler optimizer or by adding language features (like SIMD).
Feb 06 2015
On 2/6/15 3:02 PM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:On Friday, 6 February 2015 at 18:51:34 UTC, Steven Schveighoffer wrote:In the proposal, trusted code is actually considered the same as safe, but allows system escapes. I don't have any time to read your further points, but I will catch up with them later, sorry! -SteveI see the point now that making sure safe functions don't have escapes has the advantage of not requiring *as much* review as a system or trusted function. I am leaning so much towards H.S. Teoh's solution of making trusted safe by default, and allowing escapes into system code. That seems like the right abstraction.Just to make sure that I got this right: I don't really understand why you need to escape to system from trusted. Isn't trusted the same as system but with a seal that says that it has been manually verified to be memory safe? system simply allows the same internal semantics as trusted but with no such declared guarantee to the caller?
Feb 06 2015
On Friday, 6 February 2015 at 20:13:18 UTC, Steven Schveighoffer wrote:In the proposal, trusted code is actually considered the same as safe, but allows system escapes.But that can't work: trusted_is_safe { auto tmp = get_hardware_config(); system{ mess_up_hardware_config(); } // now this unsafe call is called in a safe context, but is unsafe... // DMD does not catch this, so " trusted_is_safe" is broken call_safe_code_that_now_is_messed_up(); system{ restore_hardware_config(tmp); } }
Feb 06 2015
On 2/6/15 4:36 PM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:On Friday, 6 February 2015 at 20:13:18 UTC, Steven Schveighoffer wrote:The idea is that trusted code still has to be reviewed for memory issues, but is mechanically checked for most of the function for obvious safe violations. It limits to a degree the scrutiny one must apply to the trusted function. Remember, the whole point of a trusted function is that it's manually verified. -SteveIn the proposal, trusted code is actually considered the same as safe, but allows system escapes.But that can't work: trusted_is_safe { auto tmp = get_hardware_config(); system{ mess_up_hardware_config(); } // now this unsafe call is called in a safe context, but is unsafe... // DMD does not catch this, so " trusted_is_safe" is broken call_safe_code_that_now_is_messed_up(); system{ restore_hardware_config(tmp); } }
Feb 07 2015
On Saturday, 7 February 2015 at 11:32:41 UTC, Steven Schveighoffer wrote:The idea is that trusted code still has to be reviewed for memory issues, but is mechanically checked for most of the function for obvious safe violations. It limits to a degree the scrutiny one must apply to the trusted function. Remember, the whole point of a trusted function is that it's manually verified.This is the wrong way to do it and this is a tooling issue, not a language issue. The right way to do it is this: 1. annotate the trusted region manually where it is needed 2. mechanically verify the whole trusted region Of course, then you also need a theorem prover... You are trying to do this: 1. mechanically verify the whole trusted region 2. manually verify the whole trusted region, but be sloppy about it here an there 3. Ooops, we were sloppy in the wrong spot... Not good.
Feb 07 2015
On 2/7/15 7:11 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:You are trying to do this: 1. mechanically verify the whole trusted region 2. manually verify the whole trusted region, but be sloppy about it here an there 3. Ooops, we were sloppy in the wrong spot...No. A trusted function is manually verified, period. But we also must tag potential points of leakage with system. In fact, it probably could be a warning/error if you have a trusted function without any system escapes (it could just be marked safe). Think of it this way: the system tags are the only places where issues can creep into the function. But then you have to apply the leaks to the whole function. It makes the problem of finding potential safety issues more tractable, because the compiler forces us to identify the root causes. -Steve
Feb 09 2015
On Monday, 9 February 2015 at 14:40:36 UTC, Steven Schveighoffer wrote:On 2/7/15 7:11 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:That's a nice migration path, btw. First, warn about trusted functions without system blocks and don't enforce safe-ty inside them, later disallow them and do enforce safe-ty in the others.You are trying to do this: 1. mechanically verify the whole trusted region 2. manually verify the whole trusted region, but be sloppy about it here an there 3. Ooops, we were sloppy in the wrong spot...No. A trusted function is manually verified, period. But we also must tag potential points of leakage with system. In fact, it probably could be a warning/error if you have a trusted function without any system escapes (it could just be marked safe).
Feb 09 2015
On 2/9/15 10:13 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:On Monday, 9 February 2015 at 14:40:36 UTC, Steven Schveighoffer wrote:Yes, that solves the problem of breaking code with this... Nice idea. -SteveOn 2/7/15 7:11 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:That's a nice migration path, btw. First, warn about trusted functions without system blocks and don't enforce safe-ty inside them, later disallow them and do enforce safe-ty in the others.You are trying to do this: 1. mechanically verify the whole trusted region 2. manually verify the whole trusted region, but be sloppy about it here an there 3. Ooops, we were sloppy in the wrong spot...No. A trusted function is manually verified, period. But we also must tag potential points of leakage with system. In fact, it probably could be a warning/error if you have a trusted function without any system escapes (it could just be marked safe).
Feb 09 2015
On Monday, 9 February 2015 at 14:40:36 UTC, Steven Schveighoffer wrote:But we also must tag potential points of leakage with system. In fact, it probably could be a warning/error if you have a trusted function without any system escapes (it could just be marked safe). Think of it this way: the system tags are the only places where issues can creep into the function. But then you have to apply the leaks to the whole function. It makes the problem of finding potential safety issues more tractable, because the compiler forces us to identify the root causes.The compiler should only verify what is needed for the type system to work. There is no need to differentiate between trusted and system for that. If you require using " system" for annotation, then you will have to change the language every time you improve the verifier. Because this ad hoc annotation will be unsuitable for a more powerful verifier. And it isn't obvious that treating trusted as safe will not lead to false positives.
Feb 09 2015
On Friday, 6 February 2015 at 20:13:18 UTC, Steven Schveighoffer wrote:In the proposal, trusted code is actually considered the same as safe, but allows system escapes.That seems like a good idea and in the spirit of what the goal is. However, won't it be a breaking change?
Feb 06 2015
On 2/6/15 5:19 PM, Meta wrote:On Friday, 6 February 2015 at 20:13:18 UTC, Steven Schveighoffer wrote:Yes. The big question is, is it worth it? I would say yes, since trusted is already incorrectly used in most cases. -SteveIn the proposal, trusted code is actually considered the same as safe, but allows system escapes.That seems like a good idea and in the spirit of what the goal is. However, won't it be a breaking change?
Feb 07 2015
On Friday, 6 February 2015 at 13:42:40 UTC, Ola Fosheim Grøstad wrote:"cannot modify this without detailed review".This quote from Ola, here? That basically describes my job maintaining big piles of legacy C: the compiler verifies nothing, so every change to the anything in the API of "safe" functions or anything in their entire call chain must be painstakingly reviewed. A single change generally takes me several days of research, verification, and testing. I fixed about 150 potential memory issues (and several really dumb logic errors) with Clang's static analysis when I first inherited the code; it took weeks. (And now writing new stuff using this "safe" API is turning up memory safety issues anyway!) So from my perspective, calling this situation "completely impractical" reveals a stunning gift for understatement. Is this really the best we can do after however many years? Because it blows. The current trusted semantics (and accompanying politics) make it exceedingly clear that safe is meaningless for anything beyond trivial, one-off tools that will never receive maintenance. -Wyatt
Feb 06 2015
On Friday, 6 February 2015 at 15:14:14 UTC, Wyatt wrote:So from my perspective, calling this situation "completely impractical" reveals a stunning gift for understatement. Is this really the best we can do after however many years? Because it blows. The current trusted semantics (and accompanying politics) make it exceedingly clear that safe is meaningless for anything beyond trivial, one-off tools that will never receive maintenance.I don't get this. If: 1. safe actually works. 2. trusted sections are written without dependencies 3. trusted are formally proven safe 4. trusted functions rarely change 5. trusted is 0-2% of the codebase Then how is this more work than implementing something like a linear type system that is both tedious for the programmer and has taken Rust 8 years to get into working shape...? Jonathan recently said he would like to volunteer some, and he has mentioned a background with math/proofs. If he is willing to do safety review, then so I am, then so will someone else who feel like refreshing their training in program verification... Use the resources you have. Those resources, we do have, I think. Unused. The resources we obviously don't have is experts on type systems and automated proof and verification engines.
Feb 06 2015
On Friday, 6 February 2015 at 15:48:45 UTC, Ola Fosheim Grøstad wrote:2. trusted sections are written without dependenciesThis really won't happen unless statically enforced because humans are involved.3. trusted are formally proven safe...by humans?4. trusted functions rarely changeIs this so? Data, please.5. trusted is 0-2% of the codebaseIn Phobos, you mean? You've checked? 2% in my world is already thousands of lines of code, and I'm far from having the largest of maintenance burdens. Get it to a small fraction of a percent and then maybe we can talk.linear type systemTime and place, man. I'm not even sure why you're bringing this up here.Jonathan recently said he would like to volunteer some, and he has mentioned a background with math/proofs. If he is willing to do safety review, then so I am, then so will someone else who feel like refreshing their training in program verification... Use the resources you have. Those resources, we do have, I think. Unused.That's great; thanks for that. Seriously. But to my mind, that adds a whole new stack of concerns. How many people do you think you'll need to absorb the patch flow to Phobos? In perpetuity? How do you separate the qualified from the overconfident? How many people need to check something independently before you're reasonably certain there are no mistakes? etc. Any time you bind yourself to human process, you've created a bottleneck of uncertainty. And that's just Phobos! You don't scale horizontally and it's kind of problematic to approach this with the assumption that everyone wanting to write something that even reasonably approximates safe code is a mathematician. Rather, that doesn't bear out in practice at all. Bottom Line: If it can't be even partially automated, it's not useful. -Wyatt
Feb 06 2015
On Friday, 6 February 2015 at 17:02:44 UTC, Wyatt wrote:On Friday, 6 February 2015 at 15:48:45 UTC, Ola Fosheim Grøstad wrote:At least I expect the amount of trusted in phobos to be much higher than in normal user code.2. trusted sections are written without dependenciesThis really won't happen unless statically enforced because humans are involved.3. trusted are formally proven safe...by humans?4. trusted functions rarely changeIs this so? Data, please.5. trusted is 0-2% of the codebaseIn Phobos, you mean? You've checked?
Feb 06 2015
On 2/6/15 9:07 AM, Tobias Pankrath wrote:At least I expect the amount of trusted in phobos to be much higher than in normal user code.Exactly. There's a bunch of low-level interfaces in Phobos and also some code that aims at maximum efficiency. Andrei
Feb 06 2015
On Friday, 6 February 2015 at 17:02:44 UTC, Wyatt wrote:It isn't that hard for typical library code that is required to be non-safe. You don't have to do better than the compiler code in terms of probability of slipping things through... :-P3. trusted are formally proven safe...by humans?That would be a requirement. That means you should have high requirements for design before allowing implementation of trusted.4. trusted functions rarely changeIs this so? Data, please.That would be a requirement. If you have lots of trusted, then there is something wrong with the abstraction level trusted is used at (or the compiler features).5. trusted is 0-2% of the codebaseIn Phobos, you mean? You've checked?What is your alternative? You need to point at the alternative. The only alternative I see is to drop safe or keep trusted or change the type system.linear type systemTime and place, man. I'm not even sure why you're bringing this up here.perpetuity? How do you separate the qualified from the overconfident? How many people need to check something independently before you're reasonably certain there are no mistakes?One semi-formal proof written down. 3 qualified (education) independent reviews of the proof. What makes this more difficult for the standard library than for the compiler internals?etc. Any time you bind yourself to human process, you've created a bottleneck of uncertainty.And the alternative is?And that's just Phobos! You don't scale horizontally and it's kind of problematic to approach this with the assumption that everyone wanting to write something that even reasonably approximates safe code is a mathematician. Rather, that doesn't bear out in practice at all. Bottom Line: If it can't be even partially automated, it's not useful.Then drop safe...
Feb 06 2015
On 2/6/2015 7:48 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:Then how is this more work than implementing something like a linear type system that is both tedious for the programmer and has taken Rust 8 years to get into working shape...?Rust has "unsafe" blocks with specific instructions that it cannot be verified mechanically and it is up to the programmer to ensure a safe interface to it. So no, Rust didn't get that working, either, and it is far beyond current compiler technology to do it.
Feb 06 2015
On Friday, 6 February 2015 at 22:24:48 UTC, Walter Bright wrote:Rust has "unsafe" blocks with specific instructions that it cannot be verified mechanically and it is up to the programmer to ensure a safe interface to it. So no, Rust didn't get that working, either, and it is far beyond current compiler technology to do it.Rust guarantees, though, that all code outside of unsafe blocks/functions is completely safe, which D doesn't do because of trusted. I think that `unsafe` in Rust is more like trust in D, but I'm not completely sure about that.
Feb 06 2015
On 2/6/2015 2:39 PM, Meta wrote:On Friday, 6 February 2015 at 22:24:48 UTC, Walter Bright wrote:Rust guarantees no such thing, because it is explicitly up to the Rust programmer to verify a safe interface to unsafe code blocks. It is no different from the D trusted programmer verifying a safe interface to trusted code.Rust has "unsafe" blocks with specific instructions that it cannot be verified mechanically and it is up to the programmer to ensure a safe interface to it. So no, Rust didn't get that working, either, and it is far beyond current compiler technology to do it.Rust guarantees, though, that all code outside of unsafe blocks/functions is completely safe, which D doesn't do because of trusted. I think that `unsafe` in Rust is more like trust in D, but I'm not completely sure about that.
Feb 06 2015
On Friday, 6 February 2015 at 15:14:14 UTC, Wyatt wrote:On Friday, 6 February 2015 at 13:42:40 UTC, Ola Fosheim Grøstad wrote:Exactly the reason why I never liked C and C++ only makes it better if everyone on team stays away from Cisms and uses the safer alternatives. Now the C and C++ world finally accepted the use of static analyzers, but I had the displeasure to try to find pointer related issues without one, back in the .com days. As you say, it takes weeks. Regarding D, maybe trusted should go away and only keep system (== unsafe in other languages), as it can hardly give any extra security guarantee. However, I don't see how to solve the human review process, as that is an halting problem. -- Paulo"cannot modify this without detailed review".This quote from Ola, here? That basically describes my job maintaining big piles of legacy C: the compiler verifies nothing, so every change to the anything in the API of "safe" functions or anything in their entire call chain must be painstakingly reviewed. A single change generally takes me several days of research, verification, and testing. I fixed about 150 potential memory issues (and several really dumb logic errors) with Clang's static analysis when I first inherited the code; it took weeks. (And now writing new stuff using this "safe" API is turning up memory safety issues anyway!) So from my perspective, calling this situation "completely impractical" reveals a stunning gift for understatement. Is this really the best we can do after however many years? Because it blows. The current trusted semantics (and accompanying politics) make it exceedingly clear that safe is meaningless for anything beyond trivial, one-off tools that will never receive maintenance. -Wyatt
Feb 06 2015
On 2/6/2015 7:14 AM, Wyatt wrote:The current trusted semantics (and accompanying politics) make it exceedingly clear that safe is meaningless for anything beyond trivial, one-off tools that will never receive maintenance.You are correct in how trusted is currently (mis)used in Phobos. We aim to fix this. trusted must provide a safe interface. No exceptions. Yes, that requires review of trusted code by someone who thoroughly understands this, but there's no other way.
Feb 06 2015
"Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang gmail.com> wrote:On Friday, 6 February 2015 at 13:28:59 UTC, Steven Schveighoffer wrote:I'd go even further: The compiler could even make optimizations in safe code based on the assumption that all trusted function calls expose a safe interface. I suspect this will lead to undefined behavior and very subtle bugs.The bottom line of my reasoning is that code changes over time, > by different people. Context is forgotten. It's much better to > have the compiler verify you know what you are doing when > working with trusted than it is to just allow anyone to inject > code anywhere.Actually, I think this argument goes against what you are arguing for. Anything within a trusted section has a big warning sign attached to it that says "cannot modify this without detailed review". But the compiler cannot verify that a safe function with local trusted blocks are actually safe, so it only buys you a false sense of security.
Feb 06 2015
On 2/6/2015 5:28 AM, Steven Schveighoffer wrote:It's better because I know where it is used. It's used in one place, and I can squash it right there saying "No, you can't do this in this one place." Instead of reviewing an API in ALL POSSBILE CONTEXTS (which if trustedCast is a public API, would be a lot), I have to review one call in ONE CONTEXT. The former is WORSE because it can be used in 100 places. Now I have to go through and fix ALL THOSE FUNCTIONS that use it, because its interface was exposed to the whole of phobos.This is the crux of the problem - failing to define a safe interface to the trusted code block. Without defining an interface, you're right, you must review all the context(s) that call it. With a safe interface you DO NOT. You only have to review the interface. A simple rule: "If you need to do a safety review on the context in which trusted code is called YOU ARE DOING IT WRONG because you've failed to provide a safe interface to the trusted code." It's like solving a physics problem and winding up with negative energy. If that happens, you made a mistake. It is not a matter of judgement or opinion, it is an objective fact. Going forward, all trusted code that leaks unsafety into its context will be rejected for inclusion in Phobos. The code reviewer only has to review the trusted block to determine this - he does not have to review the context.
Feb 06 2015
FWIW, and now that I think I understand how trusted is supposed to be used, the arguments are valid. But I also: 1. Agree with H S Teoh on the maintainability aspect. Depending on humans reviewing the code is never going to work out. And even if it did, subsequent edits might break everything. It's a lot harder to review a 2-line diff to an existing function for trustworthiness than the original one when it was first written. I've lost count of how many code reviews I've approved at work that introduced subtle crashy bugs. And let's face it, reviewing a trusted D function is no different from reviewing C code. 2. Agree with Dicebot that reviewing a 50-line function and making sure it isn't naughty is quite hard. Not impossible, but hard to guarantee its safety. Unfortunately, I have no suggestions on how to make it better. The " safe block/local function in a trusted function" idea sounds promising, but I don't know how well it'd work out in practice. Atila On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:Consider the following code excerpted from std.array.join: static U trustedCast(U, V)(V v) trusted { return cast(U) v; } return trustedCast!RetType(result); This is because the compiler would complain that the following line would not be safe: return cast(RetType)(result); The rationale is "I know it's safe, so I'll create an trusted wrapper to eliminate the error." What comes next is "that's cumbersome. How about a better syntax:" trusted { return cast(RetType)(result); } ? It's the rationale behind "unsafe" blocks that appear in other languages. It seems like a perfectly reasonable request. The trouble with it is, what if the cast is converting from an integer to a pointer? That could lead to memory corruption. The code allows a potentially memory corrupting operation to be inserted into code that is otherwise safe. The only way to deal with it is to then manually review everything about 'RetType' and 'result' to prove to oneself that it is not converting random bit patterns into pointers. In other words, one is manually reviewing safe code for memory corruption errors. This is an abject failure of safe, trusted, and system. The solution is to regard trusted as a means of encapsulating unsafe operations, not escaping them. Encapsulating them means that the interface from the trusted code is such that it is usable from safe code without having to manually review the safe code for memory safety. For example (also from std.array): static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); } I don't have to review callers of trustedMemory() because it encapsulates an unsafe operation (memcpy) with a safe interface. The reason trusted applies only to functions, and not to blocks of code, is that functions are the construct in D that provides an interface. Arbitrary blocks of code do not have a structured interface. Adding trusted { code } support will encourage incorrect uses like the opening example. The existence of trusted blocks will require review of every line of code in the function that encloses it, and transitively every function that calls it! Adding trusted as a function attribute, on the other hand, only requires review of the function's interface to determine if it is acceptable to use in safe code. Safety review of its callers is unnecessary.
Feb 06 2015
On Friday, 6 February 2015 at 14:00:24 UTC, Atila Neves wrote:1. Agree with H S Teoh on the maintainability aspect. Depending on humans reviewing the code is never going to work out.Of course it can work out. You need a formalized process and a group of people with training in math or comp.sci to do the review. Proving memory safety for a single function in a semi-formal manner is not like proving full correctness. I suggest the following: 1. trusted should only be used on high priority code (not to gain minor speed ups) 2. trusted code should always carry the safety-proof as embedded comments 3. trusted templates should carry the most stringent type constraints (and proof required to weaken them) 4. At least 3 reviewers with knowledge of compsci/math MUST verify the soundness of the proof. 5. Have a list of volunteers that are called in by email to review trusted code. If only 2% is trusted then this should work out fine. The alternative is to give up safe completely or completely change the typesystem.
Feb 06 2015
6. trusted code should be self contained so that changes in called functions don't break the proof...
Feb 06 2015
On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:The solution is to regard trusted as a means of encapsulating unsafe operations, not escaping them. Encapsulating them means that the interface from the trusted code is such that it is usable from safe code without having to manually review the safe code for memory safety. For example (also from std.array): static void trustedMemcopy(T[] dest, T[] src) trusted { assert(src.length == dest.length); memcpy(dest.ptr, src.ptr, src.length * T.sizeof); } I don't have to review callers of trustedMemory() because it encapsulates an unsafe operation (memcpy) with a safe interface.If I understand correctly, your rule o be a trusted function is: "Unable to create a memory corrutpion whatever the arguments". But here: - dest or src could be the null slice - the assert would go away in release So I though this example _could_ corrupt memory?The reason trusted applies only to functions, and not to blocks of code, is that functions are the construct in D that provides an interface. Arbitrary blocks of code do not have a structured interface. Adding trusted { code } support will encourage incorrect uses like the opening example. The existence of trusted blocks will require review of every line of code in the function that encloses it, and transitively every function that calls it! Adding trusted as a function attribute, on the other hand, only requires review of the function's interface to determine if it is acceptable to use in safe code. Safety review of its callers is unnecessary.
Feb 07 2015
On Saturday, 7 February 2015 at 10:02:23 UTC, ponce wrote:If I understand correctly, your rule o be a trusted function is: "Unable to create a memory corrutpion whatever the arguments". But here: - dest or src could be the null slice - the assert would go away in release So I though this example _could_ corrupt memory?I see know it was already addressed: http://forum.dlang.org/post/mb1vmt$etn$1 digitalmars.com
Feb 07 2015