gh-143050: correct PyLong_FromString() to use _PyLong_Negate()#145901
gh-143050: correct PyLong_FromString() to use _PyLong_Negate()#145901vstinner merged 13 commits intopython:mainfrom
Conversation
The long_from_string_base() might return a small integer, when the _pylong.py is used to do conversion. Hence, we must be careful here to not smash it "small int" bit by using the _PyLong_FlipSign().
|
Shouldn't affect users, so - no news. |
|
|
| with support.adjust_int_max_str_digits(0): | ||
| a = int('-' + '0' * 7000, 10) | ||
| del a | ||
| _testcapi.test_immortal_small_ints() |
There was a problem hiding this comment.
That's okay as long as it catches the regression in a debug build.
There was a problem hiding this comment.
_testcapi is always built with assertions, even in release mode.
There was a problem hiding this comment.
I built Python in release mode without PyLong_FromString() fix. _PyLong_FlipSign() assertion didn't catch the bug since Python was built without assertions. But at least, test_immortal_small_ints() was able to detect that small integers were corrupted:
test_bug_143050 (test.test_capi.test_long.LongTests.test_bug_143050) ...
python: ./Modules/_testcapi/immortal.c:35: test_immortal_small_ints: Assertion `has_int_immortal_bit' failed.
Fatal Python error: Aborted
Current thread 0x00007f617b91b780 [python] (most recent call first):
File "/home/vstinner/python/main/Lib/test/test_capi/test_long.py", line 811 in test_bug_143050
eendebakpt
left a comment
There was a problem hiding this comment.
Minor comment on the naming. But the PR fixes a bug, adds a test and cleans up along the way, so good enough for me!
colesbury
left a comment
There was a problem hiding this comment.
Looks good to me. Small comment about the function name below.
| with support.adjust_int_max_str_digits(0): | ||
| a = int('-' + '0' * 7000, 10) | ||
| del a | ||
| _testcapi.test_immortal_small_ints() |
There was a problem hiding this comment.
That's okay as long as it catches the regression in a debug build.
colesbury
left a comment
There was a problem hiding this comment.
Let me know if you change the function name or keep it as is.
e28e94c to
78c5b4b
Compare
|
@colesbury, I did renaming.
|
|
|
||
| /* Return true if the argument is a small int */ | ||
| static inline bool | ||
| _PyLong_HasImmortalTag(const PyLongObject *op) |
There was a problem hiding this comment.
IMO the intent here is to check if an integer is a small integer, rather than checking for a tag. So I would prefer to rename the function to _PyLong_IsSmallInt().
I wanted to suggest referring to _PY_IS_SMALL_INT() but I noticed the macro is wrong. I wrote #146631 to fix the macro.
There was a problem hiding this comment.
There are two notions for "small int"'s. One - by value and other is - this. If @colesbury is ok - I'm fine with renaming..
There was a problem hiding this comment.
_PyLong_HasImmortalTag() and _PY_IS_SMALL_INT() should be true or false for the same values.
For example, you can add the following check for _PyLong_HasImmortalTag():
+ assert((_PyLong_IsCompact(op) && _PY_IS_SMALL_INT(_PyLong_CompactValue(op)))
+ || (!is_small_int));
(You need to update your branch to retrieve my _PY_IS_SMALL_INT() change.)
For me, testing IMMORTALITY_BIT_MASK is just an implementation detail to check if an integer is "a small int".
There was a problem hiding this comment.
I've added an assert. BTW, what do you think on #145901 (comment)?
I don't think we should mention _PY_IS_SMALL_INT in the description of the function, assert is readable enough.
For me, testing IMMORTALITY_BIT_MASK is just an implementation detail to check if an integer is "a small int".
For now, we use _PY_IS_SMALL_INT() to check this. But eventually this could be just testing a flag.
There was a problem hiding this comment.
I would prefer to rename the function to _PyLong_IsSmallInt().
There was a problem hiding this comment.
I've added suggestions.
Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
|
It looks unrelated to this change. I just re-ran the CI. |
|
To backport this change to 3.14, |
|
Why we need a backport? |
This change uses |
|
Thanks @skirpichev for the PR, and @vstinner for merging it 🌮🎉.. I'm working now to backport this PR to: 3.14. |
|
GH-147331 is a backport of this pull request to the 3.14 branch. |
…ythonGH-145901) The long_from_string_base() might return a small integer, when the _pylong.py is used to do conversion. Hence, we must be careful here to not smash it "small int" bit by using the _PyLong_FlipSign(). (cherry picked from commit db5936c) Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com> Co-authored-by: Victor Stinner <vstinner@python.org>
|
GH-147437 is a backport of this pull request to the 3.13 branch. |
…GH-145901) (#147331) gh-143050: Correct PyLong_FromString() to use _PyLong_Negate() (GH-145901) The long_from_string_base() might return a small integer, when the _pylong.py is used to do conversion. Hence, we must be careful here to not smash it "small int" bit by using the _PyLong_FlipSign(). (cherry picked from commit db5936c) Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com> Co-authored-by: Victor Stinner <vstinner@python.org>
…#145901) (#147437) The long_from_string_base() might return a small integer, when the _pylong.py is used to do conversion. Hence, we must be careful here to not smash it "small int" bit by using the _PyLong_FlipSign(). Co-authored-by: Victor Stinner <vstinner@python.org> (cherry picked from commit db5936c) Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
…ython#145901) The long_from_string_base() might return a small integer, when the _pylong.py is used to do conversion. Hence, we must be careful here to not smash it "small int" bit by using the _PyLong_FlipSign(). Co-authored-by: Victor Stinner <vstinner@python.org>
…ython#145901) The long_from_string_base() might return a small integer, when the _pylong.py is used to do conversion. Hence, we must be careful here to not smash it "small int" bit by using the _PyLong_FlipSign(). Co-authored-by: Victor Stinner <vstinner@python.org>
The long_from_string_base() might return a small integer, when the _pylong.py is used to do conversion. Hence, we must be careful here to not smash it "small int" bit by using the _PyLong_FlipSign().
Co-authored-by: Sam Gross colesbury@gmail.com