Comment by Panzerschrek
2 days ago
> but it's still possible to use memory incorrectly
Only by misusing unsafe. Using it in regular programs actually isn't that necessary. In languages like C you have unsafe code almost in every line.
> My understanding is that a memory bug is when you use memory in an unintended way
Memory safety rules are more strict and formalized than you think. Memory safety issues are typically reading uninitialized memory (or strictly speaking changing observable behavior based on contents of uninitialized memory), reading/writing memory after it have been freed (free/delete call or out-of-scope going for local variables), concurrent unsynchronized memory access.
> No compiler or tool can make sure you don't write to or read deallocated memory
I am author of a programming language, where you can't write to or read deallocated memory, unless you misusing unsafe.
> no compiler can read your thoughts
But many languages more complex than C have powerful features allowing telling the compiler your about intents. At least partially.
> Memory allocation is relative. In a sense, no program that runs under an operating system can use deallocated memory
You are mixing two different concepts. One is memory model of the abstract machine defined by the specification of a language and other is the OS processes model. They have much in common, but there are a lot of differences.
> So again, everything is safe if you use it as intended
Such mindset is considered harmful, since it provides an excuse to use languages where making mistakes is easy (like C).
Say I implement a dynamic array in the usual way with buffer, length, capacity. Currently the capacity is 50 and the length is 20. I access element 30 i.e. an unallocated element. Was that memory unsafe?
I think the point you missed or don't want to accept is that I think of all layers of memory management as the same thing just on different layers. Where you say that I mix different concepts, I say that it's just different layers of the same problem.
So which layer should we care about? All of them? Yes, if we want the most safety.
I will give you an example of how I can use memory incorrectly in "safe" rust. Let's say I have an integer that contains my age. Now I forget what the number was used for and I use it as shoe size. I have now used memory (the content of the variable) as something it was not intended for. Maybe you think this example is silly, but what is really the difference between using a float pointer as an int pointer and using age as shoe size? Another thing we could do is to use an index for one array as an index for another array. That's an example of using a pointer as the wrong type because an index is just a relative pointer.
So if we want to care about all layers of memory safety then we have to care about not using ages as shoe sizes and indexes with the wrong arrays. "Memory safe" languages usually don't help us with that and therefore they don't give us total memory safety. I think "memory safety" is not a very useful term because all data in a program lies in memory and basically all bugs have something to do with using that memory in wrong ways.
> we have to care about not using ages as shoe sizes and indexes with the wrong arrays. "Memory safe" languages usually don't help
In languages even slightly better than C one can create a wrapper type for int/float with additional semantics like age, shoe size or something else. Since they are different types, using one in place of other isn't possible. This doesn't solve all problems, but at least can prevent silly mistakes.
Interesting, I have had ideas about having that feature in a language: being able to make subtypes, like "this is an integer but on the next level it is a shoe size". Can you give an example of such a language or how they usually do that?
2 replies →
You can also simply wrap an int in a struct in C.