mirror of
https://github.com/znc/znc.git
synced 2026-06-11 01:05:05 +02:00
ZNCString: guard Replace/Split against empty-width arguments
CString::Replace with an empty sReplace underflowed 'p += uReplaceWidth - 1' to SIZE_MAX and then the per-iteration 'p++' brought p back to the same byte, so the function looped forever appending sWith to the output and eventually OOMed. CString::Split with empty sDelim and bAllowEmpty=false spun in the prefix-skip loops because strncasecmp(p, "", 0) is unconditionally 0 and p += 0 never advances. No in-tree caller currently passes the bad argument, but the public library API should not be a bear trap for module authors. Same shape as #1994.
This commit is contained in:
+14
-2
@@ -626,6 +626,14 @@ unsigned int CString::Replace(const CString& sReplace, const CString& sWith,
|
||||
unsigned int CString::Replace(CString& sStr, const CString& sReplace,
|
||||
const CString& sWith, const CString& sLeft,
|
||||
const CString& sRight, bool bRemoveDelims) {
|
||||
// An empty needle would make strncmp(_, _, 0) match at every position
|
||||
// and `p += uReplaceWidth - 1` underflow to SIZE_MAX, producing an
|
||||
// infinite loop that appends sWith until OOM. Guard at the entry so
|
||||
// the invariant "the loop always advances" holds.
|
||||
if (sReplace.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int uRet = 0;
|
||||
CString sCopy = sStr;
|
||||
sStr.clear();
|
||||
@@ -851,7 +859,10 @@ CString::size_type CString::Split(const CString& sDelim, VCString& vsRet,
|
||||
size_type uRightLen = sRight.length();
|
||||
const char* p = c_str();
|
||||
|
||||
if (!bAllowEmpty) {
|
||||
// An empty delimiter with bAllowEmpty=false would spin forever in the
|
||||
// prefix-skip / post-token loops below because `strncasecmp(_, _, 0)`
|
||||
// returns 0 and `p += 0` never advances.
|
||||
if (!bAllowEmpty && uDelimLen) {
|
||||
while (strncasecmp(p, sDelim.c_str(), uDelimLen) == 0) {
|
||||
p += uDelimLen;
|
||||
}
|
||||
@@ -890,7 +901,8 @@ CString::size_type CString::Split(const CString& sDelim, VCString& vsRet,
|
||||
sTmp.clear();
|
||||
p += uDelimLen;
|
||||
|
||||
if (!bAllowEmpty) {
|
||||
// Same zero-width guard as at the top of the function.
|
||||
if (!bAllowEmpty && uDelimLen) {
|
||||
while (strncasecmp(p, sDelim.c_str(), uDelimLen) == 0) {
|
||||
p += uDelimLen;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user