Skip to content

Commit 17aaecb

Browse files
committed
ValueFlow: Improved handling of sizeof
1 parent 461e5cc commit 17aaecb

4 files changed

Lines changed: 76 additions & 1 deletion

File tree

lib/symboldatabase.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4650,6 +4650,13 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, const Sett
46504650
}
46514651
}
46524652

4653+
ValueType ValueType::parseDecl(const Token *type, const Settings *settings)
4654+
{
4655+
ValueType vt;
4656+
parsedecl(type, &vt, settings->defaultSign == 'u' ? Sign::UNSIGNED : Sign::SIGNED, settings);
4657+
return vt;
4658+
}
4659+
46534660
bool ValueType::fromLibraryType(const std::string &typestr, const Settings *settings)
46544661
{
46554662
const Library::PodType* podtype = settings->library.podtype(typestr);

lib/symboldatabase.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,8 @@ class CPPCHECKLIB ValueType {
11531153
ValueType(enum Sign s, enum Type t, unsigned int p, unsigned int c) : sign(s), type(t), pointer(p), constness(c), typeScope(nullptr) {}
11541154
ValueType(enum Sign s, enum Type t, unsigned int p, unsigned int c, const std::string &otn) : sign(s), type(t), pointer(p), constness(c), typeScope(nullptr), originalTypeName(otn) {}
11551155

1156+
static ValueType parseDecl(const Token *type, const Settings *settings);
1157+
11561158
bool isIntegral() const {
11571159
return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT);
11581160
}

lib/valueflow.cpp

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti
649649
ValueFlow::Value value(0);
650650
value.setKnown();
651651
setTokenValue(const_cast<Token *>(tok), value, settings);
652-
} else if (Token::simpleMatch(tok, "sizeof (") && tok->tokAt(2)) {
652+
} else if (Token::simpleMatch(tok, "sizeof (")) {
653653
const Token *tok2 = tok->tokAt(2);
654654
if (tok2->enumerator() && tok2->enumerator()->scope) {
655655
long long size = settings->sizeof_int;
@@ -681,6 +681,56 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti
681681
value.setKnown();
682682
setTokenValue(const_cast<Token *>(tok), value, settings);
683683
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
684+
} else if (Token::Match(tok, "sizeof ( %var% ) / sizeof (") && tok->next()->astParent() == tok->tokAt(4)) {
685+
// Get number of elements in array
686+
const Token *sz1 = tok->tokAt(2);
687+
const Token *sz2 = tok->tokAt(7);
688+
const unsigned int varid1 = sz1->varId();
689+
if (varid1 &&
690+
sz1->variable() &&
691+
sz1->variable()->isArray() &&
692+
!sz1->variable()->dimensions().empty() &&
693+
sz1->variable()->dimensionKnown(0) &&
694+
(Token::Match(sz2, "* %varid% )", varid1) || Token::Match(sz2, "%varid% [ 0 ] )", varid1))) {
695+
ValueFlow::Value value(sz1->variable()->dimension(0));
696+
value.setKnown();
697+
setTokenValue(const_cast<Token *>(tok->tokAt(4)), value, settings);
698+
}
699+
} else if (!tok2->type()) {
700+
const ValueType &vt = ValueType::parseDecl(tok2,settings);
701+
if (vt.pointer) {
702+
ValueFlow::Value value(settings->sizeof_pointer);
703+
value.setKnown();
704+
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
705+
} else if (vt.type == ValueType::Type::CHAR) {
706+
ValueFlow::Value value(1);
707+
value.setKnown();
708+
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
709+
} else if (vt.type == ValueType::Type::SHORT) {
710+
ValueFlow::Value value(settings->sizeof_short);
711+
value.setKnown();
712+
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
713+
} else if (vt.type == ValueType::Type::INT) {
714+
ValueFlow::Value value(settings->sizeof_int);
715+
value.setKnown();
716+
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
717+
} else if (vt.type == ValueType::Type::LONG) {
718+
ValueFlow::Value value(settings->sizeof_long);
719+
value.setKnown();
720+
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
721+
} else if (vt.type == ValueType::Type::LONGLONG) {
722+
ValueFlow::Value value(settings->sizeof_long_long);
723+
value.setKnown();
724+
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
725+
} else if (vt.type == ValueType::Type::FLOAT) {
726+
ValueFlow::Value value(settings->sizeof_float);
727+
value.setKnown();
728+
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
729+
} else if (vt.type == ValueType::Type::DOUBLE) {
730+
ValueFlow::Value value(settings->sizeof_double);
731+
value.setKnown();
732+
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
733+
}
684734
}
685735
// skip over enum
686736
tok = tok->linkAt(1);

test/testvalueflow.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,22 @@ class TestValueFlow : public TestFixture {
480480
ASSERT_EQUALS(1U, values.size());
481481
ASSERT_EQUALS(-10, values.back().intvalue);
482482

483+
// sizeof
484+
code = "void f() {\n"
485+
" x = sizeof(int);\n"
486+
"}";
487+
values = tokenValues(code,"( int )");
488+
ASSERT_EQUALS(1U, values.size());
489+
ASSERT_EQUALS(settings.sizeof_int, values.back().intvalue);
490+
491+
code = "void f() {\n"
492+
" struct S *a[10];"
493+
" x = sizeof(a) / sizeof(a[0]);\n"
494+
"}";
495+
values = tokenValues(code,"/");
496+
ASSERT_EQUALS(1U, values.size());
497+
ASSERT_EQUALS(10, values.back().intvalue);
498+
483499
// function call => calculation
484500
code = "void f(int x) {\n"
485501
" a = x + 8;\n"

0 commit comments

Comments
 (0)