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

[PATCH] Fix RT 25274: Math::BigInt::Calc->_num() overflow. #10917

Closed
p5pRT opened this issue Dec 22, 2010 · 6 comments
Closed

[PATCH] Fix RT 25274: Math::BigInt::Calc->_num() overflow. #10917

p5pRT opened this issue Dec 22, 2010 · 6 comments

Comments

@p5pRT
Copy link

p5pRT commented Dec 22, 2010

Migrated from rt.perl.org#81170 (status was 'resolved')

Searchable as RT81170$

@p5pRT
Copy link
Author

p5pRT commented Dec 22, 2010

From @pjacklam

Why​: Math​::BigInt​::Calc->_num() converts a big integer (in the internal
format) to a Perl scalar. If the big integer is too large to be
represented as a Perl scalar, it might return a Perl scalar numeric
"nan", rather than "inf". The reason is that the current algorithm might
multiply "inf" by "0", giving a "nan" which propagates. The following
example illustrates the bug​:

  perl -MMath​::BigInt=lib,Calc -wle \
  'print Math​::BigInt->new("1e999999")->numify()'

How​: This fix computes the output in a different way, never multiply
"inf" by "0".

Test​: It is not obvious to me how to test this automatically in a
portable way, since Perl has no standard way of stringifying a scalar
numeric infinity. However the desired behaviour is verified manually and
no existing tests fail with the new code.


dist/Math-BigInt/lib/Math/BigInt/Calc.pm | 23 ++++++++++++++---------
1 files changed, 14 insertions(+), 9 deletions(-)

