Is it legal for a second thread to delete an object while a first thread is still potentially inside a member function of that object, if the deletion occurs after the last (explicit) field access inside that function?
This will probably be clearer with an example:
#include <thread>
#include <atomic>
struct handoff {
std::atomic<int> flag{};
void signal() { flag = 1; }
};
int main() {
auto h = new handoff;
auto t2 = std::thread([=]{
while (!h->flag) {
}
delete h;
});
h->signal();
t2.join();
}
Here, the handoff h object is used to communicate between T1 (the main thread) and T2. The flag field is initially zero, and T2 waits until it becomes non-zero then immediately deletes the h object. T1 calls h->signal() which sets the flag to non-zero. So the object will be deleted (by T2) while T1 is still potentially "inside" the signal() call. However, there are no further accesses to any fields of the handoff object in signal().
Is it defined behavior? I think it is clear that calling a member function (even an empty one) is UB after an object has been deleted, but how about returning from one?
TSAN thinks this is OK and I agree in practice this will work fine on sane architectures.
Your code is safe. There is no such concept of being "inside" an object. You either access (as in: read write) the object or not. Method or not, its just a function. However in your concrete case accessing this after flag = 1 line in signal method is not safe. So it is a matter of concrete code, not of being inside or not.
Also you are correct that calling a member function after delete is UB. But that's not the case. The "call" event already happened before delete, that is not UB.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With