空字符串在参数传递过程中莫名变成空指针,导致程序崩溃,寻高人指教。

kantaguo 2008-04-15 10:29:36
原来在unix平台下的代码现在要移植到linux上(redHat AS3, gcc 3.2.3),出现问题,在做函数调用的时候一个空字符串传递为参数的时候变成了空指针,导致程序崩溃,百思不得其解,请高人指教。我本身没有积分可以送,还望大家不吝赐教,谢谢。

下面是示例代码:


#include <iostream>
#include <string>

using namespace std;

struct TimeStamp
{
long year; ///< A year of a time stamp.
long month; ///< A month of a time stamp.
long day; ///< A day of a time stamp.
long hour; ///< A hour of a time stamp.
long minute; ///< A minute of a time stamp.
long second; ///< A second of a time stamp.
};

class TypeConv
{
public:
static TimeStamp toTimeStamp(const char* aString);
static TimeStamp toTimeStamp(const std::string& aString);
};

inline
TimeStamp
TypeConv::
toTimeStamp(const std::string& aString)
{
std::string str = ( aString.c_str() == 0 ) ? std::string() : aString;
if ( str.size() <= 14 )
str.append(" ", 14 - str.size());
else
str.append(" ", 14);

std::string strYear (str, 0, 4);
std::string strMonth (str, 4, 2);
std::string strDay (str, 6, 2);
std::string strHour (str, 8, 2);
std::string strMinute(str, 10, 2);
std::string strSecond(str, 12, 2);

TimeStamp timeStamp;
timeStamp.year = ::atol(strYear.c_str());
timeStamp.month = ::atol(strMonth.c_str());
timeStamp.day = ::atol(strDay.c_str());
timeStamp.hour = ::atol(strHour.c_str());
timeStamp.minute = ::atol(strMinute.c_str());
timeStamp.second = ::atol(strSecond.c_str());

return timeStamp;
}

inline
TimeStamp
TypeConv::
toTimeStamp(const char* aString)
{
return ( ::strcmp(aString, "") == 0 ) // 在此处会崩溃,用gdb调试时显示aString=0x0,为什么会这样,如何避免?
? TypeConv::toTimeStamp(std::string())
: TypeConv::toTimeStamp(std::string(aString));
}

int main()
{
cout << "begin" << endl;

string sTimeStr = "";

//const char* str = NULL;

TimeStamp time = TypeConv::toTimeStamp(sTimeStr.c_str());

cout << "end" << endl;

return 0;
}
...全文
633 19 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
meiZiNick 2008-05-01
  • 打赏
  • 举报
回复
不知,帮顶
kantaguo 2008-04-28
  • 打赏
  • 举报
回复
再自己顶起来一次,如果没办法只能做无满意结帖了。
kantaguo 2008-04-22
  • 打赏
  • 举报
回复
怎么都没人进来了,顶起来继续寻求帮助。
two_ears 2008-04-16
  • 打赏
  • 举报
回复
上面给你贴的用color=#FF0000标颜色的地方出问题了,呵呵,凑合看吧,加了一点注释
是我用vc的debug,step in看了一下,linux的人好像都不屑于vc,呵呵
VC中的实现可以看到,肯定不会分配内存,grow也返回了false
mingw的gdb显示string内部指针为"",可见两种实现有区别
kantaguo 2008-04-16
  • 打赏
  • 举报
回复
补充一句,我的程序是个demon的多线程server程序。
two_ears 2008-04-16
  • 打赏
  • 举报
回复
深了,学习
d
kantaguo 2008-04-16
  • 打赏
  • 举报
回复
首先感谢楼上各位的热心帮助,今天在公司用gdb仔细调试了一下发现问题好像并非是或者并不全是我在主帖中所描述,由此可能会给大家带来的误导深表歉意。

今天在公司对我的代码做了一些修改,但是仍然没有实际解决问题,只是能做出一些排除,因此还是需要和大家讨论,请各位帮忙分析。

以下是我对代码做的修改及修改前后gdb调试时的堆栈信息:

修改后代码

