Bug 28759 - stringbuf writes beyond external buffer given via pubsetbuf()
Summary: stringbuf writes beyond external buffer given via pubsetbuf()
Status: VERIFIED WORKSFORME
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 3.4.5
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-08-17 00:53 UTC by Nick Gifford
Modified: 2006-08-18 02:52 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work: 4.0.0
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nick Gifford 2006-08-17 00:53:01 UTC
$ gcc -v
Reading specs from /usr/lib/gcc/i386-redhat-linux/3.4.5/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-java-awt=gtk --host=i386-redhat-linux
Thread model: posix
gcc version 3.4.5 20051201 (Red Hat 3.4.5-2)

$ uname -a
Linux localhost.localdomain 2.6.9-34.0.1.EL #1 Wed May 24 07:40:56 CDT 2006 i686 i686 i386 GNU/Linux


I encounter this bug when using ostringstream with an external buffer.

When an external buffer is given to pubsetbuf(), it is copied into the internal buffer (_M_string).  (The code comments in sstream indicate that it thinks it's destroying the buffer, but it's not.)  If the size of the external buffer is <= 115, everything is fine.  Above that, the internal buffer allocates additional storage in 128 byte increments (227, 355, ...), which increases its capacity() beyond its size().  The second step of pubsetbuf() calls _M_sync() to set up the put/get pointers.  However, setp() is then called with the external buffer pointer as the first argument (correct) and ((buffer pointer) + _M_string.capacity()) as the second (incorrect).  This capacity() is greater than the size of the external buffer, so the end put pointer points well past the end of the external buffer.

In the following example, a size of 116 is given to pubsetbuf().  However, the capacity of the internal buffer is 227.  227 'x' chars get written into the external buffer.

#include <iostream>
#include <sstream>

using namespace std;

int main() {
    ostringstream oss;
    char *buf = new char[256];
    memset(buf, 0, sizeof(buf));

    oss.rdbuf()->pubsetbuf(buf, 116);
    cout << "INTERAL BUFF SIZE " << oss.str().size() << " " << oss.str().capacity() << endl;

    for (int i=0; i<1000; i++)
    {
        oss << "x";
    }
    oss.rdbuf()->pubsetbuf(0, 0);

    cout << "EXTNERAL BUFF SIZE " << strlen(buf) << endl;
}


Let me know if I can provide any other info...
Nick
Comment 1 Paolo Carlini 2006-08-17 01:07:54 UTC
Fixed already for gcc4.0.0 with the below: time to update your compiler, the 3.4.x branch is old and not maintained anymore...

2004-10-06  Paolo Carlini  <pcarlini@suse.de>

	* include/std/std_sstream.h (_M_sync): When the caller is
	setbuf, don't trust _M_string.capacity() to be the size of
	the buffer area, use _M_string.size() in this case.
	* testsuite/27_io/basic_stringbuf/setbuf/char/4.cc: New.
	* testsuite/27_io/basic_stringbuf/setbuf/wchar_t/4.cc: Likewise.
Comment 2 Andrew Pinski 2006-08-17 01:11:27 UTC
The other thing is that  sizeof(buf) will get you sizeof(char*) which is most likely not what you wantted anyways.
Comment 3 Nick Gifford 2006-08-17 06:55:58 UTC
Sorry.  I did not know that 3.4 was no longer supported.  I wondered if upgrading to gcc4 would fix it, but was trying to stay in sync with the rest of my group.  But it sounds like upgrading is something we should all do.

Thanks for the prompt response!
Nick
Comment 4 Nick Gifford 2006-08-18 02:52:19 UTC
i guess i'm supposed to verify/close this...