Enhance error handling while opening file

In FileManager::loadFileData method:
1. Fix unnecessary GCC crashes when opening larger files in 32-bit Notepad++ binary.
2. Take into account and report correctly also other possible Scintilla error states there (than the previously handled SC_STATUS_BADALLOC).
3. Catch and report correctly also exceptions not handled by the Scintilla exception handler.
4. Catch and report correctly also Notepad++ code exceptions there.

Fix #11103, close #11112
This commit is contained in:
xomx 2022-02-01 02:06:50 +01:00 committed by Don Ho
parent 9baaef786b
commit 85e7207eef
2 changed files with 44 additions and 12 deletions

View File

@ -3,7 +3,7 @@
The comments are here for explanation, it's not necessary to translate them. The comments are here for explanation, it's not necessary to translate them.
--> -->
<NotepadPlus> <NotepadPlus>
<Native-Langue name="English" filename="english.xml" version="8.2.1"> <Native-Langue name="English" filename="english.xml" version="8.3.0">
<Menu> <Menu>
<Main> <Main>
<!-- Main Menu Entries --> <!-- Main Menu Entries -->
@ -1243,6 +1243,7 @@ Do you want to go to Notepad++ page to download the latest version?"/> <!-- HowT
<DocTooDirtyToMonitor title="Monitoring problem" message="The document is dirty. Please save the modification before monitoring it."/> <DocTooDirtyToMonitor title="Monitoring problem" message="The document is dirty. Please save the modification before monitoring it."/>
<DocNoExistToMonitor title="Monitoring problem" message="The file should exist to be monitored."/> <DocNoExistToMonitor title="Monitoring problem" message="The file should exist to be monitored."/>
<FileTooBigToOpen title="File size problem" message="File is too big to be opened by Notepad++"/> <!-- HowToReproduce: Try to open a 4GB file (it's not easy to reproduce, it depends on your system). --> <FileTooBigToOpen title="File size problem" message="File is too big to be opened by Notepad++"/> <!-- HowToReproduce: Try to open a 4GB file (it's not easy to reproduce, it depends on your system). -->
<FileLoadingException title="Exception code: $STR_REPLACE$" message="An error occurred while loading the file!"/>
<CreateNewFileOrNot title="Create new file" message="&quot;$STR_REPLACE$&quot; doesn't exist. Create it?"/> <CreateNewFileOrNot title="Create new file" message="&quot;$STR_REPLACE$&quot; doesn't exist. Create it?"/>
<CreateNewFileError title="Create new file" message="Cannot create the file &quot;$STR_REPLACE$&quot;."/> <!-- HowToReproduce: this message prevents from system failure. It's hard to reproduce. --> <CreateNewFileError title="Create new file" message="Cannot create the file &quot;$STR_REPLACE$&quot;."/> <!-- HowToReproduce: this message prevents from system failure. It's hard to reproduce. -->
<OpenFileError title="ERROR" message="Can not open file &quot;$STR_REPLACE$&quot;."/> <OpenFileError title="ERROR" message="Can not open file &quot;$STR_REPLACE$&quot;."/>

View File

@ -1461,12 +1461,15 @@ bool FileManager::loadFileData(Document doc, int64_t fileSize, const TCHAR * fil
bool success = true; bool success = true;
EolType format = EolType::unknown; EolType format = EolType::unknown;
int sciStatus = SC_STATUS_OK;
TCHAR szException[64] = { 0 };
__try __try
{ {
// First allocate enough memory for the whole file (this will reduce memory copy during loading) // First allocate enough memory for the whole file (this will reduce memory copy during loading)
_pscratchTilla->execute(SCI_ALLOCATE, WPARAM(bufferSizeRequested)); _pscratchTilla->execute(SCI_ALLOCATE, WPARAM(bufferSizeRequested));
if (_pscratchTilla->execute(SCI_GETSTATUS) != SC_STATUS_OK) sciStatus = static_cast<int>(_pscratchTilla->execute(SCI_GETSTATUS));
throw; if ((sciStatus > SC_STATUS_OK) && (sciStatus < SC_STATUS_WARN_START))
throw std::runtime_error("Scintilla error");
size_t lenFile = 0; size_t lenFile = 0;
size_t lenConvert = 0; //just in case conversion results in 0, but file not empty size_t lenConvert = 0; //just in case conversion results in 0, but file not empty
@ -1533,25 +1536,53 @@ bool FileManager::loadFileData(Document doc, int64_t fileSize, const TCHAR * fil
format = getEOLFormatForm(unicodeConvertor->getNewBuf(), unicodeConvertor->getNewSize(), EolType::unknown); format = getEOLFormatForm(unicodeConvertor->getNewBuf(), unicodeConvertor->getNewSize(), EolType::unknown);
} }
if (_pscratchTilla->execute(SCI_GETSTATUS) != SC_STATUS_OK) sciStatus = static_cast<int>(_pscratchTilla->execute(SCI_GETSTATUS));
throw; if ((sciStatus > SC_STATUS_OK) && (sciStatus < SC_STATUS_WARN_START))
throw std::runtime_error("Scintilla error");
if (incompleteMultibyteChar != 0) if (incompleteMultibyteChar != 0)
{ {
// copy bytes to next buffer // copy bytes to next buffer
memcpy(data, data + blockSize - incompleteMultibyteChar, incompleteMultibyteChar); memcpy(data, data + blockSize - incompleteMultibyteChar, incompleteMultibyteChar);
} }
} }
while (lenFile > 0); while (lenFile > 0);
} }
__except(EXCEPTION_EXECUTE_HANDLER) //TODO: should filter correctly for other exceptions; the old filter(GetExceptionCode(), GetExceptionInformation()) was only catching access violations __except(EXCEPTION_EXECUTE_HANDLER)
{ {
pNativeSpeaker->messageBox("FileTooBigToOpen", switch (sciStatus)
_pNotepadPlus->_pEditView->getHSelf(), {
TEXT("File is too big to be opened by Notepad++"), case SC_STATUS_OK:
TEXT("Exception: File size problem"), // either the Scintilla not catched this exception or the error is in the N++ code, report the exception anyway
MB_OK | MB_APPLMODAL); #if defined(__GNUC__)
// there is the std::current_exception() possibility, but getting the real exception code from there requires an ugly hack,
// because of the std::exception_ptr has its members _Data1 (GetExceptionCode) and _Data2 (GetExceptionInformation) private
_stprintf_s(szException, _countof(szException), TEXT("unknown exception"));
#else
_stprintf_s(szException, _countof(szException), TEXT("0x%X (SEH)"), ::GetExceptionCode());
#endif
break;
case SC_STATUS_BADALLOC:
pNativeSpeaker->messageBox("FileTooBigToOpen",
_pNotepadPlus->_pEditView->getHSelf(),
TEXT("File is too big to be opened by Notepad++"),
TEXT("Exception: File size problem"),
MB_OK | MB_APPLMODAL);
case SC_STATUS_FAILURE:
default:
_stprintf_s(szException, _countof(szException), TEXT("%d (Scintilla)"), sciStatus);
break;
}
if (sciStatus != SC_STATUS_BADALLOC)
{
pNativeSpeaker->messageBox("FileLoadingException",
_pNotepadPlus->_pEditView->getHSelf(),
TEXT("An error occurred while loading the file!"),
TEXT("Exception code: $STR_REPLACE$"),
MB_OK | MB_APPLMODAL,
0,
szException);
}
success = false; success = false;
} }