summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Leroy <xavier.leroy@inria.fr>2013-05-08 08:38:55 +0000
committerXavier Leroy <xavier.leroy@inria.fr>2013-05-08 08:38:55 +0000
commit0f45880800ac00767889f462dd6d5255bb93d742 (patch)
tree3f0d114fdea088cdf156112db9f4592dc898dcd0
parent51c65627cb98c11d74086af7fd90a5eb053fc5f7 (diff)
downloadocaml-0f45880800ac00767889f462dd6d5255bb93d742.tar.gz
PR#6010: Big_int.extract_big_int gives wrong results on negative arguments
git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@13660 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
-rw-r--r--Changes3
-rw-r--r--otherlibs/num/big_int.ml8
-rw-r--r--testsuite/tests/lib-num/end_test.reference2
-rw-r--r--testsuite/tests/lib-num/test_big_ints.ml10
4 files changed, 18 insertions, 5 deletions
diff --git a/Changes b/Changes
index 8bca57bbaf..29de1e3ef5 100644
--- a/Changes
+++ b/Changes
@@ -86,7 +86,8 @@ Bug fixes:
- PR#5981: Incompatibility check assumes abstracted types are injective
- PR#5985: Unexpected interaction between variance and GADTs
- PR#6004: Type information does not flow to "inherit" parameters
-- PR#6005: Obj.magic with recursive modules
+- PR#6005: Type unsoundness with recursive modules
+- PR#6010: Big_int.extract_big_int gives wrong results on negative arguments
Internals:
- Moved debugger/envaux.ml to typing/envaux.ml to publish env_of_only_summary
diff --git a/otherlibs/num/big_int.ml b/otherlibs/num/big_int.ml
index c33fea56a2..95c6f6a8a9 100644
--- a/otherlibs/num/big_int.ml
+++ b/otherlibs/num/big_int.ml
@@ -739,7 +739,13 @@ let extract_big_int bi ofs n =
if bi.sign < 0 then begin
(* Two's complement *)
complement_nat res 0 size_res;
- ignore (incr_nat res 0 size_res 1)
+ (* PR#6010: need to increment res iff digits 0...ndigits-1 of bi are 0.
+ In this case, digits 0...ndigits-1 of not(bi) are all 0xFF...FF,
+ and adding 1 to them produces a carry out at ndigits. *)
+ let rec carry_incr i =
+ i >= ndigits || i >= size_bi ||
+ (is_digit_zero bi.abs_value i && carry_incr (i + 1)) in
+ if carry_incr 0 then ignore (incr_nat res 0 size_res 1)
end;
if nbits > 0 then begin
let tmp = create_nat 1 in
diff --git a/testsuite/tests/lib-num/end_test.reference b/testsuite/tests/lib-num/end_test.reference
index 8e7ac4b6cd..1c31f7121a 100644
--- a/testsuite/tests/lib-num/end_test.reference
+++ b/testsuite/tests/lib-num/end_test.reference
@@ -82,7 +82,7 @@ shift_right_big_int
shift_right_towards_zero_big_int
1... 2...
extract_big_int
- 1... 2... 3... 4... 5... 6...
+ 1... 2... 3... 4... 5... 6... 7... 8...
hashing of big integers
1... 2... 3... 4... 5... 6...
create_ratio
diff --git a/testsuite/tests/lib-num/test_big_ints.ml b/testsuite/tests/lib-num/test_big_ints.ml
index a8a5673d8a..3bdb988868 100644
--- a/testsuite/tests/lib-num/test_big_ints.ml
+++ b/testsuite/tests/lib-num/test_big_ints.ml
@@ -932,8 +932,14 @@ test 5 eq_big_int
(extract_big_int (big_int_of_int64 0x123456789ABCDEFL) 0 32,
big_int_of_int64 2309737967L);;
test 6 eq_big_int
- (extract_big_int (big_int_of_int (-1)) 2048 254,
- zero_big_int);;
+ (extract_big_int (big_int_of_int (-1)) 0 16,
+ big_int_of_int 0xFFFF);;
+test 7 eq_big_int
+ (extract_big_int (big_int_of_int (-1)) 1027 12,
+ big_int_of_int 0xFFF);;
+test 8 eq_big_int
+ (extract_big_int (big_int_of_int (-1234567)) 0 16,
+ big_int_of_int 10617);;
testing_function "hashing of big integers";;