Skip to content

Fix #10792 FP knownConditionTrueFalse with double to int cast#3964

Merged
danmar merged 7 commits intocppcheck-opensource:mainfrom
chrchr-github:chr_Fix10792
Apr 7, 2022
Merged

Fix #10792 FP knownConditionTrueFalse with double to int cast#3964
danmar merged 7 commits intocppcheck-opensource:mainfrom
chrchr-github:chr_Fix10792

Conversation

@chrchr-github
Copy link
Copy Markdown
Collaborator

No description provided.

Comment thread lib/valueflow.cpp Outdated
ValueFlow::getSizeOf(*tok->valueType(), settings) >= ValueFlow::getSizeOf(valueType, settings))
return;
if (tok->valueType() && tok->valueType()->isFloat() && valueType.isIntegral())
value.valueType = ValueFlow::Value::ValueType::FLOAT;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be in setTokenValueCast?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the type of !='s value should not be INT, so that

void f(double d) {
	if (d != 0) {
		int i = d;
		if (i == 0) {}
	}
}

is also handled correctly.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example above gives an oppositeInnerCondition error, which seems to be a different issue.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving the code to setTokenValueCast() does not work, since tok is not available. I have now moved it to setConditionalValues(), seems to work so far.

Comment thread lib/valueflow.cpp Outdated
if (Token::Match(tok, "==|!=|>=|<=")) {
true_value = ValueFlow::Value{tok, value};
const Variable* var1 = tok->astOperand1()->variable();
const Variable* var2 = tok->astOperand2()->variable();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wont work if either side is not a variable like in:

struct A { double d; };
void f(A a) {
    if (a.d != 0) {
        int i = a.d;
        if (i == 0) {}
    }
}

Comment thread lib/valueflow.cpp Outdated
if ((var1 && var1->isFloatingType()) || (var2 && var2->isFloatingType())) {
true_value.valueType = ValueFlow::Value::ValueType::FLOAT;
false_value.valueType = ValueFlow::Value::ValueType::FLOAT;
}
Copy link
Copy Markdown
Contributor

@pfultz2 pfultz2 Apr 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code below doesnt work for floating point. This function never sets floatValue which is what the ValueType::FLOAT uses, and it uses incorrect logic for the bounds(ie value + 1 instead of using float epsilon). It probably works because floatValue is zero by default, and you are only testing with equality.

Actually, this function is mainly used in parseCompareInt(and also for symbolic conditions) which are for integral-like comparisons. I think it would be better to return null in parseCompareInt if the return token is a float. So you could add a check in addition to isSaturated check:

const Token *parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value, const std::function<std::vector<MathLib::bigint>(const Token*)>& evaluate)
{
    ...
    if (tok->isComparisonOp()) {
        ...
        if (!value1.empty()) {
            if (isSaturated(value1.front()) || astIsFloat(tok->astOperand2()))
                return nullptr;
            setConditionalValues(tok, true, value1.front(), true_value, false_value);
            return tok->astOperand2();
        } else if (!value2.empty()) {
            if (isSaturated(value2.front())|| astIsFloat(tok->astOperand1()))
                return nullptr;
            setConditionalValues(tok, false, value2.front(), true_value, false_value);
            return tok->astOperand1();
        }
    }
    ...
}

We should probably add better support for float comparisons in the future, but they are little difficult due to not being totally ordered(ie d < 0.0 != 0.0 > d).

@danmar danmar merged commit 52b4aeb into cppcheck-opensource:main Apr 7, 2022
@chrchr-github chrchr-github deleted the chr_Fix10792 branch April 10, 2022 21:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants