为什么boost :: filesystem中止而不是抛出异常? [英] Why is boost::filesystem aborting instead of throwing an exception?

查看:1346
本文介绍了为什么boost :: filesystem中止而不是抛出异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将一些代码从VS2010(使用boost 1.55)迁移到VS 2015(使用boost 1.60)。



我最终得到Microsoft Visual C ++运行时库报告说 abort()已被调用,同时提升rties以引发异常。但是,我可以得到它抛出其他异常没有任何问题(它曾经与VS2010 / boost1.55):

  #include< boost / filesystem.hpp> 
#include< boost / filesystem / operations.hpp>

#include< iostream>

int main(int argc,char * argv [])
{
//步进到文件夹:

try
{
boost :: filesystem :: current_path(B:/ dev / msvc2015 / vobs_bci / public / tst / base / cppunit / utlfile);
std :: cout<<< 工作<<的std :: ENDL; //工作OK
}
catch(...)
{

}

// test copying在copy_directory因为dource文件夹不存在:

try
{
boost :: filesystem :: copy_directory(s,b);
}
catch(...)
{
std :: cout<<< 捕获<的std :: ENDL; //工作OK
}

//测试抛出副本,因为目标文件已存在:

try
{
boost filesystem :: copy(./ test.h,./copied.cpp); // works
boost :: filesystem :: copy(./ test.h,./copied.cpp); // should throw and be catch
}
catch(...)
{
std :: cout<<< 捕获<的std :: ENDL; //从来没有达到...
}

std :: cout<<< 完成<<的std :: ENDL;

return 0;
}

输出:

 工作
抓住
- >然后中止!

使用调试器,我看到当下面的错误函数(在filesystem / src / operations .cpp)调用 BOOST_FILESYSTEM_THROW

  bool错误(err_t error_num,const路径& p1,const path& p2,error_code * ec,
const char * message)
{
if(!error_num)
{
if(ec! 0)ec-> clear();
}
else
{//错误
如果(ec == 0)
BOOST_FILESYSTEM_THROW(filesystem_error(message,
p1,p2,error_code(error_num ,system_category()))); //<<这里!
else
ec-> assign(error_num,system_category());
}
return error_num!= 0;
}

我使用调试器检查,我到达 filesystem_error 构造函数,并且可以退出它,没有任何问题,下一步(按调用器中的F11,现在应该调用 throw ), abort()被调用。



奇怪的是,当 copy_directory 引发异常时,它也可以正常工作,而 filesystem / src / operations.cpp 中的错误功能



中止时调用堆栈是:

 > ntdll.dll!KiUserExceptionDispatcher()Inconnu 
