Remix.run Logo
codys 5 days ago

Curiously, Go itself is unclear about its memory safety on go.dev. It has a few references to memory safety in the FAQ (https://go.dev/doc/faq#Do_Go_programs_link_with_Cpp_programs, https://go.dev/doc/faq#unions) implying that Go is memory safe, but never defines what those FAQ questions mean with their statements about "memory safety". There is a 2012 presentation by Rob Pike (https://go.dev/talks/2012/splash.slide#49) where it is stated that go is "Not purely memory safe", seeming to disagree with the more recent FAQ. What is meant by "purely memory safe" is also not defined. The Go documentation for the race detector talks about whether operations are "safe" when mutexes aren't added, but doesn't clarify what "safe" actually means (https://go.dev/doc/articles/race_detector#Unprotected_global...). The git record is similarly unclear.

In contrast to the go project itself, external users of Go frequently make strong claims about Go's memory safety. fly.io calls Go a "memory-safe programming language" in their security documentation (https://fly.io/docs/security/security-at-fly-io/#application...). They don't indicate what a "memory-safe programming language" is. The owners of "memorysafety.org" also list Go as a memory safe language (https://www.memorysafety.org/docs/memory-safety/). This later link doesn't have a concrete definition of the meaning of memory safety, but is kind enough to provide a non-exaustive list of example issues one of which ("Out of Bounds Reads and Writes") is shown by the article from this post to be something not given to us by Go, indicating memorysafety.org may wish to update their list.

It seems like at the very least Go and others could make it more clear what they mean by memory safety, and the existence of this kind of error in Go indicates that they likely should avoid calling Go memory safe without qualification.

ralfj 4 days ago | parent | next [-]

> Curiously, Go itself is unclear about its memory safety on go.dev.

Yeah... I was actually surprised by that when I did the research for the article. I had to go to Wikipedia to find a reference for "Go is considered memory-safe".

Maybe they didn't think much about it, or maybe they enjoy the ambiguity. IMO it'd be more honest to just clearly state this. I don't mind Go making different trade-offs than my favorite language, but I do mind them not being upfront about the consequences of their choices.

phire 5 days ago | parent | prev [-]

The definition kind of changed.

At the time Go was created, it met one common definition of "memory safety", which was essentially "have a garbage collector". And compared to c/c++, it is much safer.

ralfj 4 days ago | parent | next [-]

> it met one common definition of "memory safety", which was essentially "have a garbage collector"

This is the first time I hear that being suggested as ever having been the definition of memory safety. Do you have a source for this?

Given that except for Go every single language gets this right (to my knowledge), I am kind of doubtful that this is a consequence of the term changing its meaning.

phire 4 days ago | parent [-]

True, "have a garbage collector" was never the formal definition, it was more "automatic memory management". But this predates the work on Rust's ownership system and while there were theories of static automatic memory management, all practical examples of automatic memory management were some form of garbage collection.

If you go to the original 2009 announcement presentation for Go [1], not only is "memory-safety" listed as a primary goal, but Pike provides the definition of memory-safe that they are using, which is:

"The program should not be able to derive a bad address and just use it"

Which Go mostly achieves with a combination of garbage collection and not allowing pointer arithmetic.

The source of Go's failure is concurrency, which has a knock-on effect that invalidates memory safety. Note that stated goal from 2009 is "good support for concurrency", not "concurrent-safe".

[1] https://youtu.be/rKnDgT73v8s?t=463

ralfj 3 days ago | parent [-]

Thanks! I added a reference to that in the blog post.

Interestingly, in 2012 Rob Pike explicitly said that Go is "not purely memory safe" because "sharing is legal": https://go.dev/talks/2012/splash.slide#49. However it is not entirely clear what he means by that (I was not able to find a recording of the talk), but it seems likely he's referring to this very issue.

> "The program should not be able to derive a bad address and just use it"

My example does exactly that, so -- as you say, Go mostly achieves this, but not entirely.

> Note that stated goal from 2009 is "good support for concurrency", not "concurrent-safe".

My argument is that being concurrency-unsafe implies being memory-unsafe, for the reasons laid down in the blog post. I understand that that is a somewhat controversial opinion. :)

camgunz 3 days ago | parent [-]

Hey! Cards on the table I'm not in love w/ your post, but mostly I'm curious about what discussion or outcome you were hoping for with it. Doesn't this boil down to "bad things will happen if you have data races in your code, so don't have data races in your code". Does it really matter what those bad things are?

codys 5 days ago | parent | prev [-]

That seems contrasted by Rob Pike's statement in 2012 in the linked presentation being one of the places where it's called "not purely memory safe". That would have been early, and Go is not called memory safe then. It seems like calling Go memory safe is a more recent thing rather than a historical thing.

phire 5 days ago | parent [-]

Keep in mind that the 2012 presentations dates to 10 months after Rust's first release, and its version of "Memory Safety" was collecting quite a bit of attention. I'd argue the definition was already changing by this point. It's also possible that Go was already discovering their version of "Memory Safety" just wasn't safe enough.

If you go back to the original 2009 announcement talk, "Memory Safety" is listed as an explicit goal, with no carveouts:

"Safety is critical. It's critical that the language be type-safe and that it be memory-safe."

"It is important that a program not be able to derive a bad address and just use it; That a program that compiles is type-safe and memory-safe. That is a critical part of making robust software, and that's just fundamental."

https://youtu.be/rKnDgT73v8s?t=463

SkiFire13 5 days ago | parent | next [-]

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

phire 5 days ago | parent [-]

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 system and borrow checker were very much front-and-centre for the 0.1 release, it was what everyone was talking about.

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.

SkiFire13 4 days ago | parent [-]

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

codys 5 days ago | parent | prev [-]

That's a very good point on the timing. Thanks for adding that extra info.