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 = (op->long_value.lv_tag & IMMORTALITY_BIT_MASK) != 0;
+ assert(PyLong_CheckExact(op) || (!is_small_int));
+ assert(_Py_IsImmortal(op) || (!is_small_int));
+ assert((_PyLong_IsCompact(op)
+ && _PY_IS_SMALL_INT(_PyLong_CompactValue(op)))
+ || (!is_small_int));
+ return is_small_int;
+}
+
static inline Py_ssize_t
_PyLong_DigitCount(const PyLongObject *op)
{
#define NON_SIZE_MASK ~(uintptr_t)((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(pylongwriter_create(negative, digits), num,
(negative, digits))
+ 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()
for (int i = -5; i <= 1024; i++) {
PyObject *obj = PyLong_FromLong(i);
assert(verify_immortality(obj));
- int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & IMMORTALITY_BIT_MASK;
+ int has_int_immortal_bit = _PyLong_IsSmallInt((PyLongObject *)obj);
assert(has_int_immortal_bit);
}
for (int i = 1025; i <= 1030; i++) {
PyObject *obj = PyLong_FromLong(i);
assert(obj);
- int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & IMMORTALITY_BIT_MASK;
+ int has_int_immortal_bit = _PyLong_IsSmallInt((PyLongObject *)obj);
assert(!has_int_immortal_bit);
Py_DECREF(obj);
}
}
/* 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;
Py_RETURN_RICHCOMPARE(result, 0, op);
}
-static inline int
-/// Return 1 if the object is one of the immortal small ints
-_long_is_small_int(PyObject *op)
-{
- PyLongObject *long_object = (PyLongObject *)op;
- int is_small_int = (long_object->long_value.lv_tag & IMMORTALITY_BIT_MASK) != 0;
- assert((!is_small_int) || PyLong_CheckExact(op));
- return is_small_int;
-}
-
void
_PyLong_ExactDealloc(PyObject *self)
{
assert(PyLong_CheckExact(self));
- if (_long_is_small_int(self)) {
+ if (_PyLong_IsSmallInt((PyLongObject *)self)) {
// See PEP 683, section Accidental De-Immortalizing for details
_Py_SetImmortal(self);
return;
static void
long_dealloc(PyObject *self)
{
- if (_long_is_small_int(self)) {
+ if (_PyLong_IsSmallInt((PyLongObject *)self)) {
/* This should never get called, but we also don't want to SEGV if
* we accidentally decref small Ints out of existence. Instead,
* since small Ints are immortal, re-set the reference count.