summaryrefslogtreecommitdiffstats
path: root/Modules/_decimal
diff options
context:
space:
mode:
authorStefan Krah <skrah@bytereef.org>2012-08-22 17:11:50 (GMT)
committerStefan Krah <skrah@bytereef.org>2012-08-22 17:11:50 (GMT)
commitad5b43995e758c7a1f81ce6cf2cd798b48712808 (patch)
tree807a78b4da935f606bfa066dde471a210a64a81a /Modules/_decimal
parent2fd502f6a183fde7d8b4847d27e09884bf8006c7 (diff)
downloadcpython-ad5b43995e758c7a1f81ce6cf2cd798b48712808.zip
cpython-ad5b43995e758c7a1f81ce6cf2cd798b48712808.tar.gz
cpython-ad5b43995e758c7a1f81ce6cf2cd798b48712808.tar.bz2
In the 32-bit build, dec_hash() raised InvalidOperation if the operand
had a coefficient with MAX_PREC=425000000 digits and a negative exponent. Increasing the context limits above the official values fixes the issue and is safe (in this case!).
Diffstat (limited to 'Modules/_decimal')
-rw-r--r--Modules/_decimal/_decimal.c16
-rw-r--r--Modules/_decimal/tests/bignum.py45
2 files changed, 57 insertions, 4 deletions
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
index ad84d58..6217a3f 100644
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -4338,6 +4338,11 @@ _dec_hash(PyDecObject *v)
}
tmp->exp = 0;
mpd_set_positive(tmp);
+
+ maxctx.prec = MPD_MAX_PREC + 21;
+ maxctx.emax = MPD_MAX_EMAX + 21;
+ maxctx.emin = MPD_MIN_EMIN - 21;
+
mpd_qmul(tmp, tmp, exp_hash, &maxctx, &status);
mpd_qrem(tmp, tmp, &p, &maxctx, &status);
@@ -4346,11 +4351,14 @@ _dec_hash(PyDecObject *v)
result = (result == -1) ? -2 : result;
if (status != 0) {
- status |= MPD_Invalid_operation;
- if (dec_addstatus(context, status)) {
- result = -1;
- goto finish;
+ if (status & MPD_Malloc_error) {
+ goto malloc_error;
+ }
+ else {
+ PyErr_SetString(PyExc_RuntimeError,
+ "dec_hash: internal error: please report");
}
+ result = -1;
}
diff --git a/Modules/_decimal/tests/bignum.py b/Modules/_decimal/tests/bignum.py
new file mode 100644
index 0000000..9e9e769
--- /dev/null
+++ b/Modules/_decimal/tests/bignum.py
@@ -0,0 +1,45 @@
+#
+# These tests require gmpy and test the limits of the 32-bit build. The
+# limits of the 64-bit build are so large that they cannot be tested
+# on accessible hardware.
+#
+
+import sys
+from decimal import *
+from gmpy import mpz
+
+
+_PyHASH_MODULUS = sys.hash_info.modulus
+# hash values to use for positive and negative infinities, and nans
+_PyHASH_INF = sys.hash_info.inf
+_PyHASH_NAN = sys.hash_info.nan
+
+# _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS
+_PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
+
+def xhash(coeff, exp):
+ sign = 1
+ if coeff < 0:
+ sign = -1
+ coeff = -coeff
+ if exp >= 0:
+ exp_hash = pow(10, exp, _PyHASH_MODULUS)
+ else:
+ exp_hash = pow(_PyHASH_10INV, -exp, _PyHASH_MODULUS)
+ hash_ = coeff * exp_hash % _PyHASH_MODULUS
+ ans = hash_ if sign == 1 else -hash_
+ return -2 if ans == -1 else ans
+
+
+x = mpz(10) ** 425000000 - 1
+coeff = int(x)
+
+d = Decimal('9' * 425000000 + 'e-849999999')
+
+h1 = xhash(coeff, -849999999)
+h2 = hash(d)
+
+assert h2 == h1
+
+
+