Repository navigation
Remove redundant decref from _PyLong_Negate #143050
Description
Activity
- addedtype-featureA feature request or enhancementA feature request or enhancement
on Dec 21, 2025 - addedinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
on Dec 21, 2025 Even if they are immortal, I prefer to keep incref/decref balanced. This saves time when you read code.
Maybe it is worth to replace Py_DECREF with something like Py_DECREF_IMMORTAL?
Maybe it is worth to replace Py_DECREF with something like Py_DECREF_IMMORTAL?
I would be in favor of that. There is a related discussion here #124074
Reacted by Sergey MiryanovThanks
This introduced a regression that was caught by our OSS Fuzzer (https://oss-fuzz.com/testcase-detail/6342648498814976).
$ ./python -c " import sys sys.set_int_max_str_digits(10000) while True: try: int('-' + '0' * 7000, 10) except: pass " python: Objects/longobject.c:371: _PyLong_Negate: Assertion `_long_is_small_int((PyObject *)x)' failed. Aborted (core dumped)full reproducer
To reproduce, download the testcase: https://drive.google.com/file/d/1Ain_DfzbodyKU_YiwtZPaT4ViAOssvOt/view?usp=sharing
And run it to trigger the assert, note that it requires a few iterations:
$ ./python -c " import sys sys.set_int_max_str_digits(10000) with open('/tmp/inttestcase','rb') as f: data = f.read().decode('utf-8') while True: try: int(data, 10) except: pass " python: Objects/longobject.c:371: _PyLong_Negate: Assertion `_long_is_small_int((PyObject *)x)' failed. Aborted (core dumped)Thanks for reporting, I will have a look at the reproducer tomorrow.
I stuck this into Claude and I think it (mostly) got it right:
int('-' + '0' * 7000, 10)->PyLong_FromString->_pylong.int_from_string, which returns 0- We then call
_PyLong_FlipSignon it, which corrupts 0
So it was a pre-existing bug in
PyLong_FromString.13 remaining items
- moved this from Todo to Done in Release and Deferred blockers 🚫
on Mar 31, 2026 I don't think that avoiding one Py_DECREF() in _PyLong_Negate() is worth it.
Why not do it?
I think that original PR was correct and now @eendebakpt can restore it with small adaptation (for a new helper).
Why not do it?
I will quote @serhiy-storchaka:
Even if they are immortal, I prefer to keep incref/decref balanced. This saves time when you read code.
Even if they are immortal, I prefer to keep incref/decref balanced.
We can use
_Py_DECREF_INThere, no?- added a commit that references this issue
on Apr 1, 2026 - added 4 commits that reference this issue
on Apr 25, 2026
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
Feature or enhancement
Proposal:
In
_PyLong_Negatethere is a fast path for unique referenced longs. The slow path assumes the argument is a small int. We can add an assert for this condition, and remove the final decref (small ints are immortal).Has this already been discussed elsewhere?
No response given
Links to previous discussion of this feature:
No response
Linked PRs