Bug 10975 - [3.4 only] [DR 453] incorrect initial ostringstream::tellp()
Summary: [3.4 only] [DR 453] incorrect initial ostringstream::tellp()
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 3.2.2
: P2 normal
Target Milestone: 3.4.3
Assignee: Paolo Carlini
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-05-26 00:24 UTC by Lawrence D'Oliveiro
Modified: 2004-10-05 19:52 UTC (History)
2 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work:
Known to fail:
Last reconfirmed: 2004-09-30 17:28:30


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Lawrence D'Oliveiro 2003-05-26 00:24:42 UTC
When a new ostringstream object is created but nothing has been written 
to it yet, the tellp() method returns an offset of -1, instead of 0.

Example program:

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>

int main
  (
    int argc,
    const char * const * argv,
    const char * const * envp
  )
  {
    std::ostringstream Stream1;
    std::ofstream Stream2("junk.tmp");
#if 0
    Stream1 << " ";
    Stream2 << " ";
#endif
    std::cout
        << "sstream.tellp() = "
        << Stream1.tellp()
        << ", fstream.tellp() = "
        << Stream2.tellp()
"test.cpp" 27L, 434C written
$ g++ -o test test.cpp
$ less test.cpp
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>

int main
  (
    int argc,
    const char * const * argv,
    const char * const * envp
  )
  {
        std::ostringstream Stream1;
        std::ofstream Stream2("junk.tmp");
#if 0
        Stream1 << " ";
        Stream2 << " ";
#endif
        std::cout
                << "sstream.tellp() = "
                << Stream1.tellp()
                << ", fstream.tellp() = "
                << Stream2.tellp()
                << std::endl;
        return
                0;
  } /*main*/

Output from above:

sstream.tellp() = -1, fstream.tellp() = 0

If you change the "#if 0" line to "#if 1", the output becomes

sstream.tellp() = 1, fstream.tellp() = 1
Comment 1 Andrew Pinski 2003-05-26 00:29:16 UTC
still happens on the mainline (20030525):
tin:~/src/gnu/gcctest>g++ pr10975.cc 
tin:~/src/gnu/gcctest>./a.out 
sstream.tellp() = -1, fstream.tellp() = 0
Comment 2 brendan 2003-07-17 16:19:10 UTC
  The -1 that's being received from tellp() is happening because of what's
  being given back by pubseekoff(); that, in turn, is giving the correct
  value.

  In pubseekoff() it calls this->seekoff(), which in sstream.tcc sets up to
  only do anything if its _M_string.capacity() is > 0.

 template <class _CharT, class _Traits, class _Alloc>
    typename basic_stringbuf<_CharT, _Traits, _Alloc>::pos_type
    basic_stringbuf<_CharT, _Traits, _Alloc>::
    seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
    {
       pos_type __ret =  pos_type(off_type(-1)); 
       //...
       if (_M_string.capacity() && (__testin || __testout || __testboth))
	 {
	 //...
	 }
       return __ret;
    }

  Otherwise the method goes out with the default pos_type value of -1.  (see
  below for a note about this)

  To figure out why we might not have anything allocated for the basic_string
  object being used here, we can to dive head-first into the standard to find
  out about the ostringstream object we're using.

  In $27.7.3 it says that basic_ostringstream uses a basic_stringbuf object to
  control the associated storage.

  Looking up basic_stringbuf, in $27.7.1.1.2/1 it notes that the
  basic_stringbuf default ctor "allocates no array object".  Thus by default,
  the capacity of the string will be 0.

  As such, since there's no space yet for seekoff() to move inside the
  basic_stringbuf, it gives back the -1 value which tellp() relays to the call
  in the testcase.

  Thus I believe the library's actually behaving correctly in this example.

  Hope this helps,
  B

  P.S. The returning of -1 isn't precisely what's said in the current
  published standard.  The library working group's Defect Report 55 as seen in
     http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#55
  adjusts the standard after the fact to say in 27.7.1.3 paragraph 13 about
  basic_stringbuf's seekoff() method:
      the return value is pos_type(off_type(-1))
  instead of
      the object stores an invalid stream position
  That DR was just a clarification across the board, and isn't really a part
  of this issue.

Comment 3 Lawrence D'Oliveiro 2003-07-18 08:58:41 UTC
brendan@zen.org wrote:

>As such, since there's no space yet for seekoff() to move inside the
>basic_stringbuf, it gives back the -1 value which tellp() relays to the call
>in the testcase.

That's an implementation issue. I don't see why such implementation 
issues should cause a difference in the semantics. Consider: the 
ostream object is fully initialized and ready for use. Nothing has been 
written to it yet. Therefore the output position should be 0. This is true if 
output is going to a file, why shouldn't it be true for output going to a 
string?
Comment 4 Jerry Quinn 2003-12-30 22:16:28 UTC
(In reply to comment #3) 
> That's an implementation issue. I don't see why such implementation 
> issues should cause a difference in the semantics. Consider: the 
> ostream object is fully initialized and ready for use. Nothing has been 
> written to it yet. Therefore the output position should be 0. This is true if 
> output is going to a file, why shouldn't it be true for output going to a 
> string?

Unfortunately this isn't an implementation issue.  Consider the following
according to the standard:

For ofstream:

ofstream os("junk");
os.tellp();

1) ofstream(const char*) constructs a basic_filebuf and opens "junk"
2) ofstream::tellp() returns rdbuf()->pubseekoff(0, cur, out)
3) basic_streambuf::pubseekoff(0, cur, out) returns basic_filebuf::seekoff(0,
cur, out)
4) basic_filebuf::seekoff(0, cur, out) does:
 width = codecvt.encoding()
 if !is_open() return -1
 std::fseek(file, 0, cur)
 return new position [which is 0]

