Search code examples
c++boostvisual-c++-2008boost-interprocess

How do I debug or fix the endless loop and heap corruption issue involving boost::interprocess managed_shared_memory?


I have the following "first-chance exception" message which is coming from a DLL I wrote which is running inside an executable that I did not write. That is, the DLL is a plugin. The first time this exception fires, an attempt to open a shared memory map file is failing. If I ignore first chance exceptions and just run, the application freezes or crashes eventually.

First-chance exception at 0x76a7c41f in notmyexe.exe: Microsoft C++ exception: boost::interprocess::interprocess_exception at memory location 0x002bc644..

After several hours it appears to be caused by a block of code which is looping endlessly until an expected exception condition clears. It turns out that if it never does clear, and then, eventually, this exception turns into another low-level-exception-condition and/or turns into heap corruption. All of this is just in an effort to open a shared memory area using Boost::interprocess.

The first thing that complicates things is that on my Visual C++ 2008 based project, the first boost::interprocess::interprocess_exception first-chance exception is not thrown and identified as the location where it came from because the Visual C++ 2008 compiler cannot find the complex boost-flavor templates code in question. However by single stepping through the assembly language view, I found the code that blows up.

The top level line of my own code that it all starts to go bad on is:

  segment = new managed_shared_memory(   open_or_create
                                      ,  MEMORY_AREA_NAME
                                      , SHARED_AREA_SIZE );          

The above managed_shared_memory class is from interprocess_fwd.hpp, and is a standard part of the boost shared memory API/headers. Because it's template based, the above expands into about a 2Kchars long C++ boost template expression, which is truncated at different lengths by the linker, and by the debugger. Visual C++ 2008 has no more source code debugging capabilities, it seems when these limits are in play.

For example, when it blows up I get this call stack:

    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()  

No actual end-user written source functions appear in the stack dump above.

How should I debug this? Secondly, is there some known problem with boost-interprocess, with Visual C++ 2008? Third, what is the boost code below doing and why must it endlessly loop?

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...

Further layers down, we get to:

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)
   {}  

Anyways, don't try to debug this at home kids, here's what happens:

enter image description here

Finally, using my ninja-like ability to single step through several million lines of assembly language I have defeated Visual C++ 2008's evil debugger limitations, and have found the code in question.

This is what is blowing up in fact: create_device<FileBased>(dev....

Some context here: managed_open_or_create_impl.h line 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();
         }
      }

Solution

  • I believe I've had some of the same issues you are having. Take a look at the function "shared_memory_object::priv_open_or_create" in "\boost\interprocess\shared_memory_object.hpp". At the top of that function is another function call "create_tmp_and_clean_old_and_get_filename" that starts a function chain that winds up deleting the shared memory file. I wound up moving that function call lower in the priv_open_or_create function around where the case statements start. I believe I'm using boost 1.48. Here's the final version of that function that I modified:

    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;
    }
    

    BTW, if anyone knows the official channels I can go through to try and get this verified and added to boost please let me know as I hate modifying stuff like this without knowing its full effect.

    Hope this helps!