Fix integer overflow issue in Column Editor

Fix #15167, close #15222
pull/15245/head
Don Ho 2024-05-31 02:07:51 +02:00
parent 61bcf3a2bc
commit df4e8f5b73
3 changed files with 145 additions and 144 deletions

View File

@ -15,6 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <memory> #include <memory>
#include <bitset>
#include <shlwapi.h> #include <shlwapi.h>
#include <cinttypes> #include <cinttypes>
#include <windowsx.h> #include <windowsx.h>
@ -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; size_t nbDigits = 0;
int nbDigits = 0;
do do
{ {
@ -3658,92 +3657,6 @@ bool ScintillaEditView::expandWordSelection()
return false; 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() 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); assert(repeat > 0);
@ -3849,16 +3762,16 @@ void ScintillaEditView::columnReplace(ColumnModeInfos & cmi, int initial, int in
base = 2; base = 2;
const int stringSize = 512; const int stringSize = 512;
TCHAR str[stringSize]; char str[stringSize];
// Compute the numbers to be placed at each column. // Compute the numbers to be placed at each column.
std::vector<int> numbers; std::vector<size_t> numbers;
{
int curNumber = initial; size_t curNumber = initial;
const size_t kiMaxSize = cmi.size(); const size_t kiMaxSize = cmi.size();
while (numbers.size() < kiMaxSize) while (numbers.size() < kiMaxSize)
{ {
for (int i = 0; i < repeat; i++) for (size_t i = 0; i < repeat; i++)
{ {
numbers.push_back(curNumber); numbers.push_back(curNumber);
if (numbers.size() >= kiMaxSize) if (numbers.size() >= kiMaxSize)
@ -3868,13 +3781,10 @@ void ScintillaEditView::columnReplace(ColumnModeInfos & cmi, int initial, int in
} }
curNumber += incr; curNumber += incr;
} }
}
assert(numbers.size()> 0); const size_t kibEnd = getNbDigits(*numbers.rbegin(), base);
const size_t kibInit = getNbDigits(initial, base);
const int kibEnd = getNbDigits(*numbers.rbegin(), base); const size_t kib = std::max<size_t>(kibInit, kibEnd);
const int kibInit = getNbDigits(initial, base);
const int kib = std::max<int>(kibInit, kibEnd);
intptr_t totalDiff = 0; intptr_t totalDiff = 0;
const size_t len = cmi.size(); 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]._selLpos += totalDiff;
cmi[i]._selRpos += totalDiff; cmi[i]._selRpos += totalDiff;
int2str(str, stringSize, numbers.at(i), base, kib, lead); variedFormatNumber2String<char>(str, stringSize, numbers.at(i), base, kib, lead);
const bool hasVirtualSpc = cmi[i]._nbVirtualAnchorSpc > 0; const bool hasVirtualSpc = cmi[i]._nbVirtualAnchorSpc > 0;
if (hasVirtualSpc) // if virtual space is present, then insert space 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; cmi[i]._selRpos += cmi[i]._nbVirtualCaretSpc;
} }
execute(SCI_SETTARGETRANGE, cmi[i]._selLpos, cmi[i]._selRpos); execute(SCI_SETTARGETRANGE, cmi[i]._selLpos, cmi[i]._selRpos);
execute(SCI_REPLACETARGET, static_cast<WPARAM>(-1), reinterpret_cast<LPARAM>(str));
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
size_t cp = execute(SCI_GETCODEPAGE);
const char *strA = wmc.wchar2char(str, cp);
execute(SCI_REPLACETARGET, static_cast<WPARAM>(-1), reinterpret_cast<LPARAM>(strA));
if (hasVirtualSpc) if (hasVirtualSpc)
{ {
totalDiff += cmi[i]._nbVirtualAnchorSpc + lstrlen(str); totalDiff += cmi[i]._nbVirtualAnchorSpc + strlen(str);
// Now there's no more virtual space // Now there's no more virtual space
cmi[i]._nbVirtualAnchorSpc = 0; cmi[i]._nbVirtualAnchorSpc = 0;
cmi[i]._nbVirtualCaretSpc = 0; cmi[i]._nbVirtualCaretSpc = 0;

View File

@ -245,10 +245,106 @@ const std::vector<std::vector<const char*>> g_nonPrintingChars =
{"\xEF\xBF\xBB", "IAT", "U+FFFB"} // U+FFFB : interlinear annotation terminator {"\xEF\xBF\xBB", "IAT", "U+FFFB"} // U+FFFB : interlinear annotation terminator
}; };
int getNbDigits(int aNum, int base); size_t getNbDigits(size_t aNum, size_t base);
//HMODULE loadSciLexerDll();
TCHAR* int2str(TCHAR* str, int strLen, int number, int base, int nbDigits, ColumnEditorParam::leadingChoice lead); template<typename T>
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); typedef LRESULT (WINAPI *CallWindowProcFunc) (WNDPROC,HWND,UINT,WPARAM,LPARAM);
@ -687,7 +783,7 @@ public:
ColumnModeInfos getColumnModeSelectInfo(); ColumnModeInfos getColumnModeSelectInfo();
void columnReplace(ColumnModeInfos & cmi, const TCHAR *str); 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) { void clearIndicator(int indicatorNumber) {
size_t docStart = 0; size_t docStart = 0;

View File

@ -172,7 +172,7 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
(*_ppEditView)->execute(SCI_BEGINUNDOACTION); (*_ppEditView)->execute(SCI_BEGINUNDOACTION);
constexpr int stringSize = 1024; 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)); 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 else
{ {
int initialNumber = ::GetDlgItemInt(_hSelf, IDC_COL_INITNUM_EDIT, NULL, TRUE); size_t initialNumber = ::GetDlgItemInt(_hSelf, IDC_COL_INITNUM_EDIT, NULL, TRUE);
int increaseNumber = ::GetDlgItemInt(_hSelf, IDC_COL_INCREASENUM_EDIT, NULL, TRUE); size_t increaseNumber = ::GetDlgItemInt(_hSelf, IDC_COL_INCREASENUM_EDIT, NULL, TRUE);
int repeat = ::GetDlgItemInt(_hSelf, IDC_COL_REPEATNUM_EDIT, NULL, TRUE); size_t repeat = ::GetDlgItemInt(_hSelf, IDC_COL_REPEATNUM_EDIT, NULL, TRUE);
if (repeat <= 0) if (repeat == 0)
{ {
repeat = 1; // Without this we might get an infinite loop while calculating the set "numbers" below. repeat = 1; // Without this we might get an infinite loop while calculating the set "numbers" below.
} }
UCHAR format = getFormat(); UCHAR format = getFormat();
display(false); display(false);
@ -272,31 +273,28 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
auto endLine = (*_ppEditView)->execute(SCI_LINEFROMPOSITION, endPos); auto endLine = (*_ppEditView)->execute(SCI_LINEFROMPOSITION, endPos);
// Compute the numbers to be placed at each column. // Compute the numbers to be placed at each column.
std::vector<int> numbers; std::vector<size_t> numbers;
{
int curNumber = initialNumber; size_t curNumber = initialNumber;
const size_t kiMaxSize = 1 + (size_t)endLine - (size_t)cursorLine; const size_t kiMaxSize = 1 + (size_t)endLine - (size_t)cursorLine;
while (numbers.size() < kiMaxSize) while (numbers.size() < kiMaxSize)
{ {
for (int i = 0; i < repeat; i++) for (size_t i = 0; i < repeat; i++)
{ {
numbers.push_back(curNumber); numbers.push_back(curNumber);
if (numbers.size() >= kiMaxSize) if (numbers.size() >= kiMaxSize)
{
break; break;
} }
}
curNumber += increaseNumber; curNumber += increaseNumber;
} }
}
assert(numbers.size() > 0);
constexpr int lineAllocatedLen = 1024; constexpr int lineAllocatedLen = 1024;
TCHAR *line = new TCHAR[lineAllocatedLen]; TCHAR *line = new TCHAR[lineAllocatedLen];
UCHAR f = format & MASK_FORMAT; UCHAR f = format & MASK_FORMAT;
int base = 10; size_t base = 10;
if (f == BASE_16) if (f == BASE_16)
base = 16; base = 16;
else if (f == BASE_08) 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) else if (f == BASE_02)
base = 2; base = 2;
int endNumber = *numbers.rbegin(); size_t endNumber = *numbers.rbegin();
int nbEnd = getNbDigits(endNumber, base); size_t nbEnd = getNbDigits(endNumber, base);
int nbInit = getNbDigits(initialNumber, base); size_t nbInit = getNbDigits(initialNumber, base);
int nb = std::max<int>(nbInit, nbEnd); size_t nb = std::max<size_t>(nbInit, nbEnd);
for (size_t i = cursorLine ; i <= size_t(endLine) ; ++i) 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]; line = new TCHAR[lineLen];
} }
(*_ppEditView)->getGenericText(line, lineLen, lineBegin, lineEnd); (*_ppEditView)->getGenericText(line, lineLen, lineBegin, lineEnd);
generic_string s2r(line); generic_string s2r(line);
// //
// Calcule generic_string // Calcule generic_string
// //
int2str(str, stringSize, numbers.at(i - cursorLine), base, nb, getLeading()); variedFormatNumber2String<wchar_t>(str, stringSize, numbers.at(i - cursorLine), base, nb, getLeading());
if (lineEndCol < cursorCol) if (lineEndCol < cursorCol)
{ {