2013-11-15 108 views
0

我在調試第一次訪問衝突時出現問題,該衝突是在Windows 8上崩潰了我的桌面應用程序。它尤其令人沮喪,因爲在我的Windows 8虛擬機上沒有發生崩潰我用於開發,只在平板設備上運行。引導::異常消息的第一次和第二次訪問衝突

我具有被如此定義的boost ::例外:

struct ExceptionBase: virtual std::exception, virtual boost::exception {}; 
struct DEVICES_COMMUNICATION_API CDeviceException: virtual ExceptionBase {}; 
typedef boost::error_info<struct tag_device_message, std::string> device_message; 

還有一個內聯函數來設置錯誤消息:

inline void throwDeviceException(std::string message) 
{ 
    CDeviceException de = CDeviceException() 
    << (device_message(std::string(message))); 
    BOOST_THROW_EXCEPTION(de); 
} 

此外另一個內聯函數來檢索該錯誤消息:

inline std::string retrieveDeviceExceptionMessage(CDeviceException de) 
{ 
    return *(boost::get_error_info<device_message, CDeviceException>(de)); 
} 

例外被發現在我的應用程序(這是一個服務r),然後分配到使用protobuf生成的類中,然後序列化。映入類中的異常,並將其存儲的代碼是一個升壓線程中運行一個算符:

struct invoke_fn 
{ 
    void operator()(devices::server::CDeviceServer& server, 
        boost::promise<void>&   boostPromise, 
        CDeviceClientRequest&   request, 
        CDeviceServerResponse&   response) 
    { 
     try 
     { 
     server.invoke(request, response); 
     boostPromise.set_value(); 
     } 
     catch (devices::util::CDeviceException &e) 
     { 
     std::string message = devices::util::retrieveDeviceExceptionMessage(e); 
     response.set_errormessage(message); 
     } 
     catch (std::exception &e) 
     { 
     std::string message(e.what()); 
     response.set_errormessage(message); 
     } 
    } 
}; 

以及設定響應對象,這是自動生成由protobuf的錯誤信息上的代碼,是:

inline void CDeviceServerResponse::set_errormessage(const ::std::string& value) { 
    set_has_errormessage(); 
    if (errormessage_ == &::google::protobuf::internal::kEmptyString) { 
    errormessage_ = new ::std::string; 
    } 
    errormessage_->assign(value); 
} 

這使用assign()將傳入的字符串複製到protobuf類。服務器請求正在它自己的boost :: thread裏面運行,像這樣:

boost::promise<void>  boostPromise; 
boost::unique_future<void> boostFuture = boostPromise.get_future(); 
boost::thread    boostThread([&]() 
          { 
           invoke_fn functor; 
           functor(*this, 
             boostPromise, 
             request, 
             response); 
          }); 

return (boostFuture.wait_for(boost::chrono::milliseconds(timeout)) 
     == 
     boost::future_status::ready); 

據我可以告訴這段代碼看起來OK。然而下面的棧跟蹤已經觀察到:

從Dr.Memory:

catch (devices::util::CDeviceException &e) 
{ 
    std::string message = devices::util::retrieveDeviceExceptionMessage(e); 
    response.set_errormessage(message); 
} // HERE 