KernelBase.dll!RaiseException()Inconnu
vcruntime140d.dll!_CxxThrowException(void * pExceptionObject = 0x000000000019f670,const _s__ThrowInfo * pThrowInfo = 0x000000013fd01870)Ligne 136 C ++
test_3rdparty_inprg_boost.exe!`anonymous namespace':: error(unsigned long error_num = 80,const boost :: filesystem :: path& p1 = {...},const boost :: filesystem :: path& p2 = {。 ..},boost :: system :: error_code * ec = 0x0000000000000000,const char * message = 0x000000013fcf6fb8)Ligne 321 C ++
test_3rdparty_inprg_boost.exe!boost :: filesystem :: detail :: copy_file(const boost :: filesystem :: path& from = {...},const boost :: filesystem :: path& to = {...},boost :: filesystem :: detail :: copy_option option = none,boost :: system: :const_products_products(const boost :: filesystem :: path& from = {...}),const boost :: filesystem: :path& to = {.. 。},boost :: filesystem :: copy_option option = none,boost :: system :: error_code& ec)Ligne 550 C ++
test_3rdparty_inprg_boost.exe!boost :: filesystem :: detail :: copy(const boost :: filesystem :: path& from = {...},const boost :: filesystem :: path & to = {...},boost :: system :: error_code * ec = 0x0000000000000000)Ligne 894 C ++
test_3rdparty_inprg_boost.exe!boost :: filesystem :: copy(const boost :: filesystem :: path& ; from = {...},const boost :: filesystem :: path& to = {...})Ligne 524 C ++
test_3rdparty_inprg_boost.exe!main(int argc = 1,char * * argv = 0x00000000003f3cc0)Ligne 35 C ++
test_3rdparty_inprg_boost.exe!invoke_main()Ligne 75 C ++

但是我看不到源代码 ntdll.dll!KiUserExceptionDispatcher() KernelBase.dll!RaiseException()

解决方案

boost :: filesystem :: copy 。该函数简单地调用 boost :: filesystem :: detail :: copy ,第三个参数默认为null:

  BOOST_FILESYSTEM_DECL 
void copy(const path& from,const path& to,system :: error_code * ec)
{
file_status s(symlink_status(from, * EC));
if(ec!= 0&& * ec)return;

if(is_symlink(s))
{
copy_symlink(from,to,* ec);
}
else if(is_directory(s))
{
copy_directory(from,to,* ec);
}
else if(is_regular_file(s))
{
copy_file(from,to,fs :: copy_option :: fail_if_exists,* ec);
}
else
{
if(ec == 0)
BOOST_FILESYSTEM_THROW(filesystem_error(boost :: filesystem :: copy,
from, to,error_code(BOOST_ERROR_NOT_SUPPORTED,system_category())));
ec-> assign(BOOST_ERROR_NOT_SUPPORTED,system_category());
}
}

这个函数反过来充满了无效的dereferences潜在的空指针,并且还调用声明为noexcept的特定函数的错误代码变量,传递由引用空指针导致的伪造引用,编译器可能会很好地转发(请记住,我们已经在UB在这里土地)。这些函数依次获取引用的地址(通常再次产生一个空指针),并再次调用它们自己的详细信息,使用错误函数,如果错误代码指针为null,则会抛出。



解决方法:




  • 不要使用 copy(),如果你知道你想要的东西,你可以使用具体的函数(例如 copy_file())或

  • 使用 copy()的版本,它需要一个 error_code 并自行检查代码。



我看到你已经发布了一个错误报告。这个错误报告是正确的。


I'm migrating some code from VS2010 (using boost 1.55) to VS 2015 (using boost 1.60).

I end up with "Microsoft Visual C++ Runtime Library" reporting that abort() has been called while boost rties to throw an exception. However, I could get it throw other exceptions without any problem (and it used to work with VS2010/boost1.55):

#include <boost/filesystem.hpp>
#include <boost/filesystem/operations.hpp>

#include <iostream>

int main( int argc, char* argv[] )
{
    // Stepping to folder:

    try
    {
        boost::filesystem::current_path("B:/dev/msvc2015/vobs_bci/public/tst/base/cppunit/utlfile");
        std::cout << "Worked" << std::endl; // works OK
    }
    catch (...)
    {

    }

    // test throwing upon copy_directory because dource folder does not exist:

    try
    {
        boost::filesystem::copy_directory("s", "b");
    }
    catch (...)
    {
        std::cout << "Caught" << std::endl; // works OK
    }

    // test throwing upon copy because target file already exists:

    try
    {
        boost::filesystem::copy("./test.h", "./copied.cpp"); // works
        boost::filesystem::copy("./test.h", "./copied.cpp"); // should throw and be caught
    }
    catch (...)
    {
        std::cout << "Caught" << std::endl; // never reached...
    }

    std::cout << "Done" << std::endl;

    return 0;
}

This outputs:

Worked
Caught
-> then aborts!

With the debugger, I see that abort is called when error function below (in filesystem/src/operations.cpp) calls BOOST_FILESYSTEM_THROW:

bool error(err_t error_num, const path& p1, const path& p2, error_code* ec,
    const char* message)
{
    if (!error_num)
    {
      if (ec != 0) ec->clear();
    }
    else  
    { //  error
      if (ec == 0)
        BOOST_FILESYSTEM_THROW(filesystem_error(message,
          p1, p2, error_code(error_num, system_category())));  // << Here!
      else
        ec->assign(error_num, system_category());
    }
    return error_num != 0;
  }

I checked with the debugger, and I reach filesystem_error constructor and can step out of it without any problem, next step (pressed F11 in the debugger, throw should now be called), abort() gets called.

Strange thing is that when copy_directory throws an exception, it also works, and this does call exactly the same error function in filesystem/src/operations.cpp.

Call stack upon abort is:

>   ntdll.dll!KiUserExceptionDispatcher()   Inconnu
    KernelBase.dll!RaiseException() Inconnu
    vcruntime140d.dll!_CxxThrowException(void * pExceptionObject=0x000000000019f670, const _s__ThrowInfo * pThrowInfo=0x000000013fd01870) Ligne 136 C++
    test_3rdparty_inprg_boost.exe!`anonymous namespace'::error(unsigned long error_num=80, const boost::filesystem::path & p1={...}, const boost::filesystem::path & p2={...}, boost::system::error_code * ec=0x0000000000000000, const char * message=0x000000013fcf6fb8) Ligne 321    C++
    test_3rdparty_inprg_boost.exe!boost::filesystem::detail::copy_file(const boost::filesystem::path & from={...}, const boost::filesystem::path & to={...}, boost::filesystem::detail::copy_option option=none, boost::system::error_code * ec=0x0000000000000000) Ligne 919   C++
    test_3rdparty_inprg_boost.exe!boost::filesystem::copy_file(const boost::filesystem::path & from={...}, const boost::filesystem::path & to={...}, boost::filesystem::copy_option option=none, boost::system::error_code & ec) Ligne 550  C++
    test_3rdparty_inprg_boost.exe!boost::filesystem::detail::copy(const boost::filesystem::path & from={...}, const boost::filesystem::path & to={...}, boost::system::error_code * ec=0x0000000000000000) Ligne 894    C++
    test_3rdparty_inprg_boost.exe!boost::filesystem::copy(const boost::filesystem::path & from={...}, const boost::filesystem::path & to={...}) Ligne 524   C++
    test_3rdparty_inprg_boost.exe!main(int argc=1, char * * argv=0x00000000003f3cc0) Ligne 35   C++
    test_3rdparty_inprg_boost.exe!invoke_main() Ligne 75    C++

