Live data from Hacker News

Group Borrowing: Zero-cost memory safety with fewer restrictions

verdagon.dev

21–30 of 87 posts

Re: Group Borrowing: Zero-cost memory safety with fewer restrictions

#21
post #9

I'm not sure if I understand it correctly. So, if I have a hashtable, adding or removing an element would invalidate existing pointers to any other element in the hashtable? I guess it makes sense from a memory release POV, but... I end up thinking that for databases using GC or RC is a better approach. Maybe I'm biased, but I have found far easier to work on databases written in C or C#. For that kind of programs I…

Yep, adding or removing an element would invalidate existing pointers to any other element in the hash table. This is generally regarded as a good thing if your elements are stored contiguously in the hash table, because a resize would cause any existing pointers to dangle. This should be true for C, and might be true for C# if you're using `struct`s which put the data inline (memory's a bit fuzzy on C#'s rules for r…

Thanks for the answer. For instance, usually those containers are used as indexes in DBs, so they contain pointers to data, not the data itself. That is an scenario where the references shouldn't be invalidated.

Idk if it may be possible to introduce "semantic monitors". Say, a field within a class and an external container must be updated together. In practice the only time when I have needed to break the single ownership is for keeping internal data views. I know it is safe, but convincing Rust of that is painful.

Re: Group Borrowing: Zero-cost memory safety with fewer restrictions

#22

There is also "Tree Borrows" [0] proposal for Rust, which is aimed at the same problem. [0] https://perso.crans.org/vanille/treebor/aux/preprint.pdf

No, Tree Borrows is aimed at defining the semantics of memory accesses. It does not provide a way to statically check whether they are correct, which is what the borrow checker and this proposal aim to do.

Re: Group Borrowing: Zero-cost memory safety with fewer restrictions

#23
post #9

I'm not sure if I understand it correctly. So, if I have a hashtable, adding or removing an element would invalidate existing pointers to any other element in the hashtable? I guess it makes sense from a memory release POV, but... I end up thinking that for databases using GC or RC is a better approach. Maybe I'm biased, but I have found far easier to work on databases written in C or C#. For that kind of programs I…

Yep, adding or removing an element would invalidate existing pointers to any other element in the hash table. This is generally regarded as a good thing if your elements are stored contiguously in the hash table, because a resize would cause any existing pointers to dangle. This should be true for C, and might be true for C# if you're using `struct`s which put the data inline (memory's a bit fuzzy on C#'s rules for r…

> I'm actually hoping to find a way to blend Nick's approach seamlessly with reference counting (preferably without risking panics or deadlocks) to get the best of both worlds, so that we can consider it for Mojo. I consider that the holy grail of memory safety, and some recent developments give me some hope for that!

Ante's approach manages to blend a similar scheme for safe, shared mutability with Rc. There are some examples on the most recent blog post on its website of it. IMO combined with its shared types it emulates high-level GC'd code very well.

Re: Group Borrowing: Zero-cost memory safety with fewer restrictions

#24
In memory-safety discussions it needs to be borne in mind that 'simply fix the hardware' is also a viable approach; or at least it's a lot more viable than it was or seemed to be a few decades ago https://en.wikipedia.org/wiki/Capability_Hardware_Enhanced_R... . Memory-safe BSD and applications running on real memory-safe RISC-V hardware apparently already exist, though obviously, yes, even in a best case existing architectures would not come close to being fully displaced for a long time. That said, I really hope the process isn't being further delayed by attempts to grub license money.

Re: Group Borrowing: Zero-cost memory safety with fewer restrictions

#25
post #7

> Because of those "inaccessible" rules, we can never have a readwrite reference and a readonly reference to an object at the same time. I can't not see this as a good thing. It's almost at the level of "the only thing an ownership system does". If my thread is operating on a struct of 4 int64s, do I now have to think about another read-only thread seeing that struct in an invalid partially-written state?

The general rule to prevent any data races (as I guess) between threads is that at any point of time there can be either one writer or multiple readers to the same object. Rust guarantees this by not allowing to have any other references if you have a read-write (mutable) reference.

Note that Rust is more strict than necessary - theoretically you can have multiple writable and readable references, but not use them simultaneously and observe the rule. But it is difficult (or even impossible) to verify during compilation so Rust doesn't allow it. C allows it but leaves verification to the author which doesn't work well and doesn't scale.

This situation can happen if you have a graph of objects. For example, in an OS you might have a Process object having references to a list of opened Files, and have a File hold reference back to Process that opened it. In this case you cannot ever have a writable reference to the Process from anywhere because Files already have multiple reading references. And Files can have only read-only references to the Process that opened them.

So you have to use only read-only references and additional structures like Cell, Arc etc. that allow safe writing through them. They are cheap, but not free and ideally we as developers want to have memory safety for free. That's the problem yet to solve.

Note that there are other ways to achieve safety:

- use C and manually verify that your program never breaks this rule - requires god level coding skills

- immutable data - after the writer finished writing, data are "frozen" and can be safely shared without any checks and no rules are broken. Very good, but modification is expensive and requires you to clone the data or use clever and complicated design (for example, if you have 10-elements array but shared a reference only to first 7 elements, you can safely append to the last 3 elements because nobody else knows about them - that's how ring buffers work). See immer C++ library for example.

- atomic variables - allow safe reading and writing at the same time, but can hold at most 8 bytes. Note that using a same variable from different CPU cores causes L1 cache line migrations which, last time I measured it, takes about 2-3 ns or ~10-15 cycles.

- mutexes - ensure rule is observed but make everyone wait. Python's approach.

- using only a single thread. JavaScript's approach. You can have multiple references but you still need to ensure they are pointing to a live object (JS solves this by using an expensive garbage collector).

And by the way if you know more methods or ideas please share them!

Re: Group Borrowing: Zero-cost memory safety with fewer restrictions

#26
post #7

> Because of those "inaccessible" rules, we can never have a readwrite reference and a readonly reference to an object at the same time. I can't not see this as a good thing. It's almost at the level of "the only thing an ownership system does". If my thread is operating on a struct of 4 int64s, do I now have to think about another read-only thread seeing that struct in an invalid partially-written state?

Ideally, the rules for single-threaded references and references that are allowed to be shared across threads would be different.

Even with a single thread you need to ensure that the object you are accessing, still exists and was not freed.

Re: Group Borrowing: Zero-cost memory safety with fewer restrictions

#27
post #9

I'm not sure if I understand it correctly. So, if I have a hashtable, adding or removing an element would invalidate existing pointers to any other element in the hashtable? I guess it makes sense from a memory release POV, but... I end up thinking that for databases using GC or RC is a better approach. Maybe I'm biased, but I have found far easier to work on databases written in C or C#. For that kind of programs I…

Rc is slightly expensive and Gc is super expensive. I would prefer a memory safety for free.

As for C, it leaves verifying the safety up to you, it is not easy at all and I would rather spend time on something else using safe languages.

Re: Group Borrowing: Zero-cost memory safety with fewer restrictions

#28
post #5

Hey all, this is a post explaining a new memory safety model by my friend Nick Smith (original proposal at https://gist.github.com/nmsmith/cdaa94aa74e8e0611221e65db8e4... ) It was interesting enough that I knew I had to write a post about it. Happy to answer any questions!

Thanks for the detailed writeup, that must have been a lot of work.

I think you guys should check out Verona (https://www.microsoft.com/en-us/research/project/project-ver...).

Re: Group Borrowing: Zero-cost memory safety with fewer restrictions

#29
post #7

> Because of those "inaccessible" rules, we can never have a readwrite reference and a readonly reference to an object at the same time. I can't not see this as a good thing. It's almost at the level of "the only thing an ownership system does". If my thread is operating on a struct of 4 int64s, do I now have to think about another read-only thread seeing that struct in an invalid partially-written state?

The general rule to prevent any data races (as I guess) between threads is that at any point of time there can be either one writer or multiple readers to the same object. Rust guarantees this by not allowing to have any other references if you have a read-write (mutable) reference. Note that Rust is more strict than necessary - theoretically you can have multiple writable and readable references, but not use them si…

> And by the way if you know more methods or ideas please share them!

Use a transaction manager (HTM or STM). The STM is going to boil down to lockfree synchronization, logging, and retry. Transactions can fail and retry.

But ultimately, all inter-thread communication boils down to programs (or libraries) using barriers for acquire/release semantics and/or using compare/swap and atomic read-modify-write.

> at any point of time there can be either one writer or multiple readers

Time is a slippery notion in concurrency. Most language-level memory models (e.g. Java) or even hardware-level concurrency models focus on happens-before relations, which are induced by executing certain operations. At the hardware level, you can basically think that a CPU receives asynchronous updates about cache lines from other processors (potentially out of order). While technically the cache coherence protocol pushes cache lines into processors, you can't ever guarantee that one "writer" can "push" updates into all other CPUs. Instead, you have to rely on those other CPUs executing either fences or being forced to execute fences through global OS means, such as IPIs. Those other CPUs executing fences (barriers) or other atomic operations induce happens-before relations.

Re: Group Borrowing: Zero-cost memory safety with fewer restrictions

#30
post #28
post #5

Hey all, this is a post explaining a new memory safety model by my friend Nick Smith (original proposal at https://gist.github.com/nmsmith/cdaa94aa74e8e0611221e65db8e4... ) It was interesting enough that I knew I had to write a post about it. Happy to answer any questions!

Thanks for the detailed writeup, that must have been a lot of work. I think you guys should check out Verona ( https://www.microsoft.com/en-us/research/project/project-ver... ).

Big fan of Verona, I love their memory safety approach as well. I wrote a bit about it in the Grimoire [0] too. IIRC they plan for the user to specify whether a region is backed by an arena allocator or GC, which sounds pretty nice. It's kind of hard to track down details though, most of my knowledge comes from reading David Chisnall's comments on lobste.rs.

[0] https://verdagon.dev/grimoire/grimoire

Post reply on HN