inline
TimeStamp
TypeConv::
toTimeStamp(const char* aString)
{
if( aString == NULL ) // 判断了空指针的情况,但是发现实际是根本不会出现空指针,每次依然是以""的形式进入
{
return TypeConv::toTimeStamp(std::string());
}
else // 下面实际只是将原来的代码拆分开来写
{
if(::strcmp(aString, "") == 0)
{
//std::string tmpStr = "20080416";
//TimeStamp t = TypeConv::toTimeStamp(tmpStr);

TimeStamp t = TypeConv::toTimeStamp(std::string()); // 用gdb单步调试在这里会crash,堆栈信息如后附。
// 更为奇怪的是即使我使用上面注释掉的两行代码(使用常量)依然会出问题,
// 而且同样的参数传入的时候并不是每次都会crash,网上有资料称某些版本gcc
// 的basic_string构造函数存在sharded memory管理bug,可能会导致
// segfault,不确定是否是此原因。
return t;
}
else
{
TimeStamp t = TypeConv::toTimeStamp(std::string(aString));
return t;
}

/*
return ( ::strcmp(aString, "") == 0 )
? TypeConv::toTimeStamp(std::string())
: TypeConv::toTimeStamp(std::string(aString));
*/
}
}


代码修改前的堆栈:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 193354672 (LWP 14494)]
0x0055eb16 in std::__default_alloc_template<true, 0>::allocate () from /usr/lib/libstdc++.so.5
(gdb) bt
#0 0x0055eb16 in std::__default_alloc_template<true, 0>::allocate () from /usr/lib/libstdc++.so.5
#1 0x00564b48 in std::string::_Rep::_S_create () from /usr/lib/libstdc++.so.5
#2 0x0807fd71 in std::string::_S_construct<__gnu_cxx::__normal_iterator<char*, std::string> > (__a=@0xb865280) at /usr/include/c++/3.2.3/bits/basic_string.tcc:154
#3 0x0807abb6 in IFWI::TypeConv::toTimeStamp (aString=@0x0) at /usr/include/c++/3.2.3/bits/basic_string.h:732
#4 0x057d78fe in IFWI::TIB::CommonExecuter::SET_EVENT_INFO (aMessageBody=@0xb8655f0, aEventInfo=@0xb865560, aReasonCodeRequired=false)
at /usr/include/c++/3.2.3/bits/stl_alloc.h:668
#5 0x058307e6 in IFWI::TIB::LotExecuter::makeLoggedOut (aMessageBody=@0xb8655f0, aReplyMessageBody=@0xb8657e0) at LotExecuter.cpp:726
#6 0x08066a96 in IFWI::TIB::WIPsrv::LOT_CREATE_S_REQ (this=0xbfffa810, aMessageName=0xb742050a "LOT_CREATE_S", aMessageBody=@0xb865800, aReplyMessageBody=@0xb8657e0)
at WIPsrv.cpp:1294
#7 0x08059b3f in IFWI::TIB::TService<IFWI::TIB::WIPsrv>::onRequest (this=0xbfffa810, aMessage=@0xb865930) at /data/mesapp/include/IFWTService.i:645
#8 0x003a9a1e in IFWI::TIB::RequestListener::onMsg (this=0x0, aMessage=@0xb865930) at IFWTService.cpp:328
#9 0x003a8803 in IFWI::TIB::MsgCallback::onMsg (this=0x0, aListener=0x9057bf8, aMessage=@0xb865930) at IFWTService.cpp:226
#10 0x05a1db4f in TibrvMsgCallback::onEvent () from /data/mesapp/lib/libNcTGEN.so.1.3.1
#11 0x05a1d346 in TibrvEvent::_listenCB () from /data/mesapp/lib/libNcTGEN.so.1.3.1
#12 0x0062dea0 in _tibrvQueue_Dispatch () from /usr/tibco/tibrv/lib/libtibrv.so
#13 0x0062e330 in tibrvQueueGroup_TimedDispatch () from /usr/tibco/tibrv/lib/libtibrv.so
#14 0x0062e5c3 in _tibrvDispatcher_Run () from /usr/tibco/tibrv/lib/libtibrv.so
#15 0x003dddd8 in start_thread () from /lib/tls/libpthread.so.0
#16 0x05f9cd1a in clone () from /lib/tls/libc.so.6

代码修改后的堆栈:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 193354672 (LWP 14494)]
0x0055eb16 in std::__default_alloc_template<true, 0>::allocate () from /usr/lib/libstdc++.so.5
(gdb) bt
#0 0x0055eb16 in std::__default_alloc_template<true, 0>::allocate () from /usr/lib/libstdc++.so.5
#1 0x00564b48 in std::string::_Rep::_S_create () from /usr/lib/libstdc++.so.5
#2 0x0807fd71 in std::string::_S_construct<__gnu_cxx::__normal_iterator<char*, std::string> > (__a=@0xb865280) at /usr/include/c++/3.2.3/bits/basic_string.tcc:154
#3 0x0807abb6 in IFWI::TypeConv::toTimeStamp (aString=@0x0) at /usr/include/c++/3.2.3/bits/basic_string.h:732
#4 0x057d78fe in IFWI::TIB::CommonExecuter::SET_EVENT_INFO (aMessageBody=@0xb8655f0, aEventInfo=@0xb865560, aReasonCodeRequired=false)
at /usr/include/c++/3.2.3/bits/stl_alloc.h:668
#5 0x058307e6 in IFWI::TIB::LotExecuter::makeLoggedOut (aMessageBody=@0xb8655f0, aReplyMessageBody=@0xb8657e0) at LotExecuter.cpp:726
#6 0x08066a96 in IFWI::TIB::WIPsrv::LOT_CREATE_S_REQ (this=0xbfffa810, aMessageName=0xb742050a "LOT_CREATE_S", aMessageBody=@0xb865800, aReplyMessageBody=@0xb8657e0)
at WIPsrv.cpp:1294
#7 0x08059b3f in IFWI::TIB::TService<IFWI::TIB::WIPsrv>::onRequest (this=0xbfffa810, aMessage=@0xb865930) at /data/mesapp/include/IFWTService.i:645
#8 0x003a9a1e in IFWI::TIB::RequestListener::onMsg (this=0x0, aMessage=@0xb865930) at IFWTService.cpp:328
#9 0x003a8803 in IFWI::TIB::MsgCallback::onMsg (this=0x0, aListener=0x9057bf8, aMessage=@0xb865930) at IFWTService.cpp:226
#10 0x05a1db4f in TibrvMsgCallback::onEvent () from /data/mesapp/lib/libNcTGEN.so.1.3.1
#11 0x05a1d346 in TibrvEvent::_listenCB () from /data/mesapp/lib/libNcTGEN.so.1.3.1
#12 0x0062dea0 in _tibrvQueue_Dispatch () from /usr/tibco/tibrv/lib/libtibrv.so
#13 0x0062e330 in tibrvQueueGroup_TimedDispatch () from /usr/tibco/tibrv/lib/libtibrv.so
#14 0x0062e5c3 in _tibrvDispatcher_Run () from /usr/tibco/tibrv/lib/libtibrv.so
#15 0x003dddd8 in start_thread () from /lib/tls/libpthread.so.0
#16 0x05f9cd1a in clone () from /lib/tls/libc.so.6

其实修改前和修改后几乎是相同的,导致crash的都是string的构造,但是为什么呢???

单步调试时死在gcc源文件的这一句 _Rep::_S_create(__dnew, __a) , 这就看不懂是什么了,
另外谁能告诉我 _GLIBCXX_FULLY_DYNAMIC_STRING 这个编译参数的作用是什么以及如何设置,在gcc的头文件中看到有关于他的使用
template<typename _CharT, typename _Traits, typename _Alloc>
inline basic_string<_CharT, _Traits, _Alloc>::
basic_string()
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
: _M_dataplus(_S_empty_rep()._M_refcopy(), _Alloc()) { }
#else
: _M_dataplus(_S_construct(size_type(), _CharT(), _Alloc()), _Alloc()) { }
#endif

以上望大家予以指点,在下感激不尽,因为在公司的时候上不了csdn,所以只能晚上回家来向大家讨教,见谅。
two_ears 2008-04-15
  • 打赏
  • 举报
