diff options
author | Elliott Hughes <enh@google.com> | 2021-02-04 16:58:13 -0800 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2021-02-04 17:01:55 -0800 |
commit | f9cfecf3d4d848e247dc8bdc486ed227bff7315f (patch) | |
tree | 00f1b5a19b7acaa16783ea14361d156a38a98989 /tests/stdio_test.cpp | |
parent | 15ade069b10f7f5291e48c01db2da4852dae04b7 (diff) |
Fix freopen() where the path is null.
This has been in the standard since C99, but we've never supported it
before. It's apparently used by SPIRV-Tools.
I tried implementing this the other way (with fcntl(2)) first, but
eventually realized that that's more complicated and gives worse
results. This implementation assumes that /proc is mounted, but so much
of libc relies on that at this point that I don't think there's any
realistic case where the fcntl(2) implementation would be preferable,
and there are many where it's not.
The fact that no-one's mentioned this until now suggests that it's not a
heavily used feature anyway.
I've also replaced AssertCloseOnExec() with a CloseOnExec()
boolean-valued function instead, because it's really annoying getting
assertion failures that don't point you at the test line in question,
and instead point to some common helper code.
Test: treehugger
Change-Id: Ia2e53bf2664a4f782581042054ecd492830e2aed
Diffstat (limited to 'tests/stdio_test.cpp')
-rw-r--r-- | tests/stdio_test.cpp | 83 |
1 files changed, 67 insertions, 16 deletions
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index 5680f9556..afbbf2686 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -1956,34 +1956,64 @@ TEST(STDIO_TEST, open_memstream_EINVAL) { #endif } -TEST(STDIO_TEST, fdopen_CLOEXEC) { - int fd = open("/proc/version", O_RDONLY); - ASSERT_TRUE(fd != -1); - +TEST(STDIO_TEST, fdopen_add_CLOEXEC) { // This fd doesn't have O_CLOEXEC... - AssertCloseOnExec(fd, false); - - FILE* fp = fdopen(fd, "re"); - ASSERT_TRUE(fp != nullptr); - + int fd = open("/proc/version", O_RDONLY); + ASSERT_FALSE(CloseOnExec(fd)); // ...but the new one does. - AssertCloseOnExec(fileno(fp), true); + FILE* fp = fdopen(fd, "re"); + ASSERT_TRUE(CloseOnExec(fileno(fp))); + fclose(fp); +} +TEST(STDIO_TEST, fdopen_remove_CLOEXEC) { + // This fd has O_CLOEXEC... + int fd = open("/proc/version", O_RDONLY | O_CLOEXEC); + ASSERT_TRUE(CloseOnExec(fd)); + // ...but the new one doesn't. + FILE* fp = fdopen(fd, "r"); + ASSERT_TRUE(CloseOnExec(fileno(fp))); fclose(fp); } -TEST(STDIO_TEST, freopen_CLOEXEC) { +TEST(STDIO_TEST, freopen_add_CLOEXEC) { + // This FILE* doesn't have O_CLOEXEC... FILE* fp = fopen("/proc/version", "r"); - ASSERT_TRUE(fp != nullptr); + ASSERT_FALSE(CloseOnExec(fileno(fp))); + // ...but the new one does. + fp = freopen("/proc/version", "re", fp); + ASSERT_TRUE(CloseOnExec(fileno(fp))); - // This FILE* doesn't have O_CLOEXEC... - AssertCloseOnExec(fileno(fp), false); + fclose(fp); +} - fp = freopen("/proc/version", "re", fp); +TEST(STDIO_TEST, freopen_remove_CLOEXEC) { + // This FILE* has O_CLOEXEC... + FILE* fp = fopen("/proc/version", "re"); + ASSERT_TRUE(CloseOnExec(fileno(fp))); + // ...but the new one doesn't. + fp = freopen("/proc/version", "r", fp); + ASSERT_FALSE(CloseOnExec(fileno(fp))); + fclose(fp); +} +TEST(STDIO_TEST, freopen_null_filename_add_CLOEXEC) { + // This FILE* doesn't have O_CLOEXEC... + FILE* fp = fopen("/proc/version", "r"); + ASSERT_FALSE(CloseOnExec(fileno(fp))); // ...but the new one does. - AssertCloseOnExec(fileno(fp), true); + fp = freopen(nullptr, "re", fp); + ASSERT_TRUE(CloseOnExec(fileno(fp))); + fclose(fp); +} +TEST(STDIO_TEST, freopen_null_filename_remove_CLOEXEC) { + // This FILE* has O_CLOEXEC... + FILE* fp = fopen("/proc/version", "re"); + ASSERT_TRUE(CloseOnExec(fileno(fp))); + // ...but the new one doesn't. + fp = freopen(nullptr, "r", fp); + ASSERT_FALSE(CloseOnExec(fileno(fp))); fclose(fp); } @@ -2883,3 +2913,24 @@ TEST(STDIO_TEST, tmpnam_buf) { char buf[L_tmpnam]; tmpnam_test(buf); } + +TEST(STDIO_TEST, freopen_null_filename_mode) { + TemporaryFile tf; + FILE* fp = fopen(tf.path, "r"); + ASSERT_TRUE(fp != nullptr); + + // "r" = O_RDONLY + char buf[1]; + ASSERT_EQ(0, read(fileno(fp), buf, 1)); + ASSERT_EQ(-1, write(fileno(fp), "hello", 1)); + // "r+" = O_RDWR + fp = freopen(nullptr, "r+", fp); + ASSERT_EQ(0, read(fileno(fp), buf, 1)); + ASSERT_EQ(1, write(fileno(fp), "hello", 1)); + // "w" = O_WRONLY + fp = freopen(nullptr, "w", fp); + ASSERT_EQ(-1, read(fileno(fp), buf, 1)); + ASSERT_EQ(1, write(fileno(fp), "hello", 1)); + + fclose(fp); +} |