top | item 42688375

Ask HN: Why can't C++ compilers find this error?

1 points| greggman7 | 1 year ago

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

    #include <iostream>
    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 <iostream>
    
    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?

3 comments

order

steveklabnik|1 year ago

> 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|1 year ago

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|1 year ago

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...