Skip to content

Commit e84bd70

Browse files
committed
fix: disarm moved-from pythonbuf after redirect move
The redirect guard now survives moves, but buffered output could still remain in the moved-from `pythonbuf` and be flushed during destruction through moved-out Python handles. Rebuild the destination put area from the transferred storage and clear the source put area so unflushed bytes follow the active redirect instead of crashing in the moved-from destructor. Made-with: Cursor
1 parent 58a45b5 commit e84bd70

1 file changed

Lines changed: 16 additions & 1 deletion

File tree

include/pybind11/iostream.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,22 @@ class pythonbuf : public std::streambuf {
131131
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
132132
}
133133

134-
pythonbuf(pythonbuf &&) = default;
134+
pythonbuf(pythonbuf &&other) noexcept
135+
: buf_size(other.buf_size), d_buffer(std::move(other.d_buffer)),
136+
pywrite(std::move(other.pywrite)), pyflush(std::move(other.pyflush)) {
137+
const auto pending = (other.pbase() != nullptr && other.pptr() != nullptr)
138+
? static_cast<int>(other.pptr() - other.pbase())
139+
: 0;
140+
if (d_buffer != nullptr) {
141+
// Rebuild the put area from the transferred storage.
142+
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
143+
pbump(pending);
144+
} else {
145+
setp(nullptr, nullptr);
146+
}
147+
// Prevent the moved-from destructor from flushing through moved-out handles.
148+
other.setp(nullptr, nullptr);
149+
}
135150

136151
/// Sync before destroy
137152
~pythonbuf() override { _sync(); }

0 commit comments

Comments
 (0)