返回 std::string 时指针无效(libc 如此说)
invalid pointer when returning std::string (so says libc)
>我在一个 mmapped 文件消费类中有一个成员函数,如下所示:
std::string Data::GetASCIIZ(OFFSET* offsetp) const
{
char* str = (char*)_buffer + *offsetp; // _buffer points to mmap'd file
*offsetp += strlen(str) + 1;
return std::string(str);
}
("偏移"的类型是无符号长长)
它存在的理由是(a)返回一个以空结尾的C字符串的std::string,该字符串假定存在于偏移量*offsetp
之后,在(b)将*offsetp
的值推进到所述C字符串的末尾之后。
我在很多情况下调用此函数,没有问题。 但是,我最近添加了一个新的调用,它总是以一种特殊的方式 SIGABRT:
*** glibc detected *** /home/ryan/src/coolapp/out/coolapp: free(): invalid pointer: 0xb7eb165c ***
上面的消息后面跟着一个回溯(最终在libc.so.6中的一些代码中达到高潮),以及一个内存映射......在调试此问题时,这两者都表面上对我有用。
通过使用 GDB 进行调试,我了解到 SIGABRT 实际上并不发生在上面引用的 Data::GetASCIIZ
方法中,而是发生在赋值右侧调用它的代码中。 (所以,我假设在调用 std::string 的复制构造函数期间):
[编辑:更新以与@WhozCraig的预期答案相吻合]
struct stuff
{
char version;
std::string sigstring;
// ...
};
stuff* mystuff = (stuff*)malloc(sizeof(stuff));
// ...
mystuff->sigstring = _data->GetASCIIZ(offsetp); // SIGABRT HAPPENS AT THIS SCOPE
在这种特殊情况下,偏移量 *offsetp
处的 C 字符串恰好是一个空字符串,但我已经通过临时修改 *offsetp
以指向 GDB 中的其他内容来验证这无关紧要。
我的方法被标记为const
,因为它不会修改Data
对象的任何内部状态。 我返回一个存在于堆栈上的对象,但我不是通过引用这样做的,我希望复制构造函数(在调用代码中)在该堆栈项被销毁之前做正确的事情。
我尝试重写 GetASCIIZ
方法以使用显式本地,但这没有帮助。
我错过了什么吗?
如果它有用,这里是发生此 SIGABRT 的分配期间调用的反汇编。 ("==>"位于错误点。
424 sigstring = _data->GetASCIIZ(offsetp);
0x0807def1 <+183>: mov 0x8(%ebp),%eax
0x0807def4 <+186>: mov 0x4(%eax),%eax
0x0807def7 <+189>: lea 0x4(%eax),%ecx
0x0807defa <+192>: lea -0x18(%ebp),%eax
0x0807defd <+195>: mov 0x1c(%ebp),%edx
0x0807df00 <+198>: mov %edx,0x8(%esp)
0x0807df04 <+202>: mov %ecx,0x4(%esp)
0x0807df08 <+206>: mov %eax,(%esp)
0x0807df0b <+209>: call 0x809e6ee <Data::GetASCIIZ(unsigned long long*) const>
0x0807df10 <+214>: sub $0x4,%esp
0x0807df13 <+217>: mov -0x14(%ebp),%eax
0x0807df16 <+220>: lea 0x4(%eax),%edx
0x0807df19 <+223>: lea -0x18(%ebp),%eax
0x0807df1c <+226>: mov %eax,0x4(%esp)
0x0807df20 <+230>: mov %edx,(%esp)
0x0807df23 <+233>: call 0x8049560 <_ZNSsaSEOSs@plt>
0x0807df28 <+238>: lea -0x18(%ebp),%eax
0x0807df2b <+241>: mov %eax,(%esp)
=> 0x0807df2e <+244>: call 0x80497f0 <_ZNSsD1Ev@plt>
0x0807e026 <+492>: lea -0x18(%ebp),%eax
0x0807e029 <+495>: mov %eax,(%esp)
0x0807e02c <+498>: call 0x80497f0 <_ZNSsD1Ev@plt>
0x0807e031 <+503>: mov %ebx,%eax
0x0807e033 <+505>: jmp 0x807e046 <CoolClass::SpiffyMethod(unsigned long long, unsigned long long, unsigned long long*)+524>
0x0807e035 <+507>: mov %eax,%ebx
您的示例如下所示。
std::string Data::GetASCIIZ(OFFSET* offsetp) const
{
char* str = (char*)_buffer + *offsetp; // _buffer points to mmap'd file
*offsetp += strlen(str) + 1;
return std::string(str);
}
return 语句不应该返回一个新的 STL 字符串吗?
std::string Data::GetASCIIZ(OFFSET* offsetp) const
{
char* str = (char*)_buffer + *offsetp; // _buffer points to mmap'd file
*offsetp += strlen(str) + 1;
return new std::string(str);
}
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 无法访问嵌套类.类的使用无效
- 如果用户输入无效,如何使用字符串变量-C++重复输入命令
- 带有 -stdlib=libc++ 的 clang++ 9.0.1 找不到<optional>
- 如何解决错误:SCIP C++中的 SCIP 阶段无效 <10>
- 在没有参数列表的情况下使用模板名称"Event"无效,模板问题
- FFMPEG配置文件级别id大小无效
- 错误:从"int"到枚举c++的转换无效
- 如何修复此错误:className::className的无效使用
- 为什么将值返回函数传递给重载=运算符对运算符函数有效,而对其他运算符无效
- C++-模板嵌套类的引用初始化无效
- 错误:无效的预处理指令 #i 的意思是 #if?
- 多维数组 C++ 中数组下标的类型"int[int]"无效
- 在 C++ 中使用正则表达式错误时出现问题 括号表达式中的范围无效
- C++17 - 使用自定义分配器的节点提取/重新插入 - 适用于 clang++/libc++,但不适用于 libstd
- 从 'int' 到 'int*' CPP 的转换无效
- 如何接受 [ENTER] 键作为无效输入并发送错误消息
- Android Oreo 8.0本机C 崩溃:无效的PTHREAD_T传递给LIBC
- OSX 10.8上-stdlib=libc++的部署目标无效
- 返回 std::string 时指针无效(libc 如此说)