Inline Patch
diff --git a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm b/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
index 3cb2025..c778dcd 100644
--- a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
+++ b/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
@@ -272,17 +272,22 @@ sub _str
 
 sub _num
   {
-  # Make a number (scalar int/float) from a BigInt object 
-  my $x = $_[1];
+    # Make a Perl scalar number (int/float) from a BigInt object.
+    my $x = $_[1];
 
-  return 0+$x->[0] if scalar @$x == 1;  # below $BASE
-  my $fac = 1;
-  my $num = 0;
-  foreach (@$x)
-    {
-    $num += $fac*$_; $fac *= $BASE;
+    return 0 + $x->[0] if scalar @$x == 1;      # below $BASE
+
+    # Start with the most significant element and work towards the least
+    # significant element. Avoid multiplying "inf" (which happens if the number
+    # overflows) with "0" (if there are zero elements in $x) since this gives
+    # "nan" which propagates to the output.
+
+    my $num = 0;
+    for (my $i = $#$x ; $i >= 0 ; --$i) {
+        $num *= $BASE;
+        $num += $x -> [$i];
     }
-  $num; 
+    return $num;
   }
 
 ##############################################################################
-- 
1.7.2.3

@p5pRT
Copy link
Author

p5pRT commented Dec 26, 2010

From @cpansprout

On Wed Dec 22 10​:43​:11 2010, pjacklam@​online.no wrote​:

Why​: Math​::BigInt​::Calc->_num() converts a big integer (in the
internal
format) to a Perl scalar. If the big integer is too large to be
represented as a Perl scalar, it might return a Perl scalar numeric
"nan", rather than "inf". The reason is that the current algorithm
might
multiply "inf" by "0", giving a "nan" which propagates. The following
example illustrates the bug​:

perl \-MMath​::BigInt=lib\,Calc \-wle \\
    'print Math​::BigInt\->new\("1e999999"\)\->numify\(\)'

How​: This fix computes the output in a different way, never multiply
"inf" by "0".

Test​: It is not obvious to me how to test this automatically in a
portable way, since Perl has no standard way of stringifying a scalar
numeric infinity. However the desired behaviour is verified manually
and
no existing tests fail with the new code.
---
dist/Math-BigInt/lib/Math/BigInt/Calc.pm | 23
++++++++++++++---------
1 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm b/dist/Math-
BigInt/lib/Math/BigInt/Calc.pm
index 3cb2025..c778dcd 100644
--- a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
+++ b/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
@​@​ -272,17 +272,22 @​@​ sub _str

sub _num
{
- # Make a number (scalar int/float) from a BigInt object
- my $x = $_[1];
+ # Make a Perl scalar number (int/float) from a BigInt object.
+ my $x = $_[1];

- return 0+$x->[0] if scalar @​$x == 1; # below $BASE
- my $fac = 1;
- my $num = 0;
- foreach (@​$x)
- {
- $num += $fac*$_; $fac *= $BASE;
+ return 0 + $x->[0] if scalar @​$x == 1; # below $BASE
+
+ # Start with the most significant element and work towards the
least
+ # significant element. Avoid multiplying "inf" (which happens if
the number
+ # overflows) with "0" (if there are zero elements in $x) since
this gives
+ # "nan" which propagates to the output.
+
+ my $num = 0;
+ for (my $i = $#$x ; $i >= 0 ; --$i) {
+ $num *= $BASE;
+ $num += $x -> [$i];
}
- $num;
+ return $num;
}

##############################################################################

Thank you. Applied as e5dcd52.

@p5pRT
Copy link
Author

p5pRT commented Dec 26, 2010

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Dec 26, 2010

@cpansprout - Status changed from 'open' to 'resolved'

@p5pRT p5pRT closed this as completed Dec 26, 2010
@p5pRT
Copy link
Author

p5pRT commented Dec 26, 2010

From @cpansprout

As often happeneth, I forgat to forward this to p5p​:

On Sun Dec 26 14​:38​:35 2010, sprout wrote​:

On Wed Dec 22 10​:43​:11 2010, pjacklam@​online.no wrote​:

Why​: Math​::BigInt​::Calc->_num() converts a big integer (in the
internal
format) to a Perl scalar. If the big integer is too large to be
represented as a Perl scalar, it might return a Perl scalar numeric
"nan", rather than "inf". The reason is that the current algorithm
might
multiply "inf" by "0", giving a "nan" which propagates. The
following
example illustrates the bug​:

perl \-MMath​::BigInt=lib\,Calc \-wle \\
    'print Math​::BigInt\->new\("1e999999"\)\->numify\(\)'

How​: This fix computes the output in a different way, never multiply
"inf" by "0".

Test​: It is not obvious to me how to test this automatically in a
portable way, since Perl has no standard way of stringifying a
scalar
numeric infinity. However the desired behaviour is verified manually
and
no existing tests fail with the new code.
---
dist/Math-BigInt/lib/Math/BigInt/Calc.pm | 23
++++++++++++++---------
1 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm b/dist/Math-
BigInt/lib/Math/BigInt/Calc.pm
index 3cb2025..c778dcd 100644
--- a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
+++ b/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
@​@​ -272,17 +272,22 @​@​ sub _str

sub _num
{
- # Make a number (scalar int/float) from a BigInt object
- my $x = $_[1];
+ # Make a Perl scalar number (int/float) from a BigInt object.
+ my $x = $_[1];

- return 0+$x->[0] if scalar @​$x == 1; # below $BASE
- my $fac = 1;
- my $num = 0;
- foreach (@​$x)
- {
- $num += $fac*$_; $fac *= $BASE;
+ return 0 + $x->[0] if scalar @​$x == 1; # below $BASE
+
+ # Start with the most significant element and work towards the
least
+ # significant element. Avoid multiplying "inf" (which happens
if
the number
+ # overflows) with "0" (if there are zero elements in $x) since
this gives
+ # "nan" which propagates to the output.
+
+ my $num = 0;
+ for (my $i = $#$x ; $i >= 0 ; --$i) {
+ $num *= $BASE;
+ $num += $x -> [$i];
}
- $num;
+ return $num;
}

##############################################################################

Thank you. Applied as e5dcd52.

@p5pRT
Copy link
Author

p5pRT commented Dec 26, 2010

From [Unknown Contact. See original ticket]

As often happeneth, I forgat to forward this to p5p​:

On Sun Dec 26 14​:38​:35 2010, sprout wrote​:

On Wed Dec 22 10​:43​:11 2010, pjacklam@​online.no wrote​:

Why​: Math​::BigInt​::Calc->_num() converts a big integer (in the
internal
format) to a Perl scalar. If the big integer is too large to be
represented as a Perl scalar, it might return a Perl scalar numeric
"nan", rather than "inf". The reason is that the current algorithm
might
multiply "inf" by "0", giving a "nan" which propagates. The
following
example illustrates the bug​:

perl \-MMath​::BigInt=lib\,Calc \-wle \\
    'print Math​::BigInt\->new\("1e999999"\)\->numify\(\)'

How​: This fix computes the output in a different way, never multiply
"inf" by "0".

Test​: It is not obvious to me how to test this automatically in a
portable way, since Perl has no standard way of stringifying a
scalar
numeric infinity. However the desired behaviour is verified manually
and
no existing tests fail with the new code.
---
dist/Math-BigInt/lib/Math/BigInt/Calc.pm | 23
++++++++++++++---------
1 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm b/dist/Math-
BigInt/lib/Math/BigInt/Calc.pm
index 3cb2025..c778dcd 100644
--- a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
+++ b/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
@​@​ -272,17 +272,22 @​@​ sub _str

sub _num
{
- # Make a number (scalar int/float) from a BigInt object
- my $x = $_[1];
+ # Make a Perl scalar number (int/float) from a BigInt object.
+ my $x = $_[1];

- return 0+$x->[0] if scalar @​$x == 1; # below $BASE
- my $fac = 1;
- my $num = 0;
- foreach (@​$x)
- {
- $num += $fac*$_; $fac *= $BASE;
+ return 0 + $x->[0] if scalar @​$x == 1; # below $BASE
+
+ # Start with the most significant element and work towards the
least
+ # significant element. Avoid multiplying "inf" (which happens
if
the number
+ # overflows) with "0" (if there are zero elements in $x) since
this gives
+ # "nan" which propagates to the output.
+
+ my $num = 0;
+ for (my $i = $#$x ; $i >= 0 ; --$i) {
+ $num *= $BASE;
+ $num += $x -> [$i];
}
- $num;
+ return $num;
}

##############################################################################

Thank you. Applied as e5dcd52.

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

No branches or pull requests

1 participant