summaryrefslogtreecommitdiff
path: root/tests/stdio_test.cpp
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2018-07-10 14:39:49 -0700
committerElliott Hughes <enh@google.com>2018-07-11 12:15:26 -0700
commit468efc80da2504f4ae7de8b5e137426d44dda9d7 (patch)
tree464d20ef3a5ae493a9728ddc53629764b59f300d /tests/stdio_test.cpp
parentf0296f35f67cf4c112b3ed407858999bdc2f33b0 (diff)
Reimplement popen(3)/pclose(3).
pclose(3) is now an alias for fclose(3). We could add a FORTIFY check that you use pclose(3) if and only if you used popen(3), but there seems little value to that when we can just do the right thing. This patch also adds the missing locking to _fwalk --- we need to lock both the global list of FILE*s and also each FILE* we touch. POSIX says that "The popen() function shall ensure that any streams from previous popen() calls that remain open in the parent process are closed in the new child process", which we implement via _fwalk(fclose) in the child, but we might want to just make *all* popen(3) file descriptors O_CLOEXEC in all cases. Ignore fewer errors in popen(3) failure cases. Improve popen(3) test coverage. Bug: http://b/72470344 Test: ran tests Change-Id: Ic937594bf28ec88b375f7e5825b9c05f500af438
Diffstat (limited to 'tests/stdio_test.cpp')
-rw-r--r--tests/stdio_test.cpp60
1 files changed, 59 insertions, 1 deletions
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 33514d4ff..6282ec3cc 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -22,6 +22,7 @@
#include <math.h>
#include <stdio.h>
#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wchar.h>
@@ -888,7 +889,7 @@ TEST(STDIO_TEST, fprintf_failures_7229520) {
ASSERT_EQ(-1, fclose(fp));
}
-TEST(STDIO_TEST, popen) {
+TEST(STDIO_TEST, popen_r) {
FILE* fp = popen("cat /proc/version", "r");
ASSERT_TRUE(fp != NULL);
@@ -900,6 +901,63 @@ TEST(STDIO_TEST, popen) {
ASSERT_EQ(0, pclose(fp));
}
+TEST(STDIO_TEST, popen_socketpair) {
+ FILE* fp = popen("cat", "r+");
+ ASSERT_TRUE(fp != NULL);
+
+ fputs("hello\nworld\n", fp);
+ fflush(fp);
+
+ char buf[16];
+ ASSERT_NE(nullptr, fgets(buf, sizeof(buf), fp));
+ EXPECT_STREQ("hello\n", buf);
+ ASSERT_NE(nullptr, fgets(buf, sizeof(buf), fp));
+ EXPECT_STREQ("world\n", buf);
+
+ ASSERT_EQ(0, pclose(fp));
+}
+
+TEST(STDIO_TEST, popen_socketpair_shutdown) {
+ FILE* fp = popen("uniq -c", "r+");
+ ASSERT_TRUE(fp != NULL);
+
+ fputs("a\na\na\na\nb\n", fp);
+ fflush(fp);
+ ASSERT_EQ(0, shutdown(fileno(fp), SHUT_WR));
+
+ char buf[16];
+ ASSERT_NE(nullptr, fgets(buf, sizeof(buf), fp));
+ EXPECT_STREQ(" 4 a\n", buf);
+ ASSERT_NE(nullptr, fgets(buf, sizeof(buf), fp));
+ EXPECT_STREQ(" 1 b\n", buf);
+
+ ASSERT_EQ(0, pclose(fp));
+}
+
+TEST(STDIO_TEST, popen_return_value_0) {
+ FILE* fp = popen("true", "r");
+ ASSERT_TRUE(fp != NULL);
+ int status = pclose(fp);
+ EXPECT_TRUE(WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+}
+
+TEST(STDIO_TEST, popen_return_value_1) {
+ FILE* fp = popen("false", "r");
+ ASSERT_TRUE(fp != NULL);
+ int status = pclose(fp);
+ EXPECT_TRUE(WIFEXITED(status));
+ EXPECT_EQ(1, WEXITSTATUS(status));
+}
+
+TEST(STDIO_TEST, popen_return_value_signal) {
+ FILE* fp = popen("kill -7 $$", "r");
+ ASSERT_TRUE(fp != NULL);
+ int status = pclose(fp);
+ EXPECT_TRUE(WIFSIGNALED(status));
+ EXPECT_EQ(7, WTERMSIG(status));
+}
+
TEST(STDIO_TEST, getc) {
FILE* fp = fopen("/proc/version", "r");
ASSERT_TRUE(fp != NULL);