-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fixed #13513 - adjusted access of known int values #7181
base: main
Are you sure you want to change the base?
Conversation
3ac7fcc
to
516a7f3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it.. good catch
This obviously still needs to use the proper calls but that might silently change the behavior and I would like to know if it does. But so far I have not been able to trigger any of those asserts and I do not feel comfortable putting those actually out there. I will still give it a spin with daca and have some other tests to run which might help with finding at least a single test case. |
I will take a tiered approach. Using the wrapping functions here and actually adjusting to the proper calls in a follow-up. I am doing this because I still want to test if we might trigger this along with some other tests. And I also need to profile this to make sure that I do not accidentally introduce performance regressions. Also it is not a drop-in replacement in several cases. |
Turns out the unit tests actually trigger this. I definitely ran those locally with the changes and had no failures. Not sure what I did wrong... |
The code in question was only added a few days ago. That explains why. |
lib/symboldatabase.cpp
Outdated
if (dimension_.tok && (dimension_.tok->hasKnownIntValue() || | ||
(dimension_.tok->isTemplateArg() && !dimension_.tok->values().empty()))) { | ||
dimension_.num = dimension_.tok->getKnownIntValue(); | ||
if (dimension_.tok) { | ||
if (dimension_.tok->hasKnownIntValue()) | ||
dimension_.num = dimension_.tok->getKnownIntValue(); | ||
else if (dimension_.tok->isTemplateArg() && !dimension_.tok->values().empty()) { | ||
assert(dimension_.tok->values().front().isKnown()); | ||
dimension_.num = dimension_.tok->values().front().intvalue; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@chrchr-github Please have a look. You changed this logic a few days ago in 46781df.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For template arguments, the values are only possible, not known. But since getKnownIntValue()
just returns the first one, it is what we want in this case (I think).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So like the previous behavior? Just unconditionally use the first value and set dimension_.known
to true
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, pretty much. I imagine/hope that template arguments can have at most one value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should set those values to known in the future, and prevent unwanted knownConditionTrueFalse
warnings in a different way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I imagine/hope that template arguments can have at most one value.
I will just add a different assert.
lib/valueflow.cpp
Outdated
@@ -944,7 +944,7 @@ static void valueFlowRightShift(TokenList& tokenList, const Settings& settings) | |||
if (!tok->astOperand2()->hasKnownValue()) | |||
continue; | |||
|
|||
const MathLib::bigint rhsvalue = tok->astOperand2()->values().front().intvalue; | |||
const MathLib::bigint rhsvalue = tok->astOperand2()->getKnownValue()->intvalue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not getKbownIntValue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the preceding check is hasKnownValue()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a bug, it should be checking for a known int value since it's creating an int value below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see.
But the value is created on tok
which has another hasKnownValue()
check above. So that does not seem related (to me). Unless all of them need to be adjusted.
Also given the information in the other comment if this already has a non-int value and we set the int-value wouldn't that break that the case that it may only hold a single value (if that is even possible)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is related, all the checks in this pass should check for int value only.
return nullptr; | ||
auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), std::mem_fn(&ValueFlow::Value::isKnown)); | ||
return it == mImpl->mValues->end() ? nullptr : &*it; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can be multiple known values of different types on a token and with the exception of int, they can be in any order. It seems like it would always be better to use the overload that takes the type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can be multiple known values of different types on a token and with the exception of int, they can be in any order.
Good to know. So I guess there is no need for an intermediate step and this can simply be cleaned up.
Could that assumption be used to simplify the lookup? A getKnownIntValue()
which will bail out when the size is not 1 and it is not known? That would avoid unnecessary iterations. I will of course only do that if profiling shows that it would have an impact.
Should we add some kind of validation to make sure that it is always the case? A future change might accidentally break that.
It seems like it would always be better to use the overload that takes the type.
Yeah. I just aligned the code as a first step so the intent is clear and it is easier to refactor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can be multiple known values of different types on a token and with the exception of int, they can be in any order.
Good to know. So I guess there is no need for an intermediate step and this can simply be cleaned up.
What intermediate step?
Could that assumption be used to simplify the lookup? A
getKnownIntValue()
which will bail out when the size is not 1 and it is not known?
The size is not guaranteed to be 1. There could be other values, such as known from other types or possible values, etc.
For known int value you don't need iteration, you can just check the first element.
It seems like it would always be better to use the overload that takes the type.
Yeah. I just aligned the code as a first step so the intent is clear and it is easier to refactor.
The overload without a type doesn't express intent and very likely its a bug in the code.
No description provided.