symisc / unqlite

An Embedded NoSQL, Transactional Database Engine

Home Page:https://unqlite.symisc.net

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

multiprocess access crash

mike07026 opened this issue · comments

version: unqlite 1.1.9 (master branch)
platform : mac, windows
description: multiprocess access crash

how to reproduce:
step 1: start process A, open db, write, commit and wait forever(keep database open)
step 2: start process B, open db, write, commit, write commit, and crash!

[process A] main.cpp

extern "C" {
#include "unqlite.h"
}
#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char * argv[]) {
    
    unqlite* db = NULL;
    int ret = UNQLITE_OK;
    
    do {
        ret = unqlite_open(&db, "/Users/ali/code/test.db", UNQLITE_OPEN_CREATE);
        if (ret != UNQLITE_OK) break;
        ret = unqlite_kv_store(db, "key", 3, "value", 5);
        if (ret != UNQLITE_OK) break;
        ret = unqlite_commit(db);
        if (ret != UNQLITE_OK) break;
        
    } while(0);
    
    if (ret == UNQLITE_OK) {
        printf("process A: db test ready\n");
    }
    else {
        printf("process A: db test fail");
    }

    while(1) {
        getchar(); // wait forever
    }
    
    return 0;
}

[process B] main.cpp

extern "C" {
#include "unqlite.h"
}
#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char * argv[]) {
    
    unqlite* db = NULL;
    
    unqlite_open(&db, "/Users/ali/code/test.db", UNQLITE_OPEN_CREATE);
        
    unqlite_begin(db);
    unqlite_kv_store(db, "key", 3, "value", 5);
    unqlite_commit(db);
        
    unqlite_begin(db);
    unqlite_kv_store(db, "key", 3, "value", 5);
    printf("process B, i am going to crash");
    unqlite_commit(db); // crash here
    
    return 0;
}

[process B backtrace]

Thread 1 Queue : com.apple.main-thread (serial)
#0	0x000000010001aa5c in unqliteOsWrite at /Users/ali/code/dev_test/test_unqlite_2/test_unqlite_2/unqlite.c:52480
#1	0x000000010001bad5 in WriteInt32 at /Users/ali/code/dev_test/test_unqlite_2/test_unqlite_2/unqlite.c:55574
#2	0x000000010001b63f in unqliteFinalizeJournal at /Users/ali/code/dev_test/test_unqlite_2/test_unqlite_2/unqlite.c:56961
#3	0x0000000100067240 in pager_commit_phase1 at /Users/ali/code/dev_test/test_unqlite_2/test_unqlite_2/unqlite.c:57152
#4	0x00000001000092c5 in unqlitePagerCommit at /Users/ali/code/dev_test/test_unqlite_2/test_unqlite_2/unqlite.c:57290
#5	0x0000000100009297 in unqlite_commit at /Users/ali/code/dev_test/test_unqlite_2/test_unqlite_2/unqlite.c:6190
#6	0x0000000100067cc2 in main at /Users/ali/code/dev_test/test_unqlite_2/test_unqlite_2/main.cpp:22
#7	0x00000001000b94fe in start ()

Hi @mike07026,

Thanks for reporting this bug. We were effectively be able to reproduce this extremely rare bug where two distinct process share the same database, one hangs, the other tries to open a journal file without success due to a failure to acquire an exclusive lock on the database.
The crash cause is a null pointer dereferencing on the function unqliteFinalizeJournal() when UnQLite tries to finalize the journal file. The crash could be easily avoided by the checking the return code of each UnQLite public function rc != UNQLITE_OK

The latest hot patch fix the whole issue. Please update as soon as possible.

Hi @mike07026,

Thanks for reporting this bug. We were effectively be able to reproduce this extremely rare bug where two distinct process share the same database, one hangs, the other tries to open a journal file without success due to a failure to acquire an exclusive lock on the database. The crash cause is a null pointer dereferencing on the function unqliteFinalizeJournal() when UnQLite tries to finalize the journal file. The crash could be easily avoided by the checking the return code of each UnQLite public function rc != UNQLITE_OK

The latest hot patch fix the whole issue. Please update as soon as possible.

@symisc Thank you very much. And I will test it later ^_^