HACKER Q&A
📣 greggman7

Why can't C++ compilers find this error?


Debugging some 3rd party library I ran into a "reference a stack object that no longer exists" error. repo

    #include 
    int* f() { int x = 4; int* xp = &x; return xp; }
    
    int main() {
        int* p = f();
        std::cout << *p;
    }
Without giving it much thought, why is this hard for a modern C++ compiler to detect?

Note that gcc will detect some of these

    #include 
    
    int main() {
        int* p;
        { int j = 123; p = &j; }
        std::cout << *p;
    }
Gets an error in gcc (not in clang)

I know this type of issue is a strong reason people prefer rust but I'm still surprised a modern C++ compile doesn't find these issues. Is it an intractable issue?


  👤 steveklabnik Accepted Answer ✓
> Without giving it much thought, why is this hard for a modern C++ compiler to detect?

It is hard in the general case because none of the operations individually are a problem: "create a variable on the stack", "create a pointer to a variable on the stack", and "return a pointer" are all valid operations. It's the last two together that become a problem. And there's no mechanism in C++ to connect the two together, so that this case can be recognized and protected against. Compilers can try, and see some obvious cases, like you've noticed, but it's going to be a conservative analysis at best.

> Is it an intractable issue?

In some sense, yes, in others, no. Solving it correctly in 100% of cases is not going to happen. But they're working on some things that will hopefully catch most cases. We are supposed to get some more news on that soon, we'll see.


👤 FrankWilhoit
Back in the 1990s, Borland Turbo C permitted this -- it even worked in some DOS memory models, because it depended on the 8088 or 80286 segment registers not being reused. I had to teach a cohort of developers who were migrating from Turbo C to a C89-compliant compiler. In C89 this was "undefined behavior".

👤 stefanos82
Well with the help of `-fsanitize=address,undefined` flag, it can possibly catch it.

If you use the aforementioned flag and still face this issue, then you can try `-fanalyzer` combined with `-Wanalyzer-too-complex` and hopefully the static analyzer will return something.

For more info, read https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.h...