PyLong_AsInt32(), PyLong_AsUInt32(), PyLong_AsInt64() and PyLong_AsUInt64() are documented as
Set *value and return 0 on success.
Set an exception and return -1 on error.
but on overflow they write the truncated value into *value before returning -1.
They are implemented on top of PyLong_AsNativeBytes(), which copies the lowest bytes and reports the required size, and the LONG_TO_INT/LONG_TO_UINT macros in Objects/longobject.c only raise OverflowError afterwards:
Py_ssize_tbytes=PyLong_AsNativeBytes(obj, value, sizeof(*value), flags);
if (bytes<0) {
return-1;
}
if ((size_t)bytes>sizeof(*value)) {
PyErr_SetString(PyExc_OverflowError,
"Python int too large to convert to "type_name);
return-1;
}
This makes the straightforward usage unsafe.
For example, _sqlite3_Cursor_arraysize_set_impl() in Modules/_sqlite/cursor.c passes the target field directly:
importsqlite3cu=sqlite3.connect(":memory:").cursor()
try:
cu.arraysize=2**32exceptOverflowError:
passprint(cu.arraysize) # 0, was 1
Either the functions should leave *value unchanged on error, or the documentation should say that its value is unspecified after a failure.
Activity
serhiy-storchaka commented on Aug 20, 2026
cc @vstinner
gh-156101: Fix sqlite3 Cursor.arraysize on a failed assignment (GH-15…
[3.14] gh-156101: Fix sqlite3 Cursor.arraysize on a failed assignment (…
vstinner commented on Aug 31, 2026
IMO they should leave *value unchanged on error. They can use a temporary variable: I wrote PR gh-156727 to do that.
gh-156101: Don't set the result in error in PyLong_AsInt32() (#156727)
[3.14] gh-156101: Don't set the result in error in PyLong_AsInt32() (G…
pythongh-156101: Don't set the result in error in PyLong_AsInt32() (p…
[3.15] gh-156101: Don't set the result in error in PyLong_AsInt32() (G…
[3.15] gh-156101: Fix sqlite3 Cursor.arraysize on a failed assignment (…