Subject: | Math::BigRat->new can corrupt arguments |
Example (with $VERSION = '0.2614'):
% perl -wle 'use Math::BigRat; my $q = Math::BigRat->new("-1/2"); my($n, $d) = $q->parts; print "before: n=$n"; my $q2 = Math::BigRat->new($n, $d); print "after: n=$n"'
before: n=-1
after: n=1
%
Judging by my installed perls, this appears to be a regression introduced some time between 0.260802 and 0.2613, possibly the 0.260803 rewrite of new().
While some earlier cases correctly call copy() on object arguments before modifying them, from around line 370 ("make sure denominator is positive") it starts treating $n and $d as safe to manipulate.
Simplest would be to add a mandatory copy just before this, as per the patch below; however doing it far earlier would allow the rest of the code to be a bit cleaner, and should introduce a performance cost only for degenerate cases such as new(bigint, 0) which are presumably rare.
Hugo
--- BigRat.pm.old 2020-05-26 16:20:33.301875097 +0100
+++ BigRat.pm 2020-05-26 16:48:35.362139908 +0100
@@ -366,6 +366,9 @@
return $class -> binf($d -> sign()) if $d -> is_zero();
# At this point, neither $n nor $d is a NaN or a zero.
+ # Copy them now before manipulating them.
+ $n = $n -> copy();
+ $d = $d -> copy();
if ($d < 0) { # make sure denominator is positive
$n -> bneg();