|  | 
| 5 | 5 | 
 | 
| 6 | 6 |     All rights reserved. Use of this source code is governed by a | 
| 7 | 7 |     BSD-style license that can be found in the LICENSE file. | 
|  | 8 | +
 | 
|  | 9 | +    WARNING: The implementation in this file is NOT thread safe. Multiple | 
|  | 10 | +    threads writing to a redirected ostream concurrently cause data races | 
|  | 11 | +    and potentially buffer overflows. Therefore it is currrently a requirement | 
|  | 12 | +    that all (possibly) concurrent redirected ostream writes are protected by | 
|  | 13 | +    a mutex. | 
|  | 14 | +    #HelpAppreciated: Work on iostream.h thread safety. | 
|  | 15 | +    For more background see the discussions under | 
|  | 16 | +    https://github.com/pybind/pybind11/pull/2982 and | 
|  | 17 | +    https://github.com/pybind/pybind11/pull/2995. | 
| 8 | 18 | */ | 
| 9 | 19 | 
 | 
| 10 | 20 | #pragma once | 
| @@ -85,30 +95,25 @@ class pythonbuf : public std::streambuf { | 
| 85 | 95 |         return remainder; | 
| 86 | 96 |     } | 
| 87 | 97 | 
 | 
| 88 |  | -    // This function must be non-virtual to be called in a destructor. If the | 
| 89 |  | -    // rare MSVC test failure shows up with this version, then this should be | 
| 90 |  | -    // simplified to a fully qualified call. | 
|  | 98 | +    // This function must be non-virtual to be called in a destructor. | 
| 91 | 99 |     int _sync() { | 
| 92 | 100 |         if (pbase() != pptr()) { // If buffer is not empty | 
| 93 | 101 |             gil_scoped_acquire tmp; | 
| 94 |  | -            // Placed inside gil_scoped_acquire as a mutex to avoid a race. | 
| 95 |  | -            if (pbase() != pptr()) { // Check again under the lock | 
| 96 |  | -                // This subtraction cannot be negative, so dropping the sign. | 
| 97 |  | -                auto size        = static_cast<size_t>(pptr() - pbase()); | 
| 98 |  | -                size_t remainder = utf8_remainder(); | 
| 99 |  | - | 
| 100 |  | -                if (size > remainder) { | 
| 101 |  | -                    str line(pbase(), size - remainder); | 
| 102 |  | -                    pywrite(line); | 
| 103 |  | -                    pyflush(); | 
| 104 |  | -                } | 
| 105 |  | - | 
| 106 |  | -                // Copy the remainder at the end of the buffer to the beginning: | 
| 107 |  | -                if (remainder > 0) | 
| 108 |  | -                    std::memmove(pbase(), pptr() - remainder, remainder); | 
| 109 |  | -                setp(pbase(), epptr()); | 
| 110 |  | -                pbump(static_cast<int>(remainder)); | 
|  | 102 | +            // This subtraction cannot be negative, so dropping the sign. | 
|  | 103 | +            auto size        = static_cast<size_t>(pptr() - pbase()); | 
|  | 104 | +            size_t remainder = utf8_remainder(); | 
|  | 105 | + | 
|  | 106 | +            if (size > remainder) { | 
|  | 107 | +                str line(pbase(), size - remainder); | 
|  | 108 | +                pywrite(line); | 
|  | 109 | +                pyflush(); | 
| 111 | 110 |             } | 
|  | 111 | + | 
|  | 112 | +            // Copy the remainder at the end of the buffer to the beginning: | 
|  | 113 | +            if (remainder > 0) | 
|  | 114 | +                std::memmove(pbase(), pptr() - remainder, remainder); | 
|  | 115 | +            setp(pbase(), epptr()); | 
|  | 116 | +            pbump(static_cast<int>(remainder)); | 
| 112 | 117 |         } | 
| 113 | 118 |         return 0; | 
| 114 | 119 |     } | 
|  | 
0 commit comments