4 ms·
Yes totally, I keep seeing people mention these arena / flattened tree and graph structures, without mentioning memory safety. And also weird claims that aren
by chubot 3y ago
Yes totally, I keep seeing people mention these arena / flattened tree and graph structures, without mentioning memory safety.
And also weird claims that arenas solve memory safety problems in C, when it's equally likely (depending on the program) that they CAUSE dangling pointers, use-after-free, etc.
The same issue comes up in slightly different ways in both C/C++ and Rust
---
My comment on this post from 2 months ago:
https://old.reddit.com/r/ProgrammingLanguages/comments/1350dfw/flattening_asts_and_other_compiler_data_structures/jiid1mb/ https://old.reddit.com/r/ProgrammingLanguages/comments/1350d...
Summary: the upsides are very real, but we should mention the downsides too:
- Arenas punt on memory safety; Ownership can be nontrivial (a bunch of examples)
- Mutation, and appending to list/vectors are complications
- Pointer representations are more friendly to debuggers
My wiki page is linked at the bottom of this article (which I appreciate because it actually has code and measurements!)
https://github.com/oilshell/oil/wiki/Compact-AST-Representation https://github.com/oilshell/oil/wiki/Compact-AST-Representat...
- kazinator 3y ago> when it's equally likely (depending on the program) that they CAUSE dangling pointers Packing your objects into their own tight heap not only doesn't solve memory allocation issues, but makes them harder to debug. The tools for fighting these problems in C don't work as well. In TXR Lisp, I have to have a number of strategies in place for debugging GC issues. One is Valgrind integration. If you want to use Valgrind, but have implemented your own bump allocation within packed heaps, Valgrind won't be as helpful. For example, what is a semantic use-after-free in your world (something accessing an object that has been garbage collected) looks fine to the C library; you're just dereferencing a pointer into a large object that you allocated just fine. With Valgrind integration, you can use the API mark free objects inaccessible. But: that only means Valgrind will detect the wrong use of a reclaimed object (quite swiftly, thank you very much). It will not tell you who allocated that object. The diagnostic will be something like "invalid read, 15300 bytes into a 262164 object, allocated at <call stack>". That is not very useful! It gives you the call stack when that entire heap was allocated, not when that misused object within that heap was allocated. I have some debug support which takes advantage of reproducible repro test cases where we can count on addresses of bad objects being the same. Once I know the address of the offending object, I can put it into a debug variable called break_obj. When the object is allocated or reclaimed, there is a VALGRIND_PRINTF which will dump a trace. I can also get a breakpoint in gdb (that's why it's the break_obj). There is also an option to run the GC in a kind of torture mode where garbage collection is invoked on every allocation. Newly allocated objects that are not properly retained by the caller (made visible to gc) will be scavenged immediately, revealing those kinds of bugs by bringing the allocation and misuse contexts close together. A substantial portion of the test suite runs in this GC torture mode. Not everything, because it's quite slow.
- chubot 3y agoYes, I mentioned the same issue a few days ago -- arenas break ASAN/Valgrind, and those are the BEST tools to ensure memory safety: https://news.ycombinator.com/item?id=36427264 https://news.ycombinator.com/item?id=36427264 In response to a claim about arena-based allocators and memory safety
- kazinator 3y agoMaybe Valgrind has an API now to attach a backtrace to a custom allocation out of an arena. I haven't touched that in years. I did the initial Valgrind integration in 2009 and just maintained it with changes to the gc. I see this in the current manual: VALGRIND_MALLOCLIKE_BLOCK: If your program manages its own memory instead of using the standard malloc / new / new[], tools that track information about heap blocks will not do nearly as good a job. For example, Memcheck won't detect nearly as many errors, and the error messages won't be as informative. To improve this situation, use this macro just after your custom allocator allocates some new memory. See the comments in valgrind.h for information on how to use it. I can't remember whether I saw this before; i.e. is this something existing that had not been useful, or is it something new. I will look into it. It does look like it should be attacking the same problem: that the errors aren't detected well or nearly as informative in blocks carved out of larger block by custom allocators.
- kazinator 3y agoAlas, I've not been able to get it working. Possibly, the issue is that in my heaps, I do not have red zones; things are tightly packed. That's okay because the heap cells do not store arrays. I'm not concerned about overruns whatsoever. When I go through the hoops of registering each heap as a memory pool, which supports malloc-like allocations doled out of it, problems happen. When cell [0] of a heap becomes garbage and is indicated as freed (reclaimed by GC), Valgrind throws an invalid free/delete/delete[] error, saying there is a conflict between that and the entire block. I think this is because there is no offset between the block and the start of the heap. Valgrind assumes there will be some header or red zone between the entire memory zone and the pool area. It seems to be saying, whoa, you can't do VALGRIND_FREELIKE_BLOCK at that address; you allocated that address from malloc. Well no shit, and I told you that block was a heap, from which I'm getting VALGRIND_MALLOCLIKE_BLOCK blocks. Secondly, after the first GC cycles, errors go haywire, like "invalid read of 2 bytes: 0 bytes after 16 byte block allocated at ... blah blah". Basically, it thinks that various accesses are overruns, possibly due to there being no red zones between the blocks. Its quite baffling. Maybe current Valgrind has fixes for some of this; I just use what distros package.