News for hackers. Stuff that matters.
Re:Getting Past C by staticassertion on Tuesday January 03, 2017 @04:59PM (#13313521)
Because your 'safe' implementation will certainly have a performance cost, and won't be the default. This is why, despite C++ providing std::array, you'll still find buffer overflows in C++ code. C++'s std::array provides the safe 'at' function but you're opting into a performance penalty and it's not the more familiar [] syntax.

Rust arrays/ vectors are safe-by-default. To use the unchecked, unsafe version requires using the 'unsafe' keyword.

let v = vec![0, 1, 2]; unsafe { let x = v.get_unchecked(5); }

This means you can basically grep audit for vulnerabilities, and the above code should be very rare.

Re:Getting Past C by jdmichal on Tuesday January 03, 2017 @05:03PM (#13313559)
In addition, the Rust compiler can also remove the built-in indexing checks if it can prove the code is safe. So, say, iterator loops over an array won't have any index checking.
Re:Getting Past C by dbaupp on Tuesday January 03, 2017 @05:31PM (#13313811)
As others have said, this is a fairly standard optimisation: compilers (Rust, C, C++, Java, PHP, whatever) will remove branches if they can see that it can never be taken. Iterators are slightly different in that they don't have any indexing checks at all: an array iterator yields a plain reference, and these are always dereferenced like plain pointers.
Re:Getting Past C by Veedrac on Tuesday January 03, 2017 @06:27PM (#13314275)
Iterator loops are different. They don't elide bounds checks automatically, like frequently claimed. Instead they merge it with the loop branch, so there's no redundant checking.
Re:Getting Past C by ori_b on Tuesday January 03, 2017 @08:51PM (#13315039)
So can the C compiler. The optimization is called 'value range propagation'.
Re:Getting Past C by staticassertion on Tuesday January 03, 2017 @05:08PM (#13313595)
C/ C++ compilers are also capable of doing this, though rust's iterator syntax tends to make it a pretty natural optimization.
Re:Getting Past C by Animats on Tuesday January 03, 2017 @07:31PM (#13314635)
Neither C nor C++ knows, at the language level, the size of an array, unless that size is fixed. The subscript checking variants of C and C++ have to use "fat pointers" which carry along size information. The overhead for this is large and nobody uses that. Fat pointers used to be a feature you could turn on in gcc, but it's somewhat abandoned now.
Re:Getting Past C by sirclueless on Tuesday January 03, 2017 @09:19PM (#13315156)
> Neither C nor C++ knows, at the language level, the size of an array, unless that size is fixed.

Neither does Rust.

> The subscript checking variants of C and C++ have to use "fat pointers" which carry along size information.

So do Rust's Slices.

> The overhead for this is large and nobody uses that.

People use std::vector all the time for this purpose in C++. It has about the performance you'd expect, with very little overhead except where you want it in bounds-checking.

I don't think there's actually a performance difference here. Rust's default is safer because it requires dropping to unsafe code to do something dangerous, but the same optimizations are available in both.

Re:Getting Past C by steveklabnik on Tuesday January 03, 2017 @10:02PM (#13315327)
One thing that I've heard might be a difference, but haven't confirmed yet: Rust's lack of move constructors. So you have a vector, it's full, you push one more. It has to reallocate. How do you copy all of the elements over to the new allocation? In Rust, it's a straight memcpy of T * n bytes. But due to move constructors in C++, IIRC they must be moved one at a time.

Again, I haven't actually dug into this; maybe someone more knowledgeable about this can point me in the right direction here?

Re:Getting Past C by Manishearth on Tuesday January 03, 2017 @10:33PM (#13315456)
This is correct. I suppose if you could get folks to mark all memcpy move ctors explicitly with a macro instead of relying on the default you could specialize std::vector's move with sfinae. Bit hacky. It already specializes for pod types though.

Lack of move and copy ctors in rust greatly simplifies things like this, and makes it very explicit when code is running, but the trade-off is that intrusive data structures are hard to do on the stack in rust.

Re:Getting Past C by rustmemcpy on Tuesday January 03, 2017 @11:38PM (#13315719)
How would a self-referential object work in Rust in that case? The move or copy constructor could not be a simple memcpy.

The self-reference would point to the old object. See this for an example: http://ideone.com/sEFtbN

Re:Getting Past C by Manishearth on Wednesday January 04, 2017 @12:22AM (#13315872)
https://github.com/Kimundi/owning-ref-rs exists, but basically you just don't do intrusive datastructures on the stack in rust.

(Intrusive datastructures on the heap are doable with some tricks.)

They're not very essential so it works out.

Re:Getting Past C by sirclueless on Tuesday January 03, 2017 @11:55PM (#13315786)
See steveklabnik's detailed answers elsewhere in this thread, but the short answer is that you can't write this data type in Rust.
Re:Getting Past C by sirclueless on Tuesday January 03, 2017 @10:31PM (#13315448)
Well, for trivially copyable types[1] the reallocation can be a straight memcpy. For the rest, I don't know that having or not having a move constructor is the important distinction; it will be preferred over the copy constructor if it is declared as not throwing exceptions, but either way some constructor of the object must be called if it exists (though it might be inlined and optimized away).

I imagine Rust does something similar, copying bytes if the underlying type has the `Copy` trait and calling some actual code if not, but I'm not familiar with the details.

[1]: http://en.cppreference.com/w/cpp/concept/TriviallyCopyable

Re:Getting Past C by Manishearth on Tuesday January 03, 2017 @10:38PM (#13315471)
No, all moves in rust are memcpy if not optimized out entirely. Rust has affine types so moves don't need to "invalidate" the source value at runtime, the compiler just doesn't allow you to use the source variable after a move.

Rust's answer to copy ctors is Clone, which is always explicitly called. Variable use in rust is a move. Trivially copyable types (Copy) will be copied without compile-time invalidating the old type.

Re:Getting Past C by steveklabnik on Tuesday January 03, 2017 @10:33PM (#13315457)
Thanks for elaborating on this!

> copying bytes if the underlying type has the `Copy` trait and calling some actual code if not,

It does not. Moves and copies are both "memcopy these bytes", the only difference is if you can use the previous copy or not. (This is also, of course, subject to the optimizer, which may elide the copy.)

> either way some constructor of the object must be called if it exists (though it might be inlined and optimized away).

Yeah, this is what I was getting at; this has to happen in C++, but not in Rust. You are right to point out that this only matters for things that aren't trivially copyable.

Re:Getting Past C by sirclueless on Tuesday January 03, 2017 @10:45PM (#13315508)
Interesting. How does Rust handle types that want to do interesting things when copied, like bookkeeping or updating internal pointers? Maybe you just can't, which would preclude some kinds of intrusive data structures, or owning non-copyable mutexes for example. Does `drop()` get called on objects that have been copied from?
Re:Getting Past C by steveklabnik on Tuesday January 03, 2017 @10:53PM (#13315532)
You pretty much just can't; that's what Manish was referencing above about this kind of thing being awkward.

It would be cool to have those things, but it also means that there's less "magic" stuff going on, which is nice. And it makes the semantics of stuff like this a lot simpler.

> Does `drop()` get called on objects that have been copied from?

Nope. In fact, Copy types can't have a Drop at all, but types that move don't have their Drop impl called when they move.

Re:Getting Past C by sirclueless on Tuesday January 03, 2017 @11:09PM (#13315613)
Thanks for all the responses, I'm learning a lot. This explains to me why iterators and other references to the internals of a data type have to take ownership of the whole data type, which is something I ran into several times during my (brief) explorations with Rust.
Re:Getting Past C by steveklabnik on Tuesday January 03, 2017 @11:22PM (#13315662)
Totally. There's one other interesting subtlety you might find interesting here, and that's self-referenceing structs. So for example,

struct Foo { s1: String, s2: &str, }

where s2 is always intended to point at s1's backing storage. What's unfortunate here is that Rust will disallow this, as it doesn't understand that s2 is pointing to some data on the heap, with a stable address, not the parts of the String struct in s1 that are part of the struct itself. So what this means is, in plain Rust, this type isn't movable, Rust is concerned about the invalidation.

However, you can get around this restriction with some unsafe code to teach Rust about it; this is the premise of the "owning-ref" crate.

Re:Getting Past C by Manishearth on Wednesday January 04, 2017 @12:20AM (#13315867)
> have to take ownership of the whole data type,

This isn't the case. They only need to borrow it. A borrowed value isn't allowed to move (the borrow itself can be copied around and shared within the scope of the borrow), so that works out.

Most Rust iterators only borrow the container or iterator they operate on. It's only explicitly moving iterators like .into_iter() (which extracts elements by-move) that don't.

Re:Getting Past C by jdcarter on Tuesday January 03, 2017 @05:23PM (#13313738)
Go also does this as of version 1.7:

http://www.tapirgames.com/blog/golang-1.7-bce

Re:Getting Past C by pjmlp on Tuesday January 03, 2017 @06:13PM (#13314171)
Compilers for Pascal dialects, Ada and Modula-2 were already doing that in the early 90's.
Re:Getting Past C by sbov on Tuesday January 03, 2017 @05:39PM (#13313870)
This is everyone's favorite excuse to trot out. But in reality the vast majority of projects I've seen never actually measure WHAT the performance cost would be and whether or not it's acceptable. So in the usual case the answer tends to be a mix of laziness and "that's how it's always been done."
Re:Getting Past C by sidlls on Tuesday January 03, 2017 @05:25PM (#13313757)
How do you suppose runtime bounds checks are done in Rust? They certainly also incur a performance penalty in not-trivial cases.

Also, "safe by grep audit" means "safe according to a human." The argument of course is that it lowers the surface area of what a human must be trusted to verify. I'm still not convinced by that argument, because human error is a thing. And for actual systems programming, "very rare" may not be true.

Re:Getting Past C by staticassertion on Tuesday January 03, 2017 @05:40PM (#13313878)
> How do you suppose runtime bounds checks are done in Rust? They certainly also incur a performance penalty in not-trivial cases.

Certainly. I didn't intend to imply otherwise.

> Also, "safe by grep audit" means "safe according to a human."

Again, totally correct here.

> The argument of course is that it lowers the surface area of what a human must be trusted to verify. I'm still not convinced by that argument, because human error is a thing. And for actual systems programming, "very rare" may not be true.

Well, given a codebase where both safe and unsafe code exists, the amount of unsafe code is strictly less than the amount of both safe and unsafe code. So it does reduce the amount of code needed to audit, even in a very atypical case where a ton of the code is unsafe.

It's true that a project may use egregious amounts of unsafe. That would be unfortunate. Rust is still safer than C in that case, since it just defines more behavior (like arithmetic overflow), but I certainly wouldn't pretend that the rust code should be trusted.

When writing rust one should certainly strive to write less unsafe code, and to always document the invariants required for unsafe code to be safe.

Rust is not 100% safe 100% of the time, I'm only arguing that safe defaults are critical, and that grep auditing is a powerful tool.

Re:Getting Past C by alexkehayias on Wednesday January 04, 2017 @12:24AM (#13315877)
I wrote a little tool to help check Rust crates on GitHub. It's been really interesting seeing how different libs use unsafety. https://github.com/alexkehayias/harbor
Re:Getting Past C by EugeneOZ on Tuesday January 03, 2017 @06:14PM (#13314187)
Rust is safe in terms of memory usage and race conditions, nobody claims that Rust compiler will catch all 100% of bugs human can invent.
Re:Getting Past C by sidlls on Tuesday January 03, 2017 @06:21PM (#13314238)
Rust is safe by default in terms of memory usage. It is not, however, strictly memory safe. It is trivial to overflow a buffer in Rust, for example. I haven't discovered a trivial way to hide it, though.
Re:Getting Past C by steveklabnik on Tuesday January 03, 2017 @06:23PM (#13314245)
If Rust is not memory safe in safe code, then you've found a bug. Please report it to https://www.rust-lang.org/security.html
Re:Getting Past C by derefr on Tuesday January 03, 2017 @06:44PM (#13314390)
If you're relying on any random third-party Rust crates you haven't audited yourself, don't you lose the safety guarantee? A given crate might turn out to have implemented operations on some data-structure using unsafe blocks, and then to have failed to mark its own API functions as unsafe in turn (like the Rust stdlib does, but without the "extensive manual auditing" that the stdlib gets).

AFAIK, cargo doesn't have any feature to point out when a crate contains unsafe code—so you pretty much need to grep the source of every crate you consume for "unsafe".

Re:Getting Past C by Animats on Tuesday January 03, 2017 @07:33PM (#13314647)
There's a lot more unsafe code in Rust crates than there should be. That's a fixable problem. Some stuff from the early days predates the optimizer getting smart enough that unsafe code isn't needed. I wrote on this a few days ago in a Rust topic.
Re:Getting Past C by Manishearth on Tuesday January 03, 2017 @09:02PM (#13315082)
While I now mostly agree with you that there is more unsafe code than there should be, I still maintain that the frequency of unsafe in a deptree is usually still small enough to be practically auditable, ignoring FFI. It could/should be much less, but it's not too bad. I've done such audits a few times and it's not been too hard and taken very little time.

Auditing FFI is a whole other challenge, however :(

Re:Getting Past C by pjmlp on Wednesday January 04, 2017 @03:04AM (#13316532)
> I still maintain that the frequency of unsafe in a deptree is usually still small enough to be practically auditable

Not in binary libraries, hence why it is important to have a culture to only use unsafe if it really must be used.

Re:Getting Past C by Manishearth on Wednesday January 04, 2017 @03:24PM (#13321735)
Well, yeah, but you don't really download Rust binary libraries yet :)

You do have C libraries which you access through FFI. This is inevitably unsafe. We should be auditing more there. Though IMO it's still manageable, for most crates.

Re:Getting Past C by staticassertion on Tuesday January 03, 2017 @09:51PM (#13315289)
Hmmmm. Note to self - actually try to audit a reasonably sized project's unsafe code to see how reasonable it is.
Re:Getting Past C by steveklabnik on Tuesday January 03, 2017 @06:49PM (#13314419)
That's why I said "safe code," I mean, not using any unsafe.

The issue you're talking about is related, but different.

Re:Getting Past C by derefr on Tuesday January 03, 2017 @07:07PM (#13314507)
Right, I was just trying to put a finer point on your use of "using any unsafe" here. It sounds like you mean "using" in the lexical sense (writing the token "unsafe" in your code), but you mean it in the dynamic sense (having an unsafe block in your control flow graph.)
Re:Getting Past C by steveklabnik on Tuesday January 03, 2017 @08:39PM (#13314991)
That's a good distinction to draw, thanks.
Re:Getting Past C by sidlls on Tuesday January 03, 2017 @06:37PM (#13314352)
Let me clarify: in Rust it is trivial to use memory unsafely. It is not, so far as I have found, trivial to hide that fact because it is required to use "unsafe" syntax decoration" to do so.
Re:Getting Past C by Manishearth on Tuesday January 03, 2017 @06:45PM (#13314396)
The issue here is that that definition of "safe" language basically excludes all practical languages, including languages like Python, because FFI is possible.

In general when talking about safety in a language it's about the level of explicitness required to trigger unsafety.

I like the distinction made in the nomicon (https://doc.rust-lang.org/stable/nomicon/meet-safe-and-unsaf...) -- Rust comprises of two distinct languages. You have everyday Rust, which is completely memory safe, and "unsafe Rust", which looks similar to everyday Rust but is not safe. `unsafe {}` blocks are your FFI between the two. Looking at unsafe blocks as FFI is IMO a very useful mental model especially for understanding the changes to invariants involved.

Re:Getting Past C by staticassertion on Tuesday January 03, 2017 @06:35PM (#13314338)
In safe rust it is definitely not trivial to overflow a buffer in a way that violates memory safety.
Re:Getting Past C by rtpg on Tuesday January 03, 2017 @09:22PM (#13315171)
"Actual systems programming" mostly does not involve unsafe code.

For example, most OS code is _not_ interrupt hooks or malloc but the rest of the OS. Most of Postgres is not reading data quickly, but higher-level abstractions.

Large-scale systems programming will always be mostly higher-level abstractions, because that's the only way to write large programs. Name any "systems programming" OSS project, choose a random C file, and you'll see that most code does not require pointer arithmetic except because that's how you do things in C.

You don't bit-twiddle for 200k lines of code, so being able to limit dangerous stuff like that to the 5k lines that actually need it makes work an order of magnitude easier.

Re:Getting Past C by anarazel on Wednesday January 04, 2017 @06:29AM (#13317334)
> "Actual systems programming" mostly does not involve unsafe code.

True. Or slightly rephrased: Most of the unsafe code is centralized to some core pieces.

From the POV of a PG dev: The big problem using something like rust for something like PostgreSQL is its it's portability, stability and uncertainty about where things are going. We do five years of back-branch releases (and for many that's not even enough!). Language and tooling around the new crop of languages simply aren't mature enough for that yet.

Re:Getting Past C by mistaken on Tuesday January 03, 2017 @05:49PM (#13313965)
To be fair the [] syntax is an overridable operator and you could just point it to use the "at" method. Not sure why they've implemented it as an usafe function.
Re:Getting Past C by loup-vaillant on Tuesday January 03, 2017 @05:53PM (#13314000)
With C++, the default is zero overhead, not safety.
Re:Getting Past C by temac on Tuesday January 03, 2017 @07:30PM (#13314628)
If people start to consider bound checking branches as overhead (which, in some extremely rare limited cases, they are in the right to do so), they should as well understand what happen with e.g. some largely used calling convention such as the one of Windows. Even in optimised builds, a unique_ptr<> for example can have an overhead compared to a raw pointer, IIRC because it forces going through the stack. If I remember my typical latencies correctly, for modern Intel CPU and probably a lot of high perf CPU, that can actually in some cases have a greater impact than an extra bound check...

So if you are in a so performance critical section that you start to care about the "zero overhead" kind of stuff and the cost of your (predicted) bound checks, you might be impacted by this non-zero overhead... (that is falsely widely believed to be zero!)

And don't get me started about debug builds with all mainstream compilers. The performance is then complete utter shit. This is made worse by the fact such an unsafe language needs debug builds more...

C++ was an interesting experiment in its domain, and has been and still is a success in some aspects, but honestly given core language modifications are needed to significantly extend the behaviour of core types (like vectors, unique_ptr, strings, etc. -- e.g. with the introduction of rvalue references and all the associated machinery and default constructors and so over), I'm starting to believe there are little advantages of this approach over integrating such fundamental types/concepts in the core language (I'm not advocating to do that for C++, I'm thinking about other/future languages). Then you can have more true "zero overhead" stuffs, whatever that means.

Re:Getting Past C by loup-vaillant on Wednesday January 04, 2017 @05:43AM (#13317117)
> if you are in a so performance critical section that you start to care about the "zero overhead" kind of stuff

If I don't have this kind of performance needs, I have no reason to use C++ to begin with. I mean, why use such a monster if I don't need the crazy performance it may offer when used properly? And even then, C, D, or Rust may be viable alternatives.

Re:Getting Past C by Veedrac on Tuesday January 03, 2017 @09:56PM (#13315308)
If a call is statically dispatched, calling convention doesn't matter because static dispatch gets inlined away in hot functions. If a call is dynamically dispatched, you have much bigger things to worry about. Bounds checking is a much bigger problem for hot code.
Re:Getting Past C by pjmlp on Tuesday January 03, 2017 @06:19PM (#13314225)
Not 100% true when using the standard library and compilers like VC++, which do provide such checks in debug builds, while allowing to selectively turn them on, on release builds.
Re:Getting Past C by pjmlp on Tuesday January 03, 2017 @06:17PM (#13314216)
It is, if you are using VC++ debug builds or define the macro for secure STL.

The idea of ANSI C++ was to provide safety behind library calls instead of compiler switches.

Re:Getting Past C by lacampbell on Tuesday January 03, 2017 @05:13PM (#13313653)
Would you care to provide a short rust implementation of reading an arbitrary length string from standard input?

I have rust installed. I would be curious to benchmark it and see if is indeed faster than the same thing in C, using a user-defined bounds checked array.

Re:Getting Past C by steveklabnik on Tuesday January 03, 2017 @05:33PM (#13313828)
I'm not going to make any performance claims, but in the interest of sample code, https://doc.rust-lang.org/stable/std/io/struct.Stdin.html#me... has a very small program that does this in the most straightforward way. (You'll have to wrap it in `fn main()`, we don't show that in examples in the docs)

If you want a true speed comparison, you'd have to define more than just "read an arbitrary string". For example, encoding requirements. Your C is going to treat it as just a bag of bytes, and you can do that in Rust too, but it's not the most natural way; you'd convert to UTF-8, which isn't free. Stuff like that.

Re:Getting Past C by rnestler on Tuesday January 03, 2017 @05:35PM (#13313844)
Did you mean something like this?

    use std::io::{self, Read};
    fn main() {
        let stdin = io::stdin();
        let mut data = vec![];
        stdin.lock().read_to_end(&mut data)
            .expect("Reading stdin failed");
    }
Re:Getting Past C by dbaupp on Tuesday January 03, 2017 @05:49PM (#13313970)
(FWIW, You could golf that to io::stdin().read_to_end(...), because the Read implementation for Stdin does the same locking internally: https://github.com/rust-lang/rust/blob/8f62c2920077eb5cb8132... .)
Re:Getting Past C by _sh on Tuesday January 03, 2017 @05:31PM (#13313810)
It's not so much a question of benchmarks, it's that one of the standard C tools for reading an arbitrary string from standard input is gets(). And if you reach for that from the standard toolbox, you've failed before you've started.
Re:Getting Past C by caf on Tuesday January 03, 2017 @09:57PM (#13315310)
gets() isn't part of the C standard anymore (it was entirely removed in C11, and prior to that was marked "obsolescent and deprecated" 18 years ago in C99).
Re:Getting Past C by lacampbell on Tuesday January 03, 2017 @05:34PM (#13313831)
Many rust advocates talk about the performance cost of doing things safely in C, and inform me that rust has "Zero-cost abstractions". So it's fairly natural I ask for something I can benchmark.
Re:Getting Past C by caconym_ on Tuesday January 03, 2017 @08:55PM (#13315051)
> Many rust advocates talk about the performance cost of doing things safely in C

Who's saying this? It doesn't really make sense, taken out of context as it is here.

> inform me that rust has "Zero-cost abstractions"

IMO at best the array bounds checking thing is an extremely poor example of a "zero-cost abstraction"; at worst it's not an example of it at all. As I understand it, the term refers to things like static dispatch on closures and trait methods, iterator fusion, and generally any place where the compiler can transform high level abstractions into really efficient low-level code where in other languages/implementations you might incur a performance penalty, for instance by dynamic dispatch to heap-allocated closures, or allocation of an intermediate vector at every "link" in an iterator method chain.

Re:Getting Past C by tjr on Tuesday January 03, 2017 @05:39PM (#13313873)
Having used C (on and off) for about twenty years, including writing aerospace software in C, I strongly agree that writing safe C is possible.

Rust (which I have thus far only tinkered with) looks pretty appealing to me, though. Do you suggest using C instead of Rust? If so, why?

Re:Getting Past C by dreta on Wednesday January 04, 2017 @05:54AM (#13317164)
If Rust solves the kinds of problems you have, then by all means use it. I don't think there exists a language that's in all aspects better than any other. For me personally, C is the language that gets in my way the least without forcing me to write ASM, and that happens to be highest on my list. If there was a language with the same idea of minimalism behind it as C, but with all the quirks and bad syntax choices out, i'd switch in a heartbeat.
Re:Getting Past C by lacampbell on Tuesday January 03, 2017 @05:47PM (#13313952)
Rust (which I have thus far only tinkered with) looks pretty appealing to me, though. Do you suggest using C instead of Rust? If so, why?

I'd probably suggest a higher level language if you can get away with it (portability, performance, etc), but I am not really advocating for using one language over another here.. What I am advocating is writing a thin layer of abstraction to avoid buffer overflows in the already extant code base. I suspect it would be a better choice in terms of cost/benefit than re-writing the code.

Re:Getting Past C by staticassertion on Tuesday January 03, 2017 @05:17PM (#13313687)
I didn't claim that rust would be faster than C (not that it can't be) in that situation. I would expect very similar performance.

I'm not feeling very well unfortunately, not really in the mood to code.

Re:Getting Past C by lacampbell on Tuesday January 03, 2017 @05:30PM (#13313807)
I just keep hearing about how rust handles safe bounds checked arrays with (and I quote) "Zero-cost abstractions", which to me implied it would be faster than C, since C pays some performance penalty by branching.

Hope you feel better soon.

Re:Getting Past C by wmf on Tuesday January 03, 2017 @05:35PM (#13313842)
"Zero-cost abstraction" really means zero additional cost beyond what is required. So Rust still pays a cost for bounds checking, but it's the same cost as if you optimally hand-coded the bounds check in C.
Re:Getting Past C by pekk on Tuesday January 03, 2017 @11:28PM (#13315681)
Adding the cost of bounds checking is not actually "zero cost" relative to a C default of not bounds checking. There's really no reason to speak in this misleading way except marketing.

Of course, bounds checking is worth paying a cost! As are many other common foot-guns like remembering to free memory. Which starts to raise the issue of when it would actually be necessary to reach for Rust instead of (arbitrary example) Java. Because a language with enforced bounds checking is not really the same kind of thing as C, and we've already had languages that are safer than C for decades.

Re:Getting Past C by Manishearth on Tuesday January 03, 2017 @06:23PM (#13314246)
"Zero cost abstraction" means that the abstraction doesn't impose an additional cost. It is the same cost of branching that C will have, modulo optimizations.

(Languages with dependent types can help move bounds checks to compile time, but Rust does not have those)

Re:Getting Past C by staticassertion on Tuesday January 03, 2017 @05:35PM (#13313847)
Ah, I see. For what it's worth C will perform similar optimizations to Rust, which is why I expect similar performance. And thank you.
Re:Getting Past C by EugeneOZ on Tuesday January 03, 2017 @06:12PM (#13314164)
No, Rust arrays are not safe by default: https://is.gd/iY5lPQ
Re:Getting Past C by staticassertion on Tuesday January 03, 2017 @06:36PM (#13314347)
Panics do not violate memory safety. In C that code would be undefined behavior.
Re:Getting Past C by EugeneOZ on Tuesday January 03, 2017 @07:26PM (#13314601)
You are right, my mistake. I just can't call code failing in runtime "safe" (because I can't rely on it). But in terms of memory safety it's safe.
Re:Getting Past C by moosingin3space on Tuesday January 03, 2017 @07:30PM (#13314625)
Then use the get() function on an array/slice. It returns an Option so it won't perform an access off the end of the array, and you can catch it.
Re:Getting Past C by EugeneOZ on Tuesday January 03, 2017 @07:35PM (#13314657)
thanks, I do. Only thing left is explain it to everybody else to avoid panicking in 3-party crates. I really hate when people use panicking just because it's easier than error handling. So it was "surprise" to see such behavior from "[x]" construction.
Re:Getting Past C by cesarb on Wednesday January 04, 2017 @06:44AM (#13317435)
Like in C, you are not supposed to pass out-of-bounds indexes to the [] operator. If anyone does so, it's a bug. Rust converts it to a panic, which safely terminates the thread/program, instead of C's undefined behavior.

You can also catch this panic at the thread boundary, so other threads in your program can keep running, unless the program was compiled to call abort() on panic.

Re:Getting Past C by EugeneOZ on Wednesday January 04, 2017 @06:54AM (#13317493)
You still think in C limits of possibilities. Rust could just return Option as a result for [x] syntax.
Re:Getting Past C by cesarb on Wednesday January 04, 2017 @07:21AM (#13317638)
And then people would simply call .unwrap() on the return of the [] operator, leading to the same situation. It's extremely common for an array dereference to always be within the bounds, by code construction (I'm iterating over the indexes of the array, or I have an index into the array saved inside some other structure, and so on). The programmer knows it will never be out of bounds. The assert!() within the [] operator is only to protect you when the programmer gets it wrong, and in a correctly written program, will never trigger.

(The alternative instead of .unwrap() would be to propagate the error, polluting the whole program with code to handle errors which never will happen. And since they will never happen, many programmers would simply start ignoring them - and in the process, they would by accident end up ignoring errors that can happen. Not a good situation.)

Re:Getting Past C by EugeneOZ on Wednesday January 04, 2017 @08:39AM (#13318121)
There is HUGE difference between "unwrap" (which can found by grep) and mutual dangerous behavior. Programmer can only assume, not know, without additional checks. "Polluting with error" is much better than panicking.
Re:Getting Past C by EugeneOZ on Wednesday January 04, 2017 @02:03PM (#13321075)
And for safe iterations Rust has "for .. in".
Re:Getting Past C by steveklabnik on Tuesday January 03, 2017 @06:16PM (#13314203)
Panics are definitely safe. They are significantly different than the segfault you'd get out of the C code.
Re:Getting Past C by EugeneOZ on Tuesday January 03, 2017 @07:29PM (#13314617)
Besides of memory safety, what is different in panicking? I'm not trying to argue - I don't know it. For me result is the same - process failed. What is difference in consequences for memory?
Re:Getting Past C by gue5t on Tuesday January 03, 2017 @07:59PM (#13314794)
Not all violations of memory safety result in immediate program termination. There's an intervening period of execution during which your program simply performs unintended operations such as overwriting unrelated memory (which could be a memory-mapped file), terminating "correctly" (and performing whatever operations that entails) with corrupt state, and generally an unbounded set of other potential consequences. An immediate segfault is the absolute best hope for a program without memory safety, since you both see no unintended effects performed on the program's behalf and you learn that your program needs fixing.
Re:Getting Past C by EugeneOZ on Tuesday January 03, 2017 @08:11PM (#13314858)
Got it, thank you.
Re:Getting Past C by gpderetta on Tuesday January 03, 2017 @08:25PM (#13314918)
Panic behaviour is well defined. Segfaults are non-reliable (i.e. it might or might not crash) and often exploitable.
Re:Getting Past C by ue_ on Wednesday January 04, 2017 @07:07AM (#13317560)
There are tools you can use with C compilers that don't access OOB memory on OOB access. What's your point?

I think I'd rather not have it panic at all. They were making a language from scratch and still didn't solve the crash-at-runtime problem that C has. Instead they just made a common C compiler option default and called it 'safe'.

It's worse than the fact that the Go creators ignored years of research after the year 1970 and didn't implement generics, for no good reason.

Rust's safety is a joke, and so is the idea that a lot of it is anything 'new'. They had the chance to fix it and they didn't. Boo.

Re:Getting Past C by the_why_of_y on Wednesday January 04, 2017 @05:41PM (#13322801)
Which common C compiler has a production quality implementation of array bounds checking?

Before you say Address Sanitizer you should be aware that its authors intended it as a debugging tool and recommend against using it in production as it introduces new attack surface, as described in the "Address Sanitizer local root" mail.

http://seclists.org/oss-sec/2016/q1/363

Re:Getting Past C by steveklabnik on Wednesday January 04, 2017 @11:20AM (#13319513)
> What's your point?

My point is that panics are memory safe, contrary to what my parent said.

Re:Getting Past C by outworlder on Tuesday January 03, 2017 @07:09PM (#13314517)
I get: thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4'

Looks pretty safe to me.

Re:Getting Past C by ue_ on Wednesday January 04, 2017 @07:15AM (#13317604)
How is such a crash remotely safe, for example, in an aviation system? Or a hospital's main computer?

A panic isn't safe, and if you are going to claim that it is, you can get the same safety in C using gcc and clang features.

Re:Getting Past C by dbaupp on Wednesday January 04, 2017 @11:40AM (#13319716)
Something crashing, so an error can be reported and a watchdog can restart it (etc.) is far better than just forging on with corrupt memory and wrong answers.

People do not use the sanitisers nearly as much as they should, and nor are they designed to be used in production. There's has been CVEs issued for them caused by the testing mindset in which they are written.

In any case, how much a programming language helps the programmer get a correct program (I.e. the most general form of safety) is a thing of degree, not all or nothing. Rust does a lot more than C, pushing many many errors to compile time, meaning they're fixed before the code even runs. Sanitisers only catch these when they actually happen, and will presumably result in the runtime crash you're so concerned about, if used in production. The fact that Rust isn't dependently typed and so can't catch OOB at compile time is unfortunate in this respect, but don't throw the baby out with the bath water.

Re:Getting Past C by cesarb on Wednesday January 04, 2017 @10:44AM (#13319154)
> A panic isn't safe, and if you are going to claim that it is, you can get the same safety in C using gcc and clang features.

There's one important difference. As far as I know, the bounds checking of gcc or clang can either print a warning and continue, or terminate the process.

A panic in Rust, however, will safely unwind the stack (similar to a C++ exception, in fact it's the same mechanism) and terminate only the thread. The rest of the program can continue running, and even start a new thread to replace the terminated one.

You can see this in action when running "cargo test". A panic in a test (the assert!() and assert_eq!() macros, often used in tests, do a panic in case of failure) will not terminate the whole process; the rest of the tests still run.

Re:Getting Past C by steveklabnik on Wednesday January 04, 2017 @11:22AM (#13319528)
(panics are for "non-recoverable" errors, and so don't _have_ to unwind the stack: you can abort on panic as well. The important difference is that you get well-defined behavior in all cases.)
Re:Getting Past C by macintux on Wednesday January 04, 2017 @11:22AM (#13319539)
This sounds like the "fail fast" philosophy in Erlang. Crashing is the standard behavior for any unexpected data, but the process model makes it straightforward to manage those crashes.