Live data from Hacker News

How do I deal with memory leaks? (2022)

stroustrup.com

71–76 of 76 posts

Re: How do I deal with memory leaks? (2022)

#71

Earlier quoted context omitted.

> I do sometimes miss how utterly simple and dumb C is You can make an argument that the K&R C "is" an utterly simple and dumb language, but if it was it's long gone and it's also irrelevant for modern hardware. Today because C only has a single kind of reference, the raw pointer, that means if you want references at all (which you do) you need pointers, and to get decent performance from this sort of language you ne…

To be fair, it's a very hard problem. Even in Rust, the formal model of how provenance works is very much WIP

Rust's Provenance itself stabilized, some time ago in fact, as basically the Tower of Weakenings. If you noticed the raw pointer provenance APIs are all marked stable since Rust 1.84, that's because the underpinning model is also stable - however the provenance rules do need to care about aliasing and Rust's aliasing rules are to some extent a WIP. So there is definitely a creaky floorboard in the specific case that you want to do pointer twiddling and your pointers might arguably alias and you'd like clarity about exactly where the line is on that.

I haven't seen places where they wanted this, but they definitely can exist. In the cases I'm thinking of any valid pointers are definitely unique (so no aliasing), or they're definitely pointing at something immutable (so aliasing is fine) or both and so there's no problem as I understand it.

There is an outstanding issue with LLVM - for any language including Rust - that it has unsound optimizations for pointers and this has implications for provenance tricks, but as I said that's not Rust specific and I think worse there are signs the same illness afflicts the GCC backend so maybe it's worse than "LLVM is buggy" and is a wider problem in how compiler developers have thought about this vague unspecified problem.

Re: How do I deal with memory leaks? (2022)

#72
post #63

Earlier quoted context omitted.

1) In practice, this is not true, especially if you implement unwinding in your arena. You probably don't want to have an Arena in main, and you do all of your allocations from there, for example. That "just" leaks everything. Here's a classic Arena-with-rewind bug: { Arena a; avec v(a); { RewindMark rm(a); v.push(1); v.push(1); // Trigger resize } v[2] // Oh no! The underlying data array has been deallocated }

I’m sorry, but I look at this code and I can immediately see the bug? Instead of a rewind mark I personally create a local arena from the outer arena. If any allocations leak to the parent scope I put the code in a local function that takes the parent arena as a parameter. Again, if you’re so inclined you can use Rust or C++ to create smart pointers that catch this at runtime or even compile time, it’s just not a rea…

That's right! I made the example in such a way that it is obvious what the bug is, for pedagogical reasons :-). This particular bug is a bit trickier to spot when you have more complex programs, and is something that I have seen in real (large) codebases. Your inner/outer arena sounds exactly like the same thing, though?

Generally, it's best to avoid the rewind trick, IMO, it makes it difficult to create composable programs.

Re: How do I deal with memory leaks? (2022)

#73
post #61
post #55

Earlier quoted context omitted.

> having to worry about Send and Sync and Pin and fighting with the borrow checker and all that fun stuff. To be fair, the alternative to having to worry about Send/Sync/Pin is not "not worrying about Send/Sync/Pin". It's having to worry about correctly enforcing the constraints they describe on your own, without any kind of mechanical help. E.g., not moving data to another thread that shouldn't be and not accessing…

I don't disagree; I was coming from Java most recently, and a lot of the equivalents of "Sync" and "Send" were just mental notes I was making myself, and I wasn't really used to it being encoded into the type system.

Yeah, and writing thread safe Java is fraught with hidden shotgun and footguns because whether something is thread safe depends on bunch of notes about this class/method not being thread safe.

And relying on people to check them. Versus a compiler.

Re: How do I deal with memory leaks? (2022)

#74
post #60

Earlier quoted context omitted.

> have to understand everything, because if you don't do it in the "Rust way", it often won't compile I confess I haven't dug into it much yet, but this reminds me of how Haskell was. By the time you got a program to compile your project was more or less done.

In some senses I actually find Rust a bit harder than Haskell. With Haskell the types are immutable and as such they can be happily shared everywhere. That required basically no rewiring in my brain. With Rust, I had to get used to single ownership or explicit cloning. There's an argument that this is "better", but I found it a bit harder to learn.

You can choose to make all your things immutable and have the same "no rewiring" as Haskell. Sometimes that's an excellent idea, sometimes it's obviously a terrible idea, many times you'd have to measure to find out and IMHO in Rust you should write the easiest thing in those cases and only measure if your perf isn't acceptable.

Re: How do I deal with memory leaks? (2022)

#75

In raw C, I like to use the "open"/"close" metaphor and when developing, invoke the routes in parallel. For example: https://repo.autonoma.ca/repo/mandelbrot/blob/HEAD/main.c When writing: fractal.image = image_open( fractal.width, fractal.height ); I will immediately write below it: image_close( fractal.image ); This hides memory allocations altogether. As long as the open/close functions are paired up, it gives me…

As you add more code between the "open" and the "close", you introduce more opportunities for control flow to accidentally skip the "close" (leak), or call it more than once (double-free). It forces you to use single-return style, which can make some things very awkward to express.

You're basically doing "defer"-style cleanup manually; you may as well just use the real "defer" if your compiler supports it. It's supposed to be official in a future standard, too.

Re: How do I deal with memory leaks? (2022)

#76
post #41

Earlier quoted context omitted.

> Imagine if this was a new language that the dev community was seeing for the first time. It's hard to imagine it gaining much traction. But it's not a new language. It's backwards compatible with C. So "iterators" behave the same as pointers, since that's how you'd iterate through an array. You can add and subtract, then pass them to other functions. You can't just have a function that returns a vector of strings,…

D doesn't allow pointer arithmetic in @safe code. At first it seems like that cannot work, but it works very well. Pointer arithmetic is relegated to functions that are @system. The reason it works is because D has actual array types. If you choose to use automatic memory management with D, you are memory safe.

I'm referring to C heavily using pointer arithmetic.

If you wanted to make it easier to convert arbitrary functions to use your shiny new resizable type, you end up with something simulator to iterators.

Post reply on HN