Live data from Hacker News

There is no memory safety without thread safety

ralfj.de

41–50 of 517 posts

Re: There is no memory safety without thread safety

#41

This is false as a generality. A memory safe, managed language doesn't become unsafe just because you have a race condition in a program. Like, say, reading and writing several related shared variables without a mutex. Say that the language ensures that the reads and writes themselves of these word-sized variables are safe without any lock, and that memory operations and reclamation of memory are thread safe: there a…

If the variables are word-sized, sure. But what if they are larger? Now a race condition between one thread writing and another thread reading or writing a variable is a memory safety issue.

Re: There is no memory safety without thread safety

#42
I agree with the author's claim that you need thread safety for memory safety.

But I don't agree with:

> I will argue that this distinction isn’t all that useful, and that the actual property we want our programs to have is absence of Undefined Behavior.

There is plenty of undefined behavior that can't lead to violating memory safety. For example, in many languages, argument evaluation order is undefined. If you have some code like:

    foo(print(1), print(2));
In some languages, it's undefined as to whether "1" is printed before "2" or vice versa. But there's no way to violate memory safety with this.

I think the only term the author needs here is "memory safety", and they correctly observe that if the language has threading, then you need a memory model that ensures that threads can't break your memory safety.

Go lacks that. It seems to be a rare problem in practice, but if you want guarantees, Go doesn't give you them. In return, I guess it gives you slightly faster execution speed for writes that it allows to potentially be torn.

Re: There is no memory safety without thread safety

#43

Earlier quoted context omitted.

See the article's comments on Java, which is "thread safe" in the sense of preventing undefined behavior but not in the sense of preventing data-race-related logic bugs. .NET is precisely analogous in this respect.

I can buy that claim for the .NET CLR but I've never seen it nailed down properly the way Java did which gives me pause. I worry about the Win95-era "Microsoft Pragmatism" at work and a concrete example which comes to mind is nullability. In the nice modern software I often work on I can say some function takes a string and in that program C# will tell me that's not allowed to be null, it has to be an actual string -…

There's a documented memory model (https://github.com/dotnet/runtime/blob/main/docs/design/spec...), does that not address this concern?

Re: There is no memory safety without thread safety

#44
post #30
post #23

Earlier quoted context omitted.

It took months to finally solve a data race in Go. No race detector would see anything. Nobody understood what was happening. It ultimately resulted in a loop counter overflowing, which recomputed the same thing a billion of time (but always the same!). So the visible effect was a request would randomly take 3 min instead of 100ms. I ended up using perf in production, which indirectly lead me to understand the data r…

I think the true answer is that the moment you have to do tricky concurrency in Go, it becomes less desirable. I think that Go is still better at tricky concurrency than C, though there are some downsides too (I think it's a bit easier to sneak in a torn read issue in Go due to the presence of fat pointers and slice headers everywhere.) Go is really good at easy concurrency tasks, like things that have almost no shar…

> And frankly, a lot of software I write is just boring, and Go does fine for a lot of that. I try Rust periodically for things, and romantically it feels like it's the closest language to "the future", but I think the future might still have a place for languages like Go.

It's not so much about being "boring" or not; Rust does just fine at writing boring code once you get familiar with the boilerplate patterns (Real-world experience has shown that Rust is not really at a disadvantage wrt. productivity or iteration speed).

There is a case for Golang and similar languages, but it has to do with software domains where there literally is no viable alternative to GC, such as when dealing with arbitrary, "spaghetti" reference graphs. Most programs aren't going to look like that though, and starting with Rust will yield a higher quality solution overall.

Re: There is no memory safety without thread safety

#45

I agree with the author's claim that you need thread safety for memory safety. But I don't agree with: > I will argue that this distinction isn’t all that useful, and that the actual property we want our programs to have is absence of Undefined Behavior. There is plenty of undefined behavior that can't lead to violating memory safety. For example, in many languages, argument evaluation order is undefined. If you have…

That's "unspecified" not "undefined". "Undefined behavior" literally means "anything goes", so any program that invokes it is broken by definition.

Re: There is no memory safety without thread safety

#46
post #27

Earlier quoted context omitted.

It should be possible to construct an exploit for such programs. But even for truly unsafe languages, vulnerabilities just from data races are very rare, because they are much harder to exploit. You could argue Go is safe from memory vulnerabilities, and that'll be 99% correct (we can't know what will happen if some very strong organization (e.g. a nation-state actor) will heavily invest in exploiting some Go program…

There's enormous incentive to construct those exploits. Why don't they exist?

I'm not sure that's correct.

Yes, this is an enormous effort to construct exploits, but constructing exploits for C/C++ code is much much easier and gives not less, or even more, benefit. Therefore it makes sense the efforts are focused on that.

If/when most C/C++ code in the world will be gone, I assume we'll see more exploits of Go code.

Re: There is no memory safety without thread safety

#47

This is false as a generality. A memory safe, managed language doesn't become unsafe just because you have a race condition in a program. Like, say, reading and writing several related shared variables without a mutex. Say that the language ensures that the reads and writes themselves of these word-sized variables are safe without any lock, and that memory operations and reclamation of memory are thread safe: there a…

If the variables are word-sized, sure. But what if they are larger? Now a race condition between one thread writing and another thread reading or writing a variable is a memory safety issue.

Don't have such things, if you know what's good for you, or else don't have threads.

Re: There is no memory safety without thread safety

#48

I agree with the author's claim that you need thread safety for memory safety. But I don't agree with: > I will argue that this distinction isn’t all that useful, and that the actual property we want our programs to have is absence of Undefined Behavior. There is plenty of undefined behavior that can't lead to violating memory safety. For example, in many languages, argument evaluation order is undefined. If you have…

That's "unspecified" not "undefined". "Undefined behavior" literally means "anything goes", so any program that invokes it is broken by definition.

That is not true, that is a very specific definition of UB which C developers (among others) favor. That doesn't mean that another language can't say "this is undefined behavior" without all the baggage that accompanies the term in C.

Re: There is no memory safety without thread safety

#49

Wow that's a really big gotcha in go! To be fair though, go has a big emphasis on using its communication primitives instead of directly sharing memory between goroutines [1]. [1] https://go.dev/blog/codelab-share

Real-world golang programs share memory all the time, because the "share by communicating" pattern leads to pervasive logical problems, i.e. "safe" race conditions and "safe" deadlocks.

Re: There is no memory safety without thread safety

#50

Earlier quoted context omitted.

That's "unspecified" not "undefined". "Undefined behavior" literally means "anything goes", so any program that invokes it is broken by definition.

That is not true, that is a very specific definition of UB which C developers (among others) favor. That doesn't mean that another language can't say "this is undefined behavior" without all the baggage that accompanies the term in C.

It's literally how the term "UB" is defined, and understood by experts. Why would anyone want to say "undefined" when they really mean "unspecified"? That's just confusing.
Post reply on HN