Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Comments on Is it correct to run code inside a method whose object has been destroyed?

Post

Is it correct to run code inside a method whose object has been destroyed?

+8
−0

Consider an object for which a method is invoked. Beyond certain point the method no longer accesses this at all. No read/writes of non-static members. No invocation of non-static methods. Is it safe to destroy such object in another thread after being sure the method has gone beyond such point even if it has not finished executing the whole method?

Consider the following example:

#include <mutex>
#include <condition_variable>
#include <memory>
#include <thread>

class InstrumentedMutex {
public:
  void lock() {
    internalMutex.lock();
  }
  void unlock() {
    internalMutex.unlock();
    printf("unlocked\n"); //A. Maybe undefined behaviour.
    variable = 3;         //B. Undefined behaviour for sure
  }                       //C. Maybe undefined behaviour.
  std::mutex& mutex() {
    return internalMutex;
  }
private:
  std::mutex internalMutex;
  int variable;
};

std::unique_ptr<InstrumentedMutex> instMutex;
std::condition_variable cv;
bool flag = false;

void f1() {
  instMutex->lock();
  flag = true; 
  cv.notify_one();
  instMutex->unlock();
}

int main() {
  instMutex.reset ( new InstrumentedMutex() );
  std::thread extra_thread(f1);
  std::unique_lock<std::mutex> lock(instMutex->mutex());
  cv.wait(lock, []() { return flag; });
  lock.unlock();
  lock.release();
  instMutex.reset(); // Will this cause undefined behaviour
                     // regarding comments A, B and C?
  extra_thread.join();
  return 0;
}

Line with comment B is undefined behaviour for sure because of this possible execution schedule:

     main thread               extra_thread
     -----------               ------------
     cv.wait(lock) // unlocks
     // lock and waits 
                               instMutex->lock();
                               flag=true
                               cv.notify_one()
                               instMutex->unlock() {
                                 internalMutex.unlock(); 
                                 // At this point the cv has been notified
                                 // the flag set and the mutex
                                 // unlocked. So main thread may
                                 // continue

    lock.unlock();
    lock.release();
    instMutex.reset(); 
    // At this point the instMutex
    // object has been destroyed
                               // But here we are executing
                               // "inside" the destroyed object.
                               printf("unlocked\n");
                               variable = 3; // Here we are 
                               // writing to freed memory.

Would line for comment A also be undefined behaviour?

What about line for comment C? Which is meant to be when the method has executed completely (and any destructors for local objects which might reference this have also finished executing), and the method just has to return.

"Has just to return" is not very formal and kind of assumes a stack based implementation. So maybe a better way to express the question regarding line C would be: If a method has no code after a synchronization barrier (not even destructors for local objects), is it always safe to destroy the associated object after ensuring that such synchronization barrier has completed?

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.
Why should this post be closed?

1 comment thread

General comments (4 comments)
General comments
ghost-in-the-zsh‭ wrote almost 4 years ago · edited almost 4 years ago

Legal does not mean moral. Just because you can does not mean you should. This is like asking if playing Russian Roulette with all chambers loaded is ok b/c you keep "assuring" yourself that you have taken "precautions"... in this case, it looks like the code in question shouldn't even be part of the class and knowingly doing something like this is almost the equivalent of booby-trapping your code.

Estela‭ wrote almost 4 years ago

@ghost-in-the-zsh‭ Do you mean lines A, B, C or something else? B is undefined behaviour. After Hyperlinx's answer I see no problem with A and C, self-synchronized objects are common practice. Or maybe you mean method mutex() which returns a reference to a private? Sure, not good practice. This is just a MCVE.

ghost-in-the-zsh‭ wrote almost 4 years ago · edited over 3 years ago

@Estela: Well, the question title itself asking about whether it's "correct to run code inside a method whose object has been destroyed" first makes me wonder why someone would like to, e.g., get object A to destroy some other object B and then try to run object B's code after instance B no longer exists. All of that just seems like a design issue, even if the implementer manages to hack it up to an "it works" state. That's my thought...

Hyperlynx‭ wrote over 3 years ago · edited over 3 years ago

I must be honest, I didn't actually follow through the threads of execution myself to see which specific lines are or aren't legal. I just cut straight to "yes, it is legal to run a method in an object that has been deleted", which is what the question appears to be asking overall, and is true in all cases as far as I'm aware.