From 459c17bc350f93e7da9dd3f57345fbda75e20290 Mon Sep 17 00:00:00 2001
From: Jason Hiser <jdhiser@gmail.com>
Date: Tue, 17 Dec 2019 20:25:59 -0500
Subject: [PATCH] fixed deadlock in pipe code

---
 src/cmdstr.hpp | 60 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 41 insertions(+), 19 deletions(-)

diff --git a/src/cmdstr.hpp b/src/cmdstr.hpp
index 48d67c5e5..eeccc1bb0 100644
--- a/src/cmdstr.hpp
+++ b/src/cmdstr.hpp
@@ -1,10 +1,7 @@
 #ifndef cmdstr_hpp 
 #define cmdstr_hpp 
 
-/*BINFMTCXX: -std=c++11 -Wall -Werror
-*/
-
-#include <spawn.h> // see manpages-posix-dev
+#include <spawn.h> 
 #include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -14,19 +11,45 @@
 #include <iostream>
 #include <string>
 #include <vector>
-using namespace std;
+#include <array>
 
+using namespace std;
 
 static inline pair<string,int> command_to_string( const string& command)
 {
 	auto ret=string();
 	int exit_code=0;
-	int cout_pipe[2];
-	int cerr_pipe[2];
 	posix_spawn_file_actions_t action;
 
-	if(pipe(cout_pipe) || pipe(cerr_pipe))
-		cout << "pipe returned an error.\n";
+
+	const auto pipe_closer = function<void(int*)>([](int *p_pipefd) -> void
+		{
+			const auto pipe = *p_pipefd;
+			close(pipe);
+			delete p_pipefd;
+		});
+	using PipeFD_t = unique_ptr<int,decltype(pipe_closer)>;
+
+	const auto pipe_opener = [&]() -> vector<PipeFD_t>
+		{
+			auto pipe_fds = array<int,2>();
+			if(pipe( pipe_fds.data()))
+			{
+				const auto err_str = string(strerror(errno));
+				throw runtime_error("Cannot open pipe: " + err_str);
+			}
+			auto ret = vector<PipeFD_t>();
+//			PipeFD_t p(new int(pipe_fds[0]), pipe_closer);
+//			ret.push_back(move(p));
+			ret.push_back({new int(pipe_fds[0]), pipe_closer});
+			ret.push_back({new int(pipe_fds[1]), pipe_closer});
+			return ret;
+		};
+
+	auto cout_pipe_vec = pipe_opener();
+	auto cerr_pipe_vec = pipe_opener();
+	const auto cout_pipe = vector<int>{*(cout_pipe_vec[0]), *(cout_pipe_vec[1])};
+	const auto cerr_pipe = vector<int>{*(cerr_pipe_vec[0]), *(cerr_pipe_vec[1])};
 
 	posix_spawn_file_actions_init(&action);
 	posix_spawn_file_actions_addclose(&action, cout_pipe[0]);
@@ -37,8 +60,6 @@ static inline pair<string,int> command_to_string( const string& command)
 	posix_spawn_file_actions_addclose(&action, cout_pipe[1]);
 	posix_spawn_file_actions_addclose(&action, cerr_pipe[1]);
 
-	//  string command = "echo bla"; // example #1
-	//  string command = "pgmcrater -width 64 -height 9 |pgmtopbm |pnmtoplainpnm";
 	vector<char> argsmem[] = {{'s', 'h', '\0'}, {'-', 'c', '\0'}}; // allows non-const access to literals
 	char *args[] = {&argsmem[0][0], &argsmem[1][0],const_cast<char*>(command.c_str()),nullptr};
 
@@ -46,23 +67,23 @@ static inline pair<string,int> command_to_string( const string& command)
 	if(posix_spawnp(&pid, args[0], &action, NULL, args, environ) != 0)
 		cout << "posix_spawnp failed with error: " << strerror(errno) << "\n";
 
-	close(cout_pipe[1]), close(cerr_pipe[1]); // close child-side of pipes
+  	cout_pipe_vec[1].reset();
+	cerr_pipe_vec[1].reset(); // close child-side of pipes
+
 
 	// Read from pipes
 	string buffer(1024,' ');
-	std::vector<pollfd> plist = { {cout_pipe[0],POLLIN}, {cerr_pipe[0],POLLIN} };
+	vector<pollfd> plist = { {cout_pipe[0],POLLIN}, {cerr_pipe[0],POLLIN} };
 	for ( int rval; (rval=poll(&plist[0],plist.size(),/*timeout*/-1))>0; ) 
 	{
-		if ( plist[0].revents&POLLIN) {
+		if ( plist[0].revents&POLLIN) 
+		{
 			const auto bytes_read = read(cout_pipe[0], &buffer[0], buffer.length());
-			// cout << "read " << bytes_read << " bytes from stdout.\n";
-			// cout << buffer.substr(0, static_cast<size_t>(bytes_read)) << "\n";
 			ret += buffer.substr(0, static_cast<size_t>(bytes_read));
 		}
-		else if ( plist[1].revents&POLLIN ) {
+		else if ( plist[1].revents&POLLIN ) 
+		{
 			const auto bytes_read = read(cerr_pipe[0], &buffer[0], buffer.length());
-			// cout << "read " << bytes_read << " bytes from stderr.\n";
-			// cout << buffer.substr(0, static_cast<size_t>(bytes_read)) << "\n";
 			ret +=  buffer.substr(0, static_cast<size_t>(bytes_read));
 		}
 		else 
@@ -85,4 +106,5 @@ static inline int command_to_stream(const string& command, ostream& stream)
         return res.second;
 }
 
+
 #endif
-- 
GitLab