• Kirill Smelkov's avatar
    libgolang/gevent: Fix io_read deadlock and io_read/io_write potential data corruption · 3c10a0a3
    Kirill Smelkov authored
    When underlying pygfobj is FileObjectThread its .readinto() leads to
    deadlock because it is no cooperative(*). This manifests as
    test_pyx_os_pipe_cpp hang when run by gpython on windows.
    
    -> Workaround this by reading first into intermediate buffer and then
    copying data to buffer that user provided.
    
    After this the deadlock is gone but test_pyx_os_pipe_cpp starts to fail
    and crash randomly. That's because similarly to channels we need to
    care and not access a buffer if it is located on stack and owning
    greenlet is inactive. Because when a greenlet is inactive, its stack is
    reused by another active greenlet and writing/reading to on-stack memory
    accesses that second greenlet stack, corrupting it on write.
    
    -> do the same what we do in chan operations: use intermediate on-heap
    buffer to protect original user's buffer to be accesses because it might
    be located on stack. That's what actually happens in
    test_pyx_os_pipe_cpp where two goroutines read and write to each other
    via pipe and using on-stack located buffers. And becuase on windows
    pipes, like regular files, are wrapped with FileObjectThread, when
    reading greenlet becomes suspended waiting for read reasul, it will be
    another greenlet to run on its stack, write to another end of a pipe,
    wakeup IO thread, which will write the data to requested buffer on G1
    stack and oops - it was G2 there.
    
    (*) see https://github.com/gevent/gevent/pull/1948 for details
    3c10a0a3
_runtime_gevent.pyx 13.7 KB