Skip to content

possible crash when recursively entering the Notepad++ backup_mutex #14906

@xomx

Description

@xomx

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
  1. Simulate blocked file-IO by putting superfluous modal MessageBox WINAPI call to the N++ Win32_IO_File::write or Win32_IO_File::close()
  2. Run that special N++ build.
  3. Ensure that the N++ Preferences > Backup is ON:
    npp-pref-backup
  4. 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

  1. The simplest (I highly do not recommend that) is the replacing std::mutex by std::recursive_mutex. This will only delay the possible crash of the app. The std::recursive_mutex has not its own locking counter method (and its native_handle() method is unfortunately not implemented on the Windows platform) needed for a proper solution.
  2. Use a custom std::mutex solution enhanced by a safe lockcount() method, as the correct solution is the immediate returning from that FileManager::backupCurrentBuffer() func when a recursive lock-situation (not finished previous backup) is detected.
  3. 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.

Metadata

Metadata

Assignees

Labels

bugcrashissue causing N++ to crash

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions