From dfad48c6e89fcfed91f31f3a23b4c904a7455d11 Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Wed, 12 Nov 2003 01:14:34 +0000 Subject: [PATCH] re PR libstdc++/12875 (Weird behaviour in basic_filebuf::setbuf()) 2003-11-11 Paolo Carlini PR libstdc++/12875 * include/bits/fstream.tcc (setbuf): Don't do anything after open(), in particular don't discard data. (_M_allocate_internal_buffer): Tweak to not allocate memory in case the buffer is provided by the user via setbuf. * include/ext/stdio_filebuf.h: Tweak comment. * testsuite/27_io/basic_filebuf/setbuf/char/12875-1.cc: New. * testsuite/27_io/basic_filebuf/setbuf/char/12875-2.cc: Likewise. * testsuite/27_io/basic_filebuf/setbuf/char/2.cc: Tweak, now setbuf does nothing after open(). * testsuite/27_io/basic_filebuf/setbuf/char/3.cc: Likewise. From-SVN: r73477 --- libstdc++-v3/ChangeLog | 14 +++++ libstdc++-v3/include/bits/fstream.tcc | 49 +++++++--------- libstdc++-v3/include/ext/stdio_filebuf.h | 10 +--- .../basic_filebuf/setbuf/char/12875-1.cc | 57 +++++++++++++++++++ .../basic_filebuf/setbuf/char/12875-2.cc | 55 ++++++++++++++++++ .../27_io/basic_filebuf/setbuf/char/2.cc | 2 +- .../27_io/basic_filebuf/setbuf/char/3.cc | 8 +-- 7 files changed, 155 insertions(+), 40 deletions(-) create mode 100644 libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/12875-1.cc create mode 100644 libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/12875-2.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 1df66abe038..791cee3e85f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,17 @@ +2003-11-11 Paolo Carlini + + PR libstdc++/12875 + * include/bits/fstream.tcc (setbuf): Don't do anything + after open(), in particular don't discard data. + (_M_allocate_internal_buffer): Tweak to not allocate memory + in case the buffer is provided by the user via setbuf. + * include/ext/stdio_filebuf.h: Tweak comment. + * testsuite/27_io/basic_filebuf/setbuf/char/12875-1.cc: New. + * testsuite/27_io/basic_filebuf/setbuf/char/12875-2.cc: Likewise. + * testsuite/27_io/basic_filebuf/setbuf/char/2.cc: Tweak, now + setbuf does nothing after open(). + * testsuite/27_io/basic_filebuf/setbuf/char/3.cc: Likewise. + 2003-11-11 Doug Gregor * docs/html/debug.html: Document libstdc++ debug mode. diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc index 56497412fce..a2daab54761 100644 --- a/libstdc++-v3/include/bits/fstream.tcc +++ b/libstdc++-v3/include/bits/fstream.tcc @@ -44,15 +44,15 @@ namespace std basic_filebuf<_CharT, _Traits>:: _M_allocate_internal_buffer() { - if (!_M_buf_allocated && this->_M_buf_size) + // Allocate internal buffer only if one doesn't already exist + // (either allocated or provided by the user via setbuf). + if (!_M_buf_allocated && !this->_M_buf) { - // Allocate internal buffer. this->_M_buf = new char_type[this->_M_buf_size]; _M_buf_allocated = true; } } - // Both close and setbuf need to deallocate internal buffers, if it exists. template void basic_filebuf<_CharT, _Traits>:: @@ -213,8 +213,8 @@ namespace std else { // Worst-case number of external bytes. - // XXX Not done encoding() == -1. - const int __enc = _M_codecvt->encoding(); + // XXX Not done encoding() == -1. + const int __enc = _M_codecvt->encoding(); streamsize __blen; // Minimum buffer size. streamsize __rlen; // Number of chars to read. if (__enc > 0) @@ -539,29 +539,22 @@ namespace std basic_filebuf<_CharT, _Traits>:: setbuf(char_type* __s, streamsize __n) { - if (!this->is_open() && __s == 0 && __n == 0) - this->_M_buf_size = 1; - else if (__s && __n > 0) - { - // This is implementation-defined behavior, and assumes that - // an external char_type array of length __n exists and has - // been pre-allocated. If this is not the case, things will - // quickly blow up. When __n > 1, __n - 1 positions will be - // used for the get area, __n - 1 for the put area and 1 - // position to host the overflow char of a full put area. - // When __n == 1, 1 position will be used for the get area - // and 0 for the put area, as in the unbuffered case above. - - // Step 1: Destroy the current internal array. - _M_destroy_internal_buffer(); - - // Step 2: Use the external array. - this->_M_buf = __s; - this->_M_buf_size = __n; - _M_reading = false; - _M_writing = false; - _M_set_buffer(-1); - } + if (!this->is_open()) + if (__s == 0 && __n == 0) + this->_M_buf_size = 1; + else if (__s && __n > 0) + { + // This is implementation-defined behavior, and assumes that + // an external char_type array of length __n exists and has + // been pre-allocated. If this is not the case, things will + // quickly blow up. When __n > 1, __n - 1 positions will be + // used for the get area, __n - 1 for the put area and 1 + // position to host the overflow char of a full put area. + // When __n == 1, 1 position will be used for the get area + // and 0 for the put area, as in the unbuffered case above. + this->_M_buf = __s; + this->_M_buf_size = __n; + } return this; } diff --git a/libstdc++-v3/include/ext/stdio_filebuf.h b/libstdc++-v3/include/ext/stdio_filebuf.h index 8750f5801e3..9e04807b33e 100644 --- a/libstdc++-v3/include/ext/stdio_filebuf.h +++ b/libstdc++-v3/include/ext/stdio_filebuf.h @@ -66,9 +66,7 @@ namespace __gnu_cxx * @param fd An open file descriptor. * @param mode Same meaning as in a standard filebuf. * @param del Whether to close the file on destruction. - * @param size Optimal or preferred size of internal buffer, in bytes. - * Note that it includes a position for the overflow char, - * therefore, can't be smaller than 2. + * @param size Optimal or preferred size of internal buffer, in chars. * * This constructor associates a file stream buffer with an open * POSIX file descriptor. Iff @a del is true, then the associated @@ -80,10 +78,8 @@ namespace __gnu_cxx /** * @param f An open @c FILE*. * @param mode Same meaning as in a standard filebuf. - * @param size Optimal or preferred size of internal buffer, in bytes. - * Defaults to system's @c BUFSIZ. Note that it includes - * a position for the overflow char, therefore, can't be - * smaller than 2. + * @param size Optimal or preferred size of internal buffer, in chars. + * Defaults to system's @c BUFSIZ. * * This constructor associates a file stream buffer with an open * C @c FILE*. The @c FILE* will not be automatically closed when the diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/12875-1.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/12875-1.cc new file mode 100644 index 00000000000..5013b87fcf9 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/12875-1.cc @@ -0,0 +1,57 @@ +// Copyright (C) 2003 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// 27.8.1.4 Overridden virtual functions + +#include +#include +#include +#include + +// libstdc++/12875 +void test01() +{ + using namespace std; + bool test __attribute__((unused)) = true; + + const char* name = "tmp_setbuf4"; + static char buf[1024]; + + FILE* out = fopen(name, "w"); + fputs("Hello, world", out); + fclose(out); + + filebuf in; + in.open(name, ios_base::in); + char str[256]; + streamsize r = in.sgetn(str, 6); + VERIFY( r == 6 ); + VERIFY( !memcmp(str, "Hello,", 6) ); + in.pubsetbuf(buf, 1024); + r = in.sgetn(str, 6); + VERIFY( r == 6 ); + VERIFY( !memcmp(str, " world", 6) ); + in.close(); +} + +// libstdc++/12875 +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/12875-2.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/12875-2.cc new file mode 100644 index 00000000000..c50a5ed4a12 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/12875-2.cc @@ -0,0 +1,55 @@ +// Copyright (C) 2003 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// 27.8.1.4 Overridden virtual functions + +#include +#include +#include +#include + +// libstdc++/12875 +void test02() +{ + using namespace std; + bool test __attribute__((unused)) = true; + + const char* name = "tmp_setbuf5"; + static char buf[1024]; + + filebuf out; + out.open(name, ios_base::out); + streamsize r = out.sputn("Hello,", 6); + VERIFY( r == 6 ); + out.pubsetbuf(buf, 1024); + r = out.sputn(" world", 6); + VERIFY( r == 6 ); + VERIFY( out.close() ); + + FILE* in = fopen(name, "r"); + char str[256]; + fgets(str, 256, in); + VERIFY( !strcmp(str, "Hello, world") ); + fclose(in); +} + +int main() +{ + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/2.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/2.cc index 7cca957e17f..524935a1c84 100644 --- a/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/2.cc +++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/2.cc @@ -32,8 +32,8 @@ void test01() const char* strlit = "how to tell a story and other essays: mark twain"; const size_t strlitsize = std::strlen(strlit); filebuf fbuf; - fbuf.open("tmp_setbuf2", ios_base::out); fbuf.pubsetbuf(buf, 512); + fbuf.open("tmp_setbuf2", ios_base::out); fbuf.sputn(strlit, strlitsize); VERIFY( std::strncmp(strlit, buf, strlitsize) == 0 ); } diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/3.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/3.cc index b5512d76534..11702dc0336 100644 --- a/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/3.cc +++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/3.cc @@ -23,7 +23,7 @@ #include #include -void test02() +void test03() { using namespace std; @@ -32,17 +32,17 @@ void test02() const char* strlit = "how to tell a story and other essays: mark twain"; const size_t strlitsize = std::strlen(strlit); filebuf fbuf01; - fbuf01.open("tmp", ios_base::out); - // NB: +2 otherwise sputn is optimized to a direct write, // bypassing the buffer. fbuf01.pubsetbuf(buf, strlitsize + 2); + fbuf01.open("tmp_setbuf3", ios_base::out); + fbuf01.sputn(strlit, strlitsize); VERIFY( std::strncmp(strlit, buf, strlitsize) == 0 ); } int main() { - test02(); + test03(); return 0; }