diff options
author | Romain Geissler <romain.geissler@amadeus.com> | 2020-03-11 22:30:20 (GMT) |
---|---|---|
committer | Romain Geissler <romain.geissler@amadeus.com> | 2020-03-11 22:39:20 (GMT) |
commit | a1b0173df92bbbad69254f929e341f8dbf1cc708 (patch) | |
tree | a9250c6dfa08a770fef5c1f0c472a6036371347d | |
parent | e588eb1ff9ff6598666279b737b27f983156ad85 (diff) | |
download | googletest-a1b0173df92bbbad69254f929e341f8dbf1cc708.zip googletest-a1b0173df92bbbad69254f929e341f8dbf1cc708.tar.gz googletest-a1b0173df92bbbad69254f929e341f8dbf1cc708.tar.bz2 |
Make sure IsATTY does not clobber errno.refs/pull/2746/head
Exposition of the problem:
> cat main.cpp
TEST(errnoTest, errnoTest)
{
ASSERT_EQ(errno, 0);
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Compiled with gcc 10 like this:
> g++ -pthread -o runtest main.cpp -Wl,-Bstatic -lgtest -Wl,-Bdynamic
Before patch:
> ./runtest
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from errnoTest
[ RUN ] errnoTest.errnoTest
[ OK ] errnoTest.errnoTest (0 ms)
[----------] 1 test from errnoTest (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
(output is colored, I run this inside an interactive terminal).
> ./runtest | cat
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from errnoTest
[ RUN ] errnoTest.errnoTest
main.cpp:5: Failure
Expected equality of these values:
(*__errno_location ())
Which is: 25
0
[ FAILED ] errnoTest.errnoTest (0 ms)
[----------] 1 test from errnoTest (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] errnoTest.errnoTest
1 FAILED TEST
(output is not colored, since IsTTY return false, because of the pipe,
however it also clobbered errno for the tests).
After the patch, both cases are working fine:
> ./runtest
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from errnoTest
[ RUN ] errnoTest.errnoTest
[ OK ] errnoTest.errnoTest (0 ms)
[----------] 1 test from errnoTest (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
> ./runtest | cat
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from errnoTest
[ RUN ] errnoTest.errnoTest
[ OK ] errnoTest.errnoTest (0 ms)
[----------] 1 test from errnoTest (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
-rw-r--r-- | googletest/include/gtest/internal/gtest-port.h | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h index 60ff471..c7c79ae 100644 --- a/googletest/include/gtest/internal/gtest-port.h +++ b/googletest/include/gtest/internal/gtest-port.h @@ -252,6 +252,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <cerrno> #include <cstdint> #include <limits> #include <type_traits> @@ -1960,16 +1961,16 @@ namespace posix { typedef struct _stat StatStruct; # ifdef __BORLANDC__ -inline int IsATTY(int fd) { return isatty(fd); } +inline int DoIsATTY(int fd) { return isatty(fd); } inline int StrCaseCmp(const char* s1, const char* s2) { return stricmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } # else // !__BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE -inline int IsATTY(int /* fd */) { return 0; } +inline int DoIsATTY(int /* fd */) { return 0; } # else -inline int IsATTY(int fd) { return _isatty(fd); } +inline int DoIsATTY(int fd) { return _isatty(fd); } # endif // GTEST_OS_WINDOWS_MOBILE inline int StrCaseCmp(const char* s1, const char* s2) { return _stricmp(s1, s2); @@ -1994,7 +1995,7 @@ inline bool IsDir(const StatStruct& st) { typedef struct stat StatStruct; inline int FileNo(FILE* file) { return fileno(file); } -inline int IsATTY(int fd) { return isatty(fd); } +inline int DoIsATTY(int fd) { return isatty(fd); } inline int Stat(const char* path, StatStruct* buf) { // stat function not implemented on ESP8266 return 0; @@ -2011,7 +2012,7 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } typedef struct stat StatStruct; inline int FileNo(FILE* file) { return fileno(file); } -inline int IsATTY(int fd) { return isatty(fd); } +inline int DoIsATTY(int fd) { return isatty(fd); } inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } inline int StrCaseCmp(const char* s1, const char* s2) { return strcasecmp(s1, s2); @@ -2022,6 +2023,18 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } #endif // GTEST_OS_WINDOWS +inline int IsATTY(int fd) +{ + // DoIsATTY might change errno (for example ENOTTY in case you redirect stdout + // to a file on Linux), which is unexpected, so save the previous value, and + // restore it after the call. + int savedErrno = errno; + int isAttyValue = DoIsATTY(fd); + errno = savedErrno; + + return isAttyValue; +} + // Functions deprecated by MSVC 8.0. GTEST_DISABLE_MSC_DEPRECATED_PUSH_() |