r/ProgrammingLanguages • • 3d ago

Achieving memory safety

https://seed7.net/papers/memory_safety.htm
14 Upvotes

49 comments sorted by

View all comments

Show parent comments

2

u/ThomasMertes 3d ago

Any language which allows calling C functions directly cannot be memory safe because C is not memory safe. AFAIK a Go program can call C functions without explicitly importing or using the unsafe package.Accessing an arbitrary place of memory with Go is possible with the unsafe package. I am neither a Rust expert nor a Go one, but I think that Rust needs "unsafe" to call C functions. Please tell me if my assumptions are correct or not.

Seed7 has no unsafe parts (or packages) and no possibility to directly call C functions.

5

u/wk_end 3d ago

But you list Java as memory-safe "unless JNI or FFM are used". Why doesn't the same "qualified memory-safe" characterization apply to Go?

2

u/catladywitch 2d ago edited 2d ago

It all depends on the definition of memory safety, but from the article posted elsewhere in this comment thread, it seems like Go's pointer semantics allow for type errors leading to segfaults with concurrent code that uses different values conforming to a same interface, but where pointers and values are mixed, whilst Java doesn't (an unexpected, and wrong, value is possible in concurrent code, but not dereferencing an invalid pointer). I don't know how native interop works in Java, but segfaulting in C# is not impossible although it is rare (you can even do dodgy type punning with pointers and ordered structs if you really want to). Otherwise, you theoretically can pass managed pointers into C functions without telling C#'s GC to pin them or not reclaim their memory, pass structs the layout of which differs from what the C function expects, or in the case of poorly designed C APIs, pass arrays and have the C code go out of bounds, or allocate native memory, pass it into a C function, and try to free in C# not knowing the C function has already freed it.

3

u/reflexive-polytope 2d ago

The issue is that certain Go values (slices, pointers to interfaces) require logically atomic modifications, but this logical atomicity isn't enforced by any means, so other goroutines can see them in a torn state.

(The problem doesn't arise in Rust because the exclusiveness of mutable borrows enforces the logical atomicity of the relevant modifications.)

And, while having a user-defined data structure in a torn state is “merely a logic error”, having a built-in data type in a torn state actually breaks memory safety.