gtest-port.cc (googletest-release-1.10.0) | : | gtest-port.cc (googletest-release-1.11.0) | ||
---|---|---|---|---|
skipping to change at line 36 | skipping to change at line 36 | |||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
#include "gtest/internal/gtest-port.h" | #include "gtest/internal/gtest-port.h" | |||
#include <limits.h> | #include <limits.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <string.h> | #include <string.h> | |||
#include <cstdint> | ||||
#include <fstream> | #include <fstream> | |||
#include <memory> | #include <memory> | |||
#if GTEST_OS_WINDOWS | #if GTEST_OS_WINDOWS | |||
# include <windows.h> | # include <windows.h> | |||
# include <io.h> | # include <io.h> | |||
# include <sys/stat.h> | # include <sys/stat.h> | |||
# include <map> // Used in ThreadLocal. | # include <map> // Used in ThreadLocal. | |||
# ifdef _MSC_VER | # ifdef _MSC_VER | |||
# include <crtdbg.h> | # include <crtdbg.h> | |||
skipping to change at line 199 | skipping to change at line 200 | |||
sizeof(struct kinfo_proc), | sizeof(struct kinfo_proc), | |||
0, | 0, | |||
}; | }; | |||
u_int miblen = sizeof(mib) / sizeof(mib[0]); | u_int miblen = sizeof(mib) / sizeof(mib[0]); | |||
// get number of structs | // get number of structs | |||
size_t size; | size_t size; | |||
if (sysctl(mib, miblen, NULL, &size, NULL, 0)) { | if (sysctl(mib, miblen, NULL, &size, NULL, 0)) { | |||
return 0; | return 0; | |||
} | } | |||
mib[5] = size / mib[4]; | ||||
mib[5] = static_cast<int>(size / static_cast<size_t>(mib[4])); | ||||
// populate array of structs | // populate array of structs | |||
struct kinfo_proc info[mib[5]]; | struct kinfo_proc info[mib[5]]; | |||
if (sysctl(mib, miblen, &info, &size, NULL, 0)) { | if (sysctl(mib, miblen, &info, &size, NULL, 0)) { | |||
return 0; | return 0; | |||
} | } | |||
// exclude empty members | // exclude empty members | |||
int nthreads = 0; | size_t nthreads = 0; | |||
for (int i = 0; i < size / mib[4]; i++) { | for (size_t i = 0; i < size / static_cast<size_t>(mib[4]); i++) { | |||
if (info[i].p_tid != -1) | if (info[i].p_tid != -1) | |||
nthreads++; | nthreads++; | |||
} | } | |||
return nthreads; | return nthreads; | |||
} | } | |||
#elif GTEST_OS_QNX | #elif GTEST_OS_QNX | |||
// Returns the number of threads running in the process, or 0 to indicate that | // Returns the number of threads running in the process, or 0 to indicate that | |||
// we cannot detect it. | // we cannot detect it. | |||
skipping to change at line 538 | skipping to change at line 540 | |||
// Maps a thread to a set of ThreadIdToThreadLocals that have values | // Maps a thread to a set of ThreadIdToThreadLocals that have values | |||
// instantiated on that thread and notifies them when the thread exits. A | // instantiated on that thread and notifies them when the thread exits. A | |||
// ThreadLocal instance is expected to persist until all threads it has | // ThreadLocal instance is expected to persist until all threads it has | |||
// values on have terminated. | // values on have terminated. | |||
class ThreadLocalRegistryImpl { | class ThreadLocalRegistryImpl { | |||
public: | public: | |||
// Registers thread_local_instance as having value on the current thread. | // Registers thread_local_instance as having value on the current thread. | |||
// Returns a value that can be used to identify the thread from other threads. | // Returns a value that can be used to identify the thread from other threads. | |||
static ThreadLocalValueHolderBase* GetValueOnCurrentThread( | static ThreadLocalValueHolderBase* GetValueOnCurrentThread( | |||
const ThreadLocalBase* thread_local_instance) { | const ThreadLocalBase* thread_local_instance) { | |||
#ifdef _MSC_VER | ||||
MemoryIsNotDeallocated memory_is_not_deallocated; | ||||
#endif // _MSC_VER | ||||
DWORD current_thread = ::GetCurrentThreadId(); | DWORD current_thread = ::GetCurrentThreadId(); | |||
MutexLock lock(&mutex_); | MutexLock lock(&mutex_); | |||
ThreadIdToThreadLocals* const thread_to_thread_locals = | ThreadIdToThreadLocals* const thread_to_thread_locals = | |||
GetThreadLocalsMapLocked(); | GetThreadLocalsMapLocked(); | |||
ThreadIdToThreadLocals::iterator thread_local_pos = | ThreadIdToThreadLocals::iterator thread_local_pos = | |||
thread_to_thread_locals->find(current_thread); | thread_to_thread_locals->find(current_thread); | |||
if (thread_local_pos == thread_to_thread_locals->end()) { | if (thread_local_pos == thread_to_thread_locals->end()) { | |||
thread_local_pos = thread_to_thread_locals->insert( | thread_local_pos = thread_to_thread_locals->insert( | |||
std::make_pair(current_thread, ThreadLocalValues())).first; | std::make_pair(current_thread, ThreadLocalValues())).first; | |||
StartWatcherThreadFor(current_thread); | StartWatcherThreadFor(current_thread); | |||
skipping to change at line 685 | skipping to change at line 690 | |||
static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals(); | static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals(); | |||
return map; | return map; | |||
} | } | |||
// Protects access to GetThreadLocalsMapLocked() and its return value. | // Protects access to GetThreadLocalsMapLocked() and its return value. | |||
static Mutex mutex_; | static Mutex mutex_; | |||
// Protects access to GetThreadMapLocked() and its return value. | // Protects access to GetThreadMapLocked() and its return value. | |||
static Mutex thread_map_mutex_; | static Mutex thread_map_mutex_; | |||
}; | }; | |||
Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); | Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); // NOLINT | |||
Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); | Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); // NOLIN | |||
T | ||||
ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( | ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( | |||
const ThreadLocalBase* thread_local_instance) { | const ThreadLocalBase* thread_local_instance) { | |||
return ThreadLocalRegistryImpl::GetValueOnCurrentThread( | return ThreadLocalRegistryImpl::GetValueOnCurrentThread( | |||
thread_local_instance); | thread_local_instance); | |||
} | } | |||
void ThreadLocalRegistry::OnThreadLocalDestroyed( | void ThreadLocalRegistry::OnThreadLocalDestroyed( | |||
const ThreadLocalBase* thread_local_instance) { | const ThreadLocalBase* thread_local_instance) { | |||
ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); | ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); | |||
skipping to change at line 1092 | skipping to change at line 1097 | |||
0, // Generate unique file name. | 0, // Generate unique file name. | |||
temp_file_path); | temp_file_path); | |||
GTEST_CHECK_(success != 0) | GTEST_CHECK_(success != 0) | |||
<< "Unable to create a temporary file in " << temp_dir_path; | << "Unable to create a temporary file in " << temp_dir_path; | |||
const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); | const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); | |||
GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " | GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " | |||
<< temp_file_path; | << temp_file_path; | |||
filename_ = temp_file_path; | filename_ = temp_file_path; | |||
# else | # else | |||
// There's no guarantee that a test has write access to the current | // There's no guarantee that a test has write access to the current | |||
// directory, so we create the temporary file in the /tmp directory | // directory, so we create the temporary file in a temporary directory. | |||
// instead. We use /tmp on most systems, and /sdcard on Android. | std::string name_template; | |||
// That's because Android doesn't have /tmp. | ||||
# if GTEST_OS_LINUX_ANDROID | # if GTEST_OS_LINUX_ANDROID | |||
// Note: Android applications are expected to call the framework's | // Note: Android applications are expected to call the framework's | |||
// Context.getExternalStorageDirectory() method through JNI to get | // Context.getExternalStorageDirectory() method through JNI to get | |||
// the location of the world-writable SD Card directory. However, | // the location of the world-writable SD Card directory. However, | |||
// this requires a Context handle, which cannot be retrieved | // this requires a Context handle, which cannot be retrieved | |||
// globally from native code. Doing so also precludes running the | // globally from native code. Doing so also precludes running the | |||
// code as part of a regular standalone executable, which doesn't | // code as part of a regular standalone executable, which doesn't | |||
// run in a Dalvik process (e.g. when running it through 'adb shell'). | // run in a Dalvik process (e.g. when running it through 'adb shell'). | |||
// | // | |||
// The location /data/local/tmp is directly accessible from native code. | // The location /data/local/tmp is directly accessible from native code. | |||
// '/sdcard' and other variants cannot be relied on, as they are not | // '/sdcard' and other variants cannot be relied on, as they are not | |||
// guaranteed to be mounted, or may have a delay in mounting. | // guaranteed to be mounted, or may have a delay in mounting. | |||
char name_template[] = "/data/local/tmp/gtest_captured_stream.XXXXXX"; | name_template = "/data/local/tmp/"; | |||
# elif GTEST_OS_IOS | ||||
char user_temp_dir[PATH_MAX + 1]; | ||||
// Documented alternative to NSTemporaryDirectory() (for obtaining creating | ||||
// a temporary directory) at | ||||
// https://developer.apple.com/library/archive/documentation/Security/Concep | ||||
tual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP400025 | ||||
85-SW10 | ||||
// | ||||
// _CS_DARWIN_USER_TEMP_DIR (as well as _CS_DARWIN_USER_CACHE_DIR) is not | ||||
// documented in the confstr() man page at | ||||
// https://developer.apple.com/library/archive/documentation/System/Conceptu | ||||
al/ManPages_iPhoneOS/man3/confstr.3.html#//apple_ref/doc/man/3/confstr | ||||
// but are still available, according to the WebKit patches at | ||||
// https://trac.webkit.org/changeset/262004/webkit | ||||
// https://trac.webkit.org/changeset/263705/webkit | ||||
// | ||||
// The confstr() implementation falls back to getenv("TMPDIR"). See | ||||
// https://opensource.apple.com/source/Libc/Libc-1439.100.3/gen/confstr.c.au | ||||
to.html | ||||
::confstr(_CS_DARWIN_USER_TEMP_DIR, user_temp_dir, sizeof(user_temp_dir)); | ||||
name_template = user_temp_dir; | ||||
if (name_template.back() != GTEST_PATH_SEP_[0]) | ||||
name_template.push_back(GTEST_PATH_SEP_[0]); | ||||
# else | # else | |||
char name_template[] = "/tmp/captured_stream.XXXXXX"; | name_template = "/tmp/"; | |||
# endif // GTEST_OS_LINUX_ANDROID | # endif | |||
const int captured_fd = mkstemp(name_template); | name_template.append("gtest_captured_stream.XXXXXX"); | |||
// mkstemp() modifies the string bytes in place, and does not go beyond the | ||||
// string's length. This results in well-defined behavior in C++17. | ||||
// | ||||
// The const_cast is needed below C++17. The constraints on std::string | ||||
// implementations in C++11 and above make assumption behind the const_cast | ||||
// fairly safe. | ||||
const int captured_fd = ::mkstemp(const_cast<char*>(name_template.data())); | ||||
if (captured_fd == -1) { | if (captured_fd == -1) { | |||
GTEST_LOG_(WARNING) | GTEST_LOG_(WARNING) | |||
<< "Failed to create tmp file " << name_template | << "Failed to create tmp file " << name_template | |||
<< " for test; does the test have access to the /tmp directory?"; | << " for test; does the test have access to the /tmp directory?"; | |||
} | } | |||
filename_ = name_template; | filename_ = std::move(name_template); | |||
# endif // GTEST_OS_WINDOWS | # endif // GTEST_OS_WINDOWS | |||
fflush(nullptr); | fflush(nullptr); | |||
dup2(captured_fd, fd_); | dup2(captured_fd, fd_); | |||
close(captured_fd); | close(captured_fd); | |||
} | } | |||
~CapturedStream() { | ~CapturedStream() { | |||
remove(filename_.c_str()); | remove(filename_.c_str()); | |||
} | } | |||
skipping to change at line 1284 | skipping to change at line 1318 | |||
for (size_t i = 0; i != full_flag.length(); i++) { | for (size_t i = 0; i != full_flag.length(); i++) { | |||
env_var << ToUpper(full_flag.c_str()[i]); | env_var << ToUpper(full_flag.c_str()[i]); | |||
} | } | |||
return env_var.GetString(); | return env_var.GetString(); | |||
} | } | |||
// Parses 'str' for a 32-bit signed integer. If successful, writes | // Parses 'str' for a 32-bit signed integer. If successful, writes | |||
// the result to *value and returns true; otherwise leaves *value | // the result to *value and returns true; otherwise leaves *value | |||
// unchanged and returns false. | // unchanged and returns false. | |||
bool ParseInt32(const Message& src_text, const char* str, Int32* value) { | bool ParseInt32(const Message& src_text, const char* str, int32_t* value) { | |||
// Parses the environment variable as a decimal integer. | // Parses the environment variable as a decimal integer. | |||
char* end = nullptr; | char* end = nullptr; | |||
const long long_value = strtol(str, &end, 10); // NOLINT | const long long_value = strtol(str, &end, 10); // NOLINT | |||
// Has strtol() consumed all characters in the string? | // Has strtol() consumed all characters in the string? | |||
if (*end != '\0') { | if (*end != '\0') { | |||
// No - an invalid character was encountered. | // No - an invalid character was encountered. | |||
Message msg; | Message msg; | |||
msg << "WARNING: " << src_text | msg << "WARNING: " << src_text | |||
<< " is expected to be a 32-bit integer, but actually" | << " is expected to be a 32-bit integer, but actually" | |||
<< " has value \"" << str << "\".\n"; | << " has value \"" << str << "\".\n"; | |||
printf("%s", msg.GetString().c_str()); | printf("%s", msg.GetString().c_str()); | |||
fflush(stdout); | fflush(stdout); | |||
return false; | return false; | |||
} | } | |||
// Is the parsed value in the range of an Int32? | // Is the parsed value in the range of an int32_t? | |||
const Int32 result = static_cast<Int32>(long_value); | const auto result = static_cast<int32_t>(long_value); | |||
if (long_value == LONG_MAX || long_value == LONG_MIN || | if (long_value == LONG_MAX || long_value == LONG_MIN || | |||
// The parsed value overflows as a long. (strtol() returns | // The parsed value overflows as a long. (strtol() returns | |||
// LONG_MAX or LONG_MIN when the input overflows.) | // LONG_MAX or LONG_MIN when the input overflows.) | |||
result != long_value | result != long_value | |||
// The parsed value overflows as an Int32. | // The parsed value overflows as an int32_t. | |||
) { | ) { | |||
Message msg; | Message msg; | |||
msg << "WARNING: " << src_text | msg << "WARNING: " << src_text | |||
<< " is expected to be a 32-bit integer, but actually" | << " is expected to be a 32-bit integer, but actually" | |||
<< " has value " << str << ", which overflows.\n"; | << " has value " << str << ", which overflows.\n"; | |||
printf("%s", msg.GetString().c_str()); | printf("%s", msg.GetString().c_str()); | |||
fflush(stdout); | fflush(stdout); | |||
return false; | return false; | |||
} | } | |||
skipping to change at line 1340 | skipping to change at line 1374 | |||
const std::string env_var = FlagToEnvVar(flag); | const std::string env_var = FlagToEnvVar(flag); | |||
const char* const string_value = posix::GetEnv(env_var.c_str()); | const char* const string_value = posix::GetEnv(env_var.c_str()); | |||
return string_value == nullptr ? default_value | return string_value == nullptr ? default_value | |||
: strcmp(string_value, "0") != 0; | : strcmp(string_value, "0") != 0; | |||
#endif // defined(GTEST_GET_BOOL_FROM_ENV_) | #endif // defined(GTEST_GET_BOOL_FROM_ENV_) | |||
} | } | |||
// Reads and returns a 32-bit integer stored in the environment | // Reads and returns a 32-bit integer stored in the environment | |||
// variable corresponding to the given flag; if it isn't set or | // variable corresponding to the given flag; if it isn't set or | |||
// doesn't represent a valid 32-bit integer, returns default_value. | // doesn't represent a valid 32-bit integer, returns default_value. | |||
Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { | int32_t Int32FromGTestEnv(const char* flag, int32_t default_value) { | |||
#if defined(GTEST_GET_INT32_FROM_ENV_) | #if defined(GTEST_GET_INT32_FROM_ENV_) | |||
return GTEST_GET_INT32_FROM_ENV_(flag, default_value); | return GTEST_GET_INT32_FROM_ENV_(flag, default_value); | |||
#else | #else | |||
const std::string env_var = FlagToEnvVar(flag); | const std::string env_var = FlagToEnvVar(flag); | |||
const char* const string_value = posix::GetEnv(env_var.c_str()); | const char* const string_value = posix::GetEnv(env_var.c_str()); | |||
if (string_value == nullptr) { | if (string_value == nullptr) { | |||
// The environment variable is not set. | // The environment variable is not set. | |||
return default_value; | return default_value; | |||
} | } | |||
Int32 result = default_value; | int32_t result = default_value; | |||
if (!ParseInt32(Message() << "Environment variable " << env_var, | if (!ParseInt32(Message() << "Environment variable " << env_var, | |||
string_value, &result)) { | string_value, &result)) { | |||
printf("The default value %s is used.\n", | printf("The default value %s is used.\n", | |||
(Message() << default_value).GetString().c_str()); | (Message() << default_value).GetString().c_str()); | |||
fflush(stdout); | fflush(stdout); | |||
return default_value; | return default_value; | |||
} | } | |||
return result; | return result; | |||
#endif // defined(GTEST_GET_INT32_FROM_ENV_) | #endif // defined(GTEST_GET_INT32_FROM_ENV_) | |||
End of changes. 14 change blocks. | ||||
19 lines changed or deleted | 58 lines changed or added |