From 53bad84e6f63ae3fd64db50ad46803f6686d12d5 Mon Sep 17 00:00:00 2001 From: xomx Date: Sun, 30 Nov 2025 01:54:00 +0100 Subject: [PATCH] Fix crashing when hashing SHA256 for large files Handle possible getFileContent exceptions and add currently missing possibility to signalize the file loading error. (as returning an empty string may not be enough - e.g. for hash calculations, an empty file for hashing is also a valid case...) Fix #17243, close #17252 --- PowerEditor/src/MISC/Common/Common.cpp | 59 ++++++++++++++----- PowerEditor/src/MISC/Common/Common.h | 2 +- .../src/MISC/Common/verifySignedfile.cpp | 6 +- PowerEditor/src/MISC/md5/md5Dlgs.cpp | 5 +- PowerEditor/src/Notepad_plus_Window.cpp | 36 ++++++----- PowerEditor/src/Parameters.cpp | 12 ++-- 6 files changed, 81 insertions(+), 39 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 845aeaf91..a3edd4a90 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -50,26 +50,53 @@ wstring commafyInt(size_t n) return ss.str(); } -std::string getFileContent(const wchar_t *file2read) +std::string getFileContent(const wchar_t* file2read, bool* pbFailed) { + if (pbFailed) + *pbFailed = false; // reset + if (!doesFileExist(file2read)) - return ""; - - const size_t blockSize = 1024; - char data[blockSize]; - std::string wholeFileContent = ""; - FILE *fp = _wfopen(file2read, L"rb"); - if (!fp) - return ""; - - size_t lenFile = 0; - do { - lenFile = fread(data, 1, blockSize, fp); - if (lenFile == 0) break; - wholeFileContent.append(data, lenFile); + if (pbFailed) + *pbFailed = true; + return ""; + } + + FILE* fp = _wfopen(file2read, L"rb"); + if (!fp) + { + if (pbFailed) + *pbFailed = true; + return ""; + } + + static constexpr size_t blockSize = 1024 * 4; // 4K is optimal chunk for memory, cache, disk or network + char data[blockSize]; + std::string wholeFileContent; + size_t lenFile = 0; + try + { + do + { + lenFile = fread(data, 1, blockSize, fp); + if (lenFile == 0) break; + wholeFileContent.append(data, lenFile); + } while (lenFile > 0); + } + catch ([[maybe_unused]] const std::bad_alloc& ex) + { + if (pbFailed) + *pbFailed = true; + std::string().swap(wholeFileContent); // to immediately release all the allocated memory + ::MessageBoxW(NULL, L"std::bad_alloc exception caught!\n\nProbably not enough contiguous memory to complete the operation.", + L"Notepad++ - getFileContent", MB_OK | MB_ICONWARNING | MB_APPLMODAL); + } + catch (...) + { + if (pbFailed) + *pbFailed = true; + std::string().swap(wholeFileContent); // to immediately release all the allocated memory } - while (lenFile > 0); fclose(fp); return wholeFileContent; diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index 54bed0dd6..c13ae75ef 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -56,7 +56,7 @@ std::string wstring2string(const std::wstring & rwString, UINT codepage); bool isInList(const wchar_t *token, const wchar_t *list); std::wstring BuildMenuFileName(int filenameLen, unsigned int pos, const std::wstring &filename, bool ordinalNumber = true); -std::string getFileContent(const wchar_t *file2read); +std::string getFileContent(const wchar_t* file2read, bool* pbFailed = nullptr); std::wstring relativeFilePathToFullFilePath(const wchar_t *relativeFilePath); void writeFileContent(const wchar_t *file2write, const char *content2write); bool matchInList(const wchar_t *fileName, const std::vector & patterns); diff --git a/PowerEditor/src/MISC/Common/verifySignedfile.cpp b/PowerEditor/src/MISC/Common/verifySignedfile.cpp index da2a2121c..e7f9d028f 100644 --- a/PowerEditor/src/MISC/Common/verifySignedfile.cpp +++ b/PowerEditor/src/MISC/Common/verifySignedfile.cpp @@ -72,7 +72,11 @@ bool SecurityGuard::checkSha256(const std::wstring& filePath, NppModule module2c return true; */ - std::string content = getFileContent(filePath.c_str()); + bool bLoadingFailed = false; + std::string content = getFileContent(filePath.c_str(), &bLoadingFailed); + if (bLoadingFailed) + return false; + uint8_t sha2hash[32]; calc_sha_256(sha2hash, reinterpret_cast(content.c_str()), content.length()); diff --git a/PowerEditor/src/MISC/md5/md5Dlgs.cpp b/PowerEditor/src/MISC/md5/md5Dlgs.cpp index bf43d1d11..19876e610 100644 --- a/PowerEditor/src/MISC/md5/md5Dlgs.cpp +++ b/PowerEditor/src/MISC/md5/md5Dlgs.cpp @@ -148,7 +148,10 @@ intptr_t CALLBACK HashFromFilesDlg::run_dlgProc(UINT message, WPARAM wParam, LPA } else { - std::string content = getFileContent(it.c_str()); + bool bLoadingFailed = false; + std::string content = getFileContent(it.c_str(), &bLoadingFailed); + if (bLoadingFailed) + return FALSE; uint8_t hash[HASH_MAX_LENGTH]{}; wchar_t hashStr[HASH_STR_MAX_LENGTH]{}; diff --git a/PowerEditor/src/Notepad_plus_Window.cpp b/PowerEditor/src/Notepad_plus_Window.cpp index b23b1aa46..e20833c63 100644 --- a/PowerEditor/src/Notepad_plus_Window.cpp +++ b/PowerEditor/src/Notepad_plus_Window.cpp @@ -376,24 +376,28 @@ void Notepad_plus_Window::init(HINSTANCE hInst, HWND parent, const wchar_t *cmdL { if (doesFileExist(cmdLineParams->_easterEggName.c_str())) { - std::string content = getFileContent(cmdLineParams->_easterEggName.c_str()); - WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance(); - _userQuote = wmc.char2wchar(content.c_str(), SC_CP_UTF8); - if (!_userQuote.empty()) + bool bLoadingFailed = false; + std::string content = getFileContent(cmdLineParams->_easterEggName.c_str(), &bLoadingFailed); + if (!bLoadingFailed) { - _quoteParams.reset(); - _quoteParams._quote = _userQuote.c_str(); - _quoteParams._quoter = L"Anonymous #999"; - _quoteParams._shouldBeTrolling = false; - _quoteParams._lang = cmdLineParams->_langType; - if (cmdLineParams->_ghostTypingSpeed == 1) - _quoteParams._speed = QuoteParams::slow; - else if (cmdLineParams->_ghostTypingSpeed == 2) - _quoteParams._speed = QuoteParams::rapid; - else if (cmdLineParams->_ghostTypingSpeed == 3) - _quoteParams._speed = QuoteParams::speedOfLight; + WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance(); + _userQuote = wmc.char2wchar(content.c_str(), SC_CP_UTF8); + if (!_userQuote.empty()) + { + _quoteParams.reset(); + _quoteParams._quote = _userQuote.c_str(); + _quoteParams._quoter = L"Anonymous #999"; + _quoteParams._shouldBeTrolling = false; + _quoteParams._lang = cmdLineParams->_langType; + if (cmdLineParams->_ghostTypingSpeed == 1) + _quoteParams._speed = QuoteParams::slow; + else if (cmdLineParams->_ghostTypingSpeed == 2) + _quoteParams._speed = QuoteParams::rapid; + else if (cmdLineParams->_ghostTypingSpeed == 3) + _quoteParams._speed = QuoteParams::speedOfLight; - _notepad_plus_plus_core.showQuote(&_quoteParams); + _notepad_plus_plus_core.showQuote(&_quoteParams); + } } } } diff --git a/PowerEditor/src/Parameters.cpp b/PowerEditor/src/Parameters.cpp index 16e2a8292..36e9a82eb 100644 --- a/PowerEditor/src/Parameters.cpp +++ b/PowerEditor/src/Parameters.cpp @@ -1238,10 +1238,14 @@ bool NppParameters::load() if (_isCloud) { // Read cloud choice - std::string cloudChoiceStr = getFileContent(cloudChoicePath.c_str()); - WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance(); - std::wstring cloudChoiceStrW = wmc.char2wchar(cloudChoiceStr.c_str(), SC_CP_UTF8); - + std::wstring cloudChoiceStrW = L""; + bool bLoadingFailed = false; + std::string cloudChoiceStr = getFileContent(cloudChoicePath.c_str(), &bLoadingFailed); + if (!bLoadingFailed) + { + WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance(); + cloudChoiceStrW = wmc.char2wchar(cloudChoiceStr.c_str(), SC_CP_UTF8); + } if (!cloudChoiceStrW.empty() && doesDirectoryExist(cloudChoiceStrW.c_str())) { _userPath = cloudChoiceStrW;