News for hackers. Stuff that matters.
Re:Major standard library changes in Go 1.20 by astrange on Monday January 16, 2023 @10:27PM (#34408798)
Adding manual arena memory management seems like a weird choice for a supposedly memory-safe and GC'd language where this is supposed to be an implementation issue.

I mean, you should hear the screams from Rust/Go people about how bad C is, and now you're just going to do it?

Re:Major standard library changes in Go 1.20 by slimsag on Monday January 16, 2023 @10:37PM (#34408852)
> now you're just going to do it?

"you can’t import it by default", "you probably shouldn’t be using it at all", "experimental arena package", and 'you must opt-in to even be able to use it via an GOEXPERIMENT environment variable'

As for screams from Rust/Go people about how bad C is, it said:

> This is highly efficient, but also highly dangerous. What if the programmer makes a mistake [...] > > To mitigate the risk of these kinds of bugs, the arena package will deliberately cause a panic if can detect someone reusing memory after it has been freed.

and goes on to explain that each arena has its own unique/distinct address space, so that if a pointer to an object still exists and is dereference it will get a memory access fault, causing the Go program to terminate, with an error message specifying that arena as the cause of the problem.

Sounds like a pretty reasonable/cautious experiment to me.

Re:Major standard library changes in Go 1.20 by lnxg33k1 on Monday January 16, 2023 @11:28PM (#34409132)
Yeah I think a language is safe or unsafe according to the ecosystem they live in. A project a developer works on is hardly 100% self-developed and depends on library and third party code, so I understand you have experiments you need to enable, but once it starts spreading in libraries, I think the whole safety guarantee just goes out of the window?

As a rust student myself, even the unsafe{} block is stupid

Re:Major standard library changes in Go 1.20 by kaba0 on Tuesday January 17, 2023 @03:00AM (#34410161)
Rust’s unsafe is still much safer than your average C code. The borrow checker checks inside unsafe blocks as well, you can just circumvent it through pointers.

But the great thing with unsafe blocks is that you get to create a safe API abstraction on top. You manually verify closely the unsafe parts, and if you got that short part right you can use the safe wrapper wherever you want safely.

Re:Major standard library changes in Go 1.20 by cormacrelf on Monday January 16, 2023 @11:58PM (#34409315)
> and goes on to explain that each arena has its own unique/distinct address space

That does not seem to be how it is implemented now. Try the example use-after-free on https://uptrace.dev/blog/posts/go-memory-arena.html under 'Address Sanitizer'. There is no error at all when you dereference, it silently keeps working as freed pointers often do (until they don't). Maybe they will add the virtual address space thing later.

Edit: the issue (https://github.com/golang/go/issues/51317) in which that comment was made also has some people referring to the arena being freed "when the runtime gets around to it" rather than immediately. I can't imagine why the virtual address space wouldn't be made poisonous inside the arena.Free method, but it's possible they do do it later. So your pointers maybe do stop working at an indeterminate time. Sounds pretty much like C. I even tried adding a few `runtime.GC()` calls before dereferencing but to no avail, couldn't get it to crash.

The Java 20 implementation has no such issues (https://gist.github.com/cormacrelf/8ddd3cc1b086e4ade93c029a9...), partly because there is no API for allocating a generic T in the arena, so all dereferences are through the managed MemorySegment API. It only seems to offer raw memory, which you can use to implement arrays of unboxed C-style structs, which is great for FFI and network buffers etc. This would be a good tradeoff for Go as well, surely.

Re:Major standard library changes in Go 1.20 by klodolph on Tuesday January 17, 2023 @01:22AM (#34409674)
If you want network buffers in Go, you can just use []byte. The Go GC is designed to make this work well, so nobody in Go is asking for a separate buffer type like you have in Java. In Java you have Buffer in the first place because there are good reasons why you might not want to use byte[].

Unboxed C types in Go can be done with cgo (it's not necessarily pleasant, but it works).

Re:Major standard library changes in Go 1.20 by kaba0 on Tuesday January 17, 2023 @02:56AM (#34410141)
> why you might not want to use byte[]

Such as? Java buffers use byte arrays by default as underlying storage.

Re:Major standard library changes in Go 1.20 by klodolph on Tuesday January 17, 2023 @05:49AM (#34411086)
https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffe...

Look for "Direct vs. non-direct buffers". Some buffers are backed by arrays, some are not.

You're basically deciding whether you are okay with a higher cost for I/O or a higher-cost for interacting with the data in the buffer.

Re:Major standard library changes in Go 1.20 by kaba0 on Tuesday January 17, 2023 @07:50AM (#34411818)
I do know about it, I was trying to find out what difference do the parent mean between Go’s byte arrays and Java’s solution(s).

Also, I fail to get your conclusion — direct buffers only have a higher cost for initialization/dealloc otherwise reading/writing should be as cheap as it gets. Byte buffers on the other hand do get write barriers but that is also unlikely to be hit that often (and I believe larger byte arrays get allocated in a separate region that doesn’t get moved).

Re:Major standard library changes in Go 1.20 by eptcyka on Tuesday January 17, 2023 @03:20AM (#34410281)
Why do Go enthusiasts look at types that specialize more generic data structures to ensure invariants and scoff? Maybe go only ever needed []byte, and nothing else - it's always just bytes anyway, right?

Moreover, when the go team accomplishes the same goals by extending the language instead of using a library, this is well received.

Re:Major standard library changes in Go 1.20 by stickupkid on Tuesday January 17, 2023 @04:58AM (#34410825)
Specifically to the arena, this required integration with the GC, so couldn't be done as an external library. Hence why a language spec was required.
Re:Major standard library changes in Go 1.20 by klodolph on Tuesday January 17, 2023 @05:44AM (#34411054)
> Why do Go enthusiasts look at types that specialize more generic data structures to ensure invariants and scoff?

I'm sorry, I'm not really sure what difference between Buffer and byte[] in Java I'm supposed to care about, except for the details of how these objects are allocated in memory. There is not really any semantic difference between them, as far as I can tell.

Maybe I don't understand what you're saying--I'd love for you to clarify the reasons why you think Go developers are, I guess, a little bit dense, or foolish, or whatever negative adjectives you like to apply to people who use Go (you know, rather than talking about the language itself--it's always fun to make fun of people).

Re:Major standard library changes in Go 1.20 by _old_dude_ on Tuesday January 17, 2023 @04:58AM (#34410827)
yes, Java/C# GCs (Android included) and Go GC are very different beasts.

Go GC does not move objects in memory (mark and sweep) while other GCs (mark and compact) do, to avoid heap fragmentation and better throughput (see generational GCs).

One issue with mark and compact GCs is that you can not move the array of bytes during a system call. A ByteBuffer/Memory object, is an object that allocates its byte arrays using malloc, outside of the heap, so the bytes are not moved by the GC.

Re:Major standard library changes in Go 1.20 by mknyszek on Tuesday January 17, 2023 @05:39PM (#34420510)
The functionality to poison the address space is there, and it does work.

What you're encountering is one of two exceptions in the implementation where you might not get an immediate failure:

1. If you use only a very small amount of an arena chunk and free it, it goes back on a reuse list as an optimization. Accessing that chunk's memory, despite the fact that the arena was freed, is entirely memory safe: nothing else will use that memory. That address space will be properly poisoned once the arena chunk is full, or close to it. 2. If the GC is actively marking, arena chunk poisoning is delayed to avoid races with the GC that might cause it to dereference a pointer into poisoned memory. The arena chunk is poisoned as soon as the GC is done.

The API explicitly does not guarantee a crash on use-after-free[1] because the Go team wanted a valid implementation of arenas to be simply "new" for New and noop for Free. The point is to just stay memory safe and have a high probability of catching an issue _in production_ where presumably arenas are filled up (otherwise why are you using arenas?).

[1]: https://cs.opensource.google/go/go/+/master:src/arena/arena....

Re:Major standard library changes in Go 1.20 by cormacrelf on Tuesday January 17, 2023 @07:33PM (#34421650)
> If you use only a very small amount of an arena chunk and free it, it goes back on a reuse list as an optimization. Accessing that chunk's memory, despite the fact that the arena was freed, is entirely memory safe: nothing else will use that memory.

I still have a pointer into the chunk. If you reuse the chunk in a different arena, I still have a pointer into the chunk. At no point is it invalidated, and the new arena will now start allocating new stuff from the start of the chunk. Right? And my old pointer still works, and the data inside it is at some point overwritten. How is that memory safe?

Are you eventually unmapping the virtual address space and remapping the underlying allocation somewhere else? So the poisoning happens when the chunk is picked up for reuse by a new arena?

Re:Major standard library changes in Go 1.20 by mknyszek on Wednesday January 18, 2023 @01:56PM (#34431200)
> At no point is it invalidated, and the new arena will now start allocating new stuff from the start of the chunk. Right? And my old pointer still works, and the data inside it is at some point overwritten.

It doesn't allocate at the start of the chunk, it just picks up wherever the last one left off. That allocated memory in the chunk from previous arena allocations is not reused until the chunk as a whole is unmapped and the GC can confirm that no more pointers point into that chunk's address space (if you leave a dangling pointer, you only waste address space). This points-into property is cheap to check, it's equivalent to whether the chunk has been marked by the GC.

Again, I think that MSAN/ASAN should probably just be more strict with these kinds of use-after-frees. You won't crash, but it's still technically incorrect. (Not much can be done about the "GC is in the mark phase" case, unfortunately. Otherwise MSAN/ASAN will complain when the GC inevitably tries to access a pointer into a delayed chunk.)

Re:Major standard library changes in Go 1.20 by latch on Monday January 16, 2023 @10:45PM (#34408891)
Seems to fit the goroutine model well: initialize the arena at goroutine start, destroy it on goroutine end (I assume this happens automatically when it falls out of scope). Like Erlang's process-specific GC.

It would be nice for some debug/testing mechanism (akin to -race, or zig's detectLeaks) to proactively verify nothing has outlived the arena.

Re:Major standard library changes in Go 1.20 by zozbot234 on Monday January 16, 2023 @11:09PM (#34409029)
> I mean, you should hear the screams from Rust/Go people about how bad C is, and now you're just going to do it?

Wait until you learn how Rust now has a crate that implements seamless concurrent tracing GC, just like Go... https://redvice.org/2023/samsara-garbage-collector/

Re:Major standard library changes in Go 1.20 by astrange on Tuesday January 17, 2023 @12:33AM (#34409461)
Sounds fine to me. That's safe.

But if you have a compacting GC, you shouldn't need an arena. You should be able to get away with fixing the GC.

Re:Major standard library changes in Go 1.20 by klodolph on Tuesday January 17, 2023 @01:30AM (#34409700)
> You should be able to get away with fixing the GC.

Practically speaking, "fixing the GC" is just a really, super hard problem. You're making a tradeoff between memory usage, CPU usage, pause times, and the performance of various features like pinned objects.

It makes sense that you may want different tradeoffs in different parts of your program. "Fixing the GC" is right up there with "just make a smart enough compiler" type sentiment that gets you in trouble--it's easy to say that you desire a better GC or better compiler, but when you actually try to make a better GC or better compiler, you find out that it doesn't solve the problems you were hoping it would solve.

Go's GC is tuned aggressively for short pause times. A lot of people actually want short pause times in their GCs, enough so that it's a selling point for Go. In Go, those short pause times were achieved partly by sacrificing CPU efficiency. You can't just go in and "fix" the CPU efficiency problems, but you can make new APIs that give you an escape hatch.

Re:Major standard library changes in Go 1.20 by jchw on Monday January 16, 2023 @11:40PM (#34409220)
I mean, it's opt-in. If you really want to crap your pants, in today's Go, you can import C and call malloc and free, then import unsafe and make pointers into the void. The point of memory safe programming languages is NOT that they entirely disallow all unsafe operations, it's that the language has a proper model for memory safety. In Rust, unsafe code needs to be in unsafe blocks. In Go, unsafe code is only possible by importing unsafe or C.

Adding more unsafe tools to Go or Rust do not diminish their safety guarantees. In fact, when Go and Rust add new unsafe features, they generally do so in a fashion that is much more constrained and has better defined edges than traditional methods, so that it's easier to use them correctly and easier to detect misuses. For example, the borrow checker still runs in Rust unsafe blocks; you still have to circumvent the borrow checker even once you're in unsafe. As for this arena package, it seems to have a few safety mechanisms, and hell, I don't even think it's off the table that it could be made entirely memory safe. This is especially true since memory safe does not mean "free of runtime errors", so all that is needed is to be able to detect the error conditions without allowing potentially undefined behavior to occur first.

Re:Major standard library changes in Go 1.20 by heywhatupboys on Tuesday January 17, 2023 @03:52AM (#34410446)
> In Go, unsafe code is only possible by importing unsafe or C.

of course, this is completely wrong, for anyone reading this. that is simply not how systems work

Re:Major standard library changes in Go 1.20 by the-smug-one on Tuesday January 17, 2023 @04:43AM (#34410728)
OK, do you intend to say why?
Re:Major standard library changes in Go 1.20 by thiht on Tuesday January 17, 2023 @04:53AM (#34410793)
How do "systems" (whatever you're talking about) work then?
Re:Major standard library changes in Go 1.20 by mikedelago on Tuesday January 17, 2023 @11:12AM (#34414292)
I think they are speaking without the context that "unsafe = lack of memory safety" and with the context that "unsafe = you can still drop the database"
Re:Major standard library changes in Go 1.20 by jchw on Tuesday January 17, 2023 @09:00AM (#34412408)
Note that "unsafe" in this context refers to memory safety. I am not making the claim that Go code which does not import unsafe or C is free of bugs; however, if you don't import unsafe or C anywhere in your application or dependencies (sans the stdlib) then it is memory safe (assuming no compiler or OS bugs compromise that guarantee.) That's just how Go is specified.

The unsafe package in Go provides unsafe.Pointer, which allows you to convert between a pointer and integral type, essentially allowing you to make pointers of any type to any address, giving up type safety. Without it, Go pointers are safe, because the GC will never free memory that has live pointers, and you can't do math on Go pointers.

Re:Major standard library changes in Go 1.20 by beltsazar on Tuesday January 17, 2023 @12:08AM (#34409362)
> Adding manual arena memory management seems like a weird choice for a supposedly memory-safe and GC'd language where this is supposed to be an implementation issue.

Yes, it's because Go's GC is primarily tuned for latency at the cost of (memory allocation) throughput. Furthermore, there are only a few knobs for Go's GC.

If Go's GC is implemented a bit differently and has a few more knobs so that it can be optimized for memory allocation throughput, maybe Go doesn't need an arena library. I don't even know other GC-ed languages that have/need an arena library because their GC is customizable enough.

Re:Major standard library changes in Go 1.20 by kubb on Tuesday January 17, 2023 @02:20AM (#34409950)
Garbage collector is too slow, so they're reintroducing malloc and free. Life writes the best scenarios.