Bug 47921 - pbump will overflow when input n is larger than 2G-1
Summary: pbump will overflow when input n is larger than 2G-1
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.1.2
: P3 normal
Target Milestone: 4.6.0
Assignee: Paolo Carlini
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-02-28 10:47 UTC by Robert Python
Modified: 2011-02-28 23:54 UTC (History)
1 user (show)

See Also:
Host:
Target: x86_64-redhat-linux
Build: gcc version 4.1.2 20071124 (Red Hat 4.1.2-42)
Known to work:
Known to fail:
Last reconfirmed: 2011-02-28 13:09:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Robert Python 2011-02-28 10:47:52 UTC
in function int basic_streambuf::pbump(int n), n is a int which is easily overflow in 64bit environment, especially when it is called in overflow function.
Comment 1 Robert Python 2011-02-28 10:51:30 UTC
try below program in a 64bit environment with about 8G memory:

#include <string>
#include <strstream>
#include <iostream>

#define N 100000000
#define SIZE 40

using namespace std;

int main()
{
        const char msg[SIZE] = "aaaaaaaaaaaaaaaaaaaaaaaaaaa";
        strstreambuf *new_data = new strstreambuf();
        for (int i = 0; i < N; ++i)
        {
                new_data->freeze(false);
                new_data->sputn(msg, SIZE);
        }

        delete new_data;
        return 0;
}
Comment 2 Paolo Carlini 2011-02-28 11:13:55 UTC
Yes, but there is nothing we can do as libstdc++ project, this is the ISO Standard: see 27.5.2.
Comment 3 Jonathan Wakely 2011-02-28 12:36:28 UTC
We can't change the signature of pbump, but that doesn't mean we have to call it with values that cause overflow. Could we add a safe_pbump(streamsize n) which calls pbump in a loop so it doesn't call it with a value outside the range of an int?
Comment 4 Jonathan Wakely 2011-02-28 12:43:41 UTC
something like this (untested)

--- include/std/streambuf.orig  2011-02-28 12:40:44.559350898 +0000
+++ include/std/streambuf       2011-02-28 12:32:20.445685621 +0000
@@ -38,6 +38,7 @@

 #include <bits/c++config.h>
 #include <iosfwd>
+#include <limits>
 #include <bits/localefwd.h>
 #include <bits/ios_base.h>
 #include <bits/cpp_type_traits.h>
--- include/bits/streambuf.tcc.orig     2011-02-28 12:40:35.554301020 +0000
+++ include/bits/streambuf.tcc  2011-02-28 12:42:30.761788519 +0000
@@ -91,6 +91,11 @@
              traits_type::copy(this->pptr(), __s, __len);
              __ret += __len;
              __s += __len;
+             while (__len > std::numeric_limits<int>::max())
+               {
+                 this->pbump(std::numeric_limits<int>::max());
+                 __len -= std::numeric_limits<int>::max();
+               }
              this->pbump(__len);
            }

--- src/strstream.cc.orig       2011-02-28 12:40:25.373244770 +0000
+++ src/strstream.cc    2011-02-28 12:42:10.945712166 +0000
@@ -161,6 +161,11 @@
              }

            setp(buf, buf + new_size);
+           while (old_size > INT_MAX)
+           {
+             this->pbump(INT_MAX);
+             old_size -= INT_MAX;
+           }
            pbump(old_size);

            if (reposition_get)
Comment 5 Paolo Carlini 2011-02-28 13:01:16 UTC
This is a different issue. Anyway, concentrating on basic_streambuf<>::xsputn (I don't think we should fiddle that late with the deprecated strstream), note that __len is smaller than __buf_len, and typically __buf_len ~= 8192. Thus I would consider the problem rather minor. Anyway, I'm in favor of something like your first hunk, with a comment before about streamsize == ptrdiff_t, and using __gnu_cxx::__numeric_traits<int>::__max instead (thus avoiding bringing in the whole <limits>).

Probably we used to be not careful enough in xsputn because streamsize is (was) normally 32 bits on 32-bit machines (being ptrdiff_t).
Comment 6 Paolo Carlini 2011-02-28 13:09:00 UTC
Ok, let me handle this, we have another couple unsafe on 64-bit uses in sstream.tcc. Note, in general we can't rely on additional member functions being available in basic_streambuf, can be specialized.
Comment 7 Paolo Carlini 2011-02-28 14:11:39 UTC
Actually, fixing strstream too is easy, because it derives from basic_streambuf<char>, which can be assumed to have __safe_pbump
Comment 8 paolo@gcc.gnu.org 2011-02-28 23:51:02 UTC
Author: paolo
Date: Mon Feb 28 23:50:57 2011
New Revision: 170579

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=170579
Log:
2011-02-28  Paolo Carlini  <paolo.carlini@oracle.com>

	PR libstdc++/47921
	* include/std/streambuf (basic_streambuf<>::__safe_gbump,
	__safe_pbump): Add.
	* include/bits/streambuf.tcc (basic_streambuf<>::xgetn,
	xputn): Use the latter.
	* include/bits/streambuf_iterator.h: Likewise.
	* src/strstream.cc: Likewise.
	* src/streambuf.cc: Likewise.
	* src/compatibility.cc: Likewise.
	* src/istream.cc: Likewise.
	* include/bits/fstream.tcc (basic_filebuf<>::xsgetn): Use setg
	instead of gbump.
	* include/std/sstream (basic_stringbuf<>::_M_pbump): Add.
	* include/bits/sstream.tcc (basic_stringbuf<>::seekoff,
	seekpos, _M_sync): Use setg, setp, and _M_pbump.
	* config/abi/pre/gnu.ver: Tweak.


Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/config/abi/pre/gnu.ver
    trunk/libstdc++-v3/include/bits/fstream.tcc
    trunk/libstdc++-v3/include/bits/sstream.tcc
    trunk/libstdc++-v3/include/bits/streambuf.tcc
    trunk/libstdc++-v3/include/bits/streambuf_iterator.h
    trunk/libstdc++-v3/include/std/sstream
    trunk/libstdc++-v3/include/std/streambuf
    trunk/libstdc++-v3/src/compatibility.cc
    trunk/libstdc++-v3/src/istream.cc
    trunk/libstdc++-v3/src/streambuf.cc
    trunk/libstdc++-v3/src/strstream.cc
Comment 9 Paolo Carlini 2011-02-28 23:54:34 UTC
Fixed for 4.6.0.