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

Restrict the maximum length of BigInteger #102874

Merged
merged 3 commits into from
May 31, 2024

Conversation

tannergooding
Copy link
Member

As per the comment in the code we have several APIs that are already restricted and will throw for big integers above this limit, so this just enforces it consistently. An almost 256MB BigInteger is enormous and well above any typical input range, it is more than enough for the in-box type to support and helps avoid other edge case considerations for users. It will also allow us to bound the computation time for some APIs in a more sensible fashion.

Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-numerics
See info in area-owners.md if you want to be subscribed.

@huoyaoyuan
Copy link
Member

Some overflow checks in ToString and DebuggerDisplay can also be simplified.

@tannergooding
Copy link
Member Author

Some overflow checks in ToString and DebuggerDisplay can also be simplified.

Yep, but I plan on handling those in a separate PR. This is just the simplest change to give consistent behavior with the existing logiic.

I'm working (slowly) on a change to switch to using nuint as the backing data storage so we can get better performance.

@@ -527,87 +536,88 @@ private BigInteger(ReadOnlySpan<uint> value, bool negative)
/// <param name="value"></param>
private BigInteger(Span<uint> value)
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious why we have two separate implementations one for Span<uint> and one for ReadOnlySpan<uint> + isNegative. Could this ctor just do the checks to compute isNegative and then delegate to the other in order to avoid duplication? Or are they dealing with completely different formats?

Copy link
Member Author

Choose a reason for hiding this comment

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

Mostly because BigInteger is an old type in desperate need of a rewrite 😆. I imagine we could, with a bit more refactoring, share some or most of the implementation here.

private BigInteger(ReadOnlySpan<uint> value, bool negative) is an optimized implementation that assumes we are already in almost the right shape. So value is the unsigned storage data (the absolute value) and we're really just trimming unnecessary leading zeros and deciding whether to store it in _bits or compress it into _sign.

private BigInteger(Span<uint> value) on the other hand is taking a two's complement little-endian span. So it has to detect if its positive or negative and if its negative fix it up to be the absolute value for storage purposes. So I expect we could implement it as:

  • determine if negative, trimming leading sign data (0xFF if negative, 0x00 if positive)
  • if negative, compute the two's complement (absolute value)
  • call private BigInteger(ReadOnlySpan<uint> value, bool negative)

@@ -29,19 +29,21 @@ public static void BigShiftsTest()
public static void LargeNegativeBigIntegerShiftTest()
{
// Create a very large negative BigInteger
BigInteger bigInt = new BigInteger(-1) << int.MaxValue;
Assert.Equal(2147483647, bigInt.GetBitLength());
Copy link
Member

Choose a reason for hiding this comment

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

Should this become a test that validates an exception is thrown?

Copy link
Member Author

Choose a reason for hiding this comment

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

Potentially. There's some general cleanup and additional validation I'd like to do here long term, but I'll get this back up to validate it throws in a follow up PR.

@tannergooding tannergooding merged commit 635c816 into dotnet:main May 31, 2024
83 checks passed
@tannergooding tannergooding deleted the bigint-maxlength branch May 31, 2024 15:21
@github-actions github-actions bot locked and limited conversation to collaborators Jul 1, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants