Skip to content

PyLong_AsInt32() and friends modify *value when they raise OverflowError #156101

Description

@serhiy-storchaka

Bug report

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_t bytes = 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:

import sqlite3
cu = sqlite3.connect(":memory:").cursor()
try:
    cu.arraysize = 2**32
except OverflowError:
    pass
print(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.

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    stdlibStandard Library Python modules in the Lib/ directory
    3.14bugs and security fixes
    3.15bugs and security fixes
    3.16new features, bugs and security fixes
    on Aug 20, 2026
  2. serhiy-storchaka commented on Aug 20, 2026

    @serhiy-storchaka
    MemberAuthor
  3. added 2 commits that reference this issue on Aug 21, 2026
  4. vstinner commented on Aug 31, 2026

    @vstinner
    Member

    Either the functions should leave *value unchanged on error, or the documentation should say that its value is unspecified after a failure.

    IMO they should leave *value unchanged on error. They can use a temporary variable: I wrote PR gh-156727 to do that.

  5. added a commit that references this issue on Aug 31, 2026
  6. added a commit that references this issue on Aug 31, 2026
  7. added a commit that references this issue on Sep 12, 2026
  8. added a commit that references this issue on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixes3.15bugs and security fixes3.16new features, bugs and security fixesextension-modulesC modules in the Modules dirstdlibStandard Library Python modules in the Lib/ directorytopic-C-APItopic-sqlite3type-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions