Opened 5 years ago
Last modified 5 years ago
#13028 new Bugs
boost::filesystem::canonical(const path& p, system::error_code& ec) throws exception
| Reported by: | Owned by: | Beman Dawes | |
|---|---|---|---|
| Milestone: | To Be Determined | Component: | filesystem |
| Version: | Boost 1.65.0 | Severity: | Problem |
| Keywords: | Cc: |
Description
Per the docs, this function should report filesystem errors through the error_code. In the case of permission issues, this contract is violated.
This is best explained with the test case:
#include <boost/detail/lightweight_test_report.hpp>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int test_main(int, char*[])
{
// Ensure that we do not have read permissions on pwd
fs::path tmp_path = fs::temp_directory_path();
fs::path unique_path = fs::unique_path();
fs::path dir_path = tmp_path / unique_path;
fs::create_directory(dir_path);
fs::current_path(dir_path);
fs::permissions(dir_path, fs::no_perms);
// Try to get a canonical path with the error_code API. This should return an
// error through the error_code, but instead throws an exception (because
// canonical(const path& p, system::error_code& ec) calls current_path()
// without error_code)
boost::system::error_code e;
fs::canonical("foo", e);
BOOST_TEST(e.value() != 0);
return ::boost::report_errors();
}
Test output:
bin/bug Clang version 8.0.0 (clang-800.0.38), __GXX_EXPERIMENTAL_CXX0X__ not defined libc++ version 3700 Mac OS Boost version 1.65.0 Command line: bin/bug ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ****************************** std::exception ***************************** boost::filesystem::current_path: Permission denied ***************************************************************************
This unexpected exception causes a crash in osquery. See https://github.com/facebook/osquery/issues/3279
Note:
See TracTickets
for help on using tickets.

I just ran into the same issue in one of our internal applications. There are actually 2 bugs causing the same problem. The first is that the
canonical(const path& p, system::error_code& ec)callscurrent_path()without passing in theerror_code. However, when that is fixed, then same problem shows up again if you pass in a relative path asbasebecausedetail::canonical()immediately callsabsolute(), which in turn callscurrent_path().It's easy to fix by simply calling the no except version of
current_path()in both places (although, sinceabsolute()doesn't take anerror_code, it can get a bit wordy):operations.hpp:
inline path canonical(const path& p, system::error_code& ec) { path base = detail::current_path(&ec); if (ec) return path(); return detail::canonical(p, base, &ec); }operations.cpp
BOOST_FILESYSTEM_DECL path canonical(const path& p, const path& base, system::error_code* ec) { path source(p); if (!p.is_absolute()) { path absBase(base); if (!absBase.is_absolute()) { path curr = current_path(ec); if (ec && *ec) return path(); absBase = absolute(base, curr); } source = absolute(p, absBase); }