您的位置:首页 > 其它

STL std:string引起的User breakpoint exception/User breakpoint called from code at

2010-11-30 01:46 337 查看
SYMPTOMS:
程序崩溃,弹出 User breakpoint called from code at 0x????????对话框;
崩溃时的调用栈有如下几种常见情形:
(1)
TDLL! 7c92120e()
NTDLL! 7c96b460()
NTDLL! 7c98ee40()
NTDLL! 7c96b3a2()
NTDLL! 7c93aa2b()
_heap_alloc_base(unsigned int 80) line 200
_heap_alloc_dbg(unsigned int 33, int 1, const char * 0x00000000, int 0) line 378 + 9 bytes
_nh_malloc_dbg(unsigned int 33, int 1, int 1, const char * 0x00000000, int 0) line 248 + 21 bytes
_nh_malloc(unsigned int 33, int 1) line 197 + 19 bytes
operator new(unsigned int 33) line 24 + 11 bytes
std::_Allocate(int 33, char * 0x00000000) line 30 + 9 bytes
std::allocator<char>::allocate(unsigned int 33, const void * 0x00000000) line 59 + 18 bytes
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Copy(unsigned int 21) line 526 + 17 bytes
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Grow(unsigned int 21, unsigned char 1) line 568
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & {0x000379c1 "?"}, unsigned int 0, unsigned int 4294967295) line 128 + 16 bytes
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> >(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & {0x000379c1 "?"}) line 44 + 43 bytes
(2)
_CrtIsValidHeapPointer(const void * 0x000379c0) line 1697
_free_dbg_lk(void * 0x000379c0, int 1) line 1044 + 9 bytes
_free_dbg(void * 0x000379c0, int 1) line 1001 + 13 bytes
free(void * 0x000379c0) line 956 + 11 bytes
operator delete(void * 0x000379c0) line 7 + 10 bytes
std::allocator<char>::deallocate(void * 0x000379c0, unsigned int 33) line 64 + 16 bytes
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Tidy(unsigned char 1) line 592
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Copy(unsigned int 24) line 535
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Grow(unsigned int 24, unsigned char 0) line 557
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::append(const char * 0x0041402c `string', unsigned int 3) line 94 + 32 bytes
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::append(const char * 0x0041402c `string') line 99 + 32 bytes
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator+=(const char * 0x0041402c `string') line 73 + 19 bytes

CAUSE:
由于VC6.0的STL版本的std:string类使用了浅拷贝机制来优化字符串赋值操作。例如:
string g="线程安全问题";
string a=g;
执行a=g操作,是将a指向g的内部缓冲区,即a和g指向相同的内存(实际存储字符串的缓冲区),避免内存拷贝,提高程序效率。
因此需要配套的引起计数机制来跟踪有多少对象在使用同一个内存区,以便最后一个对象销毁时去销毁实际的内存区。
而VC6.0提供的版本在引用计数机制上不是线程安全的。例如:
string g="线程安全问题";
string a=g;///<线程1
string b=g;///<线程2
g是全局对象,a=g和b=g在不同的线程中并发执行。
执行a=g时,需要将g的引用计数加1,类似如下代码:
g.refcnt_++;
自加1的代码需要先将内存的值送到寄存器,然后在寄存器上执行完加1后,再将新值写入内存,类似:
int reg_var = g.refcnt_;
reg_var = reg_var+1;
g.refcnt_ = reg_var;
设,g.refcnt_=1,A线程执行a=g,当执行完 int reg_var = g.refcnt_;时,线程被打断,此时reg_var=1,线程上下文被保存;
然后另一个线程B被调度获得cpu,执行b=g,当b=g执行完后,g.refcnt_=2;
此时,A线程被再唤醒获得cpu继续往下执行,应为被中断时,reg_var=1,加1后等于2并写入g.refcnt_,所以,执行完a=g后,g.refcnt_=2.
显然,g的引用计数少加1,而在析构b时,b会将g.refcnt_减1,此时g.refcnt_=1;然后析构a,a同样会将g.refcnt_减1,此时g.refcnt_=0;当
g.refcnt_=0时,则认为没有对象引用,则释放内存,而此时g保存的内存已经被破坏,再次访问将不可预期。

SOLUTION:
(1)将开发环境升级到vc7或更高版本
(2) 使用第三方stl而不是使用vc6.0自带的stl

我采用的是方法2,使用stlport(5.2.1)
下载地址:http://www.stlport.org

vc6使用stlport的方法
1)将STLport-5.2.1.tar.bz2解压缩,设解压缩后的路径是%stlport%
2)修改C:/Program Files/Microsoft Visual Studio/VC98/Bin/VCVARS32.BAT中,
把%STLport%/stlport;(注意有英文的分号)加入Include路径中;
把%STLport%/lib; ,加入Lib路径中;(%STLport%下没有lib子目录,编译后会自动生成).
例如:
set INCLUDE=C:/STLport-5.2.1/STLport-5.2.1/stlport;%MSVCDir%/ATL/INCLUDE;%MSVCDir%/INCLUDE;%MSVCDir%/MFC/INCLUDE;%INCLUDE%
set LIB=C:/STLport-5.2.1/STLport-5.2.1/lib;%MSVCDir%/LIB;%MSVCDir%/MFC/LIB;%LIB%
3)打开cmd,执行C:/Program Files/Microsoft Visual Studio/VC98/Bin/VCVARS32.BAT文件
4)进入%STLport%,运行configure msvc6,正常情况下,提示如下:

STLport Configuration Tool for Windows
Setting compiler: Microsoft Visual C++ 6.0
Setting platform: Windows XP
Done configuring STLport.
Go to build/lib folder and type "nmake clean install" to build and
install STLport to the "lib" and "bin" folders.
Go to build/test/unit folder and type nmake clean install to
build unit tests and install them in bin folder.
5)进入%STLport%/build/lib,执行nmake /fmsvc.mak
耐心等待,需要一会...
6)进入%STLport%/build/lib,执行nmake /fmsvc.mak install
执行copy,将lib,dll复制到应用的目录
7)设置VC6.0开发环境
选择tools/options菜单,弹出对话框,设置includes路径包含:%STLport%/stlport
设置lib搜索路径包含:%STLport%/lib
并且,将以上2个路径都移到相应的最上面,以便能优先搜索。
8)与ACE的兼容问题
当使用了stlport后,需要重新编译ACE,否则使用了ACE的应用程序在连接时,会出现如下错误:
error LNK2001: unresolved external symbol "__declspec(dllimport) public: void __thiscall ACE_Log_Msg::set(char const *,int,int,int,int,class stlp_std::basic_ostream<char,class stlp_std::char_traits<char> > *,class ACE_Log_Msg_Callbac
k *)" (__imp_?set@ACE_Log_Msg@@QAEXPBDHHHHPAV?$basic_ostream@DV?$char_traits@D@stlp_std@@@stlp_std@@PAVACE_Log_Msg_Callback@@@Z)
9)与openssl的兼容问题
因为openssl的部分代码使用了hash这个标识符,而该标识符被stlport使用并定义为了一个结构体,如果先包含string,然后再包含openssl的话,则可能
会出现编译问题.

例如:error C2955: 'hash' : use of class template requires template argument list
解决办法:可以在包含string的上面加上如下语句:
#include <openssl/err.h>。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: