0

This answer claims:

The exception object is destroyed when the last catch block that does not exit via a re-throw (i.e. a parameterless throw expression evaluation) completes.

However, this code prints asdf:

#include <iostream>
#include <thread>
#include <stdexcept>

std::exception& get_err() {
  try {
    throw std::runtime_error("asdf");
  } catch (std::exception& e) {
    return e;
  }
}

int main() {
  std::thread t;
  {
    std::exception& err = get_err();
    t = std::thread([&](){
      std::this_thread::sleep_for(std::chrono::seconds(1));
      // is this not a use-after-free error?
      std::cout << err.what() << "\n";
    });
  }
  t.join();

  return 0;
}

Is this undefined behavior? Why can I use a reference to this exception object long after the "last catch block"?

Is the l-value reference to err extending the lifetime of the object (into the thread's lambda)? What if the lifetime wasn't extended, would this still work?

I am on MSVC 2019 C++20, but would be interested in other compilers/standard as well.

MHebes
  • 2,290
  • 1
  • 16
  • 29
  • 3
    It's just Undefined Behavior. You can see it failing when another exception is thrown here : https://godbolt.org/z/7dWM4znhx It's just that, probably, the storage that `what()` points to hasn't been reused or release back to the OS yet. – François Andrieux Oct 04 '22 at 20:01
  • @FrançoisAndrieux thanks, I understood the rules about local variables but wasn't sure how exceptions' lifetimes played into that. You clarified that for me. – MHebes Oct 04 '22 at 20:10

0 Answers0