如何调试或修复涉及boost :: interprocess managed_shared_memory的无限循环和堆损坏问题?

War*_* P 9 c++ boost boost-interprocess visual-c++-2008

我有以下"第一次机会异常"消息,它来自我写的DLL,它运行在我没写的可执行文件中.也就是说,DLL是一个插件.第一次触发此异常时,尝试打开共享内存映射文件失败.如果我忽略了第一次机会异常并且只是运行,应用程序最终会冻结或崩溃.

First-chance exception at 0x76a7c41f in notmyexe.exe: Microsoft C++ exception: boost::interprocess::interprocess_exception at memory location 0x002bc644..
Run Code Online (Sandbox Code Playgroud)

几个小时之后,它似乎是由一个代码块引起的,这个代码块无休止地循环,直到预期的异常条件清除为止.事实证明,如果它永远不会清除,那么,最终,这个异常会变成另一个低级异常条件和/或变成堆损坏.所有这些只是为了使用Boost :: interprocess打开共享内存区域.

使事情变得复杂的第一件事是,在我的基于Visual C++ 2008的项目中,第boost::interprocess::interprocess_exception一次机会异常没有被抛出并被识别为它来自的位置,因为Visual C++ 2008编译器无法找到复杂的boost-flavor模板代码.题.但是,通过单步执行汇编语言视图,我发现代码爆炸了.

我自己的代码的顶级行开始变坏了:

  segment = new managed_shared_memory(   open_or_create
                                      ,  MEMORY_AREA_NAME
                                      , SHARED_AREA_SIZE );          
Run Code Online (Sandbox Code Playgroud)

上面的managed_shared_memory类来自interprocess_fwd.hpp,是boost共享内存API /头文件的标准部分.因为它是基于模板的,所以上面扩展到大约2Kchars长的C++ boost模板表达式,它由链接器和调试器截断不同的长度.Visual C++ 2008没有更多源代码调试功能,似乎在这些限制发挥作用时.

例如,当它爆炸时,我得到这个调用堆栈:

    KernelBase.dll!76a7c41f()   
    [Frames below may be incorrect and/or missing, no symbols loaded for KernelBase.dll]    
    KernelBase.dll!76a7c41f()   
>   msvcr90d.dll!_malloc_dbg(unsigned int nSize=2290875461, int nBlockUse=264, const char * szFileName=0x01fcb983, int nLine=1962999808)  Line 160 + 0x1b bytes C++
    8bfc4d89()  
Run Code Online (Sandbox Code Playgroud)

上面的堆栈转储中没有实际的最终用户编写的源函数.

我该怎么调试呢?其次,使用Visual C++ 2008,boost-interprocess是否存在一些已知问题?第三,下面的提升代码是什么,为什么必须无休止地循环?

boost::interprocess::basic_managed_shared_memory<char,
   boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,
        boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,
        boost::interprocess::iset_index>::basic_managed_shared_memory<char,boo...
Run Code Online (Sandbox Code Playgroud)

进一步下层,我们得到:

basic_managed_shared_memory (open_or_create_t,
                              const char *name, size_type size,
                              const void *addr = 0, const permissions& perm = permissions())
      : base_t()
      , base2_t(open_or_create, name, size, read_write, addr,
                create_open_func_t(get_this_pointer(),
                ipcdetail::DoOpenOrCreate), perm)
   {}  
Run Code Online (Sandbox Code Playgroud)

无论如何,不​​要试图在家里调试这个孩子,这是怎么回事:

在此输入图像描述

最后,使用我的类似忍者的能力单步执行几百万行汇编语言,我已经击败了Visual C++ 2008的恶意调试器限制,并且发现了有问题的代码.

实际上这就是爆炸:create_device<FileBased>(dev....

这里有一些上下文:managed_open_or_create_impl.h第351行......

else if(type == DoOpenOrCreate){
         //This loop is very ugly, but brute force is sometimes better
         //than diplomacy. If someone knows how to open or create a
         //file and know if we have really created it or just open it
         //drop me a e-mail!
         bool completed = false;
         while(!completed){
            try{
               create_device<FileBased>(dev, id, size, perm, file_like_t()); // <-- KABOOM!
               created     = true;
               completed   = true;
            }
            catch(interprocess_exception &ex){
               if(ex.get_error_code() != already_exists_error){
                  throw;
               }
               else{
                  try{
                     DeviceAbstraction tmp(open_only, id, read_write);
                     dev.swap(tmp);
                     created     = false;
                     completed   = true;
                  }
                  catch(interprocess_exception &e){
                     if(e.get_error_code() != not_found_error){
                        throw;
                     }
                  }
                  catch(...){
                     throw;
                  }
               }
            }
            catch(...){
               throw;
            }
            thread_yield();
         }
      }
Run Code Online (Sandbox Code Playgroud)

小智 2

我相信我也遇到过一些与您相同的问题。看一下“\boost\interprocess\shared_memory_object.hpp”中的函数“shared_memory_object::priv_open_or_create”。该函数的顶部是另一个函数调用“create_tmp_and_clean_old_and_get_filename”,它启动一个函数链,最终删除共享内存文件。我最终将该函数调用移到了 priv_open_or_create 函数中 case 语句开始位置的较低位置。我相信我正在使用 boost 1.48。这是我修改后的该函数的最终版本:

inline bool shared_memory_object::priv_open_or_create
   (ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm)
{
   m_filename = filename;
   std::string shmfile;
   std::string root_tmp_name;

   //Set accesses
   if (mode != read_write && mode != read_only){
      error_info err = other_error;
      throw interprocess_exception(err);
   }

   switch(type){
      case ipcdetail::DoOpen:
            ipcdetail::get_tmp_base_dir(root_tmp_name);
            shmfile = root_tmp_name;
            shmfile += "/";
            shmfile += filename;
            m_handle = ipcdetail::open_existing_file(shmfile.c_str(), mode, true);
      break;
      case ipcdetail::DoCreate:
            ipcdetail::create_tmp_and_clean_old_and_get_filename(filename, shmfile);
          m_handle = ipcdetail::create_new_file(shmfile.c_str(), mode, perm, true);
      break;
      case ipcdetail::DoOpenOrCreate:
         ipcdetail::create_tmp_and_clean_old_and_get_filename(filename, shmfile);
          m_handle = ipcdetail::create_or_open_file(shmfile.c_str(), mode, perm, true);
      break;
      default:
         {
            error_info err = other_error;
            throw interprocess_exception(err);
         }
   }

   //Check for error
   if(m_handle == ipcdetail::invalid_file()){
      error_info err = system_error_code();
      this->priv_close();
      throw interprocess_exception(err);
   }

   m_mode = mode;
   return true;
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,如果有人知道我可以通过官方渠道尝试验证并添加到增强功能,请告诉我,因为我讨厌在不知道其全部效果的情况下修改这样的东西。

希望这可以帮助!