Boost C++ Libraries: Ticket #11906: BOOST_TEST() violates expectations about expression lifetime https://svn.boost.org/trac10/ticket/11906 <p> The new BOOST_TEST() macro is a step in a great direction. However, because of how the macro expands to multiple expressions, it leads to simple checks performing undefined behaviour. </p> <p> For example, consider the following complete test program: </p> <pre class="wiki">#define BOOST_TEST_MAIN #include &lt;boost/test/included/unit_test.hpp&gt; struct Object { Object() : m_value("A value for this string to have") {} const std::string &amp;get() const { return m_value; } private: std::string m_value; }; BOOST_AUTO_TEST_CASE(test) { BOOST_TEST(Object().get() == "check"); } </pre><p> This program fails because only a "const std::string &amp;" is captured for the left-hand side of the test, and then, in a separate expression (in the expanded BOOST_TEST() macro), that reference is used to evaluate the expression. This fails because the temporary Object has already been dereferenced. </p> <p> Compare to BOOST_CHECK() with the same content (or BOOST_CHECK_EQUAL() with a comma instead of "=="). </p> <p> This kind of subtlety makes it difficult to write safe checks with BOOST_TEST(). </p> <p> Example valgrind output from the above program: </p> <pre class="wiki">==24714== Invalid read of size 8 ==24714== at 0x4EF3C2E: std::string::compare(char const*) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20) ==24714== by 0x414160: operator==&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; (basic_string.h:2540) ==24714== by 0x414160: eval (assertion.hpp:162) ==24714== by 0x414160: value (assertion.hpp:348) ==24714== by 0x414160: evaluate (assertion.hpp:357) ==24714== by 0x414160: test::test_method() (foo.cc:19) ==24714== by 0x414529: test_invoker() (foo.cc:17) ==24714== by 0x4294BA: operator() (function_template.hpp:771) ==24714== by 0x4294BA: operator() (execution_monitor.ipp:1304) ==24714== by 0x4294BA: boost::detail::function::function_obj_invoker0&lt;boost::detail::forward, int&gt;::invoke(boost::detail::function::function_buffer&amp;) (function_template.hpp:138) ==24714== by 0x40ABEC: operator() (function_template.hpp:771) ==24714== by 0x40ABEC: do_invoke&lt;boost::shared_ptr&lt;boost::detail::translator_holder_base&gt;, boost::function&lt;int()&gt; &gt; (execution_monitor.ipp:281) ==24714== by 0x40ABEC: boost::execution_monitor::catch_signals(boost::function&lt;int ()&gt; const&amp;) (execution_monitor.ipp:870) ==24714== by 0x40AC98: boost::execution_monitor::execute(boost::function&lt;int ()&gt; const&amp;) (execution_monitor.ipp:1207) ==24714== by 0x40B376: boost::execution_monitor::vexecute(boost::function&lt;void ()&gt; const&amp;) (execution_monitor.ipp:1313) ==24714== by 0x410F31: boost::unit_test::unit_test_monitor_t::execute_and_translate(boost::function&lt;void ()&gt; const&amp;, unsigned int) (unit_test_monitor.ipp:46) ==24714== by 0x43A332: boost::unit_test::framework::state::execute_test_tree(unsigned long, unsigned int) (framework.ipp:685) ==24714== by 0x43A466: boost::unit_test::framework::state::execute_test_tree(unsigned long, unsigned int) (framework.ipp:636) ==24714== by 0x41C4A1: boost::unit_test::framework::run(unsigned long, bool) (framework.ipp:1220) ==24714== by 0x41C8AE: boost::unit_test::unit_test_main(boost::unit_test::test_suite* (*)(int, char**), int, char**) (unit_test_main.ipp:228) ==24714== Address 0x5a11a50 is 0 bytes inside a block of size 56 free'd ==24714== at 0x4C2A360: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==24714== by 0x41433B: _M_dispose (lazy_ostream.hpp:35) ==24714== by 0x41433B: ~basic_string (basic_string.h:547) ==24714== by 0x41433B: ~Object (foo.cc:4) ==24714== by 0x41433B: test::test_method() (foo.cc:19) ==24714== by 0x414529: test_invoker() (foo.cc:17) ==24714== by 0x4294BA: operator() (function_template.hpp:771) ==24714== by 0x4294BA: operator() (execution_monitor.ipp:1304) ==24714== by 0x4294BA: boost::detail::function::function_obj_invoker0&lt;boost::detail::forward, int&gt;::invoke(boost::detail::function::function_buffer&amp;) (function_template.hpp:138) ==24714== by 0x40ABEC: operator() (function_template.hpp:771) ==24714== by 0x40ABEC: do_invoke&lt;boost::shared_ptr&lt;boost::detail::translator_holder_base&gt;, boost::function&lt;int()&gt; &gt; (execution_monitor.ipp:281) ==24714== by 0x40ABEC: boost::execution_monitor::catch_signals(boost::function&lt;int ()&gt; const&amp;) (execution_monitor.ipp:870) ==24714== by 0x40AC98: boost::execution_monitor::execute(boost::function&lt;int ()&gt; const&amp;) (execution_monitor.ipp:1207) ==24714== by 0x40B376: boost::execution_monitor::vexecute(boost::function&lt;void ()&gt; const&amp;) (execution_monitor.ipp:1313) ==24714== by 0x410F31: boost::unit_test::unit_test_monitor_t::execute_and_translate(boost::function&lt;void ()&gt; const&amp;, unsigned int) (unit_test_monitor.ipp:46) ==24714== by 0x43A332: boost::unit_test::framework::state::execute_test_tree(unsigned long, unsigned int) (framework.ipp:685) ==24714== by 0x43A466: boost::unit_test::framework::state::execute_test_tree(unsigned long, unsigned int) (framework.ipp:636) ==24714== by 0x41C4A1: boost::unit_test::framework::run(unsigned long, bool) (framework.ipp:1220) ==24714== by 0x41C8AE: boost::unit_test::unit_test_main(boost::unit_test::test_suite* (*)(int, char**), int, char**) (unit_test_main.ipp:228) </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/11906 Trac 1.4.3 Raffi Enficiaud Wed, 13 Jan 2016 09:13:49 GMT owner, status changed https://svn.boost.org/trac10/ticket/11906#comment:1 https://svn.boost.org/trac10/ticket/11906#comment:1 <ul> <li><strong>owner</strong> changed from <span class="trac-author">Gennadiy Rozental</span> to <span class="trac-author">Raffi Enficiaud</span> </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> Ticket Raffi Enficiaud Wed, 13 Jan 2016 09:14:50 GMT <link>https://svn.boost.org/trac10/ticket/11906#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11906#comment:2</guid> <description> <p> Would you please give a try to the branch <code>fix/handling-rvalue-erasure</code>? Thanks </p> </description> <category>Ticket</category> </item> <item> <author>bspencer@…</author> <pubDate>Wed, 13 Jan 2016 17:13:41 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11906#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11906#comment:3</guid> <description> <p> I grabbed <a class="ext-link" href="https://github.com/boostorg/test/commit/4124e3b754b2f524365fd420f6bad516b4445e99.patch"><span class="icon">​</span>https://github.com/boostorg/test/commit/4124e3b754b2f524365fd420f6bad516b4445e99.patch</a> and applied it to boost-1.59.0 and all seems well. </p> <p> FWIW, the changes also makes sense to me ;) </p> <p> Thanks for the fast patch! </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Raffi Enficiaud</dc:creator> <pubDate>Wed, 13 Jan 2016 19:23:40 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/11906#comment:4 https://svn.boost.org/trac10/ticket/11906#comment:4 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">duplicate</span> </li> </ul> <p> Duplicates <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/11887" title="#11887: Bugs: BOOST_TEST(3u == (std::max)(0u, 3u)) fails (closed: fixed)">#11887</a>, fixed in branch <code>fix/handling-rvalue-erasure</code>. </p> Ticket Raffi Enficiaud Wed, 13 Jan 2016 19:25:03 GMT <link>https://svn.boost.org/trac10/ticket/11906#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11906#comment:5</guid> <description> <p> Thanks for the quick feedback! </p> </description> <category>Ticket</category> </item> </channel> </rss>