Index: third_party/protobuf/conformance/conformance_test_runner.cc |
diff --git a/third_party/protobuf/conformance/conformance_test_runner.cc b/third_party/protobuf/conformance/conformance_test_runner.cc |
index f2b0dabf2967930e33df67ef03e93eec49839189..376a60b9aa6edf1ff9e459ab0f83815a1ad36ee8 100644 |
--- a/third_party/protobuf/conformance/conformance_test_runner.cc |
+++ b/third_party/protobuf/conformance/conformance_test_runner.cc |
@@ -55,16 +55,21 @@ |
#include <algorithm> |
#include <errno.h> |
-#include <unistd.h> |
#include <fstream> |
+#include <sys/types.h> |
+#include <sys/wait.h> |
+#include <unistd.h> |
#include <vector> |
+#include <google/protobuf/stubs/stringprintf.h> |
+ |
#include "conformance.pb.h" |
#include "conformance_test.h" |
using conformance::ConformanceRequest; |
using conformance::ConformanceResponse; |
using google::protobuf::internal::scoped_array; |
+using google::protobuf::StringAppendF; |
using std::string; |
using std::vector; |
@@ -81,14 +86,14 @@ using std::vector; |
class ForkPipeRunner : public google::protobuf::ConformanceTestRunner { |
public: |
ForkPipeRunner(const std::string &executable) |
- : running_(false), executable_(executable) {} |
+ : child_pid_(-1), executable_(executable) {} |
virtual ~ForkPipeRunner() {} |
void RunTest(const std::string& test_name, |
const std::string& request, |
std::string* response) { |
- if (!running_) { |
+ if (child_pid_ < 0) { |
SpawnTestProgram(); |
} |
@@ -97,7 +102,31 @@ class ForkPipeRunner : public google::protobuf::ConformanceTestRunner { |
uint32_t len = request.size(); |
CheckedWrite(write_fd_, &len, sizeof(uint32_t)); |
CheckedWrite(write_fd_, request.c_str(), request.size()); |
- CheckedRead(read_fd_, &len, sizeof(uint32_t)); |
+ |
+ if (!TryRead(read_fd_, &len, sizeof(uint32_t))) { |
+ // We failed to read from the child, assume a crash and try to reap. |
+ GOOGLE_LOG(INFO) << "Trying to reap child, pid=" << child_pid_; |
+ |
+ int status; |
+ waitpid(child_pid_, &status, WEXITED); |
+ |
+ string error_msg; |
+ if (WIFEXITED(status)) { |
+ StringAppendF(&error_msg, |
+ "child exited, status=%d", WEXITSTATUS(status)); |
+ } else if (WIFSIGNALED(status)) { |
+ StringAppendF(&error_msg, |
+ "child killed by signal %d", WTERMSIG(status)); |
+ } |
+ GOOGLE_LOG(INFO) << error_msg; |
+ child_pid_ = -1; |
+ |
+ conformance::ConformanceResponse response_obj; |
+ response_obj.set_runtime_error(error_msg); |
+ response_obj.SerializeToString(response); |
+ return; |
+ } |
+ |
response->resize(len); |
CheckedRead(read_fd_, (void*)response->c_str(), len); |
} |
@@ -141,7 +170,7 @@ class ForkPipeRunner : public google::protobuf::ConformanceTestRunner { |
CHECK_SYSCALL(close(fromproc_pipe_fd[1])); |
write_fd_ = toproc_pipe_fd[1]; |
read_fd_ = fromproc_pipe_fd[0]; |
- running_ = true; |
+ child_pid_ = pid; |
} else { |
// Child. |
CHECK_SYSCALL(close(STDIN_FILENO)); |
@@ -171,28 +200,40 @@ class ForkPipeRunner : public google::protobuf::ConformanceTestRunner { |
} |
} |
- void CheckedRead(int fd, void *buf, size_t len) { |
+ bool TryRead(int fd, void *buf, size_t len) { |
size_t ofs = 0; |
while (len > 0) { |
ssize_t bytes_read = read(fd, (char*)buf + ofs, len); |
if (bytes_read == 0) { |
- GOOGLE_LOG(FATAL) << current_test_name_ |
+ GOOGLE_LOG(ERROR) << current_test_name_ |
<< ": unexpected EOF from test program"; |
+ return false; |
} else if (bytes_read < 0) { |
- GOOGLE_LOG(FATAL) << current_test_name_ |
+ GOOGLE_LOG(ERROR) << current_test_name_ |
<< ": error reading from test program: " |
<< strerror(errno); |
+ return false; |
} |
len -= bytes_read; |
ofs += bytes_read; |
} |
+ |
+ return true; |
+ } |
+ |
+ void CheckedRead(int fd, void *buf, size_t len) { |
+ if (!TryRead(fd, buf, len)) { |
+ GOOGLE_LOG(FATAL) << current_test_name_ |
+ << ": error reading from test program: " |
+ << strerror(errno); |
+ } |
} |
int write_fd_; |
int read_fd_; |
- bool running_; |
+ pid_t child_pid_; |
std::string executable_; |
std::string current_test_name_; |
}; |
@@ -239,12 +280,12 @@ int main(int argc, char *argv[]) { |
char *program; |
google::protobuf::ConformanceTestSuite suite; |
+ vector<string> failure_list; |
+ |
for (int arg = 1; arg < argc; ++arg) { |
if (strcmp(argv[arg], "--failure_list") == 0) { |
if (++arg == argc) UsageError(); |
- vector<string> failure_list; |
ParseFailureList(argv[arg], &failure_list); |
- suite.SetFailureList(failure_list); |
} else if (strcmp(argv[arg], "--verbose") == 0) { |
suite.SetVerbose(true); |
} else if (argv[arg][0] == '-') { |
@@ -259,6 +300,7 @@ int main(int argc, char *argv[]) { |
} |
} |
+ suite.SetFailureList(failure_list); |
ForkPipeRunner runner(program); |
std::string output; |