From 612bb7116583802ccbc42050bbcf4b66641633cd Mon Sep 17 00:00:00 2001 From: Edward Hennis Date: Fri, 22 Aug 2014 19:50:15 -0400 Subject: [PATCH] Add enable_if_lvalue --- src/beast/beast/utility/meta.h | 77 +++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/beast/beast/utility/meta.h b/src/beast/beast/utility/meta.h index b76df42d8..e7af4e1f4 100644 --- a/src/beast/beast/utility/meta.h +++ b/src/beast/beast/utility/meta.h @@ -20,7 +20,7 @@ #ifndef BEAST_UTILITY_META_H_INCLUDED #define BEAST_UTILITY_META_H_INCLUDED -#include +#include // namespace beast { @@ -60,6 +60,81 @@ struct static_sum<> static_assert(static_sum<5, 2, 17, 0>::value == 24, ""); +template +struct enable_if_lvalue + : public std::enable_if + < + std::is_same, U>::value && + std::is_lvalue_reference::value + > +{ +}; + +/** Ensure const reference function parameters are valid lvalues. + + Some functions, especially class constructors, accept const references and + store them for later use. If any of those parameters are rvalue objects, + the object will be freed as soon as the function returns. This could + potentially lead to a variety of "use after free" errors. + + If the function is rewritten as a template using this type and the + parameters references as rvalue references (eg. TX&&), a compiler + error will be generated if an rvalue is provided in the caller. + + @code + // Example: + struct X + { + }; + struct Y + { + }; + + struct Unsafe + { + Unsafe (X const& x, Y const& y) + : x_ (x) + , y_ (y) + { + } + + X const& x_; + Y const& y_; + }; + + struct Safe + { + template , + class = beast::enable_if_lvalue_t < TY, Y >> + Safe (TX&& x, TY&& y) + : x_ (x) + , y_ (y) + { + } + + X const& x_; + Y const& y_; + }; + + struct demo + { + void + createObjects () + { + X x {}; + Y const y {}; + Unsafe u1 (x, y); // ok + Unsafe u2 (X (), y); // compiles, but u2.x_ becomes invalid at the end of the line. + Safe s1 (x, y); // ok + // Safe s2 (X (), y); // compile-time error + } + }; + @endcode +*/ +template +using enable_if_lvalue_t = typename enable_if_lvalue::type; + } // beast #endif // BEAST_UTILITY_META_H_INCLUDED