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

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

Reply via email to