Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

PEP 670: Convert _PyObject_SIZE() and _PyObject_VAR_SIZE() macros to functions #99845

Closed
Labels
type-bugAn unexpected behavior, bug, or error
@vstinner

Description

@vstinner

The _PyObject_SIZE() and _PyObject_VAR_SIZE() macros should be converted to functions: seePEP 670 for the rationale.

My problem is that I don't know if the return type should be signed (Py_ssize_t) or unsigned (size_t).

CPython usage of _PyObject_SIZE():

  • Signed: 18. Implementation of__sizeof__() methods.
  • Unsigned: 0
  • Implicit cast to unsigned: 2. CallsPyObject_Malloc(_PyObject_SIZE(tp)) andgc_alloc(_PyObject_SIZE(tp), presize) where the first argument type issize_t.

CPython usage of _PyObject_VAR_SIZE():

  • Signed: 5
  • Unsigned: 1
  • Implicit cast to unsigned: 1. Call_PyDebugAllocatorStats(..., _PyObject_VAR_SIZE(&PyTuple_Type, len)) where the argument type issize_t.

To get acontainer length, the C API uses signed type (Py_ssize_t): PyList_Size(), PyDict_Size(), Py_SIZE(), etc.

Toallocate memory, the C API prefers unsigned type (size_t): PyMem_Malloc(), PyObject_Realloc(), etc.

Python allocator functions reject size greater thanPY_SSIZE_T_MAX:

void *PyMem_RawMalloc(size_t size){    /*     * Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes.     * Most python internals blindly use a signed Py_ssize_t to track     * things without checking for overflows or negatives.     * As size_t is unsigned, checking for size < 0 is not required.     */    if (size > (size_t)PY_SSIZE_T_MAX)        return NULL;    return _PyMem_Raw.malloc(_PyMem_Raw.ctx, size);}

Some "sizeof" functions freely mix signed and unsigned types. Example:

static PyObject *deque_sizeof(dequeobject *deque, void *unused){    Py_ssize_t res;    Py_ssize_t blocks;    res = _PyObject_SIZE(Py_TYPE(deque));    blocks = (size_t)(deque->leftindex + Py_SIZE(deque) + BLOCKLEN - 1) / BLOCKLEN;    assert(deque->leftindex + Py_SIZE(deque) - 1 ==           (blocks - 1) * BLOCKLEN + deque->rightindex);    res += blocks * sizeof(block);    return PyLong_FromSsize_t(res);}

blocks andsizeof(block) are unsigned, butres is signed.


Another problem is that _PyObject_VAR_SIZE() has an undefined behavior on integer overflow. Maybe it should returnSIZE_MAX on oveflow, to make sure that Python allocator function fail (returnNULL)?

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


      [8]ページ先頭

      ©2009-2025 Movatter.jp