Opened 6 years ago

Last modified 6 years ago

#12254 new Bugs

NULL reference to error_code passing to noexcept functions caused std::terminate

Reported by: aerisnju@… Owned by: Beman Dawes
Milestone: To Be Determined Component: filesystem
Version: Boost 1.61.0 Severity: Showstopper
Keywords: noexcept Cc:

Description

With compilers that support noexcept, the following simple code may end up in std::terminate():

#include <boost/filesystem.hpp>

int main(int argc, char *argv[]) {
    try {
        boost::filesystem::path p(argv[0]);

        copy(p, p); // EEXIST, then std::terminate
    } catch (...) {}

    return 0;
}

This is because the noexcept function copy_file() has received a NULL reference, which causes one of its subroutines throws an exception. Since copy_file() is noexcept and it throws exceptions, the std::terminate() is called.

The call stack is (functions are called from bottom to top):

noexcept?	function
-----------------------------------------------------
false		error(unsigned long error_num, const boost::filesystem::path & p1, const boost::filesystem::path & p2, boost::system::error_code * ec, const char * message)
false		detail::copy_file(const boost::filesystem::path & from, const boost::filesystem::path & to, boost::filesystem::detail::copy_option option, boost::system::error_code * ec)
true		copy_file(const boost::filesystem::path & from, const boost::filesystem::path & to, boost::filesystem::copy_option option, boost::system::error_code & ec)
false		detail::copy(const boost::filesystem::path & from, const boost::filesystem::path & to, boost::system::error_code * ec)
false		copy(const boost::filesystem::path & from, const boost::filesystem::path & to)
false		main(int argc, char * * argv)

The function copy() calls detail::copy() without providing the ec parameter, so ec in detail::copy() is using the default value 0. detail::copy() then calls copy_file(), passing *ec as its parameter. Since ec in detail:copy() is NULL, copy_file() will receive a NULL reference. It then use &ec(that is NULL) to call detail::copy_file(). Since the target file exists, detail::copy_file() will generates EEXIST. Then an exception will be thrown from error(). The exception will be passed through the call stack until it reaches copy_file(). copy_file() is noexcept so it cannot throw exceptions. Then std::terminate() is called.

There may be other similar situations apart from this case in Boost.Filesystem. I think the current workaround is removing the BOOST_NOEXCEPT from these functions. For a complete solution, the functions may need careful reviews.

Attachments (1)

12254.patch (1.2 KB ) - added by aerisnju@… 6 years ago.

Download all attachments as: .zip

Change History (2)

by aerisnju@…, 6 years ago

Attachment: 12254.patch added

comment:1 by anonymous, 6 years ago

Added a patch for fix this problem.

Note: See TracTickets for help on using tickets.