CppGuard is know part of https://github.com/JochenBaier/BugInsight
CppGuard is developer tool for testing C++ applications made with Visual Studio for deadlocks and wrong lock usage. I can be used manually and within a CI system. CppGuard consists of the DLL cppguard.dll and the header cppguard.h.
CppGuard uses the deadlock detection algorithm from C++ library Abseil. This algorithm will detect a potential deadlock even if the executed program does not actually deadlock. It maintains an acquired-before graph and checks for cycles in this graph. The underlying graph algorithm is described here. There is no relationship between the Abseil project and CppGuard.
- Test applications that cannot be tested on Linux with ThreadSanitizer
- ThreadSanitizer often cannot cover 100% as some program parts are not portable: CppGuard covers this gap
- Test with the Windows operating system on which the program will later run
- Test applications that run too slowly with other Windows OS deadlock test tools
- Test C/C++ DLLs loaded in a Java program ( Java Native Interfaces)
- Test C/C++ DLLs loaded in a .Net program
If locks are acquired in inconsistent order, it depends on the timing whether a deadlock occur or not. Example with 2 threads and mutex a and b:
std::mutex a;
std::mutex b;
//lock order: a -> b
std::thread t1([&]() {
const std::lock_guard<std::mutex> lock_a(a);
const std::lock_guard<std::mutex> lock_b(b);
});
//lock order: b -> a
std::thread t2([&]() {
const std::lock_guard<std::mutex> lock_b(b);
const std::lock_guard<std::mutex> lock_a(a);
});
t1.join();
t2.join();
If t2 will acquired lock b after t1 has locked a and b no deadlock occur. if t1 got lock a and t2 got lock b a deadlock occur.
CppGuard has detected the potential deadlock:
==========================================================================================================
CppGuard: [Error] Potential deadlock at lock: 0x1e2599ebd0, thread ID: 50092.
Lock Call Stack:
C:\dev\cppguard\cppguard\deadlock_monitor.cpp(152,0): deadlock_monitor_t::dlc_deadlock_check_before_lock
C:\dev\cppguard\cppguard\api_monitors\mutex_monitor.cpp(37,0): cppguard_mtx_lock
...
A cycle in the historical lock ordering graph has been observed:
Thread ID: 50092
Holding lock: 0x1e2599ec40
Wait for lock: 0x1e2599ebd0
Call Stack:
C:\dev\cppguard\cppguard\api_monitors\mutex_monitor.cpp(37,0): cppguard_mtx_lock
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\mutex(56,0): std::_Mutex_base::lock
...
Thread ID: 48624
Holding lock: 0x1e2599ebd0
Wait for lock: 0x1e2599ec40
Call Stack:
C:\dev\cppguard\cppguard\api_monitors\mutex_monitor.cpp(37,0): cppguard_mtx_lock
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\mutex(56,0): std::_Mutex_base::lock
...
-
Deadlock detection: A warning or an error is generated if potential deadlock (a cycle) is detected (from Abseil algorithm)
-
Detect wrong lock usage: Detect locks which are released by threads which do no hold them (from Abseil algorithm)
-
Lock watchdog: The time a lock is waiting for a lock or holding a lock is monitored and a log or error is created if a maximum time is exceeded
-
Runs on Windows OS with the native lock APIs of Windows: Critical Section, std::mutex and std::recursive_mutex
-
Test C/C++ DLLs loaded in a Java or a .Net programs
-
Overhead depends on usage. Pretty good for IO bound applications (e.g. TCPI/IP based)
-
Works with Debug, Release and RelWithDebInfo builds
-
For basic usage no source code changes are needed. Minor changes (minimum 2 lines) to the build system (CMake, or Visual Studio Project) are needed
see Quickstart
CppGuard provides:
- cppguard.dll: This DLL and has to be linked to the project to test (import library: cppguard.lib)
- cppguard.h: This header file is automatically included in all source files using Visual Studio option Forced Include File. Macros like #define EnterCriticalSection(x) cppguard_enter_critical_section(x) will intercept the lock API call
-
InitializeCriticalSection(), EnterCriticalSection(), TryEnterCriticalSection(), LeaveCriticalSection(), DeleteCriticalSection()
-
std::mutex, std::recursive_mutex: via internal functions from mutex header_Mtx_*()
-
std::lock_guard, std::unique_lock
- Slim Reader/Writer (SRW) Locks: no DeleteSRWLock() provided, needed to track delete of lock
- std::scoped_lock, std::shared_mutex, std::timed_mutex, std::recursive_timed_mutex std::shared_timed_mutex
see Options
CppGuard is licensed under the terms of the Apache 2.0 license. See LICENSE for more information.