Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deallocation scheme for memoryview is unsafe #69711

Closed
serhiy-storchaka opened this issue Oct 31, 2015 · 11 comments
Closed

Deallocation scheme for memoryview is unsafe #69711

serhiy-storchaka opened this issue Oct 31, 2015 · 11 comments
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error

Comments

@serhiy-storchaka
Copy link
Member

BPO 25525
Nosy @skrah, @vadmium, @serhiy-storchaka
Files
  • memoryview_safer_clearing.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2015-11-01.17:29:59.111>
    created_at = <Date 2015-10-31.19:14:22.640>
    labels = ['interpreter-core', 'type-bug', 'invalid']
    title = 'Deallocation scheme for memoryview is unsafe'
    updated_at = <Date 2015-11-02.15:26:51.229>
    user = 'https://github.com/serhiy-storchaka'

    bugs.python.org fields:

    activity = <Date 2015-11-02.15:26:51.229>
    actor = 'skrah'
    assignee = 'none'
    closed = True
    closed_date = <Date 2015-11-01.17:29:59.111>
    closer = 'skrah'
    components = ['Interpreter Core']
    creation = <Date 2015-10-31.19:14:22.640>
    creator = 'serhiy.storchaka'
    dependencies = []
    files = ['40917']
    hgrepos = []
    issue_num = 25525
    keywords = ['patch']
    message_count = 11.0
    messages = ['253803', '253806', '253807', '253812', '253825', '253826', '253839', '253843', '253861', '253865', '253925']
    nosy_count = 3.0
    nosy_names = ['skrah', 'martin.panter', 'serhiy.storchaka']
    pr_nums = []
    priority = 'normal'
    resolution = 'not a bug'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue25525'
    versions = ['Python 3.4', 'Python 3.5', 'Python 3.6']

    @serhiy-storchaka
    Copy link
    Member Author

    Deallocation scheme for memoryview is complex and unsafe. It crashes with chained memoryviews (bpo-25498), but I suppose deallocating unchained memoryview can crash too if the memoryview itself had exported buffers (self->exports != 0).

    Both memoryview and ManagedBuffer support garbage collector. If there is a reference to memoryview from reference loop, memoryview becomes a part of the reference loop.

    refloop -> memoryview -> ManagedBuffer -> obj
    

    First garbage collector calls tp_clear for all objects in the loop (memory_clear() for memoryview).
    If self->exports != 0 for memoryview, _memory_release() fails and the _Py_MEMORYVIEW_RELEASED flag is not set. However following Py_CLEAR(self->mbuf) deallocates ManagedBuffer and set self->mbuf to NULL. Then memoryview's owner releases memoryview, and it is deallocated (memory_dealloc). _memory_release reads self->mbuf->exports, but self->mbuf is NULL. Segmentation fault.

    Following patch makes deallocation scheme for memoryview simpler and more reliable.

    1. memory_clear does nothing if self->exports != 0. The buffer will be released when memoryview's owner release the memoryview.

    2. ManagedBuffer no longer supports garbage collector. This prevents buffer releasing before memoryview or its owner are cleared.

    @serhiy-storchaka serhiy-storchaka added interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error labels Oct 31, 2015
    @skrah
    Copy link
    Mannequin

    skrah mannequin commented Oct 31, 2015

    The "chained memoryviews" you refer to are a hack and simply
    aren't supported. Please stop spreading FUD.

    @vadmium
    Copy link
    Member

    vadmium commented Oct 31, 2015

    Did you forget your patch? :)

    @serhiy-storchaka
    Copy link
    Member Author

    Yes, the "chained memoryviews" in ctypes are a hack and it will be eliminated. But this hack exposed possible weak point in memoryview.

    @serhiy-storchaka
    Copy link
    Member Author

    WTF? Where is my patch?

    @serhiy-storchaka
    Copy link
    Member Author

    Strange bug. I can't attach any file.

    @skrah
    Copy link
    Mannequin

    skrah mannequin commented Nov 1, 2015

    First garbage collector calls tp_clear for all objects in the loop (memory_clear() for memoryview).
    If self->exports != 0 for memoryview, _memory_release() fails and the _Py_MEMORYVIEW_RELEASED flag is not set.

    I don't understand:

    1. memory_clear()

    2. _memory_release()

    3. if self->exports > 0 then BufferError.

    Please state the code path clearly.

    @serhiy-storchaka
    Copy link
    Member Author

    1. memory_clear()

    2. _memory_release()

    3. if self->exports > 0 then BufferError (but ignored).

    4. Py_CLEAR(self->mbuf)

    5. memory_dealloc()

    6. _memory_release()

    7. self->mbuf->exports where self->mbuf == NULL

    @skrah
    Copy link
    Mannequin

    skrah mannequin commented Nov 1, 2015

    First of all, the premise "exports > 0" in your example looks wrong
    to me. The deallocation process for the first view should start precisely when it no longer has any exports.

    In fact, the check for "exports > 0" is for the case when
    memoryview.release() is called from the Python level.

    Secondly, even if it did happen (show the code path leading
    to that!), BufferError would be set in memory_clear() and the
    garbage collector would throw a FatalError, i.e. step 5+ would
    not be reached.

    Lastly, I don't find it very diplomatic to use language like "Deallocation scheme for memoryview is complex and unsafe. It
    crashes with chained memoryviews..." when you don't seem to
    a test case or a clear concept of how the alleged bug should
    occur.

    @skrah skrah mannequin closed this as completed Nov 1, 2015
    @skrah skrah mannequin added the invalid label Nov 1, 2015
    @serhiy-storchaka
    Copy link
    Member Author

    Sorry for my bad wording. I wasn't going to blame or insult anybody.

    @skrah
    Copy link
    Mannequin

    skrah mannequin commented Nov 2, 2015

    Thanks, no big problem. The thing is that the parts I wrote
    (Modules/_decimal/*, Objects/memoryobject.c, Modules/_testbuffer.c)
    have been audited rather heavily and have 100% code coverage
    with a privately maintained patch that inserts allocation
    failures.

    There are even tests in test_memoryview() / test_buffer() for
    breaking up reference cycles.

    So I'd really prefer not to have things labeled as potential issues
    when there are none. That also applies to the PyMem_NEW() "potential
    overflow" fix in _testbuffer.c where overflow was impossible.

    Thus, I'll probably revert that at some point, not out of
    hostility, but just because it's not my approach to software
    development (in the _testbuffer case, I view the 'len' parameter
    as a constrained type in the Ada sense where 0 <= len <= ndim = 64).

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants