coverity 的 WRAPPER_ESCAPE 告警
const char* Foo()
{
std::string str_msg("test");
return str_msg.c_str();
}
int main() {
const char *p_msg = Foo();
printf("%s\n", p_msg);
return 0;
}
// output:(为空,或乱码)
D?
上面代码中的 Foo 函数会被 coverity 报告 WRAPPER_ESCAPE,详细说明是:
Wrapper object use after free (WRAPPER_ESCAPE)
1. escape: The internal representation of local strMsg escapes, but is destroyed when it exits scope
大意是局部变量 str_msg 在离开函数 Foo 的时候会被释放(因为 str_msg 是分配在栈上的变量),而通过函数 std::string::c_str() 获取的指向 str_msg 头部的指针会因此变为一个悬空指针,将这个悬空指针返回给函数调用者使用将会发生不可预知的行为。
而 c_str() 本身返回的是一个 const char *p,虽然我们无法直接修改指针 p 所指向的数据,但我们可以通过修改 str_msg 来达到修改 p 所指向内存的效果,例如如下的代码:
int main() {
std::string str_msg("test");
const char *p_msg = str_msg.c_str();
printf("%s\n", p_msg);
str_msg[2] = 'x';
printf("%s\n", p_msg);
return 0;
}
// output:
test
text
想要正确地使用返回的 const char*,我们可以在堆上分配一块内从,将要使用的字符串拷贝到其中并返回:
const char* Foo()
{
std::string str_msg("test");
uint32_t u32_msg_size = str_msg.size() + 1;
char *p_return = new char[u32_msg_size];
strcpy_s(p_return, u32_msg_size, str_msg.c_str());
return p_return;
}
int main() {
const char *p_msg = Foo();
printf("%s\n", p_msg);
return 0;
}
// output:
test
当然,调用者也应该则适当的时机对 p_msg 进行 delete 操作,否则将会造成内存泄漏。
应该记住的是,除非你需要立即以 const char* 的方式使用字符串,否则应该尽量避免使用 c_str(),尤其是在发生函数调用和返回时。