From 4cfe7f8da412439e863952fc5984232570fda3bb Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 28 Mar 2017 00:34:46 +0200 Subject: [PATCH] bpo-17870: Add support for C intmax_t type * Add new conversions functions for PyLong: - PyLong_FromIntMax() - PyLong_FromUIntMax() - PyLong_AsIntMax() - PyLong_AsIntMaxAndOverflow() - PyLong_AsUIntMax() * getargs: add 'm' format * New _testcapi constants: INTMAX_MAX, INTMAX_MIN, UINTMAX_MAX, SIZEOF_INTMAX_T * Add _testcapi.getargs_m() and _testcapi.test_long_intmax_api() * PyLong_FromVoidPtr() uses PyLong_FromUIntMax() * Use intmax_t in various modules array, struct, ctypes and memoryview are not modified yet to support intmax_t. --- Doc/c-api/arg.rst | 13 ++ Include/longobject.h | 5 + Lib/test/test_getargs2.py | 324 +++++++++++---------------------- Modules/_lzmamodule.c | 4 +- Modules/_testcapimodule.c | 53 ++++++ Modules/_tkinter.c | 5 +- Modules/clinic/posixmodule.c.h | 4 +- Modules/mmapmodule.c | 12 +- Modules/posixmodule.c | 55 ++---- Modules/resource.c | 7 +- Modules/testcapi_long.h | 19 +- Objects/longobject.c | 312 +++++++++++++++++++++++++++---- PC/pyconfig.h | 1 + Python/getargs.c | 18 ++ Python/modsupport.c | 3 + Python/pytime.c | 30 ++- configure | 33 ++++ configure.ac | 1 + pyconfig.h.in | 3 + 19 files changed, 568 insertions(+), 334 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index e8e7e0d559309e..070398e7ac9d21 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -275,6 +275,11 @@ Numbers ``n`` (:class:`int`) [Py_ssize_t] Convert a Python integer to a C :c:type:`Py_ssize_t`. +``m`` (:class:`int`) [intmax_t] + Convert a Python integer to a C :c:type:`intmax_t`. + + .. versionadded:: 3.7 + ``c`` (:class:`bytes` or :class:`bytearray` of length 1) [char] Convert a Python byte, represented as a :class:`bytes` or :class:`bytearray` object of length 1, to a C :c:type:`char`. @@ -600,6 +605,9 @@ Building values ``n`` (:class:`int`) [Py_ssize_t] Convert a C :c:type:`Py_ssize_t` to a Python integer. + ``m`` (:class:`int`) [intmax_t] + Convert a C :c:type:`intmax_t` to a Python integer. + ``c`` (:class:`bytes` of length 1) [char] Convert a C :c:type:`int` representing a byte to a Python :class:`bytes` object of length 1. @@ -653,6 +661,11 @@ Building values If there is an error in the format string, the :exc:`SystemError` exception is set and *NULL* returned. + .. versionchanged:: 3.7 + + Added ``m`` format for ``intmax_t``. + + .. c:function:: PyObject* Py_VaBuildValue(const char *format, va_list vargs) Identical to :c:func:`Py_BuildValue`, except that it accepts a va_list diff --git a/Include/longobject.h b/Include/longobject.h index ac09a00853d125..d838ef2b540433 100644 --- a/Include/longobject.h +++ b/Include/longobject.h @@ -17,14 +17,19 @@ PyAPI_DATA(PyTypeObject) PyLong_Type; PyAPI_FUNC(PyObject *) PyLong_FromLong(long); PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long); +PyAPI_FUNC(PyObject *) PyLong_FromIntMax(intmax_t); +PyAPI_FUNC(PyObject *) PyLong_FromUIntMax(uintmax_t); PyAPI_FUNC(PyObject *) PyLong_FromSize_t(size_t); PyAPI_FUNC(PyObject *) PyLong_FromSsize_t(Py_ssize_t); PyAPI_FUNC(PyObject *) PyLong_FromDouble(double); PyAPI_FUNC(long) PyLong_AsLong(PyObject *); PyAPI_FUNC(long) PyLong_AsLongAndOverflow(PyObject *, int *); +PyAPI_FUNC(intmax_t) PyLong_AsIntMax(PyObject *); +PyAPI_FUNC(intmax_t) PyLong_AsIntMaxAndOverflow(PyObject *, int *); PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *); PyAPI_FUNC(size_t) PyLong_AsSize_t(PyObject *); PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *); +PyAPI_FUNC(uintmax_t) PyLong_AsUIntMax(PyObject *); PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *); #ifndef Py_LIMITED_API PyAPI_FUNC(int) _PyLong_AsInt(PyObject *); diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py index e5d9aa64ee2dfd..ab381a776ff089 100644 --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -3,7 +3,7 @@ import sys from test import support # Skip this test if the _testcapi module isn't available. -support.import_module('_testcapi') +_testcapi = support.import_module('_testcapi') from _testcapi import getargs_keywords, getargs_keyword_only # > How about the following counterproposal. This also changes some of @@ -128,222 +128,120 @@ class DictSubclass(dict): pass -class Unsigned_TestCase(unittest.TestCase): - def test_b(self): - from _testcapi import getargs_b - # b returns 'unsigned char', and does range checking (0 ... UCHAR_MAX) - self.assertRaises(TypeError, getargs_b, 3.14) - self.assertEqual(99, getargs_b(Int())) - self.assertEqual(0, getargs_b(IntSubclass())) - self.assertRaises(TypeError, getargs_b, BadInt()) - with self.assertWarns(DeprecationWarning): - self.assertEqual(1, getargs_b(BadInt2())) - self.assertEqual(0, getargs_b(BadInt3())) - - self.assertRaises(OverflowError, getargs_b, -1) - self.assertEqual(0, getargs_b(0)) - self.assertEqual(UCHAR_MAX, getargs_b(UCHAR_MAX)) - self.assertRaises(OverflowError, getargs_b, UCHAR_MAX + 1) - - self.assertEqual(42, getargs_b(42)) - self.assertRaises(OverflowError, getargs_b, VERY_LARGE) - - def test_B(self): - from _testcapi import getargs_B - # B returns 'unsigned char', no range checking - self.assertRaises(TypeError, getargs_B, 3.14) - self.assertEqual(99, getargs_B(Int())) - self.assertEqual(0, getargs_B(IntSubclass())) - self.assertRaises(TypeError, getargs_B, BadInt()) - with self.assertWarns(DeprecationWarning): - self.assertEqual(1, getargs_B(BadInt2())) - self.assertEqual(0, getargs_B(BadInt3())) - - self.assertEqual(UCHAR_MAX, getargs_B(-1)) - self.assertEqual(0, getargs_B(0)) - self.assertEqual(UCHAR_MAX, getargs_B(UCHAR_MAX)) - self.assertEqual(0, getargs_B(UCHAR_MAX+1)) - - self.assertEqual(42, getargs_B(42)) - self.assertEqual(UCHAR_MAX & VERY_LARGE, getargs_B(VERY_LARGE)) - - def test_H(self): - from _testcapi import getargs_H - # H returns 'unsigned short', no range checking - self.assertRaises(TypeError, getargs_H, 3.14) - self.assertEqual(99, getargs_H(Int())) - self.assertEqual(0, getargs_H(IntSubclass())) - self.assertRaises(TypeError, getargs_H, BadInt()) - with self.assertWarns(DeprecationWarning): - self.assertEqual(1, getargs_H(BadInt2())) - self.assertEqual(0, getargs_H(BadInt3())) +class UnsignedLong_TestCase: + getargs = None + MIN = 0 + MAX = 1 + SUPPORT_INT = False + + def test_basic(self): + self.assertEqual(42, self.getargs(42)) + self.assertEqual(self.MIN, self.getargs(self.MIN)) + self.assertEqual(self.MAX, self.getargs(self.MAX)) + + def test_types(self): + self.assertRaises(TypeError, self.getargs, 3.14) + self.assertRaises(TypeError, self.getargs, "Hello") + self.assertEqual(0, self.getargs(IntSubclass())) + + def test_int(self): + if self.SUPPORT_INT: + self.assertEqual(99, self.getargs(Int())) + self.assertRaises(TypeError, self.getargs, BadInt()) + with self.assertWarns(DeprecationWarning): + self.assertEqual(1, self.getargs(BadInt2())) + else: + self.assertRaises(TypeError, self.getargs, Int()) + self.assertRaises(TypeError, self.getargs, BadInt()) + self.assertRaises(TypeError, self.getargs, BadInt2()) - self.assertEqual(USHRT_MAX, getargs_H(-1)) - self.assertEqual(0, getargs_H(0)) - self.assertEqual(USHRT_MAX, getargs_H(USHRT_MAX)) - self.assertEqual(0, getargs_H(USHRT_MAX+1)) + self.assertEqual(0, self.getargs(BadInt3())) - self.assertEqual(42, getargs_H(42)) + def test_overflow(self): + for value in (self.MIN - 1, self.MAX + 1): + self.assertEqual(value & self.MAX, self.getargs(value)) + self.assertEqual(VERY_LARGE & self.MAX, self.getargs(VERY_LARGE)) - self.assertEqual(VERY_LARGE & USHRT_MAX, getargs_H(VERY_LARGE)) - def test_I(self): - from _testcapi import getargs_I - # I returns 'unsigned int', no range checking - self.assertRaises(TypeError, getargs_I, 3.14) - self.assertEqual(99, getargs_I(Int())) - self.assertEqual(0, getargs_I(IntSubclass())) - self.assertRaises(TypeError, getargs_I, BadInt()) - with self.assertWarns(DeprecationWarning): - self.assertEqual(1, getargs_I(BadInt2())) - self.assertEqual(0, getargs_I(BadInt3())) - - self.assertEqual(UINT_MAX, getargs_I(-1)) - self.assertEqual(0, getargs_I(0)) - self.assertEqual(UINT_MAX, getargs_I(UINT_MAX)) - self.assertEqual(0, getargs_I(UINT_MAX+1)) - - self.assertEqual(42, getargs_I(42)) - - self.assertEqual(VERY_LARGE & UINT_MAX, getargs_I(VERY_LARGE)) - - def test_k(self): - from _testcapi import getargs_k - # k returns 'unsigned long', no range checking - # it does not accept float, or instances with __int__ - self.assertRaises(TypeError, getargs_k, 3.14) - self.assertRaises(TypeError, getargs_k, Int()) - self.assertEqual(0, getargs_k(IntSubclass())) - self.assertRaises(TypeError, getargs_k, BadInt()) - self.assertRaises(TypeError, getargs_k, BadInt2()) - self.assertEqual(0, getargs_k(BadInt3())) - - self.assertEqual(ULONG_MAX, getargs_k(-1)) - self.assertEqual(0, getargs_k(0)) - self.assertEqual(ULONG_MAX, getargs_k(ULONG_MAX)) - self.assertEqual(0, getargs_k(ULONG_MAX+1)) - - self.assertEqual(42, getargs_k(42)) - - self.assertEqual(VERY_LARGE & ULONG_MAX, getargs_k(VERY_LARGE)) - -class Signed_TestCase(unittest.TestCase): - def test_h(self): - from _testcapi import getargs_h - # h returns 'short', and does range checking (SHRT_MIN ... SHRT_MAX) - self.assertRaises(TypeError, getargs_h, 3.14) - self.assertEqual(99, getargs_h(Int())) - self.assertEqual(0, getargs_h(IntSubclass())) - self.assertRaises(TypeError, getargs_h, BadInt()) - with self.assertWarns(DeprecationWarning): - self.assertEqual(1, getargs_h(BadInt2())) - self.assertEqual(0, getargs_h(BadInt3())) - - self.assertRaises(OverflowError, getargs_h, SHRT_MIN-1) - self.assertEqual(SHRT_MIN, getargs_h(SHRT_MIN)) - self.assertEqual(SHRT_MAX, getargs_h(SHRT_MAX)) - self.assertRaises(OverflowError, getargs_h, SHRT_MAX+1) - - self.assertEqual(42, getargs_h(42)) - self.assertRaises(OverflowError, getargs_h, VERY_LARGE) - - def test_i(self): - from _testcapi import getargs_i - # i returns 'int', and does range checking (INT_MIN ... INT_MAX) - self.assertRaises(TypeError, getargs_i, 3.14) - self.assertEqual(99, getargs_i(Int())) - self.assertEqual(0, getargs_i(IntSubclass())) - self.assertRaises(TypeError, getargs_i, BadInt()) - with self.assertWarns(DeprecationWarning): - self.assertEqual(1, getargs_i(BadInt2())) - self.assertEqual(0, getargs_i(BadInt3())) - - self.assertRaises(OverflowError, getargs_i, INT_MIN-1) - self.assertEqual(INT_MIN, getargs_i(INT_MIN)) - self.assertEqual(INT_MAX, getargs_i(INT_MAX)) - self.assertRaises(OverflowError, getargs_i, INT_MAX+1) - - self.assertEqual(42, getargs_i(42)) - self.assertRaises(OverflowError, getargs_i, VERY_LARGE) - - def test_l(self): - from _testcapi import getargs_l - # l returns 'long', and does range checking (LONG_MIN ... LONG_MAX) - self.assertRaises(TypeError, getargs_l, 3.14) - self.assertEqual(99, getargs_l(Int())) - self.assertEqual(0, getargs_l(IntSubclass())) - self.assertRaises(TypeError, getargs_l, BadInt()) - with self.assertWarns(DeprecationWarning): - self.assertEqual(1, getargs_l(BadInt2())) - self.assertEqual(0, getargs_l(BadInt3())) - - self.assertRaises(OverflowError, getargs_l, LONG_MIN-1) - self.assertEqual(LONG_MIN, getargs_l(LONG_MIN)) - self.assertEqual(LONG_MAX, getargs_l(LONG_MAX)) - self.assertRaises(OverflowError, getargs_l, LONG_MAX+1) - - self.assertEqual(42, getargs_l(42)) - self.assertRaises(OverflowError, getargs_l, VERY_LARGE) - - def test_n(self): - from _testcapi import getargs_n - # n returns 'Py_ssize_t', and does range checking - # (PY_SSIZE_T_MIN ... PY_SSIZE_T_MAX) - self.assertRaises(TypeError, getargs_n, 3.14) - self.assertRaises(TypeError, getargs_n, Int()) - self.assertEqual(0, getargs_n(IntSubclass())) - self.assertRaises(TypeError, getargs_n, BadInt()) - self.assertRaises(TypeError, getargs_n, BadInt2()) - self.assertEqual(0, getargs_n(BadInt3())) - - self.assertRaises(OverflowError, getargs_n, PY_SSIZE_T_MIN-1) - self.assertEqual(PY_SSIZE_T_MIN, getargs_n(PY_SSIZE_T_MIN)) - self.assertEqual(PY_SSIZE_T_MAX, getargs_n(PY_SSIZE_T_MAX)) - self.assertRaises(OverflowError, getargs_n, PY_SSIZE_T_MAX+1) - - self.assertEqual(42, getargs_n(42)) - self.assertRaises(OverflowError, getargs_n, VERY_LARGE) - - -class LongLong_TestCase(unittest.TestCase): - def test_L(self): - from _testcapi import getargs_L - # L returns 'long long', and does range checking (LLONG_MIN - # ... LLONG_MAX) - self.assertRaises(TypeError, getargs_L, 3.14) - self.assertRaises(TypeError, getargs_L, "Hello") - self.assertEqual(99, getargs_L(Int())) - self.assertEqual(0, getargs_L(IntSubclass())) - self.assertRaises(TypeError, getargs_L, BadInt()) - with self.assertWarns(DeprecationWarning): - self.assertEqual(1, getargs_L(BadInt2())) - self.assertEqual(0, getargs_L(BadInt3())) - - self.assertRaises(OverflowError, getargs_L, LLONG_MIN-1) - self.assertEqual(LLONG_MIN, getargs_L(LLONG_MIN)) - self.assertEqual(LLONG_MAX, getargs_L(LLONG_MAX)) - self.assertRaises(OverflowError, getargs_L, LLONG_MAX+1) - - self.assertEqual(42, getargs_L(42)) - self.assertRaises(OverflowError, getargs_L, VERY_LARGE) - - def test_K(self): - from _testcapi import getargs_K - # K return 'unsigned long long', no range checking - self.assertRaises(TypeError, getargs_K, 3.14) - self.assertRaises(TypeError, getargs_K, Int()) - self.assertEqual(0, getargs_K(IntSubclass())) - self.assertRaises(TypeError, getargs_K, BadInt()) - self.assertRaises(TypeError, getargs_K, BadInt2()) - self.assertEqual(0, getargs_K(BadInt3())) - - self.assertEqual(ULLONG_MAX, getargs_K(ULLONG_MAX)) - self.assertEqual(0, getargs_K(0)) - self.assertEqual(0, getargs_K(ULLONG_MAX+1)) - - self.assertEqual(42, getargs_K(42)) - - self.assertEqual(VERY_LARGE & ULLONG_MAX, getargs_K(VERY_LARGE)) +class SignedLong_TestCase(UnsignedLong_TestCase): + MIN = -1 + SUPPORT_INT = True + + def test_overflow(self): + self.assertRaises(OverflowError, self.getargs, self.MIN - 1) + self.assertRaises(OverflowError, self.getargs, self.MAX + 1) + self.assertRaises(OverflowError, self.getargs, VERY_LARGE) + + +class Long_b(SignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_b + MIN = 0 + MAX = UCHAR_MAX + + +class Long_h(SignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_h + MIN = SHRT_MIN + MAX = SHRT_MAX + + +class Long_i(SignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_i + MIN = INT_MIN + MAX = INT_MAX + + +class Long_l(SignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_l + MIN = LONG_MIN + MAX = LONG_MAX + + +class LongLong_L(SignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_L + MIN = LLONG_MIN + MAX = LLONG_MAX + + +class Long_n(SignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_n + MIN = PY_SSIZE_T_MIN + MAX = PY_SSIZE_T_MAX + SUPPORT_INT = False + + +class Long_B(UnsignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_B + MAX = UCHAR_MAX + SUPPORT_INT = True + + +class Long_H(UnsignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_H + MAX = USHRT_MAX + SUPPORT_INT = True + + +class Long_I(UnsignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_I + MAX = UINT_MAX + SUPPORT_INT = True + + +class Long_k(UnsignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_k + MAX = ULONG_MAX + + +class LongLong_K(UnsignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_K + MAX = ULLONG_MAX + + +class Long_IntMax_m(SignedLong_TestCase, unittest.TestCase): + getargs = _testcapi.getargs_m + MIN = _testcapi.INTMAX_MIN + MAX = _testcapi.INTMAX_MAX class Float_TestCase(unittest.TestCase): diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index bb77552b67b15d..699a5f5e5b56c2 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -1442,9 +1442,9 @@ static PyModuleDef _lzmamodule = { /* Some of our constants are more than 32 bits wide, so PyModule_AddIntConstant would not work correctly on platforms with 32-bit longs. */ static int -module_add_int_constant(PyObject *m, const char *name, long long value) +module_add_int_constant(PyObject *m, const char *name, intmax_t value) { - PyObject *o = PyLong_FromLongLong(value); + PyObject *o = PyLong_FromIntMax(value); if (o == NULL) return -1; if (PyModule_AddObject(m, name, o) == 0) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index c6af0180dfd66e..14aac6a07a7549 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -61,6 +61,7 @@ test_config(PyObject *self) CHECK_SIZEOF(SIZEOF_VOID_P, void*); CHECK_SIZEOF(SIZEOF_TIME_T, time_t); CHECK_SIZEOF(SIZEOF_LONG_LONG, long long); + CHECK_SIZEOF(SIZEOF_INTMAX_T, intmax_t); #undef CHECK_SIZEOF @@ -401,6 +402,7 @@ raise_test_long_error(const char* msg) #define TESTNAME test_long_api_inner #define TYPENAME long +#define UTYPENAME unsigned long #define F_S_TO_PY PyLong_FromLong #define F_PY_TO_S PyLong_AsLong #define F_U_TO_PY PyLong_FromUnsignedLong @@ -416,11 +418,46 @@ test_long_api(PyObject* self) #undef TESTNAME #undef TYPENAME +#undef UTYPENAME #undef F_S_TO_PY #undef F_PY_TO_S #undef F_U_TO_PY #undef F_PY_TO_U +/* intmax_t */ + +static PyObject * +raise_test_long_intmax_error(const char* msg) +{ + return raiseTestError("test_long_intmax_api", msg); +} + +#define TESTNAME test_long_intmax_api_inner +#define TYPENAME intmax_t +#define UTYPENAME uintmax_t +#define F_S_TO_PY PyLong_FromIntMax +#define F_PY_TO_S PyLong_AsIntMax +#define F_U_TO_PY PyLong_FromUIntMax +#define F_PY_TO_U PyLong_AsUIntMax + +#include "testcapi_long.h" + +static PyObject * +test_long_intmax_api(PyObject* self, PyObject *args) +{ + return TESTNAME(raise_test_long_intmax_error); +} + +#undef TESTNAME +#undef TYPENAME +#undef UTYPENAME +#undef F_S_TO_PY +#undef F_PY_TO_S +#undef F_U_TO_PY +#undef F_PY_TO_U + +/* long long */ + static PyObject * raise_test_longlong_error(const char* msg) { @@ -429,6 +466,7 @@ raise_test_longlong_error(const char* msg) #define TESTNAME test_longlong_api_inner #define TYPENAME long long +#define UTYPENAME unsigned long long #define F_S_TO_PY PyLong_FromLongLong #define F_PY_TO_S PyLong_AsLongLong #define F_U_TO_PY PyLong_FromUnsignedLongLong @@ -444,6 +482,7 @@ test_longlong_api(PyObject* self, PyObject *args) #undef TESTNAME #undef TYPENAME +#undef UTYPENAME #undef F_S_TO_PY #undef F_PY_TO_S #undef F_U_TO_PY @@ -1166,6 +1205,15 @@ getargs_K(PyObject *self, PyObject *args) return PyLong_FromUnsignedLongLong(value); } +static PyObject * +getargs_m(PyObject *self, PyObject *args) +{ + intmax_t value; + if (!PyArg_ParseTuple(args, "m", &value)) + return NULL; + return PyLong_FromIntMax(value); +} + /* This function not only tests the 'k' getargs code, but also the PyLong_AsUnsignedLongMask() function. */ static PyObject * @@ -4041,6 +4089,7 @@ static PyMethodDef TestMethods[] = { {"dict_hassplittable", dict_hassplittable, METH_O}, {"test_lazy_hash_inheritance", (PyCFunction)test_lazy_hash_inheritance,METH_NOARGS}, {"test_long_api", (PyCFunction)test_long_api, METH_NOARGS}, + {"test_long_intmax_api", (PyCFunction)test_long_intmax_api, METH_NOARGS}, {"test_xincref_doesnt_leak",(PyCFunction)test_xincref_doesnt_leak, METH_NOARGS}, {"test_incref_doesnt_leak", (PyCFunction)test_incref_doesnt_leak, METH_NOARGS}, {"test_xdecref_doesnt_leak",(PyCFunction)test_xdecref_doesnt_leak, METH_NOARGS}, @@ -4089,6 +4138,7 @@ static PyMethodDef TestMethods[] = { {"getargs_p", getargs_p, METH_VARARGS}, {"getargs_L", getargs_L, METH_VARARGS}, {"getargs_K", getargs_K, METH_VARARGS}, + {"getargs_m", getargs_m, METH_VARARGS}, {"test_longlong_api", test_longlong_api, METH_NOARGS}, {"test_long_long_and_overflow", (PyCFunction)test_long_long_and_overflow, METH_NOARGS}, @@ -4627,7 +4677,10 @@ PyInit__testcapi(void) PyModule_AddObject(m, "UINT_MAX", PyLong_FromUnsignedLong(UINT_MAX)); PyModule_AddObject(m, "LONG_MAX", PyLong_FromLong(LONG_MAX)); PyModule_AddObject(m, "LONG_MIN", PyLong_FromLong(LONG_MIN)); + PyModule_AddObject(m, "INTMAX_MAX", PyLong_FromIntMax(INTMAX_MAX)); + PyModule_AddObject(m, "INTMAX_MIN", PyLong_FromIntMax(INTMAX_MIN)); PyModule_AddObject(m, "ULONG_MAX", PyLong_FromUnsignedLong(ULONG_MAX)); + PyModule_AddObject(m, "UINTMAX_MAX", PyLong_FromUIntMax(UINTMAX_MAX)); PyModule_AddObject(m, "FLT_MAX", PyFloat_FromDouble(FLT_MAX)); PyModule_AddObject(m, "FLT_MIN", PyFloat_FromDouble(FLT_MIN)); PyModule_AddObject(m, "DBL_MAX", PyFloat_FromDouble(DBL_MAX)); diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 7ed2b0254bd7fd..3455d8b0990bae 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1182,8 +1182,9 @@ fromWideIntObj(PyObject* tkapp, Tcl_Obj *value) { Tcl_WideInt wideValue; if (Tcl_GetWideIntFromObj(Tkapp_Interp(tkapp), value, &wideValue) == TCL_OK) { - if (sizeof(wideValue) <= SIZEOF_LONG_LONG) - return PyLong_FromLongLong(wideValue); + if (sizeof(wideValue) <= SIZEOF_INTMAX_T) { + return PyLong_FromIntMax(wideValue); + } return _PyLong_FromByteArray((unsigned char *)(void *)&wideValue, sizeof(wideValue), PY_LITTLE_ENDIAN, diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 39ac7fd54fd90e..f942f1b8e7edca 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -3606,7 +3606,7 @@ os_lseek(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } - return_value = PyLong_FromPy_off_t(_return_value); + return_value = PyLong_FromIntMax(_return_value); exit: return return_value; @@ -6493,4 +6493,4 @@ os_getrandom(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwna #ifndef OS_GETRANDOM_METHODDEF #define OS_GETRANDOM_METHODDEF #endif /* !defined(OS_GETRANDOM_METHODDEF) */ -/*[clinic end generated code: output=5a0be969e3f71660 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e3c4d69deb356f4c input=a9049054013a1b77]*/ diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 7c15d377cfdf4e..21c4299efc221e 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -432,7 +432,7 @@ mmap_size_method(mmap_object *self, #ifdef MS_WINDOWS if (self->file_handle != INVALID_HANDLE_VALUE) { DWORD low,high; - long long size; + intmax_t size; low = GetFileSize(self->file_handle, &high); if (low == INVALID_FILE_SIZE) { /* It might be that the function appears to have failed, @@ -443,8 +443,8 @@ mmap_size_method(mmap_object *self, } if (!high && low < LONG_MAX) return PyLong_FromLong((long)low); - size = (((long long)high)<<32) + low; - return PyLong_FromLongLong(size); + size = (((intmax_t)high)<<32) + low; + return PyLong_FromIntMax(size); } else { return PyLong_FromSsize_t(self->size); } @@ -455,11 +455,7 @@ mmap_size_method(mmap_object *self, struct _Py_stat_struct status; if (_Py_fstat(self->fd, &status) == -1) return NULL; -#ifdef HAVE_LARGEFILE_SUPPORT - return PyLong_FromLongLong(status.st_size); -#else - return PyLong_FromLong(status.st_size); -#endif + return PyLong_FromIntMax(status.st_size); } #endif /* UNIX */ } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 0ae06eb53eaef9..ad47446fc92625 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -645,7 +645,7 @@ _Py_Gid_Converter(PyObject *obj, void *p) #endif /* MS_WINDOWS */ -#define _PyLong_FromDev PyLong_FromLongLong +#define _PyLong_FromDev PyLong_FromIntMax #if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) @@ -1167,16 +1167,6 @@ Py_off_t_converter(PyObject *arg, void *addr) return 1; } -static PyObject * -PyLong_FromPy_off_t(Py_off_t offset) -{ -#ifdef HAVE_LARGEFILE_SUPPORT - return PyLong_FromLongLong(offset); -#else - return PyLong_FromLong(offset); -#endif -} - #ifdef MS_WINDOWS static int @@ -1927,14 +1917,8 @@ _pystat_fromstructstat(STRUCT_STAT *st) return NULL; PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode)); -#if defined(HAVE_LARGEFILE_SUPPORT) || defined(MS_WINDOWS) - Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(st->st_ino)); PyStructSequence_SET_ITEM(v, 1, - PyLong_FromUnsignedLongLong(st->st_ino)); -#else - Py_BUILD_ASSERT(sizeof(unsigned long) >= sizeof(st->st_ino)); - PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLong(st->st_ino)); -#endif + PyLong_FromUIntMax(st->st_ino)); #ifdef MS_WINDOWS PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLong(st->st_dev)); #else @@ -1948,12 +1932,7 @@ _pystat_fromstructstat(STRUCT_STAT *st) PyStructSequence_SET_ITEM(v, 4, _PyLong_FromUid(st->st_uid)); PyStructSequence_SET_ITEM(v, 5, _PyLong_FromGid(st->st_gid)); #endif -#ifdef HAVE_LARGEFILE_SUPPORT - PyStructSequence_SET_ITEM(v, 6, - PyLong_FromLongLong((long long)st->st_size)); -#else - PyStructSequence_SET_ITEM(v, 6, PyLong_FromLong(st->st_size)); -#endif + PyStructSequence_SET_ITEM(v, 6, PyLong_FromIntMax(st->st_size)); #if defined(HAVE_STAT_TV_NSEC) ansec = st->st_atim.tv_nsec; @@ -2358,7 +2337,7 @@ class Py_off_t_converter(CConverter): class Py_off_t_return_converter(long_return_converter): type = 'Py_off_t' - conversion_fn = 'PyLong_FromPy_off_t' + conversion_fn = 'PyLong_FromIntMax' class path_confname_converter(CConverter): type="int" @@ -2376,7 +2355,7 @@ class sched_param_converter(CConverter): impl_by_reference = True; [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=418fce0e01144461]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=6810f54d2201a416]*/ /*[clinic input] @@ -9153,18 +9132,12 @@ _pystatvfs_fromstructstatvfs(struct statvfs st) { #else PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long) st.f_bsize)); PyStructSequence_SET_ITEM(v, 1, PyLong_FromLong((long) st.f_frsize)); - PyStructSequence_SET_ITEM(v, 2, - PyLong_FromLongLong((long long) st.f_blocks)); - PyStructSequence_SET_ITEM(v, 3, - PyLong_FromLongLong((long long) st.f_bfree)); - PyStructSequence_SET_ITEM(v, 4, - PyLong_FromLongLong((long long) st.f_bavail)); - PyStructSequence_SET_ITEM(v, 5, - PyLong_FromLongLong((long long) st.f_files)); - PyStructSequence_SET_ITEM(v, 6, - PyLong_FromLongLong((long long) st.f_ffree)); - PyStructSequence_SET_ITEM(v, 7, - PyLong_FromLongLong((long long) st.f_favail)); + PyStructSequence_SET_ITEM(v, 2, PyLong_FromIntMax(st.f_blocks)); + PyStructSequence_SET_ITEM(v, 3, PyLong_FromIntMax(st.f_bfree)); + PyStructSequence_SET_ITEM(v, 4, PyLong_FromIntMax(st.f_bavail)); + PyStructSequence_SET_ITEM(v, 5, PyLong_FromIntMax(st.f_files)); + PyStructSequence_SET_ITEM(v, 6, PyLong_FromIntMax(st.f_ffree)); + PyStructSequence_SET_ITEM(v, 7, PyLong_FromIntMax(st.f_favail)); PyStructSequence_SET_ITEM(v, 8, PyLong_FromLong((long) st.f_flag)); PyStructSequence_SET_ITEM(v, 9, PyLong_FromLong((long) st.f_namemax)); #endif @@ -11414,11 +11387,7 @@ os_DirEntry_inode_impl(DirEntry *self) Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(self->win32_file_index)); return PyLong_FromUnsignedLongLong(self->win32_file_index); #else /* POSIX */ -#ifdef HAVE_LARGEFILE_SUPPORT - return PyLong_FromLongLong((long long)self->d_ino); -#else - return PyLong_FromLong((long)self->d_ino); -#endif + return PyLong_FromUIntMax((long)self->d_ino); #endif } diff --git a/Modules/resource.c b/Modules/resource.c index e59280f249dfe4..9268dd270d3903 100644 --- a/Modules/resource.c +++ b/Modules/resource.c @@ -473,12 +473,7 @@ PyInit_resource(void) PyModule_AddIntMacro(m, RLIMIT_NPTS); #endif - if (sizeof(RLIM_INFINITY) > sizeof(long)) { - v = PyLong_FromLongLong((long long) RLIM_INFINITY); - } else - { - v = PyLong_FromLong((long) RLIM_INFINITY); - } + v = PyLong_FromIntMax(RLIM_INFINITY); if (v) { PyModule_AddObject(m, "RLIM_INFINITY", v); } diff --git a/Modules/testcapi_long.h b/Modules/testcapi_long.h index 6bddad7bb5d249..71632d37d6012b 100644 --- a/Modules/testcapi_long.h +++ b/Modules/testcapi_long.h @@ -1,6 +1,7 @@ /* Poor-man's template. Macros used: TESTNAME name of the test (like test_long_api_inner) TYPENAME the signed type (like long) + UTYPENAME the unsigned type (like unsigned long) F_S_TO_PY convert signed to pylong; TYPENAME -> PyObject* F_PY_TO_S convert pylong to signed; PyObject* -> TYPENAME F_U_TO_PY convert unsigned to pylong; unsigned TYPENAME -> PyObject* @@ -11,7 +12,7 @@ static PyObject * TESTNAME(PyObject *error(const char*)) { const int NBITS = sizeof(TYPENAME) * 8; - unsigned TYPENAME base; + UTYPENAME base; PyObject *pyresult; int i; @@ -30,7 +31,7 @@ TESTNAME(PyObject *error(const char*)) int j; for (j = 0; j < 6; ++j) { TYPENAME in, out; - unsigned TYPENAME uin, uout; + UTYPENAME uin, uout; /* For 0, 1, 2 use base; for 3, 4, 5 use -base */ uin = j < 3 ? base : 0U - base; @@ -39,7 +40,7 @@ TESTNAME(PyObject *error(const char*)) * For 1 & 4, leave alone. * For 2 & 5, add 1. */ - uin += (unsigned TYPENAME)(TYPENAME)(j % 3 - 1); + uin += (UTYPENAME)(TYPENAME)(j % 3 - 1); pyresult = F_U_TO_PY(uin); if (pyresult == NULL) @@ -47,7 +48,7 @@ TESTNAME(PyObject *error(const char*)) "unsigned unexpected null result"); uout = F_PY_TO_U(pyresult); - if (uout == (unsigned TYPENAME)-1 && PyErr_Occurred()) + if (uout == (UTYPENAME)-1 && PyErr_Occurred()) return error( "unsigned unexpected -1 result"); if (uout != uin) @@ -79,7 +80,7 @@ TESTNAME(PyObject *error(const char*)) { PyObject *one, *x, *y; TYPENAME out; - unsigned TYPENAME uout; + UTYPENAME uout; one = PyLong_FromLong(1); if (one == NULL) @@ -93,7 +94,7 @@ TESTNAME(PyObject *error(const char*)) "unexpected NULL from PyNumber_Negative"); uout = F_PY_TO_U(x); - if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred()) + if (uout != (UTYPENAME)-1 || !PyErr_Occurred()) return error( "PyLong_AsUnsignedXXX(-1) didn't complain"); if (!PyErr_ExceptionMatches(PyExc_OverflowError)) @@ -116,7 +117,7 @@ TESTNAME(PyObject *error(const char*)) "unexpected NULL from PyNumber_Lshift"); uout = F_PY_TO_U(x); - if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred()) + if (uout != (UTYPENAME)-1 || !PyErr_Occurred()) return error( "PyLong_AsUnsignedXXX(2**NBITS) didn't " "complain"); @@ -179,7 +180,7 @@ TESTNAME(PyObject *error(const char*)) /* Test F_PY_TO_{S,U} on non-pylong input. This should raise a TypeError. */ { TYPENAME out; - unsigned TYPENAME uout; + UTYPENAME uout; Py_INCREF(Py_None); @@ -192,7 +193,7 @@ TESTNAME(PyObject *error(const char*)) PyErr_Clear(); uout = F_PY_TO_U(Py_None); - if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred()) + if (uout != (UTYPENAME)-1 || !PyErr_Occurred()) return error("PyLong_AsXXX(None) didn't complain"); if (!PyErr_ExceptionMatches(PyExc_TypeError)) return error("PyLong_AsXXX(None) raised " diff --git a/Objects/longobject.c b/Objects/longobject.c index 0bf6ae6accd77d..2ec21524dc4640 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -304,6 +304,76 @@ PyLong_FromLong(long ival) return (PyObject *)v; } +/* Create a new int object from a C intmax_t */ + +PyObject * +PyLong_FromIntMax(intmax_t ival) +{ + PyLongObject *v; + uintmax_t abs_ival; + uintmax_t t; /* unsigned so >> doesn't propagate sign bit */ + int ndigits = 0; + int sign; + + CHECK_SMALL_INT(ival); + + if (ival < 0) { + /* negate: can't write this as abs_ival = -ival since that + invokes undefined behaviour when ival is LONG_MIN */ + abs_ival = 0U-(uintmax_t)ival; + sign = -1; + } + else { + abs_ival = (uintmax_t)ival; + sign = ival == 0 ? 0 : 1; + } + + /* Fast path for single-digit ints */ + if (!(abs_ival >> PyLong_SHIFT)) { + v = _PyLong_New(1); + if (v) { + Py_SIZE(v) = sign; + v->ob_digit[0] = Py_SAFE_DOWNCAST( + abs_ival, uintmax_t, digit); + } + return (PyObject*)v; + } + +#if PyLong_SHIFT==15 + /* 2 digits */ + if (!(abs_ival >> 2*PyLong_SHIFT)) { + v = _PyLong_New(2); + if (v) { + Py_SIZE(v) = 2*sign; + v->ob_digit[0] = Py_SAFE_DOWNCAST( + abs_ival & PyLong_MASK, uintmax_t, digit); + v->ob_digit[1] = Py_SAFE_DOWNCAST( + abs_ival >> PyLong_SHIFT, uintmax_t, digit); + } + return (PyObject*)v; + } +#endif + + /* Larger numbers: loop to determine number of digits */ + t = abs_ival; + while (t) { + ++ndigits; + t >>= PyLong_SHIFT; + } + v = _PyLong_New(ndigits); + if (v != NULL) { + digit *p = v->ob_digit; + Py_SIZE(v) = ndigits*sign; + t = abs_ival; + while (t) { + *p++ = Py_SAFE_DOWNCAST( + t & PyLong_MASK, uintmax_t, digit); + t >>= PyLong_SHIFT; + } + } + return (PyObject *)v; +} + /* Create a new int object from a C unsigned long int */ PyObject * @@ -315,12 +385,44 @@ PyLong_FromUnsignedLong(unsigned long ival) if (ival < PyLong_BASE) return PyLong_FromLong(ival); + + /* Count the number of Python digits. */ + t = ival; + while (t) { + ++ndigits; + t >>= PyLong_SHIFT; + } + + v = _PyLong_New(ndigits); + if (v != NULL) { + digit *p = v->ob_digit; + while (ival) { + *p++ = (digit)(ival & PyLong_MASK); + ival >>= PyLong_SHIFT; + } + } + return (PyObject *)v; +} + +/* Create a new int object from a C unsigned long int */ + +PyObject * +PyLong_FromUIntMax(uintmax_t ival) +{ + PyLongObject *v; + uintmax_t t; + int ndigits = 0; + + if (ival < PyLong_BASE) + return PyLong_FromLong(ival); + /* Count the number of Python digits. */ t = ival; while (t) { ++ndigits; t >>= PyLong_SHIFT; } + v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->ob_digit; @@ -472,7 +574,104 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) return res; } +/* Checking for overflow in PyLong_AsIntMax is a PITA since C doesn't define + * anything about what happens when a signed integer operation overflows, + * and some compilers think they're doing you a favor by being "clever" + * then. The bit pattern for the largest positive signed long is + * (unsigned long)INTMAX_MAX, and for the smallest negative signed long + * it is abs(INTMAX_MIN), which we could write -(unsigned long)INTMAX_MIN. + * However, some other compilers warn about applying unary minus to an + * unsigned operand. Hence the weird "0-". + */ +#define PY_ABS_INTMAX_MIN (0-(uintmax_t)INTMAX_MIN) + /* Get a C long int from an int object or any object that has an __int__ + method. + + On overflow, return -1 and set *overflow to 1 or -1 depending on the sign of + the result. Otherwise *overflow is 0. + + For other errors (e.g., TypeError), return -1 and set an error condition. + In this case *overflow will be 0. +*/ + +intmax_t +PyLong_AsIntMaxAndOverflow(PyObject *vv, int *overflow) +{ + /* This version by Tim Peters */ + PyLongObject *v; + uintmax_t x, prev; + intmax_t res; + Py_ssize_t i; + int sign; + int do_decref = 0; /* if nb_int was called */ + + *overflow = 0; + if (vv == NULL) { + PyErr_BadInternalCall(); + return -1; + } + + if (PyLong_Check(vv)) { + v = (PyLongObject *)vv; + } + else { + v = _PyLong_FromNbInt(vv); + if (v == NULL) + return -1; + do_decref = 1; + } + + res = -1; + i = Py_SIZE(v); + + switch (i) { + case -1: + res = -(sdigit)v->ob_digit[0]; + break; + case 0: + res = 0; + break; + case 1: + res = v->ob_digit[0]; + break; + default: + sign = 1; + x = 0; + if (i < 0) { + sign = -1; + i = -(i); + } + while (--i >= 0) { + prev = x; + x = (x << PyLong_SHIFT) | v->ob_digit[i]; + if ((x >> PyLong_SHIFT) != prev) { + *overflow = sign; + goto exit; + } + } + /* Haven't lost any bits, but casting to intmax_t requires extra + * care (see comment above). + */ + if (x <= (uintmax_t)INTMAX_MAX) { + res = (intmax_t)x * sign; + } + else if (sign < 0 && x == PY_ABS_INTMAX_MIN) { + res = INTMAX_MIN; + } + else { + *overflow = sign; + /* res is already set to -1 */ + } + } + exit: + if (do_decref) { + Py_DECREF(v); + } + return res; +} + +/* Get a C long int from a Python int object or any object that has an __int__ method. Return -1 and set an error if overflow occurs. */ long @@ -489,6 +688,23 @@ PyLong_AsLong(PyObject *obj) return result; } +/* Get a C intmax_t from a Python int object or any object that has an __int__ + method. Return -1 and set an error if overflow occurs. */ + +long +PyLong_AsIntMax(PyObject *obj) +{ + int overflow; + long result = PyLong_AsIntMaxAndOverflow(obj, &overflow); + if (overflow) { + /* XXX: could be cute and give a different + message for overflow == -1 */ + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C long"); + } + return result; +} + /* Get a C int from an int object or any object that has an __int__ method. Return -1 and set an error if overflow occurs. */ @@ -562,7 +778,7 @@ PyLong_AsSsize_t(PyObject *vv) { return -1; } -/* Get a C unsigned long int from an int object. +/* Get a C unsigned long int from a Python int object. Returns -1 and sets an error condition if overflow occurs. */ unsigned long @@ -606,6 +822,50 @@ PyLong_AsUnsignedLong(PyObject *vv) return x; } +/* Get a C uintmax_t int from a Python int object. + Returns -1 and sets an error condition if overflow occurs. */ + +uintmax_t +PyLong_AsUIntMax(PyObject *vv) +{ + PyLongObject *v; + uintmax_t x, prev; + Py_ssize_t i; + + if (vv == NULL) { + PyErr_BadInternalCall(); + return (uintmax_t)-1; + } + if (!PyLong_Check(vv)) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return (uintmax_t)-1; + } + + v = (PyLongObject *)vv; + i = Py_SIZE(v); + x = 0; + if (i < 0) { + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to uintmax_t"); + return (uintmax_t) -1; + } + switch (i) { + case 0: return 0; + case 1: return v->ob_digit[0]; + } + while (--i >= 0) { + prev = x; + x = (x << PyLong_SHIFT) | v->ob_digit[i]; + if ((x >> PyLong_SHIFT) != prev) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert " + "to C uintmax_t"); + return (uintmax_t) -1; + } + } + return x; +} + /* Get a C size_t from an int object. Returns (size_t)-1 and sets an error condition if overflow occurs. */ @@ -1016,16 +1276,7 @@ _PyLong_AsByteArray(PyLongObject* v, PyObject * PyLong_FromVoidPtr(void *p) { -#if SIZEOF_VOID_P <= SIZEOF_LONG - return PyLong_FromUnsignedLong((unsigned long)(uintptr_t)p); -#else - -#if SIZEOF_LONG_LONG < SIZEOF_VOID_P -# error "PyLong_FromVoidPtr: sizeof(long long) < sizeof(void*)" -#endif - return PyLong_FromUnsignedLongLong((unsigned long long)(uintptr_t)p); -#endif /* SIZEOF_VOID_P <= SIZEOF_LONG */ - + return PyLong_FromUIntMax((uintptr_t)p); } /* Get a C pointer from an int object. */ @@ -1033,30 +1284,27 @@ PyLong_FromVoidPtr(void *p) void * PyLong_AsVoidPtr(PyObject *vv) { -#if SIZEOF_VOID_P <= SIZEOF_LONG - long x; + uintptr_t u; - if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) - x = PyLong_AsLong(vv); - else - x = PyLong_AsUnsignedLong(vv); -#else - -#if SIZEOF_LONG_LONG < SIZEOF_VOID_P -# error "PyLong_AsVoidPtr: sizeof(long long) < sizeof(void*)" -#endif - long long x; - - if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) - x = PyLong_AsLongLong(vv); - else - x = PyLong_AsUnsignedLongLong(vv); + if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) { + intmax_t x = PyLong_AsIntMax(vv); + if (x == -1 && PyErr_Occurred()) { + return NULL; + } -#endif /* SIZEOF_VOID_P <= SIZEOF_LONG */ + Py_BUILD_ASSERT(sizeof(uintptr_t) == sizeof(intmax_t)); + u = (uintptr_t)x; + } + else { + uintmax_t x = PyLong_AsUIntMax(vv); + if (x == (uintmax_t)-1 && PyErr_Occurred()) { + return NULL; + } - if (x == -1 && PyErr_Occurred()) - return NULL; - return (void *)x; + Py_BUILD_ASSERT(sizeof(uintptr_t) == sizeof(uintmax_t)); + u = (uintptr_t)x; + } + return (void *)u; } /* Initial long long support by Chris Herborth (chrish@qnx.com), later diff --git a/PC/pyconfig.h b/PC/pyconfig.h index c96c231a05f241..dc93bf1958b99c 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -346,6 +346,7 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ #define SIZEOF_LONG_LONG 8 #define SIZEOF_DOUBLE 8 #define SIZEOF_FLOAT 4 +#define SIZEOF_INTMAX_T 8 /* VC 7.1 has them and VC 6.0 does not. VC 6.0 has a version number of 1200. Microsoft eMbedded Visual C++ 4.0 has a version number of 1201 and doesn't diff --git a/Python/getargs.c b/Python/getargs.c index 8cb672d6abc38a..f56b5745bdfa6e 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -805,6 +805,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, *p = ival; break; } + case 'l': {/* long int */ long *p = va_arg(*p_va, long *); long ival; @@ -853,6 +854,22 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, break; } + case 'm': { /* intmax_t */ + intmax_t *p = va_arg(*p_va, intmax_t *); + intmax_t ival; + if (float_argument_error(arg)) { + RETURN_ERR_OCCURRED; + } + ival = PyLong_AsIntMax(arg); + if (ival == -1 && PyErr_Occurred()) { + RETURN_ERR_OCCURRED; + } + else { + *p = ival; + } + break; + } + case 'f': {/* float */ float *p = va_arg(*p_va, float *); double dval = PyFloat_AsDouble(arg); @@ -2241,6 +2258,7 @@ skipitem(const char **p_format, va_list *p_va, int flags) case 'L': /* long long */ case 'K': /* long long sized bitfield */ case 'n': /* Py_ssize_t */ + case 'm': /* intmax_t */ case 'f': /* float */ case 'd': /* double */ case 'D': /* complex double */ diff --git a/Python/modsupport.c b/Python/modsupport.c index 9637191feb80d4..ad3c2c5ab5b685 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -295,6 +295,9 @@ do_mkvalue(const char **p_format, va_list *p_va, int flags) case 'l': return PyLong_FromLong(va_arg(*p_va, long)); + case 'm': + return PyLong_FromIntMax(va_arg(*p_va, intmax_t)); + case 'k': { unsigned long n; diff --git a/Python/pytime.c b/Python/pytime.c index 3015a6be0b83c1..a89eb476a0eebb 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -38,31 +38,28 @@ error_time_t_overflow(void) time_t _PyLong_AsTime_t(PyObject *obj) { -#if SIZEOF_TIME_T == SIZEOF_LONG_LONG - long long val; - val = PyLong_AsLongLong(obj); -#else - long val; - Py_BUILD_ASSERT(sizeof(time_t) <= sizeof(long)); - val = PyLong_AsLong(obj); -#endif + intmax_t val; + time_t t; + + val = PyLong_AsIntMax(obj); if (val == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) error_time_t_overflow(); return -1; } - return (time_t)val; + + t = (time_t)val; + if ((intmax_t)t != val) { + error_time_t_overflow(); + return -1; + } + return t; } PyObject * _PyLong_FromTime_t(time_t t) { -#if SIZEOF_TIME_T == SIZEOF_LONG_LONG - return PyLong_FromLongLong((long long)t); -#else - Py_BUILD_ASSERT(sizeof(time_t) <= sizeof(long)); - return PyLong_FromLong((long)t); -#endif + return PyLong_FromIntMax(t); } /* Round to nearest with ties going to nearest even integer @@ -358,8 +355,7 @@ _PyTime_AsSecondsDouble(_PyTime_t t) PyObject * _PyTime_AsNanosecondsObject(_PyTime_t t) { - Py_BUILD_ASSERT(sizeof(long long) >= sizeof(_PyTime_t)); - return PyLong_FromLongLong((long long)t); + return PyLong_FromIntMax(t); } static _PyTime_t diff --git a/configure b/configure index 26b4a052711b40..71bdec7983a910 100755 --- a/configure +++ b/configure @@ -8759,6 +8759,39 @@ cat >>confdefs.h <<_ACEOF _ACEOF +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of intmax_t" >&5 +$as_echo_n "checking size of intmax_t... " >&6; } +if ${ac_cv_sizeof_intmax_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (intmax_t))" "ac_cv_sizeof_intmax_t" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_intmax_t" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (intmax_t) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_intmax_t=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_intmax_t" >&5 +$as_echo "$ac_cv_sizeof_intmax_t" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INTMAX_T $ac_cv_sizeof_intmax_t +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double support" >&5 $as_echo_n "checking for long double support... " >&6; } diff --git a/configure.ac b/configure.ac index 8ab1c03ed89192..3eba5d0184fec0 100644 --- a/configure.ac +++ b/configure.ac @@ -2213,6 +2213,7 @@ AC_CHECK_SIZEOF(fpos_t, 4) AC_CHECK_SIZEOF(size_t, 4) AC_CHECK_SIZEOF(pid_t, 4) AC_CHECK_SIZEOF(uintptr_t) +AC_CHECK_SIZEOF(intmax_t) AC_MSG_CHECKING(for long double support) have_long_double=no diff --git a/pyconfig.h.in b/pyconfig.h.in index 21354a5cb84fe5..5f76e0e2966761 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1281,6 +1281,9 @@ /* The size of `int', as computed by sizeof. */ #undef SIZEOF_INT +/* The size of `intmax_t', as computed by sizeof. */ +#undef SIZEOF_INTMAX_T + /* The size of `long', as computed by sizeof. */ #undef SIZEOF_LONG