66#include < stddef.h>
77#include < setjmp.h>
88#include < signal.h>
9+ #include < errno.h>
910#include < iostream>
1011#include < unordered_set>
1112
@@ -107,6 +108,38 @@ void test_pipe_merge_stderr_into_stdout(void**) {
107108 assert_true (memcmp (buffer, expected, sizeof (expected)-1 ) == 0 );
108109}
109110
111+ void test_pipe_kill_then_read (void **) {
112+ TLoop<TDefaultPoller> loop;
113+ auto & poller = loop.Poller ();
114+ std::string sleepPath = " /bin/sleep" ;
115+ // Start a process that produces no output and runs for a while
116+ TPipe pipe (poller, sleepPath, {" 5" });
117+
118+ int pid = pipe.Pid ();
119+ assert_true (pid > 0 );
120+
121+ int rc = kill (pid, SIGKILL);
122+ assert_true (rc == 0 || errno == ESRCH);
123+
124+ // Attempt to read from stdout; should observe EOF (0 bytes)
125+ char buffer[8 ] = {};
126+ size_t bytesRead = sizeof (buffer);
127+ auto reader = [](TPipe& pipe, char * buffer, size_t & size) -> TFuture<void > {
128+ try {
129+ size = co_await pipe.ReadSome (buffer, size);
130+ } catch (const std::exception& ex) {
131+ // Accept exceptions as valid outcome on abrupt termination
132+ size = 0 ;
133+ }
134+ }(pipe, buffer, bytesRead);
135+
136+ while (!reader.done ()) {
137+ loop.Step ();
138+ }
139+
140+ assert_true (bytesRead == 0 );
141+ }
142+
110143#endif // _WIN32
111144
112145int main (int argc, char ** argv) {
@@ -122,6 +155,7 @@ int main(int argc, char** argv) {
122155 ADD_TEST (cmocka_unit_test, test_pipe_basic_read_write);
123156 ADD_TEST (cmocka_unit_test, test_pipe_read_stderr);
124157 ADD_TEST (cmocka_unit_test, test_pipe_merge_stderr_into_stdout);
158+ ADD_TEST (cmocka_unit_test, test_pipe_kill_then_read);
125159#endif
126160
127161 return _cmocka_run_group_tests (" test_pipe" , tests.data (), tests.size (), NULL , NULL );
0 commit comments