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

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixes3.15pre-release feature fixes, bugs 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

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions