On Sat, Oct 6, 2012 at 5:17 AM, Ilia Mirkin <imir...@alum.mit.edu> wrote:
> 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.

Actually after reading through basic_string.h and basic_string.tcc, it
seems that the -1 refcount is used to indicate unsharing of the
strings. So that is actually fine (and expected). However that still
leaves me with the original bug and less confidence that my "solution"
actually fixes anything vs just being a lucky workaround (one thing it
doesn't do is cause the un-sharing to happen, which I guess was the
purpose of having written string_to_Array that way). I guess it's time
for some more debugging...

> 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

-- 
You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To post to this group, send email to protobuf@googlegroups.com.
To unsubscribe from this group, send email to 
protobuf+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/protobuf?hl=en.

Reply via email to