From 17aaecbd6b1356c66c9596f13edcb61e6a6efe29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 18 Dec 2016 14:03:48 +0100 Subject: [PATCH] ValueFlow: Improved handling of sizeof --- lib/symboldatabase.cpp | 7 ++++++ lib/symboldatabase.h | 2 ++ lib/valueflow.cpp | 52 +++++++++++++++++++++++++++++++++++++++++- test/testvalueflow.cpp | 16 +++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index f58ee1711..7965cb9a7 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -4650,6 +4650,13 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, const Sett } } +ValueType ValueType::parseDecl(const Token *type, const Settings *settings) +{ + ValueType vt; + parsedecl(type, &vt, settings->defaultSign == 'u' ? Sign::UNSIGNED : Sign::SIGNED, settings); + return vt; +} + bool ValueType::fromLibraryType(const std::string &typestr, const Settings *settings) { const Library::PodType* podtype = settings->library.podtype(typestr); diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 354c46da9..5f92a176c 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1153,6 +1153,8 @@ public: ValueType(enum Sign s, enum Type t, unsigned int p, unsigned int c) : sign(s), type(t), pointer(p), constness(c), typeScope(nullptr) {} 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) {} + static ValueType parseDecl(const Token *type, const Settings *settings); + bool isIntegral() const { return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT); } diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 283b854c0..8af3d3a32 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -649,7 +649,7 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti ValueFlow::Value value(0); value.setKnown(); setTokenValue(const_cast(tok), value, settings); - } else if (Token::simpleMatch(tok, "sizeof (") && tok->tokAt(2)) { + } else if (Token::simpleMatch(tok, "sizeof (")) { const Token *tok2 = tok->tokAt(2); if (tok2->enumerator() && tok2->enumerator()->scope) { long long size = settings->sizeof_int; @@ -681,6 +681,56 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti value.setKnown(); setTokenValue(const_cast(tok), value, settings); setTokenValue(const_cast(tok->next()), value, settings); + } else if (Token::Match(tok, "sizeof ( %var% ) / sizeof (") && tok->next()->astParent() == tok->tokAt(4)) { + // Get number of elements in array + const Token *sz1 = tok->tokAt(2); + const Token *sz2 = tok->tokAt(7); + const unsigned int varid1 = sz1->varId(); + if (varid1 && + sz1->variable() && + sz1->variable()->isArray() && + !sz1->variable()->dimensions().empty() && + sz1->variable()->dimensionKnown(0) && + (Token::Match(sz2, "* %varid% )", varid1) || Token::Match(sz2, "%varid% [ 0 ] )", varid1))) { + ValueFlow::Value value(sz1->variable()->dimension(0)); + value.setKnown(); + setTokenValue(const_cast(tok->tokAt(4)), value, settings); + } + } else if (!tok2->type()) { + const ValueType &vt = ValueType::parseDecl(tok2,settings); + if (vt.pointer) { + ValueFlow::Value value(settings->sizeof_pointer); + value.setKnown(); + setTokenValue(const_cast(tok->next()), value, settings); + } else if (vt.type == ValueType::Type::CHAR) { + ValueFlow::Value value(1); + value.setKnown(); + setTokenValue(const_cast(tok->next()), value, settings); + } else if (vt.type == ValueType::Type::SHORT) { + ValueFlow::Value value(settings->sizeof_short); + value.setKnown(); + setTokenValue(const_cast(tok->next()), value, settings); + } else if (vt.type == ValueType::Type::INT) { + ValueFlow::Value value(settings->sizeof_int); + value.setKnown(); + setTokenValue(const_cast(tok->next()), value, settings); + } else if (vt.type == ValueType::Type::LONG) { + ValueFlow::Value value(settings->sizeof_long); + value.setKnown(); + setTokenValue(const_cast(tok->next()), value, settings); + } else if (vt.type == ValueType::Type::LONGLONG) { + ValueFlow::Value value(settings->sizeof_long_long); + value.setKnown(); + setTokenValue(const_cast(tok->next()), value, settings); + } else if (vt.type == ValueType::Type::FLOAT) { + ValueFlow::Value value(settings->sizeof_float); + value.setKnown(); + setTokenValue(const_cast(tok->next()), value, settings); + } else if (vt.type == ValueType::Type::DOUBLE) { + ValueFlow::Value value(settings->sizeof_double); + value.setKnown(); + setTokenValue(const_cast(tok->next()), value, settings); + } } // skip over enum tok = tok->linkAt(1); diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 91ce2f96d..308846c83 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -480,6 +480,22 @@ private: ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(-10, values.back().intvalue); + // sizeof + code = "void f() {\n" + " x = sizeof(int);\n" + "}"; + values = tokenValues(code,"( int )"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(settings.sizeof_int, values.back().intvalue); + + code = "void f() {\n" + " struct S *a[10];" + " x = sizeof(a) / sizeof(a[0]);\n" + "}"; + values = tokenValues(code,"/"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(10, values.back().intvalue); + // function call => calculation code = "void f(int x) {\n" " a = x + 8;\n"