# error "_PY_NSMALLPOSINTS must be greater than or equal to 257"
#endif
+#define _PY_IS_SMALL_INT(val) \
+ (-_PY_NSMALLNEGINTS <= (val) && (val) < _PY_NSMALLPOSINTS)
+
// Return a reference to the immortal zero singleton.
// The function cannot return NULL.
static inline PyObject* _PyLong_GetZero(void)
return (op->long_value.lv_tag & SIGN_MASK) == 0;
}
+/* Return true if the argument is a small int */
+static inline bool
+_PyLong_IsSmallInt(const PyLongObject *op)
+{
+ assert(PyLong_Check(op));
+ bool is_small_int = false;
+ if (_PyLong_IsCompact(op)) {
+ Py_ssize_t value = _PyLong_CompactValue(op);
+ if (_PY_IS_SMALL_INT(value)) {
+ PyLongObject *small_obj;
+ small_obj = &_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + value];
+ is_small_int = (op == small_obj);
+ }
+ }
+ assert(PyLong_CheckExact(op) || (!is_small_int));
+ assert(_Py_IsImmortal(op) || (!is_small_int));
+ return is_small_int;
+}
+
static inline Py_ssize_t
_PyLong_DigitCount(const PyLongObject *op)
{
#define NON_SIZE_MASK ~((1 << NON_SIZE_BITS) - 1)
static inline void
-_PyLong_FlipSign(PyLongObject *op) {
+_PyLong_FlipSign(PyLongObject *op)
+{
+ assert(!_PyLong_IsSmallInt(op));
unsigned int flipped_sign = 2 - (op->long_value.lv_tag & SIGN_MASK);
op->long_value.lv_tag &= NON_SIZE_MASK;
op->long_value.lv_tag |= flipped_sign;
self.assertEqual(expect_u, fromnativebytes(v_be, n, 4, 1),
f"PyLong_FromNativeBytes(buffer, {n}, <big|unsigned>)")
+ def test_bug_143050(self):
+ with support.adjust_int_max_str_digits(0):
+ # Bug coming from using _pylong.int_from_string(), that
+ # currently requires > 6000 decimal digits.
+ int('-' + '0' * 7000, 10)
+ _testcapi.test_immortal_small_ints()
+ # Test also nonzero small int
+ int('-' + '0' * 7000 + '123', 10)
+ _testcapi.test_immortal_small_ints()
+
if __name__ == "__main__":
unittest.main()
#include "parts.h"
+#define Py_BUILD_CORE
+#include "internal/pycore_long.h" // _PyLong_IsSmallInt()
+
int verify_immortality(PyObject *object)
{
assert(_Py_IsImmortal(object));
test_immortal_small_ints(PyObject *self, PyObject *Py_UNUSED(ignored))
{
for (int i = -5; i <= 256; i++) {
- assert(verify_immortality(PyLong_FromLong(i)));
+ PyObject *obj = PyLong_FromLong(i);
+ assert(verify_immortality(obj));
+ int is_small_int = _PyLong_IsSmallInt((PyLongObject *)obj);
+ assert(is_small_int);
+ }
+ for (int i = 257; i <= 260; i++) {
+ PyObject *obj = PyLong_FromLong(i);
+ assert(obj);
+ int is_small_int = _PyLong_IsSmallInt((PyLongObject *)obj);
+ assert(!is_small_int);
+ Py_DECREF(obj);
}
Py_RETURN_NONE;
}
#define medium_value(x) ((stwodigits)_PyLong_CompactValue(x))
-#define IS_SMALL_INT(ival) (-_PY_NSMALLNEGINTS <= (ival) && (ival) < _PY_NSMALLPOSINTS)
+#define IS_SMALL_INT(ival) _PY_IS_SMALL_INT(ival)
#define IS_SMALL_UINT(ival) ((ival) < _PY_NSMALLPOSINTS)
#define _MAX_STR_DIGITS_ERROR_FMT_TO_INT "Exceeds the limit (%d digits) for integer string conversion: value has %zd digits; use sys.set_int_max_str_digits() to increase the limit"
}
/* Set sign and normalize */
- if (sign < 0) {
- _PyLong_FlipSign(z);
- }
long_normalize(z);
z = maybe_small_long(z);
+ if (sign < 0) {
+ _PyLong_Negate(&z);
+ }
if (pend != NULL) {
*pend = (char *)str;
* we accidentally decref small Ints out of existence. Instead,
* since small Ints are immortal, re-set the reference count.
*/
- PyLongObject *pylong = (PyLongObject*)self;
- if (pylong && _PyLong_IsCompact(pylong)) {
- stwodigits ival = medium_value(pylong);
- if (IS_SMALL_INT(ival)) {
- PyLongObject *small_pylong = (PyLongObject *)get_small_int((sdigit)ival);
- if (pylong == small_pylong) {
- _Py_SetImmortal(self);
- return;
- }
- }
+ if (_PyLong_IsSmallInt((PyLongObject*)self)) {
+ _Py_SetImmortal(self);
+ return;
}
Py_TYPE(self)->tp_free(self);
}