From bc243788edd0e564df8b67d0750a238d978c954b Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Wed, 3 May 2017 12:48:27 +0100 Subject: [PATCH] Return `long' objects when `int' is requested but the value won't fit. Organization: Straylight/Edgeware From: Mark Wooding Mostly, Python handles the error from the `int' conversion and falls back to long, but there's something weird in iteration, where if you say for i in ...: print '%d' % x then the loop finishes and /then/ you get an exception for the overflow from the failed conversion of x to an `int'. Follow Python's actual behaviour: have `mp_tolong_checked' take an extra argument indicating whether to throw an exception, and modify most of the call sites to fall back to a conversion based on `mp_topylong'. --- catacomb-python.h | 2 +- ec.c | 4 ++-- field.c | 6 ++++-- group.c | 4 ++-- mp.c | 14 ++++++++------ pgen.c | 5 ++--- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/catacomb-python.h b/catacomb-python.h index f1e6365..8f8da9d 100644 --- a/catacomb-python.h +++ b/catacomb-python.h @@ -321,7 +321,7 @@ extern PyObject *gf_pywrap(mp *); extern mp *mp_frompyobject(PyObject *, int); extern PyObject *mp_topystring(mp *, int, const char *, const char *, const char *); -extern int mp_tolong_checked(mp *, long *); +extern int mp_tolong_checked(mp *, long *, int); /*----- Abstract fields ---------------------------------------------------*/ diff --git a/ec.c b/ec.c index 6dcf1cb..0489bc0 100644 --- a/ec.c +++ b/ec.c @@ -525,8 +525,8 @@ static PyObject *ecpt_pyint(PyObject *me) PyObject *rc = 0; if (EC_ATINF(ECPT_P(me))) VALERR("point at infinity"); getecptout(&p, me); - if (mp_tolong_checked(p.x, &l)) goto end; - rc = PyInt_FromLong(l); + if (!mp_tolong_checked(p.x, &l, 0)) rc = PyInt_FromLong(l); + else rc = mp_topylong(p.x); end: EC_DESTROY(&p); return (rc); diff --git a/field.c b/field.c index 2807c1c..0a5d908 100644 --- a/field.c +++ b/field.c @@ -263,10 +263,12 @@ end: static PyObject *fe_pyint(PyObject *x) { long l; + PyObject *rc; mp *xx = F_OUT(FE_F(x), MP_NEW, FE_X(x)); - if (mp_tolong_checked(xx, &l)) { MP_DROP(xx); return (0); } + if (!mp_tolong_checked(xx, &l, 0)) rc = PyInt_FromLong(l); + else rc = mp_topylong(xx); MP_DROP(xx); - return (PyInt_FromLong(l)); + return (rc); } static PyObject *fe_pylong(PyObject *x) diff --git a/group.c b/group.c index 1432fc8..71d339e 100644 --- a/group.c +++ b/group.c @@ -695,8 +695,8 @@ static PyObject *ge_pyint(PyObject *me) if ((x = G_TOINT(GE_G(me), MP_NEW, GE_X(me))) == 0) TYERR("can't convert to integer"); - if (mp_tolong_checked(x, &l)) goto end; - rc = PyInt_FromLong(l); + if (!mp_tolong_checked(x, &l, 0)) rc = PyInt_FromLong(l); + else rc = mp_topylong(x); end: mp_drop(x); return (rc); diff --git a/mp.c b/mp.c index eb6a496..79c6cf2 100644 --- a/mp.c +++ b/mp.c @@ -163,7 +163,7 @@ PyObject *gf_pywrap(mp *x) return ((PyObject *)z); } -int mp_tolong_checked(mp *x, long *l) +int mp_tolong_checked(mp *x, long *l, int must) { static mp *longmin = 0, *longmax = 0; int rc = -1; @@ -172,8 +172,10 @@ int mp_tolong_checked(mp *x, long *l) longmin = mp_fromlong(MP_NEW, LONG_MIN); longmax = mp_fromlong(MP_NEW, LONG_MAX); } - if (MP_CMP(x, <, longmin) || MP_CMP(x, >, longmax)) - VALERR("mp out of range for int"); + if (MP_CMP(x, <, longmin) || MP_CMP(x, >, longmax)) { + if (must) VALERR("mp out of range for int"); + else goto end; + } *l = mp_tolong(x); rc = 0; end: @@ -362,7 +364,7 @@ static PyObject *mp_pyid(PyObject *x) { RETURN_OBJ(x); } PyObject *z = 0; \ long n; \ if (pre##binop(x, y, &xx, &yy)) RETURN_NOTIMPL; \ - if (mp_tolong_checked(yy, &n)) goto end; \ + if (mp_tolong_checked(yy, &n, 1)) goto end; \ if (n < 0) \ z = pre##_pywrap(mp_##rname(MP_NEW, xx, -n)); \ else \ @@ -483,8 +485,8 @@ static int mp_pynonzerop(PyObject *x) { return !MP_ZEROP(MP_X(x)); } static PyObject *mp_pyint(PyObject *x) { long l; - if (mp_tolong_checked(MP_X(x), &l)) return (0); - return (PyInt_FromLong(l)); + if (!mp_tolong_checked(MP_X(x), &l, 0)) return (PyInt_FromLong(l)); + else return mp_topylong(MP_X(x)); } static PyObject *mp_pylong(PyObject *x) { return (mp_topylong(MP_X(x))); } diff --git a/pgen.c b/pgen.c index 24639ec..108fa31 100644 --- a/pgen.c +++ b/pgen.c @@ -120,9 +120,8 @@ static PyObject *pfilt_pyint(PyObject *me) long l; PyObject *rc = 0; - if (mp_tolong_checked(PFILT_F(me)->m, &l)) goto end; - rc = PyInt_FromLong(l); -end: + if (!mp_tolong_checked(PFILT_F(me)->m, &l, 0)) rc = PyInt_FromLong(l); + else rc = mp_topylong(PFILT_F(me)->m); return (rc); } -- [mdw]