re PR libstdc++/12875 (Weird behaviour in basic_filebuf::setbuf())

2003-11-11  Paolo Carlini  <pcarlini@suse.de>

	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
This commit is contained in:
Paolo Carlini 2003-11-12 01:14:34 +00:00 committed by Paolo Carlini
parent a5966c9ef9
commit dfad48c6e8
7 changed files with 155 additions and 40 deletions

View File

@ -1,3 +1,17 @@
2003-11-11 Paolo Carlini <pcarlini@suse.de>
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 <gregod@cs.rpi.edu> 2003-11-11 Doug Gregor <gregod@cs.rpi.edu>
* docs/html/debug.html: Document libstdc++ debug mode. * docs/html/debug.html: Document libstdc++ debug mode.

View File

@ -44,15 +44,15 @@ namespace std
basic_filebuf<_CharT, _Traits>:: basic_filebuf<_CharT, _Traits>::
_M_allocate_internal_buffer() _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]; this->_M_buf = new char_type[this->_M_buf_size];
_M_buf_allocated = true; _M_buf_allocated = true;
} }
} }
// Both close and setbuf need to deallocate internal buffers, if it exists.
template<typename _CharT, typename _Traits> template<typename _CharT, typename _Traits>
void void
basic_filebuf<_CharT, _Traits>:: basic_filebuf<_CharT, _Traits>::
@ -213,8 +213,8 @@ namespace std
else else
{ {
// Worst-case number of external bytes. // Worst-case number of external bytes.
// XXX Not done encoding() == -1. // XXX Not done encoding() == -1.
const int __enc = _M_codecvt->encoding(); const int __enc = _M_codecvt->encoding();
streamsize __blen; // Minimum buffer size. streamsize __blen; // Minimum buffer size.
streamsize __rlen; // Number of chars to read. streamsize __rlen; // Number of chars to read.
if (__enc > 0) if (__enc > 0)
@ -539,29 +539,22 @@ namespace std
basic_filebuf<_CharT, _Traits>:: basic_filebuf<_CharT, _Traits>::
setbuf(char_type* __s, streamsize __n) setbuf(char_type* __s, streamsize __n)
{ {
if (!this->is_open() && __s == 0 && __n == 0) if (!this->is_open())
this->_M_buf_size = 1; if (__s == 0 && __n == 0)
else if (__s && __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 // This is implementation-defined behavior, and assumes that
// been pre-allocated. If this is not the case, things will // an external char_type array of length __n exists and has
// quickly blow up. When __n > 1, __n - 1 positions will be // been pre-allocated. If this is not the case, things will
// used for the get area, __n - 1 for the put area and 1 // quickly blow up. When __n > 1, __n - 1 positions will be
// position to host the overflow char of a full put area. // used for the get area, __n - 1 for the put area and 1
// When __n == 1, 1 position will be used for the get area // position to host the overflow char of a full put area.
// and 0 for the put area, as in the unbuffered case above. // 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. this->_M_buf = __s;
_M_destroy_internal_buffer(); this->_M_buf_size = __n;
}
// 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);
}
return this; return this;
} }

View File

@ -66,9 +66,7 @@ namespace __gnu_cxx
* @param fd An open file descriptor. * @param fd An open file descriptor.
* @param mode Same meaning as in a standard filebuf. * @param mode Same meaning as in a standard filebuf.
* @param del Whether to close the file on destruction. * @param del Whether to close the file on destruction.
* @param size Optimal or preferred size of internal buffer, in bytes. * @param size Optimal or preferred size of internal buffer, in chars.
* Note that it includes a position for the overflow char,
* therefore, can't be smaller than 2.
* *
* This constructor associates a file stream buffer with an open * This constructor associates a file stream buffer with an open
* POSIX file descriptor. Iff @a del is true, then the associated * 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 f An open @c FILE*.
* @param mode Same meaning as in a standard filebuf. * @param mode Same meaning as in a standard filebuf.
* @param size Optimal or preferred size of internal buffer, in bytes. * @param size Optimal or preferred size of internal buffer, in chars.
* Defaults to system's @c BUFSIZ. Note that it includes * Defaults to system's @c BUFSIZ.
* a position for the overflow char, therefore, can't be
* smaller than 2.
* *
* This constructor associates a file stream buffer with an open * This constructor associates a file stream buffer with an open
* C @c FILE*. The @c FILE* will not be automatically closed when the * C @c FILE*. The @c FILE* will not be automatically closed when the

View File

@ -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 <fstream>
#include <cstdio>
#include <cstring>
#include <testsuite_hooks.h>
// 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;
}

View File

@ -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 <fstream>
#include <cstdio>
#include <cstring>
#include <testsuite_hooks.h>
// 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;
}

View File

@ -32,8 +32,8 @@ void test01()
const char* strlit = "how to tell a story and other essays: mark twain"; const char* strlit = "how to tell a story and other essays: mark twain";
const size_t strlitsize = std::strlen(strlit); const size_t strlitsize = std::strlen(strlit);
filebuf fbuf; filebuf fbuf;
fbuf.open("tmp_setbuf2", ios_base::out);
fbuf.pubsetbuf(buf, 512); fbuf.pubsetbuf(buf, 512);
fbuf.open("tmp_setbuf2", ios_base::out);
fbuf.sputn(strlit, strlitsize); fbuf.sputn(strlit, strlitsize);
VERIFY( std::strncmp(strlit, buf, strlitsize) == 0 ); VERIFY( std::strncmp(strlit, buf, strlitsize) == 0 );
} }

View File

@ -23,7 +23,7 @@
#include <fstream> #include <fstream>
#include <testsuite_hooks.h> #include <testsuite_hooks.h>
void test02() void test03()
{ {
using namespace std; using namespace std;
@ -32,17 +32,17 @@ void test02()
const char* strlit = "how to tell a story and other essays: mark twain"; const char* strlit = "how to tell a story and other essays: mark twain";
const size_t strlitsize = std::strlen(strlit); const size_t strlitsize = std::strlen(strlit);
filebuf fbuf01; filebuf fbuf01;
fbuf01.open("tmp", ios_base::out);
// NB: +2 otherwise sputn is optimized to a direct write, // NB: +2 otherwise sputn is optimized to a direct write,
// bypassing the buffer. // bypassing the buffer.
fbuf01.pubsetbuf(buf, strlitsize + 2); fbuf01.pubsetbuf(buf, strlitsize + 2);
fbuf01.open("tmp_setbuf3", ios_base::out);
fbuf01.sputn(strlit, strlitsize); fbuf01.sputn(strlit, strlitsize);
VERIFY( std::strncmp(strlit, buf, strlitsize) == 0 ); VERIFY( std::strncmp(strlit, buf, strlitsize) == 0 );
} }
int main() int main()
{ {
test02(); test03();
return 0; return 0;
} }