Hacker News new | ask | show | jobs
by banachtarski 1918 days ago
> 1: At work a frequent issue in C++ is UAF a pointer to a stack variable which outlives the function, Zig don't help you here..

Sorry but if this sort of UAF is actually frequent, I would hazard a guess that your coworkers would struggle in pretty much any language? RAII-based lifetime management really isn't that difficult, and the type of bug you are referring to isn't even subtle.

5 comments

I disagree, as there are lots of ways it can manifest in C++. To list a few examples:

- Implicit lambda capture where you use & (admittedly often out of laziness).

- A string_view constructed from an accidental string copy (e.g. if your function parameter is a const std::string instead of a const std::string&, or if you write for (auto foo : v) { ... }).

- A callback that references some member variables of some object on the stack, which usually completes before the function returns (but maybe you forget to synchronize in an edge case).

Tooling can help identify a number of these issues, but it's not perfect. And a number of these issues are very much C++-specific.

If you can make some mistake, it's only a matter of time until someone will make it. This scales with the codebase size. And you only need one person to make the mistake and another to miss it in review - it doesn't matter if everyone else is a 40 years of experience coder.
"Nobody would write that type of code, and if they did, you should just get better programmers" is such a common theme in these discussions.

... yet every time time I've been told "you don't need Rust, just use C++", I can point to at least one UAF in their own code, and have even pointed to CVEs on Mitre for their own projects!

People make mistakes. Use tools that stop these mistakes, rather than helping you to "write code faster" like in the article (aka writing bugs faster).

“If debugging is the process of removing bugs, then programming must be the process of putting them in.” -- Dykstra's Observation
I dunno what you’re saying; this kind of bug also proves difficult to avoid in large, security-critical projects like web browser engines.
D is very good at detecting dangling pointers into the stack at compile time.
Usually I think tooling is fairly good at catching these; I feel like misuse of dynamic memory allocation is usually harder to catch these days.
Provided developers actually bother to use it.

Most surveys place the use of such tooling around 11%, which is why all major OS vendors are pushing for hardware memory tagging, as by then is no way to avoid using them.

All three of the web browser engines are extremely heavy users of these tools; actually they are often the ones that develop and contribute to them.
A negligible amount of source code when placed against the amount of C , C++ and Objective-C written daily across the globe.

Those browsers are part of the 11% mentioned above.

They’re talking specifically of pointers to the stack.
I agree and don't understand why this would be controversial.

There are plenty of aspects of programming that need systematic solutions instead of just telling people to get better, but returning pointers to the stack should not be high on that list.

If people are doing that, it means they don't understand what they are doing or aren't thinking about what they are writing, probably both. It is much easier to return regular data structures.

In modern C++ it is rare that a raw pointer should be returned in the first place. I wouldn't be sure what to think if I had a team full of people consistently and frequently returning pointers to the stack frame of the function they came from.

It doesn’t happen very often but each time there was a new developer on the team they made such mistake, that’s a way to teach them about valgrind (what a wonderful software!) I guess. We work in a ‘low latency’ domain where heap allocation is avoided, this may explain that it happens more often to us.
Why would avoiding heap allocation explain it? Why is anyone getting the address of a stack allocated variable in the first place since it already in scope? What are people returning pointers from functions at all?
>I would hazard a guess that your coworkers would struggle in pretty much any language?

Uh? This issue wouldn't happen in Java because everything is heap(GC) allocated. Which is probably why developers new to C++ have this issue.

Walter Bright said below that the D compiler find most of these issue at compile time, well that's nice for D but unfortunately that isn't the case for C++ at least not for gcc9.

Doing what D does to detect references to expired stack frames would require some restructuring of C++'s semantics, which seems unlikely. For example, D can detect this error:

    @safe:

    int* f(int* p) { return p; }

    int* g() { int i; return f(&i); }
Compile with:

    dmd test -dip1000
and the result:

    Error: reference to local variable i assigned to non-scope parameter p calling test.f
At -O2 or above, gcc emits Wreturn-local-addr.
Yep, ‘-O2 or above’ we used to compile our UTs without optimizations because otherwise it takes too long, but now we have an additional(less frequent) CI job for UT with optimizations to benefit from these improved error detection.
Within a single compilation unit, and only in this most trivial case.
Here's an example of a much more complex case that is detected:

https://issues.dlang.org/show_bug.cgi?id=21745

Yes, sorry if my comment isn't clear. D is very capable in this regard. While gcc with C/C++ code will spot a few trivial cases... including the one in the example above.