回复
主要就是看构造函数怎么处理""了
two_ears 2008-04-15
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 kantaguo 的回复:]
引用 8 楼 two_ears 的回复:
可能就是stl的实现不同,我也用mingw试了,确实没问题,但是vc6就有问题,0长的字符串它不分配内存
这样应该就不会异常了:

C/C++ codeint main()
{
cout < < "begin" < < endl;

string sTimeStr = "ABC";

//const char* str = NULL;

TimeStamp time = TypeConv::toTimeStamp(sTimeStr.c_str());

cout < < "end" < < endl…
[/Quote]
“莫非真的就是因为stl实现不同导致这个原因?”嗯,我觉得可能
刚才我是用同样的代码,用cl和mingw分别编译,结果前者是NULL后者是""
开始以为mingw会得到你说的结果呢,因为不是说mingw移植自linux的gcc么
其实stl代码也可以看到,下面的是VC6环境下step in到string str="";看到的执行过程

basic_string(const _E *_S, const _A& _Al = _A())
: allocator(_Al) {_Tidy(), assign(_S); } // _Tidy使_Ptr=0
_Myt& assign(const _E *_S)
{return (assign(_S, _Tr::length(_S))); }
_Myt& assign(const _E *_S, size_type _N) // _N是0
{if (_Grow(_N, true)) // 返回false
{....}
return (*this); }
bool _Grow(size_type _N, bool _Trim = false)
{if (max_size() < _N)....
if (_N == 0)
{if (_Trim)
_Tidy(true); // 所以这次_Ptr还是0
else if (_Ptr != 0)
_Eos(0);
return (false); }
else....}
void _Tidy(bool _Built = false)
{if (!_Built || _Ptr == 0)
;
else if ...
else...
_Ptr = 0, _Len = 0, _Res = 0; }
kantaguo 2008-04-15
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 baishawojia 的回复:]

  常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。因此,定义或说明常类型时必须进行初始化
[/Quote]

我没太懂你的意思,你是要我去初始化什么? sTimeStr ? 如何初始化呢? 我已经负值为 “”了啊。
kantaguo 2008-04-15
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 two_ears 的回复:]
可能就是stl的实现不同,我也用mingw试了,确实没问题,但是vc6就有问题,0长的字符串它不分配内存
这样应该就不会异常了:

C/C++ codeint main()
{
cout << "begin" << endl;

string sTimeStr = "ABC";

//const char* str = NULL;

TimeStamp time = TypeConv::toTimeStamp(sTimeStr.c_str());

cout << "end" << endl;

return 0;
}


另外可以在函数toT…
[/Quote]

如果不是空字符串当然是没问题的了,在toTimeStamp内先进行检查是可以的,今天下班前写了一点还没验证。
楼上几位都提到stl的实现问题,莫非真的就是因为stl实现不同导致这个原因?
two_ears 2008-04-15
  • 打赏
  • 举报
回复
可能就是stl的实现不同,我也用mingw试了,确实没问题,但是vc6就有问题,0长的字符串它不分配内存
这样应该就不会异常了:
int main()
{
cout << "begin" << endl;

string sTimeStr = "ABC";

//const char* str = NULL;

TimeStamp time = TypeConv::toTimeStamp(sTimeStr.c_str());

cout << "end" << endl;

return 0;
}

另外可以在函数toTimeStamp里加一个检查,应该改动不大吧?
baishawojia 2008-04-15
  • 打赏
  • 举报
回复

  常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。因此,定义或说明常类型时必须进行初始化
kantaguo 2008-04-15
  • 打赏
  • 举报
回复
谢谢楼上两位的答复,我明天到公司试试看,另外到公司后我会把gdb调试时的堆栈信息贴出来请大家帮忙分析。

改函数的参数类型当然是一种办法,但是因为整个系统非常庞大,改参数类型要改的地方就太多了,而且也不打算因为平台的原因就采用不同的参数类型,因此首选还是解决空指针的问题,而且我确实也很好奇为什么会发生这个转换。
effective_person 2008-04-15
  • 打赏
  • 举报
回复
Unix平台我没有试过!不过window vs中确实可以这样写!
各种可能的写法都试试吧!
two_ears 2008-04-15
  • 打赏
  • 举报
