Skip to content

Commit 68d551c

Browse files
authored
Merge pull request #3210 from eduar-hte/shared-files-deadlock
Fixed shared files deadlock in a multi-threaded Windows application
2 parents 630751e + 4b5f719 commit 68d551c

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

src/utils/shared_files.cc

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717

1818
#include <fcntl.h>
1919
#ifdef WIN32
20-
#include <windows.h>
21-
#include <io.h>
20+
#include <algorithm>
2221
#endif
2322

2423

@@ -34,7 +33,32 @@ SharedFiles::handlers_map::iterator SharedFiles::add_new_handler(
3433
return m_handlers.end();
3534
}
3635

37-
return m_handlers.insert({ fileName, {fp, 0} }).first;
36+
#ifdef WIN32
37+
// replace invalid characters for a Win32 named object
38+
auto tmp = fileName;
39+
std::replace(tmp.begin(), tmp.end(), '\\', '_');
40+
std::replace(tmp.begin(), tmp.end(), '/', '_');
41+
42+
// use named mutex for multi-process locking support
43+
const auto mutexName = "Global\\ModSecurity_" + tmp;
44+
45+
HANDLE hMutex = CreateMutex(NULL, FALSE, mutexName.c_str());
46+
if (hMutex == NULL) {
47+
error->assign("Failed to create mutex for shared file: " + fileName);
48+
fclose(fp);
49+
return m_handlers.end();
50+
}
51+
#endif
52+
53+
auto handler = handler_info {
54+
fp,
55+
#ifdef WIN32
56+
hMutex,
57+
#endif
58+
0
59+
};
60+
// cppcheck-suppress resourceLeak ; false positive, fp is closed in SharedFiles::close
61+
return m_handlers.insert({ fileName, handler }).first;
3862
}
3963

4064

@@ -69,6 +93,9 @@ void SharedFiles::close(const std::string& fileName) {
6993
if (it->second.cnt == 0)
7094
{
7195
fclose(it->second.fp);
96+
#ifdef WIN32
97+
CloseHandle(it->second.hMutex);
98+
#endif
7299

73100
m_handlers.erase(it);
74101
}
@@ -92,9 +119,11 @@ bool SharedFiles::write(const std::string& fileName,
92119
lock.l_type = F_WRLCK;
93120
fcntl(fileno(it->second.fp), F_SETLKW, &lock);
94121
#else
95-
auto handle = reinterpret_cast<HANDLE>(_get_osfhandle(fileno(it->second.fp)));
96-
OVERLAPPED overlapped = { 0 };
97-
::LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0, MAXDWORD, MAXDWORD, &overlapped);
122+
DWORD dwWaitResult = WaitForSingleObject(it->second.hMutex, INFINITE);
123+
if (dwWaitResult != WAIT_OBJECT_0) {
124+
error->assign("couldn't lock shared file: " + fileName);
125+
return false;
126+
}
98127
#endif
99128

100129
auto wrote = fwrite(msg.c_str(), 1, msg.size(), it->second.fp);
@@ -109,8 +138,7 @@ bool SharedFiles::write(const std::string& fileName,
109138
lock.l_type = F_UNLCK;
110139
fcntl(fileno(it->second.fp), F_SETLKW, &lock);
111140
#else
112-
overlapped = { 0 };
113-
::UnlockFileEx(handle, 0, MAXDWORD, MAXDWORD, &overlapped);
141+
::ReleaseMutex(it->second.hMutex);
114142
#endif
115143

116144
return ret;

src/utils/shared_files.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919

2020
#include <stdio.h>
21+
#ifdef WIN32
22+
#include <Windows.h>
23+
#endif
2124

2225
#include <unordered_map>
2326
#include <string>
@@ -53,6 +56,9 @@ class SharedFiles {
5356

5457
struct handler_info {
5558
FILE* fp;
59+
#ifdef WIN32
60+
HANDLE hMutex;
61+
#endif
5662
unsigned int cnt;
5763
};
5864

0 commit comments

Comments
 (0)