Live data from Hacker News

There is no memory safety without thread safety

ralfj.de

341–350 of 517 posts

Re: There is no memory safety without thread safety

#341

Earlier quoted context omitted.

Right, the issue here is that the "Rust and Java sense" of memory safety is not the actual meaning of the term. People talk as if "memory safety" was a PLT axiom. It's not; it's a software security term of art. This is just two groups of people talking past each other. It's not as if Go programmers are unaware of the distinction you're talking about. It's literally the premise of the language; it's the basis for "sha…

> But: everybody understands that. Everybody does not understand that otherwise there would be zero of these issues in shipping code. This is the problem with the C++ crowd hoping to save their language. Maybe they'll finally figure out some --disallow-all-ub-and-be-memory-safe-and-thread-safe flag but at the moment it's still insanely trivial to make a mistake and return a reference to some value on the stack or any…

This comment highlights a very important philosophical difference between the Rust community and the communities of other languages:

- in other languages, it’s understood that perhaps the language is vulnerable to certain errors and one should attempt to mitigate them. But more importantly, those errors are one class of bug and bugs can happen. Set up infra to detect and recover.

- in Rust the code must be safe, must be written in a certain way, must be proven correct to the largest extent possible at compile time.

This leads to the very serious, solemn attitude typical of Rust developers. But the reality is that most people just don’t care that much about a particular type of error as opposed to other errors.

Re: There is no memory safety without thread safety

#342
post #230

Earlier quoted context omitted.

Yeah, reading binary files in go with an mmap library and the whole file is based on offsets to point to other sections of the file. Damaged file or programming error and segfault.

How is that a data race? Also, you're using unsafe. The post is about data races in safe Go leading to crashes or exploits, because things like "eface" (the tuple used to implement interfaces) and slices (again a tuple) are multi-word and thus impossible to update atomically. This is not an issue in Java because such things always box behind a pointer.

Note that C#'s Memory (a slice) isn't boxed either, but it stays memory-safe under tearing: the resulting slice might have unintended bounds, but it will either be in-bounds or will throw an exception.

This of course has some overhead, which is why you usually turn it into the cheaper, data race free Span. Go could have the same safety and fix some of the overhead with compiler optimizations, they just don't want to take the trade-off.

Re: There is no memory safety without thread safety

#343
post #300

Earlier quoted context omitted.

> Rust's first release, and its version of "Memory Safety" was collecting quite a bit of attention Note that this was not Rust's first stable release, but it's first public release. At the time it was still changing a lot and still had "garbage collected" types.

Yeah, it was the 0.1 release. I can't remember exactly when Rust entered the general "programming language discourse" on hackernews and /r/programming, but it was somewhere around here. I'm sure the people behind Go would have known about it by this point in time. And while rust did have optional "garbage collected pointers", it's important to point out that it is not a garbage collected language. The ownership syste…

> Actually, my memory is that while the language had syntax to declare garbage collected pointers, it wasn't actually hooked up to a proper garbage collector. It was always more of a "we are reserving the syntax and we will hook it up when needed", and it turns out the ownership system was powerful enough that it was never needed.

AFAIK it was just an `Rc`/`Arc` with the possibility of upgrading it to an actual GC in the future.

Re: There is no memory safety without thread safety

#344
post #291

Earlier quoted context omitted.

The point is that a segfault is not an indication for memory unsafety. It is the opposite: The OS stops some unsafe access. The problem with C implementations is that it often comes to late and the segfault does not stop a prior unsafe read or write. But this is also an implementation property, you can implement C in a memory safe way as many have shown. Rust has, unfortunately, changed the narrative so that people n…

The segfault seen here is not a property of the language implementation, it's just a consequence of the address chosen by the attacker: 42. If you replicated this code in C you would get the same result, and if you used an address pointing to mapped memory in Go then the program would continue executing like in similar exploits in C. The only reason this isn't a more critical issue is because data races are hard to e…

Whether you can a segfault if you access an out-of-bounds address or not is part of the language implementation. An implementation that guarantees a segfault for out-of-bounds accesses is memory safe.