Now consider ostringstream:

ostringstream os;
os.tellp();

1) ostringstream() constructs basic_stringbuf.
2) basic_stringbuf() constructs basic_streambuf but allocates no array object
 and sets pointers to null.
3) ostringstream::tellp() returns basic_streambuf::pubseekoff(0, cur, out)
4) basic_streambuf::pubseekoff(0, cur, out) returns
 basic_stringbuf::seekoff(0, cur, out)
5) basic_stringbuf::seekoff(0, cur, out) does:
 if pptr() == null return -1

Since the basic_stringbuf has no array object yet and its pointers are null,
basic_streambuf::pptr() returns null, and the final return value must be -1.

FWIW, I agree this is less than intuitive, but seems correct according to the
standard.
Comment 5 ncm-nospam@cantrip.org 2004-01-02 02:12:13 UTC
This is pretty clearly a defect in the standard.  I have asked Matt Austern
to open an issue on the Library Working Group issues list.  We probably
should keep this open until that issue has been looked at by the LWG.
I'd like to Do The Right Thing as soon as it looks like we can justify it.
Comment 6 Andrew Pinski 2004-01-02 02:36:23 UTC
Suspending while a DR is being filed and open.
Comment 7 Andrew Pinski 2004-04-18 02:22:33 UTC
unsuspended on accident.
Comment 8 Dan Greening 2004-05-28 13:27:19 UTC
I can reconfirm this bug is still present in gcc 3.3.1 running on Cygwin.

I think a related problem:  It turns out tellp() remains negative if the program
opens a non-existant file with ios::trunc|ios::in|ios::out|ios::bin, then did a
few binary writes.

Very annoying.
Comment 9 Paolo Carlini 2004-08-05 11:50:18 UTC
This is now DR 453 (Open):

  http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#453
Comment 10 GCC Commits 2004-09-30 17:23:24 UTC
Subject: Bug 10975

CVSROOT:	/cvs/gcc
Module name:	gcc
Changes by:	paolo@gcc.gnu.org	2004-09-30 17:23:11

Modified files:
	libstdc++-v3   : ChangeLog 
	libstdc++-v3/include/bits: sstream.tcc 
	libstdc++-v3/docs/html/ext: howto.html 
	libstdc++-v3/testsuite/27_io/basic_istream/tellg/char: 1.cc 
	libstdc++-v3/testsuite/27_io/basic_ostream/tellp/char: 1.cc 2.cc 
Added files:
	libstdc++-v3/testsuite/27_io/basic_ostream/seekp/char: 
	                                                       2346-fstream.cc 
	                                                       2346-sstream.cc 
	libstdc++-v3/testsuite/27_io/basic_stringbuf/seekoff/char: 
	                                                           10975.cc 
	libstdc++-v3/testsuite/27_io/basic_stringbuf/seekoff/wchar_t: 
	                                                              10975.cc 
Removed files:
	libstdc++-v3/testsuite/27_io/basic_istream/seekg/char: 
	                                                       2346-fstream.cc 
	                                                       2346-sstream.cc 

Log message:
	2004-09-30  Paolo Carlini  <pcarlini@suse.de>
	
	PR libstdc++/10975 (DR 453)
	* include/bits/sstream.tcc (seekoff): Don't fail if __beg == 0
	and __off == 0.
	* docs/html/ext/howto.html: Add an entry for DR 453.
	* testsuite/27_io/basic_stringbuf/seekoff/char/10975.cc: New.
	* testsuite/27_io/basic_stringbuf/seekoff/wchar_t/10975.cc: Likewise.
	* testsuite/27_io/basic_istream/tellg/char/1.cc: Tweak consistently.
	* testsuite/27_io/basic_ostream/tellp/char/1.cc: Likewise.
	* testsuite/27_io/basic_ostream/tellp/char/2.cc: Likewise.
	* testsuite/27_io/basic_istream/seekg/char/2346-fstream.cc: Fix and
	move to...
	* testsuite/27_io/basic_istream/seekp/char/2346-fstream.cc: ... here.
	* testsuite/27_io/basic_istream/seekg/char/2346-sstream.cc: Fix and
	move to...
	* testsuite/27_io/basic_istream/seekp/char/2346-sstream.cc: ... here.

