Live data from Hacker News

There is no memory safety without thread safety

ralfj.de

191–200 of 517 posts

Re: There is no memory safety without thread safety

#191
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 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.

This means that multiple goroutines were writing to the same local variable. I've never worked on a Go team where code that is structured in such a way would be considered normal or pass code review without good justification.

Re: There is no memory safety without thread safety

#192
post #97

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

Even if you use channels to send things between goroutines, go makes it very hard to do so safely because it doesn't have the idea of sendable types, ownership, read-only references, and so on. For example, is the following program safe, or does it race? func processData(lines The answer is of course that it's a data race. Why? Because `buf.Bytes()` returns the underlying memory, and then `Reset` lets you re-use the…

That code would never pass a human pull request review. It doesn't even pass AI code review with a simple "review this code" prompt: https://chatgpt.com/share/68829f14-c004-8001-ac20-4dc1796c76...

"2. Shared buffer causes race/data reuse You're writing to buf, getting buf.Bytes(), and sending it to the channel. But buf.Bytes() returns a slice backed by the same memory, which you then Reset(). This causes line in processData to read the reset or reused buffer."

I mean, you're basically passing a pointer to another thread to processData() and then promptly trying to do stuff with the same pointer.

Re: There is no memory safety without thread safety

#193

Every time this conversation comes up, I'm reminded of my team at Dropbox, where it was a rite of passage for new engineers to introduce a segfault in our Go server by not synchronizing writes to a data structure. Swift has (had?) the same issue and I had to write a program to illustrate that Swift is (was?) perfectly happy to segfault under shared access to data structures. Go has never been memory-safe (in the Rust…

I am curious. Generally basic structures like map are not thread safe and care has to be taken while modifying it. This is pretty well documented in go spec. In your case in dropbox, what was essentially going on?

I thought the same thing. Maybe the point of the story isn’t “we were surprised to learn you had to synchronize access” but instead “we all thought we were careful, but each of us made this mistake no matter how careful we tried to be.”

Re: There is no memory safety without thread safety

#194
> To see what I mean by this, consider this program written in Go, which according to Wikipedia is memory-safe:

The Wikipedia definition of memory safety is not the Go definition of memory safety, and in Go programs it is the Go definition of memory safety that matters.

The program in the article is obviously racy according to the Go language spec and memory model. So this is all very much tilting at windmills.

Re: There is no memory safety without thread safety

#195
post #186
post #155

Earlier quoted context omitted.

Oh...? Dart never gained much steam. And let's not forget about Carbon! Can you name even just one person who has tried Carbon? Have more than a handful of people even heard of Carbon? I will grant you that Carbon is still in its infancy, but when Rust was in the same youthful stage we never heard an end to all the people playing with it. You, even if not tried it yourself, definitely knew about it. You've made up a…

Already explained in another thread, learn the politics of Dart, and Carbon is still on the drawing board.

So failures are some deep valid reasons whereas success is developers don't know any better language.

Re: There is no memory safety without thread safety

#196

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.

I would recommend reading beyond the title of a post before leaving replies like this, as your comment is thoroughly addressed in the text of the article: > At this point you might be wondering, isn’t this a problem in many languages? Doesn’t Java also allow data races? And yes, Java does allow data races, but the Java developers spent a lot of effort to ensure that even programs with data races remain entirely well-…

> I would recommend reading beyond the title of a post before leaving replies like this, as your comment is thoroughly addressed in the text of the article:

The title is wrong. That's important.

> Java is in fact thread-safe in the sense of the term used in the article

The article's notion of thread safety is wrong. Java is not thread safe by construction, but it is memory safe.

Re: There is no memory safety without thread safety

#197
post #54

Earlier quoted context omitted.

"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.

> "Undefined behavior" is not a meaningless made up term that you can redefine at will. Sure, I agree with that. > The word "undefined" has a clear meaning: there is no behavior defined at all for what a given piece of code will do... That is true, but... > ...meaning it can literally do anything. This is not at all true! That is a different (but closely related) matter, which is "what is to be done about undefined b…

The original question is how UB is defined, not about the preferred way of dealing with it in a practical sense. And the definition of UB is behavior for which the language definition imposes no requirements, and explicitly leaves open the possibility of ignoring the situation altogether with unpredictable results.

Re: There is no memory safety without thread safety

#198
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…

It wasn't really tricky concurrency. Somebody just made the mistake of sharing a pointer across goroutines. It was quite indirect. Boils down to a function takeing a param and holds onto it. `go` is used at some point closing over this pointer. And now we have a data race in the waiting.

Re: There is no memory safety without thread safety

#199

Every time this conversation comes up, I'm reminded of my team at Dropbox, where it was a rite of passage for new engineers to introduce a segfault in our Go server by not synchronizing writes to a data structure. Swift has (had?) the same issue and I had to write a program to illustrate that Swift is (was?) perfectly happy to segfault under shared access to data structures. Go has never been memory-safe (in the Rust…

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…

> People talk as if "memory safety" was a PLT axiom. It's not; it's a software security term of art.

It's been in usage for PLT for at least twenty years[1]. You are at least two decades late to the party.

    Software is memory-safe if (a) it never references a memory location outside the address space allocated by or that entity, and (b) it never executes intstruction outside code area created by the compiler and linker within that address space.
[1]https://llvm.org/pubs/2003-05-05-LCTES03-CodeSafety.pdf

Re: There is no memory safety without thread safety

#200
post #156

Earlier quoted context omitted.

Originally Rust is something altogether different. Graydon has written about that extensively. Graydon wanted tail calls, reflection, more "natural" arithmetic with Python style automatic big numbers, decimal for financial work and so on. The Rust we have from 1.0 onwards is not what Graydon wanted at all. Would Graydon's language have been broadly popular? Probably not, we'll never know.

Even in pre-1.0 Rust, concurrency was a primary goal; there's a reason that Graydon listed Newsqueak, Alef, Limbo, and Erlang in the long list of influences for proto-Rust.

And yet it ignored the primary lesson of Erlang: no shared memory access whatsoever, which is what makes it so robust.
Post reply on HN