gh-153539: Fix use-after-free in TextIOWrapper.tell() with a reentrant decoder - #153540
Conversation
…entrant decoder TextIOWrapper.tell() used a borrowed next_input from the snapshot across the decoder's getstate/decode/setstate calls, so a decoder that reenters seek() from getstate could free it and leave tell() reading freed memory. Own the reference across those calls, matching the sibling textiowrapper_read_chunk.
serhiy-storchaka
left a comment
There was a problem hiding this comment.
LGTM. 👍
But the main problem is concurrency -- if two threads call seek() concurrently they can reproduce this bug. Please reflect this in NEWS and comments.
|
Done in e011fa3: noted the concurrent |
|
Thanks @tonghuaroot for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13, 3.14, 3.15. |
…entrant decoder (pythonGH-153540) TextIOWrapper.tell() used a borrowed next_input from the snapshot across the decoder's getstate/decode/setstate calls, so a decoder that reenters seek() from getstate could free it and leave tell() reading freed memory. Own the reference across those calls, matching the sibling textiowrapper_read_chunk.
|
Thanks @tonghuaroot for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13. |
|
Thanks @tonghuaroot for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 3.14. |
|
Thanks @tonghuaroot for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 3.15. |
|
Sorry, @tonghuaroot and @serhiy-storchaka, I could not cleanly backport this to |
|
Sorry, @tonghuaroot and @serhiy-storchaka, I could not cleanly backport this to |
|
Sorry, @tonghuaroot and @serhiy-storchaka, I could not cleanly backport this to |
|
GH-156193 is a backport of this pull request to the 3.15 branch. |
|
GH-156194 is a backport of this pull request to the 3.14 branch. |
|
GH-156195 is a backport of this pull request to the 3.13 branch. |
…eentrant decoder (GH-153540) (GH-156195) TextIOWrapper.tell() used a borrowed next_input from the snapshot across the decoder's getstate/decode/setstate calls, so a decoder that reenters seek() from getstate could free it and leave tell() reading freed memory. Own the reference across those calls, matching the sibling textiowrapper_read_chunk. (cherry picked from commit fa0ec86) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com>
…eentrant decoder (GH-153540) (GH-156194) TextIOWrapper.tell() used a borrowed next_input from the snapshot across the decoder's getstate/decode/setstate calls, so a decoder that reenters seek() from getstate could free it and leave tell() reading freed memory. Own the reference across those calls, matching the sibling textiowrapper_read_chunk. (cherry picked from commit fa0ec86) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com>
TextIOWrapper.tell()used a borrowednext_inputfrom the snapshot across the decoder'sgetstate/decode/setstatecalls, so a decoder that re-entersseek()fromgetstatecould free it and leavetell()reading freed memory. Own the reference across those calls, matchingtextiowrapper_read_chunk.