KEMBAR78
Fix PSMethodInvocationConstraints.GetHashCode method by crazyjncsu · Pull Request #24965 · PowerShell/PowerShell · GitHub
Skip to content

Conversation

@crazyjncsu
Copy link
Contributor

@crazyjncsu crazyjncsu commented Feb 6, 2025

PR Summary

Fix #24964

PR Context

The issue comes from #12412. The bottom line is that we need to calculate the hash for all array members, not for the array object itself.

PR Checklist

@crazyjncsu

This comment was marked as duplicate.

@iSazonov iSazonov added the CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log label Feb 10, 2025
@iSazonov iSazonov changed the title fixed gethashcode calculation Fix PSMethodInvocationConstraints.GetHashCode method Feb 10, 2025
@daxian-dbw
Copy link
Member

daxian-dbw commented Feb 11, 2025

@crazyjncsu Thank you for reporting this issue!
I think we should either revert the change back to the original hash code calculation with the addition of ParameterTypes.SequenceGetHashCode(), or use HashCode.Add to include all elements of ParameterTypes and GenericTypeParameters to the hash code calculation.

[UPDATE] I reverted the code back to the original hash code calculation with the addition of GenericTypeParameters.
@iSazonov @SeeminglyScience @crazyjncsu Can you please take a look?

@daxian-dbw
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@crazyjncsu
Copy link
Contributor Author

Looks great for my purposes ;)

@iSazonov
Copy link
Collaborator

iSazonov commented Feb 12, 2025

@daxian-dbw Could you please explain why we cannot use HashCode.Combine() with SequenceGetHashCode() as @crazyjncsu proposed? I think old custom algorithm is not best choice. Or are you thinking about performance?
(I don't mind going back to the source code, which no doubt underwent a full audit a long time ago.)

Comment on lines 2013 to 2023
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would go with this since it seems to be the preferred API now. But I also don't know enough about the specifics of hashcodes to know why one is or isn't better (partially why I'd personally stick to the API that does it "properly" for you)

Suggested change
// algorithm based on https://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
unchecked
{
int result = 61;
result = result * 397 + (MethodTargetType != null ? MethodTargetType.GetHashCode() : 0);
result = result * 397 + ParameterTypes.SequenceGetHashCode();
result = result * 397 + GenericTypeParameters.SequenceGetHashCode();
return result;
}
HashCode hashCode = new();
hashCode.Add(MethodTargetType);
if (ParameterTypes is not null)
{
foreach (Type parameterType in ParameterTypes)
{
hashCode.Add(parameterType);
}
}
else
{
hashCode.Add(0);
}
if (GenericTypeParameters is null)
{
hashCode.Add(0);
return hashCode.ToHashCode();
}
foreach (Type genericParameter in GenericTypeParameters)
{
hashCode.Add(genericParameter);
}
return hashCode.ToHashCode();

Copy link
Member

Choose a reason for hiding this comment

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

HashCode.Combine calls GetHashCode on the passed-in values (see its source code here), but Int32.GetHashCode() simply returns the integer itself, so HashCode.Combine(MethodTargetType, ParameterTypes.SequenceGetHashCode(), GenericTypeParameters.SequenceGetHashCode()) should work as expected.

Copy link
Member

Choose a reason for hiding this comment

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

but Int32.GetHashCode() simply returns the integer itself

Also given this, I guess we now can replace the utility method Utils.CombineHashCodes in PowerShell with HashCode.Combine.

Copy link
Collaborator

@iSazonov iSazonov Feb 13, 2025

Choose a reason for hiding this comment

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

But I also don't know enough about the specifics of hashcodes to know why one is or isn't better (partially why I'd personally stick to the API that does it "properly" for you)

Better:

  1. Less collisions.
  2. Random seed per process (protects against cache attacks).

@daxian-dbw
Copy link
Member

daxian-dbw commented Feb 12, 2025

My bad. I missed the fact that GetHashCode() on an integer will simply return the integer value itself.
So HashCode.Combine(MethodTargetType, ParameterTypes.SequenceGetHashCode(), GenericTypeParameters.SequenceGetHashCode()) should work as expected.

I have removed my commit.

@iSazonov

This comment was marked as outdated.

@azure-pipelines

This comment was marked as outdated.

@iSazonov iSazonov self-assigned this Feb 13, 2025
@iSazonov iSazonov merged commit 14fb6f2 into PowerShell:master Feb 13, 2025
68 of 70 checks passed
@microsoft-github-policy-service
Copy link
Contributor

microsoft-github-policy-service bot commented Feb 13, 2025

📣 Hey @crazyjncsu, how did we do? We would love to hear your feedback with the link below! 🗣️

🔗 https://aka.ms/PSRepoFeedback

@iSazonov
Copy link
Collaborator

iSazonov commented Feb 13, 2025

@crazyjncsu Thanks for you contribution!


@ArmaanMcleod Have you an interest to migrate the SequenceGetHashCode() method to new HashCode.Add() API?

pwshBot pushed a commit to pwshBot/PowerShell that referenced this pull request Apr 10, 2025
There is a difference between GetHashCode for array object itself and cumulative GetHashCode based on hashes of the array members.
@TravisEz13
Copy link
Member

@PowerShell/powershell-maintainers triage decision - wait until more data from a 7.5 release

pwshBot pushed a commit to pwshBot/PowerShell that referenced this pull request May 14, 2025
There is a difference between GetHashCode for array object itself and cumulative GetHashCode based on hashes of the array members.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backport-7.5.x-Migrated CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bad hash code calculation in PSMethodInvocationConstraints results in explosion of static cache

5 participants