-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Description
Description of the Issue
While simulating the stalled/blocked/hanged file saving / filecache flushing for the NUL-corruptions issues debugging purposes, I found a bad N++ design - under some circumstances like that blocked file-IO, there is a possibility of multiple entry to the N++ backup_mutex std::mutex from the same thread, resulting in a N++ crash.
Ref: https://en.cppreference.com/w/cpp/thread/mutex/lock
"If lock is called by a thread that already owns the std::mutex, the behavior is undefined: for example, the program may deadlock.
An implementation that can detect the invalid usage is encouraged to throw a std::system_error with error condition
resource_deadlock_would_occur instead of deadlocking."
(Note: In such a case MS C++ throws the _RESOURCE_DEADLOCK_WOULD_OCCUR)
This can lead to loss or corruption of the opened/saved files in N++, as well as failure to save some important configuration files, which are saved when the N++ is being closed (e.g. the session.xml, config.xml, etc.).
STR
Current N++ design allows calling of its FileManager::backupCurrentBuffer() func multiple times from the same thread even before finishing the backup saving there but the file-IO could be slow/blocked, e.g.:
- HW not ready (disk spinning up, waking up from a deep powerstate sleep, a network slowdown/error...)
- busy disk (saving/flushing some other-app big data, etc.)
- user set a too short backup time interval (e.g. 1 sec in the Preferences > Backup > Backup in every ...)
and the file to be saved is bigger and the disk used is not fast enough - possible disk driver errors blocking the IO
- Simulate blocked file-IO by putting superfluous modal MessageBox WINAPI call to the N++
Win32_IO_File::writeorWin32_IO_File::close() - Run that special N++ build.
- Ensure that the N++ Preferences > Backup is ON:

- Either open a new N++ tab, type something in it to make it dirty, wait for the N++ backup-thread crash (default is the 7 secs as is visible in the pic above) or close the N++ (files will be written at the N++ exit ...)
Expected Behavior
N++ handles that (temporarily) "blocked-IO" situation without the crash.
Actual Behavior
N++ will start to pointlessly stack up its NPPM_INTERNAL_SAVEBACKUP messages via the periodically called PostMessage in the Notepad_plus::backupDocument(void * /*param*/) no matter if the backup file-saving can be / is completed or not, the FileManager::backupCurrentBuffer() will be reentered from the same thread causing crash at the std::lock_guard<std::mutex> lock(backup_mutex) .
Proposed solutions
- The simplest (I highly do not recommend that) is the replacing
std::mutexbystd::recursive_mutex. This will only delay the possible crash of the app. Thestd::recursive_mutexhas not its own locking counter method (and its native_handle() method is unfortunately not implemented on the Windows platform) needed for a proper solution. - Use a custom std::mutex solution enhanced by a safe
lockcount()method, as the correct solution is the immediate returning from thatFileManager::backupCurrentBuffer()func when a recursive lock-situation (not finished previous backup) is detected. - A complete change of the N++ backup-design.
@donho
If you agree with the above no.2 proposal, assign me please to this issue, I will try a PR.