Re: There is no memory safety without thread safety

#345
post #341

Earlier quoted context omitted.

> But: everybody understands that. Everybody does not understand that otherwise there would be zero of these issues in shipping code. This is the problem with the C++ crowd hoping to save their language. Maybe they'll finally figure out some --disallow-all-ub-and-be-memory-safe-and-thread-safe flag but at the moment it's still insanely trivial to make a mistake and return a reference to some value on the stack or any…

This comment highlights a very important philosophical difference between the Rust community and the communities of other languages: - in other languages, it’s understood that perhaps the language is vulnerable to certain errors and one should attempt to mitigate them. But more importantly, those errors are one class of bug and bugs can happen. Set up infra to detect and recover. - in Rust the code must be safe, must…

> ... it's understood that perhaps the language is vulnerable to certain errors and one should attempt to mitigate them. But more importantly, those errors are one class of bug and bugs can happen. Set up infra to detect and recover.

> in Rust the code must be safe, must be written in a certain way, must be proven correct to the largest extent possible at compile time.

Only for the Safe Rust subset. Rust has the 'unsafe' keyword that shows exactly where the former case does apply. (And even then, only for possible memory unsoundness. Rust does not attempt to fix all possible errors.)

Re: There is no memory safety without thread safety

#346
post #344

Earlier quoted context omitted.

The segfault seen here is not a property of the language implementation, it's just a consequence of the address chosen by the attacker: 42. If you replicated this code in C you would get the same result, and if you used an address pointing to mapped memory in Go then the program would continue executing like in similar exploits in C. The only reason this isn't a more critical issue is because data races are hard to e…

Whether you can a segfault if you access an out-of-bounds address or not is part of the language implementation. An implementation that guarantees a segfault for out-of-bounds accesses is memory safe.

You can't really guarantee that all out-of-bounds accesses will segfault, because memory protection mechanisms are not that granular. (And actual memory segmentation, that did have the required granularity, has fallen out of use - though CHERI is an attempt to revive it.) That's why a segfault is treated as something to be avoided altogether, not as a reliable error mechanism.

What you can say though (and the point I made upthread) is that if a language manages to provably never segfault, then it must have some sort of true language-enforced safety because the difference between segfaulting or not is really just a matter of granularity.

Re: There is no memory safety without thread safety

#347

False. Java got this right. Fil-C gets it right, too. So, there is memory safety without thread safety. And it’s really not that hard. Memory safety is a separate property unless your language chooses to gate it on thread safety. Go (and some other languages) have such a gate. Not all memory safe languages have such a gate.

It's not that black and white and the solution isn't necessarily pick language X and you'll be fine. It never is that simple.

Basically, functional languages make it easier to write code that is safe. But they aren't necessarily the fastest or the easiest to deal with. Erlang and related languages are a good example. And they are popular for good reasons.

Java got quite a few things right but it took a while for it to mature. Modern day Java is quite a different beast than the first versions of Java. The Thread class, API, and the language have quite a few things in there that aren't necessarily that great of an idea. E.g. the synchronized keyword might bite you if you are trying to use the new green threads implementation (you'll get some nice deadlocks if you block the one thread you have that does everything). The modern java.concurrent package is implemented mostly without it.

Of course people that know their history might remember that green threads are actually not that new. Java did not actually support real threads until v1.1. Version 1.0 only had green threads. Those went out of fashion for about two decades and then came back with recent versions. And now it does both. Which is dangerous if you are a bit fuzzy on the difference. It's like putting spoilers on your fiesta. Using green threads because they are "faster" is a good sign that you might need to educate yourself and shut up.

On the JVM, if you want to do concurrent and parallel stuff, Scala and Kotlin might be better options. All the right primitives are there in the JVM of course. And Java definitely gives you access to all it. But it also has three decades of API cruft and a conservative attitude about keeping backwards compatible with all of that. And not all of it was necessarily that all that great. I'm a big fan of Kotlin's co-routine support that is rooted in a lot of experience with that. But that's subjective of course. And Scala-ists will probably insist that Scala has even better things. And that's before we bring up things like Clojure.

