aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordrgler <daniel.kruegler@gmail.com>2017-08-09 19:07:22 +0200
committerdrgler <daniel.kruegler@gmail.com>2017-08-09 19:08:22 +0200
commit71ca4bae1085d7f2adefcbd16b0b7cebb81d540f (patch)
tree1214077ca2650150333566239feaf4c2aa6749c3
parent4bab34d2084259cba67f3bfb51217c10d606e175 (diff)
downloadgoogletest-71ca4bae1085d7f2adefcbd16b0b7cebb81d540f.tar.gz
googletest-71ca4bae1085d7f2adefcbd16b0b7cebb81d540f.tar.bz2
googletest-71ca4bae1085d7f2adefcbd16b0b7cebb81d540f.zip
Infinite Loop when calling a mock function that takes boost::filesystem::path as parameter #521: Add is_same type trait and prevent infinite loops for recursive containers
-rw-r--r--googletest/include/gtest/gtest-printers.h19
-rw-r--r--googletest/include/gtest/internal/gtest-internal.h25
-rw-r--r--googletest/include/gtest/internal/gtest-port.h6
3 files changed, 42 insertions, 8 deletions
diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h
index e850d605..fba76614 100644
--- a/googletest/include/gtest/gtest-printers.h
+++ b/googletest/include/gtest/gtest-printers.h
@@ -460,15 +460,17 @@ void PrintTo(const T& value, ::std::ostream* os) {
// DefaultPrintTo() is overloaded. The type of its first argument
// determines which version will be picked.
//
- // Note that we check for container types here, prior to we check
- // for protocol message types in our operator<<. The rationale is:
+ // Note that we check for recursive and other container types here, prior
+ // to we check for protocol message types in our operator<<. The rationale is:
//
// For protocol messages, we want to give people a chance to
// override Google Mock's format by defining a PrintTo() or
// operator<<. For STL containers, other formats can be
// incompatible with Google Mock's format for the container
// elements; therefore we check for container types here to ensure
- // that our format is used.
+ // that our format is used. To prevent an infinite runtime recursion
+ // during the output of recursive container types, we check first for
+ // those.
//
// Note that MSVC and clang-cl do allow an implicit conversion from
// pointer-to-function to pointer-to-object, but clang-cl warns on it.
@@ -477,16 +479,17 @@ void PrintTo(const T& value, ::std::ostream* os) {
// function pointers so that the `*os << p` in the object pointer overload
// doesn't cause that warning either.
DefaultPrintTo(
- WrapPrinterType<sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)
- ? kPrintContainer : !is_pointer<T>::value
- ? kPrintOther
+ WrapPrinterType<
+ (sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) && !IsRecursiveContainer<T>::value
+ ? kPrintContainer : !is_pointer<T>::value
+ ? kPrintOther
#if GTEST_LANG_CXX11
: std::is_function<typename std::remove_pointer<T>::type>::value
#else
: !internal::ImplicitlyConvertible<T, const void*>::value
#endif
- ? kPrintFunctionPointer
- : kPrintPointer>(),
+ ? kPrintFunctionPointer
+ : kPrintPointer>(),
value, os);
}
diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h
index 72d83f0b..2a6e4dad 100644
--- a/googletest/include/gtest/internal/gtest-internal.h
+++ b/googletest/include/gtest/internal/gtest-internal.h
@@ -940,6 +940,31 @@ typedef char IsNotContainer;
template <class C>
IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; }
+template <typename C, bool =
+ sizeof(IsContainerTest<C>(0)) == sizeof(IsContainer)
+>
+struct IsRecursiveContainerImpl;
+
+template <typename C>
+struct IsRecursiveContainerImpl<C, false> : public false_type {};
+
+template <typename C>
+struct IsRecursiveContainerImpl<C, true> {
+ typedef
+ typename IteratorTraits<typename C::iterator>::value_type
+ value_type;
+ typedef is_same<value_type, C> type;
+};
+
+// IsRecursiveContainer<Type> is a unary compile-time predicate that
+// evaluates whether C is a recursive container type. A recursive container
+// type is a container type whose value_type is equal to the container type
+// itself. An example for a recursive container type is
+// boost::filesystem::path, whose iterator has a value_type that is equal to
+// boost::filesystem::path.
+template<typename C>
+struct IsRecursiveContainer : public IsRecursiveContainerImpl<C>::type {};
+
// EnableIf<condition>::type is void when 'Cond' is true, and
// undefined when 'Cond' is false. To use SFINAE to make a function
// overload only apply when a particular expression is true, add
diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h
index f6cd3c03..7e008c05 100644
--- a/googletest/include/gtest/internal/gtest-port.h
+++ b/googletest/include/gtest/internal/gtest-port.h
@@ -2241,6 +2241,12 @@ template <bool bool_value> const bool bool_constant<bool_value>::value;
typedef bool_constant<false> false_type;
typedef bool_constant<true> true_type;
+template <typename T, typename U>
+struct is_same : public false_type {};
+
+template <typename T>
+struct is_same<T, T> : public true_type {};
+
template <typename T>
struct is_pointer : public false_type {};