But I can't see the source code of ntdll.dll!KiUserExceptionDispatcher()nor KernelBase.dll!RaiseException().

解决方案

boost::filesystem::copy is a huge broken mess. The function simply calls boost::filesystem::detail::copy with the third argument defaulted to null:

  BOOST_FILESYSTEM_DECL
  void copy(const path& from, const path& to, system::error_code* ec)
  {
    file_status s(symlink_status(from, *ec));
    if (ec != 0 && *ec) return;

    if(is_symlink(s))
    {
      copy_symlink(from, to, *ec);
    }
    else if(is_directory(s))
    {
      copy_directory(from, to, *ec);
    }
    else if(is_regular_file(s))
    {
      copy_file(from, to, fs::copy_option::fail_if_exists, *ec);
    }
    else
    {
      if (ec == 0)
        BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy",
          from, to, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category())));
      ec->assign(BOOST_ERROR_NOT_SUPPORTED, system_category());
    }
  }

This function in turn is full of invalid dereferences of that potentially-null pointer, and also calls the error code variants of the specific functions that are declared noexcept, passing a bogus reference that resulted from dereferencing the null pointer, which the compiler might well forward as such (remember, we're already in UB land here). These functions in turn take the address of the reference (which typically again yields a null pointer) and call their own detail versions again, which use the error function, which throws if the error code pointer is null.

The workaround:

  • Don't use copy(), use the concrete function for the type of thing you want if you know it (e.g. copy_file()), or
  • Use the version of copy() that takes an error_code and examine the code yourself.

I see you've already posted a bug report. This bug report is correct.

这篇关于为什么boost :: filesystem中止而不是抛出异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