回复
看看string sTimeStr = "";之后string有没有分配内存,可能和stl的实现有关系吧
我是风 2008-04-15
  • 打赏
  • 举报
回复
我在MinGW下编译执行,没有问题啊。
effective_person 2008-04-15
  • 打赏
  • 举报
回复

inline TimeStamp TypeConv::toTimeStamp(const char* aString)//aString是个指针 指向的空。
{
return ( ::strcmp(aString, "") == 0 ) ? TypeConv::toTimeStamp(std::string()): TypeConv::toTimeStamp(std::string(aString));
}


inline
TimeStamp
TypeConv::
toTimeStamp(const std::string& aString)// 该成string类型看看
{
return ( aString==0 ) ? TypeConv::toTimeStamp(std::string()): TypeConv::toTimeStamp(std::string(aString));
}


TimeStamp time = TypeConv::toTimeStamp(sTimeStr);//试试看看

ouyh12345 2008-04-15
  • 打赏
  • 举报
回复
这样传会出错吗?
const char* str = sTimeStr.c_str();
TimeStamp time = TypeConv::toTimeStamp(str);
1. C 语言的指针和内存泄漏 5 2. C语言难点分析整理 10 3. C语言难点 18 4. C/C++实现冒泡排序算法 32 5. C++指针和引用的区别 35 6. const char*, char const*, char*const的区别 36 7. C可变参数函数实现 38 8. C程序内存组成部分 41 9. C编程拾粹 42 10. C语言实现数组的动态增长 44 11. C语言的位运算 46 12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试-运算符和表达式 104 20. C语言编程准则之稳定篇 107 21. C语言编程常见问题分析 108 22. C语言编程易犯毛病集合 112 23. C语言缺陷与陷阱(笔记) 119 24. C语言防止缓冲区溢出方法 126 25. C语言高效编程秘籍 128 26. C运算符优先级口诀 133 27. do/while(0)的妙用 134 28. exit()和return()的区别 140 29. exit子程序终止函数与return的差别 141 30. extern与static存储间矛盾 145 31. PC-Lint与C\C++代码质量 147 32. spirntf函数使用大全 158 33. 二叉树的数据结构 167 34. 位运算应用口诀和实例 170 35. 内存对齐与ANSI Cstruct内存布局 173 36. 冒泡和选择排序实现 180 37. 函数指针数组与返回数组指针的函数 186 38. 右左法则- 复杂指针解析 189 39. 回车和换行的区别 192 40. 堆和堆栈的区别 194 41. 堆和堆栈的区别 198 42. 如何写出专业的C头文件 202 43. 打造最快的Hash表 207 44. 指针与数组学习笔记 222 45. 数组不是指针 224 46. 标准C字符串分割的方法 228 47. 汉诺塔源码 231 48. 洗牌算法 234 49. 深入理解C语言指针的奥秘 236 50. 游戏外挂的编写原理 254 51. 程序实例分析-为什么会陷入死循环 258 52. 指针究竟指向了内存的哪个地方 260 53. 算术表达式的计算 265 54. 结构体对齐的具体含义 269 55. 连连看AI算法 274 56. 连连看寻路算法的思路 283 57. 重新认识:指向函数的指针 288 58. 链表的源码 291 59. 高质量的子程序 295 60. 高级C语言程序员测试必过的十六道最佳题目+答案详解 297 61. C语言常见错误 320 62. 超强的指针学习笔记 325 63. 程序员之路──关于代码风格 343 64. 指针、结构体、联合体的安全规范 346 65. C指针讲解 352 66. 关于指向指针的指针 368 67. C/C++ 误区一:void main() 373 68. C/C++ 误区二:fflush(stdin) 376 69. C/C++ 误区三:强制转换 malloc() 的返回值 380 70. C/C++ 误区四:char c = getchar(); 381 71. C/C++ 误区五:检查 new 的返回值 383 72. C 是 C++ 的子集吗? 384 73. C和C++的区别是什么? 387 74. 无条件循环 388 75. 产生随机数的方法 389 76. 顺序表及其操作 390 77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 419 84. C语言惠通面试题 428 85. C语言常用宏定义 450

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