xhawk18 / promise-cpp

C++ promise/A+ library in Javascript style.
MIT License
672 stars 92 forks source link

Crash on thread exit in multithreaded program #8

Open X547 opened 4 years ago

X547 commented 4 years ago

PM_MULTITHREAD is enabled.

pm_memory_pool::~pm_memory_pool crashes because node == NULL when thread exit.

part of program

Defer GetCredentials()
{
    return newPromise([](Defer d){
        TestWindow *fWnd = new TestWindow(d, BRect(0, 0, 255, 0));
        fWnd->CenterOnScreen();
        fWnd->Show();
    });
}

void TestWindow::MessageReceived(BMessage *msg)
{
    switch (msg->what) {
    case loginBtnPressed: {
        if (!fResolved) {
            fResolved = true;
            fDefer.resolve(fUserField->Text(), fPasswordField->Text());
            PostMessage(B_QUIT_REQUESTED);
        }
        break;
    }
    default:
        BWindow::MessageReceived(msg);
    }
}

TestWindow run in separate thread.

X547 commented 4 years ago

Promise is started with:

void ReadyToRun() {
    GetCredentials().then([](const char *user, const char *password){
        printf("GetCredentials done: \"%s\", \"%s\"\n", user, password);
    }).fail([](){
        printf("GetCredentials failed\n");
    });
}
xhawk18 commented 4 years ago

Hi, because we allocate Defer object on thread_local memory, please check if the thread that calls newPromise(...) keeps alived before the promise object has been destroyed.

X547 commented 4 years ago

Thread that calls newPromise continue running after fDefer.resolve is called. Another thread that calls fDefer.resolve terminate after call and crash.

X547 commented 4 years ago

Stdout with logging enabled:

> make run
objects.x86_64-cc8-debug/MinApp
new 0xe997e5b2d0
add_ref 0xe997e5b2f0
++ 0xe997e5b2d0 0 -> 1
add_ref 0xe997e5b2f0
++ 0xe997e5b2d0 1 -> 2
add_ref 0xe997e5b2f0
++ 0xe997e5b2d0 2 -> 3
add_ref 0xe997e5b2f0
++ 0xe997e5b2d0 3 -> 4
dec_ref 0xe997e5b2f0
-- 0xe997e5b2d0 4 -> 3
dec_ref 0xe997e5b2f0
-- 0xe997e5b2d0 3 -> 2
new 0xe997e67160
add_ref 0xe997e67180
++ 0xe997e67160 0 -> 1
new 0xe997e5b030
add_ref 0xe997e5b050
++ 0xe997e5b030 0 -> 1
add_ref (nil)
dec_ref (nil)
add_ref 0xe997e5b050
++ 0xe997e5b030 1 -> 2
add_ref 0xe997e5b050
++ 0xe997e5b030 2 -> 3
dec_ref (nil)
dec_ref 0xe997e5b050
-- 0xe997e5b030 3 -> 2
add_ref 0xe997e5b050
++ 0xe997e5b030 2 -> 3
dec_ref 0xe997e5b050
-- 0xe997e5b030 3 -> 2
new 0xe997e67120
add_ref 0xe997e67140
++ 0xe997e67120 0 -> 1
new 0xe997e5afc0
add_ref 0xe997e5afe0
++ 0xe997e5afc0 0 -> 1
add_ref (nil)
dec_ref (nil)
add_ref 0xe997e5afe0
++ 0xe997e5afc0 1 -> 2
add_ref 0xe997e5afe0
++ 0xe997e5afc0 2 -> 3
dec_ref (nil)
dec_ref 0xe997e5afe0
-- 0xe997e5afc0 3 -> 2
add_ref 0xe997e5afe0
++ 0xe997e5afc0 2 -> 3
dec_ref 0xe997e5afe0
-- 0xe997e5afc0 3 -> 2
dec_ref 0xe997e5afe0
-- 0xe997e5afc0 2 -> 1
dec_ref 0xe997e5b050
-- 0xe997e5b030 2 -> 1
dec_ref 0xe997e5b2f0
-- 0xe997e5b2d0 2 -> 1
new 0xe997ede840
add_ref 0xe997ede860
++ 0xe997ede840 0 -> 1
add_ref 0xe997e5b2f0
++ 0xe997e5b2d0 1 -> 2
dec_ref 0xe997ede860
-- 0xe997ede840 1 -> 0
--- release = 0xe997ede860
delete 0xe997ede840
GetCredentials done: "user", "password"
new 0xe997edd070
add_ref 0xe997edd090
++ 0xe997edd070 0 -> 1
add_ref 0xe997e5b050
++ 0xe997e5b030 1 -> 2
add_ref 0xe997e5b050
++ 0xe997e5b030 2 -> 3
dec_ref 0xe997e5b050
-- 0xe997e5b030 3 -> 2
dec_ref 0xe997e67180
-- 0xe997e67160 1 -> 0
--- release = 0xe997e67180
delete 0xe997e67160
dec_ref (nil)
add_ref 0xe997e5b050
++ 0xe997e5b030 2 -> 3
new 0xe997edd030
add_ref 0xe997edd050
++ 0xe997edd030 0 -> 1
add_ref 0xe997e5afe0
++ 0xe997e5afc0 1 -> 2
dec_ref 0xe997edd090
-- 0xe997edd070 1 -> 0
--- release = 0xe997edd090
delete 0xe997edd070
dec_ref (nil)
dec_ref 0xe997e67140
-- 0xe997e67120 1 -> 0
--- release = 0xe997e67140
delete 0xe997e67120
add_ref (nil)
dec_ref (nil)
dec_ref 0xe997e5b050
-- 0xe997e5b030 3 -> 2
add_ref 0xe997e5afe0
++ 0xe997e5afc0 2 -> 3
dec_ref 0xe997e5afe0
-- 0xe997e5afc0 3 -> 2
dec_ref 0xe997e5afe0
-- 0xe997e5afc0 2 -> 1
dec_ref 0xe997e5b2f0
-- 0xe997e5b2d0 2 -> 1
add_ref 0xe997e5b050
++ 0xe997e5b030 2 -> 3
dec_ref 0xe997e5b050
-- 0xe997e5b030 3 -> 2
dec_ref 0xe997e5b050
-- 0xe997e5b030 2 -> 1
dec_ref 0xe997e5b2f0
-- 0xe997e5b2d0 1 -> 0
dec_ref (nil)
dec_ref (nil)
dec_ref 0xe997e5b050
-- 0xe997e5b030 1 -> 0
dec_ref (nil)
dec_ref (nil)
dec_ref 0xe997e5afe0
-- 0xe997e5afc0 1 -> 0
dec_ref (nil)
dec_ref (nil)
dec_ref 0xe997edd050
-- 0xe997edd030 1 -> 0
--- release = 0xe997edd050
delete 0xe997edd030
dec_ref (nil)
--- release = 0xe997e5afe0
delete 0xe997e5afc0
--- release = 0xe997e5b050
delete 0xe997e5b030
--- release = 0xe997e5b2f0
delete 0xe997e5b2d0
Makefile:134: recipe for target 'run' failed
make: *** [run] Kill Thread
xhawk18 commented 4 years ago

thank you, there must be some problem if "resolve" thread terminated. i'll check this issue.