Fix #11191 FP moduloofone with pow() (#4312)

This commit is contained in:
chrchr-github 2022-07-28 22:11:23 +02:00 committed by GitHub
parent 898ad314ab
commit c340b6ae6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 69 additions and 1393 deletions

View File

@ -709,133 +709,145 @@ static std::unordered_map<std::string, BuiltinLibraryFunction> createBuiltinLibr
return v; return v;
}; };
functions["atan2"] = [](const std::vector<ValueFlow::Value>& args) { functions["atan2"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::atan2(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::atan2(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;
}; };
functions["remainder"] = [](const std::vector<ValueFlow::Value>& args) { functions["remainder"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::remainder(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::remainder(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;
}; };
functions["nextafter"] = [](const std::vector<ValueFlow::Value>& args) { functions["nextafter"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::nextafter(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::nextafter(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;
}; };
functions["nexttoward"] = [](const std::vector<ValueFlow::Value>& args) { functions["nexttoward"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::nexttoward(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::nexttoward(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;
}; };
functions["hypot"] = [](const std::vector<ValueFlow::Value>& args) { functions["hypot"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::hypot(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::hypot(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;
}; };
functions["fdim"] = [](const std::vector<ValueFlow::Value>& args) { functions["fdim"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::fdim(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::fdim(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;
}; };
functions["fmax"] = [](const std::vector<ValueFlow::Value>& args) { functions["fmax"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::fmax(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::fmax(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;
}; };
functions["fmin"] = [](const std::vector<ValueFlow::Value>& args) { functions["fmin"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::fmin(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::fmin(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;
}; };
functions["fmod"] = [](const std::vector<ValueFlow::Value>& args) { functions["fmod"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::fmod(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::fmod(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;
}; };
functions["pow"] = [](const std::vector<ValueFlow::Value>& args) { functions["pow"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::pow(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::pow(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;
}; };
functions["scalbln"] = [](const std::vector<ValueFlow::Value>& args) { functions["scalbln"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::scalbln(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::scalbln(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;
}; };
functions["ldexp"] = [](const std::vector<ValueFlow::Value>& args) { functions["ldexp"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2) if (args.size() != 2 || !std::all_of(args.begin(), args.end(), [](const ValueFlow::Value& v) {
return ValueFlow::Value::unknown(); return v.isFloatValue() || v.isIntValue();
ValueFlow::Value v = args[0]; }))
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown(); return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
ValueFlow::Value v;
combineValueProperties(args[0], args[1], &v);
v.floatValue = std::ldexp(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); v.floatValue = std::ldexp(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT; v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v; return v;

View File

@ -500,7 +500,7 @@ static bool isNumeric(const ValueFlow::Value& value) {
return value.isIntValue() || value.isFloatValue(); return value.isIntValue() || value.isFloatValue();
} }
static void combineValueProperties(const ValueFlow::Value &value1, const ValueFlow::Value &value2, ValueFlow::Value *result) void combineValueProperties(const ValueFlow::Value &value1, const ValueFlow::Value &value2, ValueFlow::Value *result)
{ {
if (value1.isKnown() && value2.isKnown()) if (value1.isKnown() && value2.isKnown())
result->setKnown(); result->setKnown();

View File

@ -535,4 +535,6 @@ CPPCHECKLIB std::vector<ValueFlow::Value> getLifetimeObjValues(const Token* tok,
const Token* getEndOfExprScope(const Token* tok, const Scope* defaultScope = nullptr, bool smallest = true); const Token* getEndOfExprScope(const Token* tok, const Scope* defaultScope = nullptr, bool smallest = true);
void combineValueProperties(const ValueFlow::Value& value1, const ValueFlow::Value& value2, ValueFlow::Value* result);
#endif // valueflowH #endif // valueflowH

View File

@ -10347,6 +10347,12 @@ private:
" }\n" " }\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("void f(int i, int j) {\n" // #11191
" const int c = pow(2, i);\n"
" if (j % c) {}\n"
"}\n");
ASSERT_EQUALS("", errout.str());
} }
void sameExpressionPointers() { void sameExpressionPointers() {

File diff suppressed because it is too large Load Diff