gh-143050: add helper _PyLong_InitTag()#147956
Conversation
With this we can assume, that _PyLong_Set*() operate on non-immortal integers.
| _PyLong_SetSignAndDigitCount(result, size != 0, size); | ||
| /* The digit has to be initialized explicitly to avoid | ||
| * use-of-uninitialized-value. */ | ||
| result->long_value.ob_digit[0] = 0; |
There was a problem hiding this comment.
While I'm not convinced that this initialization is useful, the comment says that it is. We should keep it, no?
There was a problem hiding this comment.
I suggested to keep this initialization. You marked my comment as resolved, I don't understand. Do you consider that it's not needed?
An alternative would be to fill digits with a pattern to detect usage of non-initialized memory when Python is built in debug mode:
#ifdef Py_DEBUG
// Fill digits with a known pattern to detect usage of uninitialized memory
memset(result->long_value.ob_digit, 0xff,
sizeof(result->long_value.ob_digit[0]) * ndigits);
#endifWe use this strategy for:
str: seeunicode_fill_invalid()function.PyBytesWriter:memset(byteswriter_data(writer), 0xff, byteswriter_allocated(writer))inPyBytesWriter_Create()
There was a problem hiding this comment.
Do you suggest to keep this just here? BTW, tests pass - I rerun one job again.
There was a problem hiding this comment.
ob_digit[0] = 0; was added by commit fc130c4 of issue gh-102509 to fix the OSS Fuzz report https://issues.oss-fuzz.com/issues/42516166.
Looks like it's complaining about a use of unit values in _PyLong_FromByteArray
Allocation happens here as part of _PyLong_NewLine 911 in 41bc101
and the claimed use is atLine 957 in 41bc101
inside of maybe_small_long and IS_SMALL_INT
I understand that the maybe_small_long() at the end of _PyLong_FromByteArray() triggered the issue when Python was built with --with-memory-sanitizer (-fsanitize=memory). From what I understood, the sign was initialized (to zero) but not ob_digit[0].
Oh interesting, k_mul() already does what I proposed above:
#ifdef Py_DEBUG
/* Fill with trash, to catch reference to uninitialized digits. */
memset(ret->long_value.ob_digit, 0xDF, _PyLong_DigitCount(ret) * sizeof(digit));
#endifk_lopsided_mul() sets explicitly all digits to zero:
memset(ret->long_value.ob_digit, 0, _PyLong_DigitCount(ret) * sizeof(digit));|
"Tests / Android (x86_64)" failed with: |
|
This yes, but linked above fuzzer failure is relevant.
…On Wed, Apr 1, 2026, 15:10 Victor Stinner ***@***.***> wrote:
*vstinner* left a comment (python/cpython#147956)
<#147956?email_source=notifications&email_token=AAQOKGA5T2QHBNZ3SVWPVWT4TUBM7A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIMJWHE3DGNZXGIZKM4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2LK4DSL5RW63LNMVXHIX3POBSW4X3DNRUWG2Y#issuecomment-4169637722>
"Tests / Android (x86_64)" failed with: Error on ZipFile unknown archive.
It's unrelated to this change.
> Task :app:maxVersionSetup
"Install Android Emulator v.36.4.10" ready.
Installing Android Emulator in /usr/local/lib/android/sdk/emulator
"Install Android Emulator v.36.4.10" complete.
"Install Android Emulator v.36.4.10" finished.
Checking the license for package AOSP ATD Intel x86_64 Atom System Image in /usr/local/lib/android/sdk/licenses
License for package AOSP ATD Intel x86_64 Atom System Image accepted.
Preparing "Install AOSP ATD Intel x86_64 Atom System Image API 32 (revision 1)".
Warning: An error occurred while preparing SDK package AOSP ATD Intel x86_64 Atom System Image: Error on ZipFile unknown archive.:
java.io.IOException: Error on ZipFile unknown archive
at org.apache.commons.compress.archivers.zip.ZipFile.<init>(ZipFile.java:383)
at org.apache.commons.compress.archivers.zip.ZipFile.<init>(ZipFile.java:323)
at org.apache.commons.compress.archivers.zip.ZipFile.<init>(ZipFile.java:279)
at com.android.repository.util.InstallerUtil.unzip(InstallerUtil.java:101)
at com.android.repository.impl.installer.BasicInstaller.doPrepare(BasicInstaller.java:91)
—
Reply to this email directly, view it on GitHub
<#147956?email_source=notifications&email_token=AAQOKGA5T2QHBNZ3SVWPVWT4TUBM7A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIMJWHE3DGNZXGIZKM4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2LK4DSL5RW63LNMVXHIX3POBSW4X3DNRUWG2Y#issuecomment-4169637722>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAQOKGB4LCCKKOKT66AWXQD4TUBM7AVCNFSM6AAAAACXIS7L4WVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DCNRZGYZTONZSGI>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
|
"Tests / CIFuzz / cpython3 (memory)" CI logs an pycore_long.h:243 is the following assertion in assert((_PyLong_IsCompact(op)
&& _PY_IS_SMALL_INT(_PyLong_CompactValue(op)))
|| (!is_small_int));Oh right, |
vstinner
left a comment
There was a problem hiding this comment.
What do you think of changing _PyLong_IsSmallInt() implementation like that?
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;
if (is_small_int) {
assert(PyLong_CheckExact(op));
assert(_Py_IsImmortal(op));
assert((_PyLong_IsCompact(op)
&& _PY_IS_SMALL_INT(_PyLong_CompactValue(op))));
}
return is_small_int;
}The current code runs many checks when is_small_int is false which are not needed.
Lets try, but I suspect it might fall in other place. |
| _PyLong_SetSignAndDigitCount(result, size != 0, size); | ||
| /* The digit has to be initialized explicitly to avoid | ||
| * use-of-uninitialized-value. */ | ||
| result->long_value.ob_digit[0] = 0; |
There was a problem hiding this comment.
I suggested to keep this initialization. You marked my comment as resolved, I don't understand. Do you consider that it's not needed?
An alternative would be to fill digits with a pattern to detect usage of non-initialized memory when Python is built in debug mode:
#ifdef Py_DEBUG
// Fill digits with a known pattern to detect usage of uninitialized memory
memset(result->long_value.ob_digit, 0xff,
sizeof(result->long_value.ob_digit[0]) * ndigits);
#endifWe use this strategy for:
str: seeunicode_fill_invalid()function.PyBytesWriter:memset(byteswriter_data(writer), 0xff, byteswriter_allocated(writer))inPyBytesWriter_Create()
|
Ok, I managed to reproduce the MSAN ( Apply the patch: diff --git a/Objects/longobject.c b/Objects/longobject.c
index b74a435b541..d46dbf0bd82 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -170,7 +170,7 @@ long_alloc(Py_ssize_t size)
Py_ssize_t ndigits = size ? size : 1;
if (ndigits == 1) {
- result = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints);
+ //result = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints);
}
if (result == NULL) {
/* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +Build Python with: Then run: |
It's a good thing that these two functions now fail in debug mode if they are called on a small integer. It will catch bugs earlier. So I merged the change. Thanks for this enhancement. |
With this we can assume, that _PyLong_Set*() operate on non-immortal integers.