> ~~3868~~ 
> ~~3868~~ Error #1: UNADDRESSABLE ACCESS: reading 0x03233e70-0x03233e74 4 byte(s) 
> ~~3868~~ # 0 amalgam-devices-communication.dl!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Grow [c:\program files (x86)\microsoft visual studio 11.0\vc\include\xstring:2226] 
> ~~3868~~ # 1 amalgam-devices-communication.dl!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign [c:\program files (x86)\microsoft visual studio 11.0\vc\include\xstring:1113] 
> ~~3868~~ # 2 amalgam-devices-communication.dl!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign [c:\program files (x86)\microsoft visual studio 11.0\vc\include\xstring:1099] 
> ~~3868~~ # 3 amalgam-devices-communication.dl!CDeviceServerResponse::set_errormessage [c:\workspace\bitbbucket\1edit_amalgam\devices\communication\src\main\c++\protobuf\src\main\cdeviceserverresponse.pb.h:294] 
> ~~3868~~ # 4 amalgam-devices-communication.dl!invoke_fn::operator()      [c:\workspace\bitbbucket\1edit_amalgam\devices\communication\src\main\c++\server\cdeviceserver.cc:156] 
> ~~3868~~ # 5 amalgam-devices-communication.dl!<lambda_e4b2ef864a7f24dec10bd7126eadbce1>::operator() [c:\workspace\bitbbucket\1edit_amalgam\devices\communication\src\main\c++\server\cdeviceserver.cc:184] 
> ~~3868~~ # 6 amalgam-devices-communication.dl!boost::detail::thread_data<<lambda_e4b2ef864a7f24dec10bd7126eadbce1> >::run [c:\workspace\bitbbucket\1edit_precompiledheaders\desktopdevices\external-sources\boost\thread\detail\thread.hpp:74] 
> ~~3868~~ # 7 amalgam-devices-communication.dl!boost::`anonymous namespace'::thread_start_function [c:\users\marcusma\source\1edit-prism\boost_1_51_0\libs\thread\src\win32\thread.cpp:190] 
> ~~3868~~ # 8 MSVCR110D.dll!beginthreadex            +0x1a0 (0x73dce001 <MSVCR110D.dll+0x5e001>) 
> ~~3868~~ # 9 MSVCR110D.dll!endthreadex             +0x170 (0x73dce1d1 <MSVCR110D.dll+0x5e1d1>) 
> ~~3868~~ #10 KERNEL32.dll!BaseThreadInitThunk           +0xd  (0x7735850d <KERNEL32.dll+0x2850d>) 
> ~~3868~~ Note: @0:00:44.759 in thread 3868 
> ~~3868~~ Note: next higher malloc: 0x03234000-0x03234030 
> ~~3868~~ Note: 0x03233e70-0x03233e74 overlaps memory 0x03233e58-0x03233e74 that was freed 
> ~~3868~~ Note: instruction: mov 0x18(%eax) -> %ecx 
> ~~3868~~ 

第一和第二訪問衝突在第一異常的端部花括號處理catch塊發生

並且Visual Studio調試器堆棧跟蹤指示在〜CDeviceException()析構函數中發生異常,同時嘗試釋放在該對象上設置的error_info(device_message)。

在Visual Studio:

First-chance exception at 0x76DA4B32 in amalgam-devices-server.exe: Microsoft C++ exception: boost::exception_detail::clone_impl<boost::broken_promise> at memory location 0x030EF55C. 
First-chance exception at 0x76DA4B32 in amalgam-devices-server.exe: Microsoft C++ exception: boost::exception_detail::clone_impl<boost::broken_promise> at memory location 0x030EF55C. 
First-chance exception at 0x76DA4B32 in amalgam-devices-server.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000. 
First-chance exception at 0x76DA4B32 in amalgam-devices-server.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000. 
First-chance exception at 0x76DA4B32 in amalgam-devices-server.exe: Microsoft C++ exception: boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> > at memory location 0x031EF6C0. 
First-chance exception at 0x76DA4B32 in amalgam-devices-server.exe: Microsoft C++ exception: boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> > at memory location 0x031EF6C0. 
First-chance exception at 0x76DA4B32 in amalgam-devices-server.exe: Microsoft C++ exception: boost::exception_detail::clone_impl<devices::util::CDeviceException> at memory location 0x031EF6A8. 
First-chance exception at 0x76DA4B32 in amalgam-devices-server.exe: Microsoft C++ exception: boost::exception_detail::clone_impl<devices::util::CDeviceException> at memory location 0x031EF6A8. 
First-chance exception at 0x76DA4B32 in amalgam-devices-server.exe: Microsoft C++ exception: devices::util::CDeviceException at memory location 0x031EF894. 
First-chance exception at 0x76DA4B32 in amalgam-devices-server.exe: Microsoft C++ exception: devices::util::CDeviceException at memory location 0x031EF894. 
Critical error detected c0000374 

