From df4e8f5b736ee9759196bea23eea78f8c3cf69e7 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Fri, 31 May 2024 02:07:51 +0200 Subject: [PATCH] Fix integer overflow issue in Column Editor Fix #15167, close #15222 --- .../ScintillaComponent/ScintillaEditView.cpp | 136 +++--------------- .../ScintillaComponent/ScintillaEditView.h | 104 +++++++++++++- .../src/ScintillaComponent/columnEditor.cpp | 49 ++++--- 3 files changed, 145 insertions(+), 144 deletions(-) diff --git a/PowerEditor/src/ScintillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScintillaComponent/ScintillaEditView.cpp index 6f94e3040..2bed802bb 100644 --- a/PowerEditor/src/ScintillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScintillaComponent/ScintillaEditView.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see . #include +#include #include #include #include @@ -163,11 +164,9 @@ LanguageNameInfo ScintillaEditView::_langNameInfoArray[L_EXTERNAL + 1] = { }; -int getNbDigits(int aNum, int base) +size_t getNbDigits(size_t aNum, size_t base) { - if (base <= 0) return 0; - - int nbDigits = 0; + size_t nbDigits = 0; do { @@ -3658,92 +3657,6 @@ bool ScintillaEditView::expandWordSelection() return false; } -TCHAR* int2str(TCHAR* str, int strLen, int number, int base, int nbDigits, ColumnEditorParam::leadingChoice lead) -{ - if (nbDigits <= 0 || nbDigits >= strLen) return NULL; - - if (base == 2) - { - const unsigned int MASK_ULONG_BITFORT = 0x80000000; - int nbBits = sizeof(unsigned int) * 8; - int nbBit2Shift = (nbDigits >= nbBits) ? nbBits : (nbBits - nbDigits); - unsigned long mask = MASK_ULONG_BITFORT >> nbBit2Shift; - int i = 0; - for (; mask > 0; ++i) - { - str[i] = (mask & number) ? '1' : '0'; - mask >>= 1; - } - str[i] = '\0'; - // str is now leading zero padded - - if (lead == ColumnEditorParam::spaceLeading) - { - // replace leading zeros with spaces - for (TCHAR* j = str; *j != '\0'; ++j) - { - if ((*j == '1') || (*(j + 1) == '\0')) - { - break; - } - else - { - *j = ' '; - } - } - } - else if (lead != ColumnEditorParam::zeroLeading) - { - // left-align within the field width, i.e. pad on right with space - - // first, remove leading zeros - for (TCHAR* j = str; *j != '\0'; ++j) - { - if (*j == '1' || *(j + 1) == '\0') - { - wcscpy_s(str, strLen, j); - break; - } - } - // add trailing spaces to pad out to field width - int i = lstrlen(str); - for (; i < nbDigits; ++i) - { - str[i] = ' '; - } - str[i] = '\0'; - } - } - else - { - constexpr size_t bufSize = 64; - TCHAR f[bufSize] = { '\0' }; - - TCHAR fStr[2] = TEXT("d"); - if (base == 16) - fStr[0] = 'X'; - else if (base == 8) - fStr[0] = 'o'; - - if (lead == ColumnEditorParam::zeroLeading) - { - swprintf(f, bufSize, TEXT("%%.%d%s"), nbDigits, fStr); - } - else if (lead == ColumnEditorParam::spaceLeading) - { - swprintf(f, bufSize, TEXT("%%%d%s"), nbDigits, fStr); - } - else - { - // left-align within the field width, i.e. pad on right with space - swprintf(f, bufSize, TEXT("%%-%d%s"), nbDigits, fStr); - } - // use swprintf (or sprintf) instead of wsprintf to make octal format work! - swprintf(str, strLen, f, number); - } - - return str; -} ColumnModeInfos ScintillaEditView::getColumnModeSelectInfo() { @@ -3821,7 +3734,7 @@ void ScintillaEditView::columnReplace(ColumnModeInfos & cmi, const TCHAR *str) } } -void ScintillaEditView::columnReplace(ColumnModeInfos & cmi, int initial, int incr, int repeat, UCHAR format, ColumnEditorParam::leadingChoice lead) +void ScintillaEditView::columnReplace(ColumnModeInfos & cmi, size_t initial, size_t incr, size_t repeat, UCHAR format, ColumnEditorParam::leadingChoice lead) { assert(repeat > 0); @@ -3849,32 +3762,29 @@ void ScintillaEditView::columnReplace(ColumnModeInfos & cmi, int initial, int in base = 2; const int stringSize = 512; - TCHAR str[stringSize]; + char str[stringSize]; // Compute the numbers to be placed at each column. - std::vector numbers; + std::vector numbers; + + size_t curNumber = initial; + const size_t kiMaxSize = cmi.size(); + while (numbers.size() < kiMaxSize) { - int curNumber = initial; - const size_t kiMaxSize = cmi.size(); - while (numbers.size() < kiMaxSize) + for (size_t i = 0; i < repeat; i++) { - for (int i = 0; i < repeat; i++) + numbers.push_back(curNumber); + if (numbers.size() >= kiMaxSize) { - numbers.push_back(curNumber); - if (numbers.size() >= kiMaxSize) - { - break; - } + break; } - curNumber += incr; } + curNumber += incr; } - assert(numbers.size()> 0); - - const int kibEnd = getNbDigits(*numbers.rbegin(), base); - const int kibInit = getNbDigits(initial, base); - const int kib = std::max(kibInit, kibEnd); + const size_t kibEnd = getNbDigits(*numbers.rbegin(), base); + const size_t kibInit = getNbDigits(initial, base); + const size_t kib = std::max(kibInit, kibEnd); intptr_t totalDiff = 0; const size_t len = cmi.size(); @@ -3888,7 +3798,7 @@ void ScintillaEditView::columnReplace(ColumnModeInfos & cmi, int initial, int in cmi[i]._selLpos += totalDiff; cmi[i]._selRpos += totalDiff; - int2str(str, stringSize, numbers.at(i), base, kib, lead); + variedFormatNumber2String(str, stringSize, numbers.at(i), base, kib, lead); const bool hasVirtualSpc = cmi[i]._nbVirtualAnchorSpc > 0; if (hasVirtualSpc) // if virtual space is present, then insert space @@ -3901,15 +3811,11 @@ void ScintillaEditView::columnReplace(ColumnModeInfos & cmi, int initial, int in cmi[i]._selRpos += cmi[i]._nbVirtualCaretSpc; } execute(SCI_SETTARGETRANGE, cmi[i]._selLpos, cmi[i]._selRpos); - - WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance(); - size_t cp = execute(SCI_GETCODEPAGE); - const char *strA = wmc.wchar2char(str, cp); - execute(SCI_REPLACETARGET, static_cast(-1), reinterpret_cast(strA)); + execute(SCI_REPLACETARGET, static_cast(-1), reinterpret_cast(str)); if (hasVirtualSpc) { - totalDiff += cmi[i]._nbVirtualAnchorSpc + lstrlen(str); + totalDiff += cmi[i]._nbVirtualAnchorSpc + strlen(str); // Now there's no more virtual space cmi[i]._nbVirtualAnchorSpc = 0; cmi[i]._nbVirtualCaretSpc = 0; diff --git a/PowerEditor/src/ScintillaComponent/ScintillaEditView.h b/PowerEditor/src/ScintillaComponent/ScintillaEditView.h index 396914cc8..ca837a34a 100644 --- a/PowerEditor/src/ScintillaComponent/ScintillaEditView.h +++ b/PowerEditor/src/ScintillaComponent/ScintillaEditView.h @@ -245,10 +245,106 @@ const std::vector> g_nonPrintingChars = {"\xEF\xBF\xBB", "IAT", "U+FFFB"} // U+FFFB : interlinear annotation terminator }; -int getNbDigits(int aNum, int base); -//HMODULE loadSciLexerDll(); +size_t getNbDigits(size_t aNum, size_t base); -TCHAR* int2str(TCHAR* str, int strLen, int number, int base, int nbDigits, ColumnEditorParam::leadingChoice lead); +template +T* variedFormatNumber2String(T* str, size_t strLen, size_t number, size_t base, size_t nbDigits, ColumnEditorParam::leadingChoice lead) +{ + if (nbDigits == 0 || nbDigits >= strLen) return NULL; + + // + // Reset the output string + // + memset(str, 0, sizeof(T) * strLen); + + // + // Form number string according its base + // + std::string numberStr; + + if (base == 2) + { + std::string tmpStr; + size_t aNum = number; + do + { + tmpStr += aNum % 2 ? "1" : "0"; + aNum = aNum / 2; + + } while (aNum != 0); + + size_t i = 0; + size_t j = tmpStr.length() - 1; + for (; j >= 0 && i < tmpStr.length(); i++, j--) + { + numberStr += tmpStr[j]; + } + } + else if (base == 8) + { + std::stringstream stream; + stream << std::oct << number; + numberStr = stream.str(); + } + else if (base == 16) + { + std::stringstream stream; + stream << std::hex << number; + numberStr = stream.str(); + } + else //if (base == 10) + { + numberStr = std::to_string(number); + } + + size_t numberStrLen = numberStr.length(); + size_t noneUsedZoneLen = nbDigits - numberStrLen; + + size_t nbStart = 0; + size_t nbEnd = 0; + + size_t noneUsedStart = 0; + size_t noneUsedEnd = 0; + + T noUsedSymbol = ' '; + + // + // Determinate leading zero/space or none + // + if (lead == ColumnEditorParam::spaceLeading) + { + noneUsedStart = 0; + noneUsedEnd = nbStart = noneUsedZoneLen; + nbEnd = nbDigits; + } + else if (lead == ColumnEditorParam::zeroLeading) + { + noUsedSymbol = '0'; + + noneUsedStart = 0; + noneUsedEnd = nbStart = noneUsedZoneLen; + nbEnd = nbDigits; + } + else //if (lead != ColumnEditorParam::noneLeading) + { + nbStart = 0; + nbEnd = noneUsedStart = numberStrLen; + noneUsedEnd = nbDigits; + } + + // + // Fill str with the correct position + // + size_t i = 0; + for (size_t k = nbStart; k < nbEnd; ++k) + str[k] = numberStr[i++]; + + size_t j = 0; + for (j = noneUsedStart; j < noneUsedEnd; ++j) + str[j] = noUsedSymbol; + + return str; +} typedef LRESULT (WINAPI *CallWindowProcFunc) (WNDPROC,HWND,UINT,WPARAM,LPARAM); @@ -687,7 +783,7 @@ public: ColumnModeInfos getColumnModeSelectInfo(); void columnReplace(ColumnModeInfos & cmi, const TCHAR *str); - void columnReplace(ColumnModeInfos & cmi, int initial, int incr, int repeat, UCHAR format, ColumnEditorParam::leadingChoice lead); + void columnReplace(ColumnModeInfos & cmi, size_t initial, size_t incr, size_t repeat, UCHAR format, ColumnEditorParam::leadingChoice lead); void clearIndicator(int indicatorNumber) { size_t docStart = 0; diff --git a/PowerEditor/src/ScintillaComponent/columnEditor.cpp b/PowerEditor/src/ScintillaComponent/columnEditor.cpp index 420a88bf6..e415c67be 100644 --- a/PowerEditor/src/ScintillaComponent/columnEditor.cpp +++ b/PowerEditor/src/ScintillaComponent/columnEditor.cpp @@ -172,7 +172,7 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR (*_ppEditView)->execute(SCI_BEGINUNDOACTION); constexpr int stringSize = 1024; - TCHAR str[stringSize]{}; + wchar_t str[stringSize]{}; bool isTextMode = (BST_CHECKED == ::SendDlgItemMessage(_hSelf, IDC_COL_TEXT_RADIO, BM_GETCHECK, 0, 0)); @@ -239,13 +239,14 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR } else { - int initialNumber = ::GetDlgItemInt(_hSelf, IDC_COL_INITNUM_EDIT, NULL, TRUE); - int increaseNumber = ::GetDlgItemInt(_hSelf, IDC_COL_INCREASENUM_EDIT, NULL, TRUE); - int repeat = ::GetDlgItemInt(_hSelf, IDC_COL_REPEATNUM_EDIT, NULL, TRUE); - if (repeat <= 0) + size_t initialNumber = ::GetDlgItemInt(_hSelf, IDC_COL_INITNUM_EDIT, NULL, TRUE); + size_t increaseNumber = ::GetDlgItemInt(_hSelf, IDC_COL_INCREASENUM_EDIT, NULL, TRUE); + size_t repeat = ::GetDlgItemInt(_hSelf, IDC_COL_REPEATNUM_EDIT, NULL, TRUE); + if (repeat == 0) { repeat = 1; // Without this we might get an infinite loop while calculating the set "numbers" below. } + UCHAR format = getFormat(); display(false); @@ -272,31 +273,28 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR auto endLine = (*_ppEditView)->execute(SCI_LINEFROMPOSITION, endPos); // Compute the numbers to be placed at each column. - std::vector numbers; + std::vector numbers; + + size_t curNumber = initialNumber; + const size_t kiMaxSize = 1 + (size_t)endLine - (size_t)cursorLine; + while (numbers.size() < kiMaxSize) { - int curNumber = initialNumber; - const size_t kiMaxSize = 1 + (size_t)endLine - (size_t)cursorLine; - while (numbers.size() < kiMaxSize) + for (size_t i = 0; i < repeat; i++) { - for (int i = 0; i < repeat; i++) - { - numbers.push_back(curNumber); - if (numbers.size() >= kiMaxSize) - { - break; - } - } - curNumber += increaseNumber; + numbers.push_back(curNumber); + + if (numbers.size() >= kiMaxSize) + break; } + curNumber += increaseNumber; } - assert(numbers.size() > 0); constexpr int lineAllocatedLen = 1024; TCHAR *line = new TCHAR[lineAllocatedLen]; UCHAR f = format & MASK_FORMAT; - int base = 10; + size_t base = 10; if (f == BASE_16) base = 16; else if (f == BASE_08) @@ -304,10 +302,10 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR else if (f == BASE_02) base = 2; - int endNumber = *numbers.rbegin(); - int nbEnd = getNbDigits(endNumber, base); - int nbInit = getNbDigits(initialNumber, base); - int nb = std::max(nbInit, nbEnd); + size_t endNumber = *numbers.rbegin(); + size_t nbEnd = getNbDigits(endNumber, base); + size_t nbInit = getNbDigits(initialNumber, base); + size_t nb = std::max(nbInit, nbEnd); for (size_t i = cursorLine ; i <= size_t(endLine) ; ++i) @@ -324,12 +322,13 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR line = new TCHAR[lineLen]; } (*_ppEditView)->getGenericText(line, lineLen, lineBegin, lineEnd); + generic_string s2r(line); // // Calcule generic_string // - int2str(str, stringSize, numbers.at(i - cursorLine), base, nb, getLeading()); + variedFormatNumber2String(str, stringSize, numbers.at(i - cursorLine), base, nb, getLeading()); if (lineEndCol < cursorCol) {