Details
-
Bug
-
Resolution: Done
-
P3: Somewhat important
-
None
-
5.12.1
-
None
Description
In the windows implementation of PCRE, the function allocator_grab_lock used when jit-compiling an expression has a race condition:
static HANDLE global_mutex = 0; SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_grab_lock(void) { /* No idea what to do if an error occures. Static mutexes should never fail... */ if (!global_mutex) global_mutex = CreateMutex(NULL, TRUE, NULL); else WaitForSingleObject(global_mutex, INFINITE); }
Multiple threads can attempt to initialize the mutex at the same time, leading sometimes to memory corruption/crashes, and sometimes to deadlocks.
The following dummy test case reproduces the problem fairly frequently on my computer:
#include <QApplication> #include <QSemaphore> #include <QThread> #include <QRegularExpression> QSemaphore sem1, sem2; struct Worker : public QThread { virtual void run() override { sem1.acquire(); QRegularExpression("\\d+").optimize(); sem2.release(); } static void msleep(int ms) { QThread::msleep(ms); } }; int main(int argc, char* argv[]) { QApplication app(argc, argv); const int N = 100; for (int i = 0; i < N; i++) (new Worker)->start(); Worker::msleep(1000); sem1.release(N); sem2.acquire(N); return 0; }
A workaround is to optimize a dummy QRegularExpression in the main thread before using regexes in other threads.
The bug has also been reported to PCRE : https://bugs.exim.org/show_bug.cgi?id=2377