且調用棧看起來是這樣的:

ntdll.dll!77a6a9ff() Unknown 
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 
ntdll.dll!77a6bcf5() Unknown 
ntdll.dll!77a6ad4a() Unknown 
ntdll.dll!77a2186c() Unknown 
ntdll.dll!779e26e8() Unknown 
ntdll.dll!779e1edb() Unknown 
ntdll.dll!779e217e() Unknown 
ntdll.dll!779e2664() Unknown 
ntdll.dll!779e2664() Unknown 
msvcr110d.dll!_free_base(void * pBlock) Line 50 C 
msvcr110d.dll!_free_dbg_nolock(void * pUserData, int nBlockUse) Line 1431 C++ 
msvcr110d.dll!_free_dbg(void * pUserData, int nBlockUse) Line 1265 C++ 
msvcr110d.dll!operator delete(void * pUserData) Line 54 C++ 
amalgam-devices-communication.dll!std::allocator<char>::deallocate(char * _Ptr, unsigned int __formal) Line 586 C++ 
amalgam-devices-communication.dll!std::_Wrap_alloc<std::allocator<char> >::deallocate(char * _Ptr, unsigned int _Count) Line 888 C++ 
amalgam-devices-communication.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Tidy(bool _Built, unsigned int _Newsize) Line 2265 C++ 
amalgam-devices-communication.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> >() Line 965 C++ 
amalgam-devices-communication.dll!invoke_fn::operator()(devices::server::CDeviceServer & server, boost::promise<void> & boostPromise, CDeviceClientRequest & request, CDeviceServerResponse & response) Line 157 C++ 
> amalgam-devices-communication.dll!<lambda_e4b2ef864a7f24dec10bd7126eadbce1>::operator()() Line 185 C++ 
amalgam-devices-communication.dll!boost::detail::thread_data<<lambda_e4b2ef864a7f24dec10bd7126eadbce1> >::run() Line 75 C++ 
amalgam-devices-communication.dll!boost::`anonymous namespace'::thread_start_function(void * param) Line 191 C++ 
msvcr110d.dll!_callthreadstartex() Line 354 C 
msvcr110d.dll!_threadstartex(void * ptd) Line 337 C 
kernel32.dll!7735850d() Unknown 
ntdll.dll!779ebf39() Unknown 
ntdll.dll!779ebf0c() Unknown 

任何幫助非常感謝,我們一直在努力,現在追蹤下來了好幾天。

回答

1

我已經找出了問題所在。 CDeviceResponse對象通過引用 傳遞給boost :: thread中的仿函數。如果線程超時,主線程將接管 並且該對象超出範圍並被銷燬。

但是,包含服務器調用的線程不會被終止,它會繼續運行,直到最終它拋出自己的異常並殺死該線程。此時, 對象再次被銷燬,導致訪問衝突。

有2種可能的修復方法。

  1. 捕獲invokeWithTimeout()返回false並顯式終止線程的事實。這將涉及到記憶有關線的詳細信息,以及我們所需要的代碼維護更簡單,所以我們去了選項2

  2. 定義的請求和響應共享指針,並通過這些來仿函數和 調用來代替。這樣,當主線程存在並繼續運行時,只有參考計數減少。當實際的線程死亡時,它會成功破壞對象。

但是如果有人知道的查殺超時線程這是調用 與下面的代碼更清潔的方式,那麼請讓我知道:

boost::promise<void>  boostPromise; 
boost::unique_future<void> boostFuture = boostPromise.get_future(); 
boost::thread    boostThread([&]() 
          { 
           invoke_fn functor; 
           functor(*this, 
             boostPromise, 
             request, 
             response); 
          }); 

bool result = (boostFuture.wait_for(boost::chrono::milliseconds(timeout)) 
       == 
       boost::future_status::ready); 
>> if result false kill the thread here 
return result;