Patches:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/ChangeLog.diff?cvsroot=gcc&r1=1.2674&r2=1.2675
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/include/bits/sstream.tcc.diff?cvsroot=gcc&r1=1.42&r2=1.43
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/docs/html/ext/howto.html.diff?cvsroot=gcc&r1=1.50&r2=1.51
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_istream/seekg/char/2346-fstream.cc.diff?cvsroot=gcc&r1=1.3&r2=NONE
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_istream/seekg/char/2346-sstream.cc.diff?cvsroot=gcc&r1=1.3&r2=NONE
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_istream/tellg/char/1.cc.diff?cvsroot=gcc&r1=1.2&r2=1.3
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_ostream/seekp/char/2346-fstream.cc.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_ostream/seekp/char/2346-sstream.cc.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_ostream/tellp/char/1.cc.diff?cvsroot=gcc&r1=1.2&r2=1.3
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_ostream/tellp/char/2.cc.diff?cvsroot=gcc&r1=1.2&r2=1.3
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_stringbuf/seekoff/char/10975.cc.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_stringbuf/seekoff/wchar_t/10975.cc.diff?cvsroot=gcc&r1=NONE&r2=1.1

Comment 11 GCC Commits 2004-10-05 19:50:15 UTC
Subject: Bug 10975

CVSROOT:	/cvs/gcc
Module name:	gcc
Branch: 	gcc-3_4-branch
Changes by:	paolo@gcc.gnu.org	2004-10-05 19:50:03

Modified files:
	libstdc++-v3   : ChangeLog 
	libstdc++-v3/docs/html/ext: howto.html 
	libstdc++-v3/include/bits: sstream.tcc 
	libstdc++-v3/testsuite/27_io/basic_istream/tellg/char: 1.cc 
	libstdc++-v3/testsuite/27_io/basic_ostream/tellp/char: 1.cc 2.cc 
Added files:
	libstdc++-v3/testsuite/27_io/basic_ostream/seekp/char: 
	                                                       2346-fstream.cc 
	                                                       2346-sstream.cc 
	libstdc++-v3/testsuite/27_io/basic_stringbuf/seekoff/char: 
	                                                           10975.cc 
Removed files:
	libstdc++-v3/testsuite/27_io/basic_istream/seekg/char: 
	                                                       2346-fstream.cc 
	                                                       2346-sstream.cc 

Log message:
	2004-10-05  Paolo Carlini  <pcarlini@suse.de>
	
	PR libstdc++/10975 (DR 453)
	* include/bits/sstream.tcc (seekoff): Don't fail if __beg == 0
	and __off == 0.
	* docs/html/ext/howto.html: Add an entry for DR 453.
	* testsuite/27_io/basic_stringbuf/seekoff/char/10975.cc: New.
	* testsuite/27_io/basic_istream/tellg/char/1.cc: Tweak consistently.
	* testsuite/27_io/basic_ostream/tellp/char/1.cc: Likewise.
	* testsuite/27_io/basic_ostream/tellp/char/2.cc: Likewise.
	* testsuite/27_io/basic_istream/seekg/char/2346-fstream.cc: Fix and
	move to...
	* testsuite/27_io/basic_istream/seekp/char/2346-fstream.cc: ... here.
	* testsuite/27_io/basic_istream/seekg/char/2346-sstream.cc: Fix and
	move to...
	* testsuite/27_io/basic_istream/seekp/char/2346-sstream.cc: ... here.

Patches:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.2224.2.185&r2=1.2224.2.186
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/docs/html/ext/howto.html.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.42.4.6&r2=1.42.4.7
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/include/bits/sstream.tcc.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.37.4.4&r2=1.37.4.5
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_istream/seekg/char/2346-fstream.cc.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.3&r2=NONE
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_istream/seekg/char/2346-sstream.cc.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.3&r2=NONE
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_istream/tellg/char/1.cc.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.2&r2=1.2.12.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_ostream/seekp/char/2346-fstream.cc.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.10.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_ostream/seekp/char/2346-sstream.cc.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.10.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_ostream/tellp/char/1.cc.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.2&r2=1.2.12.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_ostream/tellp/char/2.cc.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.2&r2=1.2.12.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc++-v3/testsuite/27_io/basic_stringbuf/seekoff/char/10975.cc.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.10.1

Comment 12 Paolo Carlini 2004-10-05 19:52:28 UTC
Fixed for 3.4.3.