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

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.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

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions