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.
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; }
Yes, but there is nothing we can do as libstdc++ project, this is the ISO Standard: see 27.5.2.
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?
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)
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).
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.
Actually, fixing strstream too is easy, because it derives from basic_streambuf<char>, which can be assumed to have __safe_pbump
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
Fixed for 4.6.0.