Ilia Mirkin
unread,Oct 6, 2012, 5:17:37 AM10/6/12Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to prot...@googlegroups.com
Hello,
I've recently run into a problem with a (newly-written) custom
protobuf decoder, and I've narrowed down the issue to this simple
program:
"""
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
inline void STLStringResizeUninitialized(string* s, size_t new_size) {
s->resize(new_size);
}
inline char* string_as_array(string* str) {
// DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
return str->empty() ? NULL : &*str->begin();
}
int main(int argc, char** argv) {
string output;
STLStringResizeUninitialized(&output, 5);
string_as_array(&output);
cout << "output: " << output << endl;
return 0;
}
"""
Running this in a gdb session:
Breakpoint 1, main (argc=1, argv=0x7fffffffdf48) at simple_repro.cc:18
18 string output;
(gdb) n
19 STLStringResizeUninitialized(&output, 5);
(gdb)
20 string_as_array(&output);
(gdb) p *output._M_rep()
$1 = {<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::_Rep_base> = {_M_length = 5,
_M_capacity = 5, _M_refcount = 0}, static _S_max_size = <optimized
out>, static _S_terminal = <optimized out>,
static _S_empty_rep_storage = {0, 0, 0, 0}}
(gdb) n
21 cout << "output: " << output << endl;
(gdb) p *output._M_rep()
$2 = {<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::_Rep_base> = {_M_length = 5,
_M_capacity = 5, _M_refcount = -1}, static _S_max_size =
<optimized out>, static _S_terminal = <optimized out>,
static _S_empty_rep_storage = {0, 0, 0, 0}}
Note that the refcount went down to -1 after string_as_array is run.
I've reproduced this with gcc-4.5, 4.4, and 4.3 (for some reason I'm
having trouble building 4.1). Obviously I didn't start with this
program, the initial code was something like
func() {
string ret;
...
cis->ReadString(&ret, length);
...
return ret;
}
And I would get an abort() in ~basic_string (sometimes, not always) like:
*** glibc detected *** free(): invalid next size (fast): 0x00007fffdc083e90 ***
on the "return ret" line. The function didn't really do very much else
with ret in those cases. Changing the code to
output.resize(val32);
if (!cis_->ReadRaw((void *)output.c_str(), val32)) {
made everything work. I obviously realize that this is not a great way
to go, but I do think it ends up working in my specific situation.
However the effectively double-free (or at least ref-count-decrease)
seems quite worrying...
Any ideas? Should that string_as_array thing really work and I should
direct this at the gcc people?
Thanks,
-ilia