Skip to content

Commit

Permalink
Fixup #12929: better handling of escape sequences in Token::isCMultiChar
Browse files Browse the repository at this point in the history
  • Loading branch information
danmar committed Jul 13, 2024
1 parent 7aa5e4a commit 87ef854
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 26 deletions.
25 changes: 3 additions & 22 deletions lib/token.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,29 +729,10 @@ nonneg int Token::getStrLength(const Token *tok)
assert(tok != nullptr);
assert(tok->mTokType == eString);

int len = 0;
// cppcheck-suppress shadowFunction - TODO: fix this
const std::string str(getStringLiteral(tok->str()));
std::string::const_iterator it = str.cbegin();
const std::string::const_iterator end = str.cend();

while (it != end) {
if (*it == '\\') {
++it;

// string ends at '\0'
if (*it == '0')
return len;
}

if (*it == '\0')
return len;

++it;
++len;
}
const std::string s(replaceEscapeSequences(getStringLiteral(tok->str())));

return len;
const auto pos = s.find('\0');
return pos < s.size() ? pos : s.size();
}

nonneg int Token::getStrArraySize(const Token *tok)
Expand Down
7 changes: 3 additions & 4 deletions lib/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -751,14 +751,13 @@ class CPPCHECKLIB Token {

bool isCChar() const {
return (((mTokType == eString) && isPrefixStringCharLiteral(mStr, '"', emptyString)) ||
((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', emptyString) && mStr.length() == 3) ||
((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', emptyString) && mStr.compare(0, 2, "\'\\") == 0 && mStr.length() == 4));
((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', emptyString) && (replaceEscapeSequences(getCharLiteral(mStr)).size() == 1)));
}

bool isCMultiChar() const {
return (((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', emptyString)) && (mStr.compare(0, 2, "\'\\") != 0 || mStr.length() > 4) &&
(mStr.length() > 3));
return (mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', emptyString) && (replaceEscapeSequences(getCharLiteral(mStr)).size() > 1);
}

/**
* @brief Is current token a template argument?
*
Expand Down
46 changes: 46 additions & 0 deletions lib/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,52 @@ CPPCHECKLIB std::string trim(const std::string& s, const std::string& t = " \t")
*/
CPPCHECKLIB void findAndReplace(std::string &source, const std::string &searchFor, const std::string &replaceWith);

/**
* Replace all escape sequences in the given string.
* @param source The string that contains escape sequences
*/
CPPCHECKLIB inline std::string replaceEscapeSequences(const std::string &source) {
std::string result;
result.reserve(source.size());
for (std::size_t i = 0; i < source.size(); ++i) {
if (source[i] != '\\' || i + 1 >= source.size())
result += source[i];
else {
if (source[i+1] == 'n') {
result += '\n';
++i;
} else if (source[i+1] == 'r') {
result += '\r';
++i;
} else if (source[i+1] == 't') {
result += '\t';
++i;
} else if (source[i+1] == 'x') {
std::string value = "0";
i++;
if (i + 1 < source.size() && std::isxdigit(source[i+1]))
value += source[i++ + 1];
if (i + 1 < source.size() && std::isxdigit(source[i+1]))
value += source[i++ + 2];
result += static_cast<char>(std::stoi(value, nullptr, 16));
} else if (source[i+1] == '0') {
std::string value;
if (i + 1 < source.size() && source[i+1] >= '0' && source[i+1] <= '7')
value += source[i++ + 1];
if (i + 1 < source.size() && source[i+1] >= '0' && source[i+1] <= '7')
value += source[i++ + 1];
if (i + 1 < source.size() && source[i+1] >= '0' && source[i+1] <= '7')
value += source[i++ + 1];
result += static_cast<char>(std::stoi(value, nullptr, 8));
} else {
result += source[i+1];
++i;
}
}
}
return result;
}

namespace cppcheck
{
NORETURN inline void unreachable()
Expand Down
8 changes: 8 additions & 0 deletions test/testtoken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,14 @@ class TestToken : public TestFixture {
ASSERT_EQUALS(false, tok.isUtf32());
ASSERT_EQUALS(false, tok.isLong());
ASSERT_EQUALS(true, tok.isCMultiChar());

tok.str("'\\x10'");
ASSERT_EQUALS(true, tok.isCChar());
ASSERT_EQUALS(false, tok.isUtf8());
ASSERT_EQUALS(false, tok.isUtf16());
ASSERT_EQUALS(false, tok.isUtf32());
ASSERT_EQUALS(false, tok.isLong());
ASSERT_EQUALS(false, tok.isCMultiChar());
}

void stringTypes() const {
Expand Down

0 comments on commit 87ef854

Please sign in to comment.