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/>.
#include <memory>
#include <bitset>
#include <shlwapi.h>
#include <cinttypes>
#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;
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<int> numbers;
std::vector<size_t> 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<int>(kibInit, kibEnd);
const size_t kibEnd = getNbDigits(*numbers.rbegin(), base);
const size_t kibInit = getNbDigits(initial, base);
const size_t kib = std::max<size_t>(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<char>(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<WPARAM>(-1), reinterpret_cast<LPARAM>(strA));
execute(SCI_REPLACETARGET, static_cast<WPARAM>(-1), reinterpret_cast<LPARAM>(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;

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
};
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<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);
@ -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;

View File

@ -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<int> numbers;
std::vector<size_t> 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<int>(nbInit, nbEnd);
size_t endNumber = *numbers.rbegin();
size_t nbEnd = getNbDigits(endNumber, base);
size_t nbInit = getNbDigits(initialNumber, base);
size_t nb = std::max<size_t>(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<wchar_t>(str, stringSize, numbers.at(i - cursorLine), base, nb, getLeading());
if (lineEndCol < cursorCol)
{