Mere moments ago, quoth I:
Once the pipe-closing issues are resolved, you should simply read the output stream until EOF. This will only occur once c++filt has terminated (and thus completed and closed its output stream). [...]
* On Windows, if you desire to pass any file handles at all to the new child process, it is completely whimsical what *other* open file handles you may inadvertently pass -- unless you play games with STARTUPINFOEXA and PROC_THREAD_ATTRIBUTE_LIST to enumerate exactly the set of handles you intend to pass.
FWIW, a slight saving grace with that is that it's most common to open files using NULL security attributes, which makes the file non-inherited by default. You can also flip any existing handle to non-inherited whenever you want.
Incidentally, this raises another good reason why it's important to close the child-end of pipes as soon as possible after child processes are launched -- as this would be the only child-inheritable handle of the pipe, then as long as processes are launched only on a single thread (and thus a second process can't be launched until after the inheritable handle is closed) this will avoid unintended inheritance. If you're going to be launching processes concurrently from multiple threads then unless Boost.Process has internal locking to prevent the race it would need to use STARTUPINFOEX to ensure only the "correct" handles get inherited. That API is not available on XP, though; not sure if you still care about that.