Skip to content
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

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

firewave
Copy link
Collaborator

@firewave firewave commented Jan 5, 2025

No description provided.

@firewave firewave force-pushed the knownint branch 2 times, most recently from 3ac7fcc to 516a7f3 Compare January 5, 2025 12:23
Copy link
Owner

@danmar danmar left a 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

@firewave
Copy link
Collaborator Author

firewave commented Jan 6, 2025

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.

@firewave firewave changed the title fixed #13513 - corrected access of known int values refs #13513 - adjusted access of known int values Jan 18, 2025
@firewave
Copy link
Collaborator Author

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.

@firewave
Copy link
Collaborator Author

I am doing this because I still want to test if we might trigger this along with some other tests.

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...

@firewave
Copy link
Collaborator Author

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.

Comment on lines 3737 to 3743
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;
}
Copy link
Collaborator Author

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.

Copy link
Collaborator

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).

Copy link
Collaborator Author

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?

Copy link
Collaborator

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.

Copy link
Collaborator

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.

Copy link
Collaborator Author

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.

@@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not getKbownIntValue?

Copy link
Collaborator Author

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().

Copy link
Contributor

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.

Copy link
Collaborator Author

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)?

Copy link
Contributor

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;
}
Copy link
Contributor

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.

Copy link
Collaborator Author

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.

Copy link
Contributor

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.

@firewave firewave changed the title refs #13513 - adjusted access of known int values fixed #13513 - adjusted access of known int values Jan 19, 2025
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.

4 participants