Go provides a good balance between ease of use / simplicity and safety. But it has quite a few well documented blind spots as well. I'm not that big of a fan but I appreciate it for what it is. It's actually a nice choice for people that aren't well versed in this topic and it naturally nudges people in a direction where things probably will be fine. Rust is a lot less forgiving and using it will make you a great engineer because your code won't even compile until you properly get it and do it right. But it won't necessarily be easy (humbled by experience here).

With languages the popular "if you have a hammer everything looks like a nail" thing is very real. And stepping out of your comfort zone and realizing that other tools are available and might be better suited to what you are trying to do is a good skill to have.

IMHO python is actually undervalued. It was kind of shit at all of this for a long time. But they are making a lot of progress modernizing the language and platform and are addressing its traditional weaknesses. Better interpreting and jit performance, removing the GIL, async support that isn't half bad, etc. We might wake up one day and find it doing a lot of stuff that we'd traditionally use JVM/GO/Rust for a few years down the line. Acknowledging weaknesses and addressing those is what I'm calling out here as a very positive thing. Oddly, I think there are a lot of python people that are a bit conflicted about progress like this. I see the same with a lot of old school Java people. You get that with any language that survives that long.

Note how I did not mention C/C++ here so far. There's a lot of it out there. But if you care about safety, you should probably not go near it. I don't care how disciplined you are. Your C/C++ code has bugs. Any insistence that it doesn't just means you haven't found them yet. Possibly because you are being sloppy looking for them. Does it even have tests? There are whole classes of bugs that we can prevent with modern languages and practices. It's kind of negligent and irresponsible not to. There are attempts to make C++ better of course.

Re: There is no memory safety without thread safety

#348
post #75

This is one of the things that I'm also looking on at Zig like a slow moving car crash about: they claim they are memory safe (or at least "good enough" memory safe if you use the safe optimization level, which is it's own discussion), but they don't have the equivalent to Rust's Send/Sync types. It just so happens that in practice no one was writing enough concurrent Zig code to get bitten by it a lot, I guess...exc…

IIUC even single-threaded Zig programs built with ReleaseSafe are not guaranteed to be free of memory corruption vulnerabilities; for example, dereferencing a pointer to a local variable that's no longer alive is undefined behavior in all optimization modes.

well just dont do it then

Re: There is no memory safety without thread safety

#349

False. Java got this right. Fil-C gets it right, too. So, there is memory safety without thread safety. And it’s really not that hard. Memory safety is a separate property unless your language chooses to gate it on thread safety. Go (and some other languages) have such a gate. Not all memory safe languages have such a gate.

It's not that black and white and the solution isn't necessarily pick language X and you'll be fine. It never is that simple. Basically, functional languages make it easier to write code that is safe. But they aren't necessarily the fastest or the easiest to deal with. Erlang and related languages are a good example. And they are popular for good reasons. Java got quite a few things right but it took a while for it t…

> IMHO python is actually undervalued. It was kind of shit at all of this for a long time. But they are making a lot of progress modernizing the language and platform and are addressing its traditional weaknesses. Better interpreting and jit performance, removing the GIL, async support that isn't half bad, etc.

The issue with Python isn't just the GIL and lack of support for concurrency. It uses dynamic types (i.e. variant types) for everything. That's way too slow, it means every single variable access must go through a dispatch step. About the only thing Python has going for it is the easy FFI with C-like languages.

Re: There is no memory safety without thread safety

#350

Honestly what I mostly want is to not have memory leaks. Which somehow stopped being a focus at some point

The "good" news is that Bjarne Stroustrup is right there with you, Bjarne sees eliminating all memory leaks as a high priority for C++ and one of his main goals.

The bad news ought to be obvious, this "goal" is not achievable, it's a fantasy that somehow we should be able to see the future, divine that some value stored won't be needed in the future and thus we don't need to store it. Goals like "We shouldn't store things we can't even refer to" are already solved in languages used today, so a goal to "not have memory leaks" refers only to that unachievable fantasy.

Post reply on HN