Live data from Hacker News

There is no memory safety without thread safety

ralfj.de

51–60 of 517 posts

Re: There is no memory safety without thread safety

#51

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…

Your example does not classify as 'undefined behavior'. Something is 'undefined behavior' if it is specified in the language spec, and in such case yes, the language is capable of doing anything including violating memory safety.

Re: There is no memory safety without thread safety

#53
post #17

Earlier quoted context omitted.

The statement "there is no memory safety without thread safety" does not suggest that memory safety is sufficient to provide thread safety. Instead, it's just saying that if you want thread safety, then memory safety is a requirement.

> Instead, it's just saying that if you want thread safety, then memory safety is a requirement. It's saying the opposite – that if you want memory safety, thread safety is a requirement – and Java and C# refute it.

> Java and C# refute it.

No, they don't. They're using a different meaning for "thread safety" that's more useful in context since they do ensure data race safety - which is the only kind of thread safety OP is talking about. By guaranteeing data race safety as a language property, Java and C# are proving OP's point, not refuting it.

Re: There is no memory safety without thread safety

#54

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.

"Undefined behavior" is not a meaningless made up term that you can redefine at will.

The word "undefined" has a clear meaning: there is no behavior defined at all for what a given piece of code will do, meaning it can literally do anything. If the language spec defines the possible behaviors you can expect (even if the behavior can vary between implementations), then by definition it's not undefined.

Re: There is no memory safety without thread safety

#55
The sad thing is that most languages with threads have a default of global variables and unrestricted shared memory access. This is the source of the vast majority of data corruption and races. Processes are generally a better concurrency model than threads, but they are unfortunately too heavyweight for many use cases. If we defaulted to message passing all required data to each thread (either by always copying or tracking ownership to elide unnecessary copying), most of these kinds of problems would go away.

In the meantime, we thankfully have agency and are free to choose not to use global variables and shared memory even if the platform offers them to us.

Re: There is no memory safety without thread safety

#56

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.

> Now a race condition between one thread writing and another thread reading or writing a variable is a memory safety issue.

No it isn't, because the torn write cannot have arbitrary effects that potentially break the program. It only becomes such if you rely on such a variable to establish an invariant about memory that's broken if a torn write occurs (such as by encoding a ptr+len in it), which is just silly. Don't do that!

Re: There is no memory safety without thread safety

#57
post #55

The sad thing is that most languages with threads have a default of global variables and unrestricted shared memory access. This is the source of the vast majority of data corruption and races. Processes are generally a better concurrency model than threads, but they are unfortunately too heavyweight for many use cases. If we defaulted to message passing all required data to each thread (either by always copying or t…

Message passing can easily lead to more logical errors (such as race conditions and/or deadlocks) than sharing memory directly with properly synchronized access. It's not a silver bullet.

Re: There is no memory safety without thread safety

#58
post #23
post #2

This comes up now and again, somewhat akin to the Rust soundness hole issue. To be fair, it is a legitimate issue, and you could definitely cause it by accident, which is more than I can say about the Rust soundness hole(s?), which as far as I know are basically incomprehensible and about as likely to come across naturally as guessing someone's private key. That said in many years of using Go in production I don't th…

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…

It is very unfortunate that we use fixed width numbers by default in most programming languages and that common ops will silently overflow. Smarter compilers can work with richer numeric primitives and either automatically promote machine words to big numbers or throw an error on overflow.

People talk a lot about the productivity gains of ai, but fixing problems like this at the language level could have an even bigger impact on productivity, but are far less sensational. Think about how much productivity is lost due to obscure but detectable bugs like this one. I don't think rust is a good answer (it doesn't check overflow by default), but at least it points a little bit in the vaguely correct direction.

Re: There is no memory safety without thread safety

#59
post #20

Earlier quoted context omitted.

You mean like the program in the article where code that never dereferences a non-pointer causes the runtime to dereference a non-pointer? That seems like evidence to me.

An exploit against a real Go program that relies on memory corruption.

That’s called "moving the goal posts".

A definition of memory safety that permits unsoundness as long as nobody has exploited said unsoundness is not a definition that anyone serious about security is going to accept. Unsoundness is unsoundness, undefined behavior is undefined behavior. The conservative stance is that once execution hits UB, anything can happen.

Re: There is no memory safety without thread safety

#60
post #55

The sad thing is that most languages with threads have a default of global variables and unrestricted shared memory access. This is the source of the vast majority of data corruption and races. Processes are generally a better concurrency model than threads, but they are unfortunately too heavyweight for many use cases. If we defaulted to message passing all required data to each thread (either by always copying or t…

Message passing can easily lead to more logical errors (such as race conditions and/or deadlocks) than sharing memory directly with properly synchronized access. It's not a silver bullet.

100%.

Some more modern languages - eg. Swift – have "sendable" value types that are inherently thread safe. In my experience some developers tend to equate "sendable" / thread safe data structures with a silver bullet. But you still have to think about what you do in a broader sense… You still have to assemble your thread safe data structures in a way that makes sense, you have to identify what "transactions" you have in your mental model and you still have to think about data consistency.

Post reply on HN