Weird g++/stdio bug

Weird g++/stdio bug

Post by Igor Shpigelm » Wed, 15 May 1996 04:00:00



Hi, all.

I have discovered a really weird problem with g++/stdio on linux.
First, some background.

CharFile and CharIO classes are implementations of an exercise from
B.Stroustrup. In short, they treat
   a[i] = b[j];
as "take j-th byte from file opened as 'b' instance and write it to
i-th byte of file, opened as 'a' instance".

The first implementation (CharFile) uses stdio, the second (CharIO)
uses iostream. The first (and original) one was written and tested
under SCO UNIX with gcc2.5.8 using native SCO libc, and libg++?.?.?
No problems were ever encountered.

Under Linux, it would die complitely on gcc2.6.3 (well, broken iostream?)
but, with gcc2.7.0/libc5.0.9/libg++?.?.?, which can produce
mixed stdio/iostream output without any problems (I'm using RedHat2.1),
my CharFile still bombs whereas CharIO works.

Corey Brenner and Mike Romberg in the responce to my followup to
"No output from c++ program", suggested that I (and original poster?)
used the newest gcc2.7.2/libc5.3.12/libg2.7.1.4 which I did,
(Many thanks, guys!), however, =my= bug was still there ...

Ok, here is the output of the test runs of CharFile and FileIO.
Note, that as the result of the run the file 'bar' must be identical
to the file 'foo', which didn't happen in case of CharFile.

And some answers to the questions likely to come:
1. Yes, as I said, CharFile worked perfectly well at least on one system.
2. Yes, SEEK_SET is defined 0 in unistd.h and stdio.h.
3. No, fgetc and fputc are not implemented as macros.
4. 'close: invalid argument' comes from the second file 'bar'.
5. Kernel 1.2.13 (ELF), RedHat 2.1, packages used:
        gcc272-no-sr-bug.lbin.tgz
        libc-5.3.12.bin.tar.gz
        libg++-2.7.1.4.bin.tar.gz

And here, finally, the typescript file:

Script started on Mon May 13 23:20:44 1996
$ cat CharFile.h

// Description: in a[i] = b[j] to read j-th byte from b
//    and write io i-th of a;
//    accept a[i] = 'c' and char c = b[i];
// See also:  B.Stroustrup, C++, 2nd edition, p. 359.

#include <stdio.h>
#include <stdlib.h>

class CharFile {
   FILE *fp;
public:
   CharFile(const char* fname, const char* mode = "r+")
      { if ((fp = fopen(fname, mode)) == NULL) perror( "open" ); }
   ~CharFile()
      { if (fclose(fp)) perror( "close" ); }
   CharFile& operator[](int i)
      { if (fseek(fp, i, 0)) perror( "fseek" ); return *this; }
   char operator=(char c)
      { if (c) fputc(c, fp); return c; }
   operator char()
      { int c = fgetc(fp); return (c == EOF) ? 0 : c; }

Quote:};

$ cat testFile.C
#include "CharFile.h"

int main(int argc, char *argv[])
{
  CharFile a( argv[1] ), b( argv[2] );

  for (int i = 0; b[i] = a[i]; i++)
    ;

Quote:}

$ c++ testFile.C -o testFile
$ echo 0123456789 >foo
$ echo XXXXXXXXXX >bar
$ testFile foo bar
close: Invalid argument
$ cat foo
0123456789
$ cat bar
XXXXXXXXXX
$ cat CharIO.h

// Description: in a[i] = b[j] to read j-th byte from b
//        and write io i-th of a;
//        accept a[i] = 'c' and char c = b[i];
// Notes:   This is a new, kosher implementation of CharFile.h
//        which uses only C++ i/o.
//        Not that I'm so much into purism, it's just that
//        my gcc-2.6.3 goes wild on any C i/o in C++ code.
// See also:  B.Stroustrup, C++, 2nd edition, p. 359.

#include <fstream.h>

class CharIO {
  fstream fp;
  long pos;

public:
  CharIO( const char* fname )
    { fp.open( fname, ios::in | ios::out ); }
  ~CharIO()
    { fp.close(); }
  CharIO& operator[]( int i )
    { pos = i; return *this; }
  char operator=( char c )
    { fp.seekp( pos, ios::beg ); if ( c ) fp.put( c ); return ( c ); }
  operator char()
    { fp.seekg( pos, ios::beg ); char c = 0; fp.get( c ); return ( c ); }

Quote:};

$ cat testIO.C
#include "CharIO.h"

int main(int argc, char *argv[])
{
  CharIO a( argv[1] ), b( argv[2] );

  for (int i = 0; b[i] = a[i]; i++)
    ;

Quote:}

$ c++ testIO.C -o testIO
$ cat foo
0123456789
$ cat bar
XXXXXXXXXX
$ testIO foo bar
$ cat foo
0123456789
$ cat bar
0123456789
$ exit
Script done on Mon May 13 23:24:49 1996

Thanks for your patience, guys :-)

--

    Igor Shpigelman               "The opposite of a profound truth

 
 
 

Weird g++/stdio bug

Post by Igor Shpigelm » Wed, 15 May 1996 04:00:00


I've got a reply from Hansel Kwok, which solves the question opened
in the original post completely.

Shortly, it has proven to be my screw-up.

And here is the reply:

Hansel Kwok wrote:

> Simple bug... :)

> I had your programs complied and got exactly
> what you had.

> ------------------------------------------------------------------------
> Script started on Tue May 14 14:50:21 1996
> (1) uranus% cat testFile.C
> #include <stdio.h>
> #include <stdlib.h>

> class CharFile {
>    FILE *fp;
> public:
>    CharFile(const char* fname, const char* mode = "r+")
>       { if ((fp = fopen(fname, mode)) == NULL) perror( "open" ); }
>    ~CharFile()
>       { if (fclose(fp)) perror( "close" ); }
>    CharFile& operator[](int i)
>       { if (fseek(fp, i, 0)) perror( "fseek" ); return *this; }
>    char operator=(char c)
>       { if (c) fputc(c, fp); return c; }
>    operator char()
>       { int c = fgetc(fp); return (c == EOF) ? 0 : c; }
> };

> int main(int argc, char *argv[])
> {
>   CharFile a( argv[1] ), b( argv[2] );

>   for (int i = 0; b[i] = a[i]; i++)
>     ;
> }
> (2) uranus% gcc -o testFile tesstFile.C
> (3) uranus% cat foo
> 0123456789
> (4) uranus% cat bar
> 0123456789
> (5) uranus% echo xxxxxxxxx > ! bar
> (6) uranus% cat bar
> xxxxxxxxx
> (7) uranus% testFile ofroofoo bo.x bar
> close: Invalid argument
> (8) uranus% exit
> exit

> Script done on Tue May 14 14:51:20 1996

> -----------------------------------------------------------

> However, I cannot see how this would work...

> b[i] = a[i]  == (CharFile &) = (CharFile &) and it
> byte copies a to b - the default behaviour.

> After deleting a, b.fp is pointing to an FILE*
> but this file is closed.  (by a's destructor)
> and hence "close: Invalid argument".

> SCO may treat closing a closed FILE* as no operation.
> I am not sure thought.

> Your operator= is only overloaded for operator= (char)
> and the code should read:

> ----------------------------------------------------------

> Script started on Tue May 14 14:51:38 1996
> (1) uranus% cat testFile.C
> #include <stdio.h>
> #include <stdlib.h>

> class CharFile {
>    FILE *fp;
> public:
>    CharFile(const char* fname, const char* mode = "r+")
>       { if ((fp = fopen(fname, mode)) == NULL) perror( "open" ); }
>    ~CharFile()
>       { if (fclose(fp)) perror( "close" ); }
>    CharFile& operator[](int i)
>       { if (fseek(fp, i, 0)) perror( "fseek" ); return *this; }
>    char operator=(char c)
>       { if (c) fputc(c, fp); return c; }
>    operator char()
>       { int c = fgetc(fp); return (c == EOF) ? 0 : c; }
> };

> int main(int argc, char *argv[])
> {
>   CharFile a( argv[1] ), b( argv[2] );

>   for (int i = 0; b[i] = (char)a[i]; i++)
>     ;
> }
> (2) uranus% cat foo
> 0123456789
> (3) uranus% cat bar
> xxxxxxxxx
> (4) uranus% gcc -o testFile testFile.C
> (5) uranus% testFile foo bar
> (6) uranus% cat foo
> 0123456789
> (7) uranus% cat bar
> 0123456789
> (8) uranus% exit
> exit

> Script done on Tue May 14 14:52:10 1996

> --------------------------------------------------------------

> Of course, you can make the operator= as  follows:

> --------------------------------------------------------------

> Script started on Tue May 14 15:06:21 1996
> (1) uranus% cat testFile.C
> #include <stdio.h>
> #include <stdlib.h>

> class CharFile {
>    FILE *fp;
> public:
>    CharFile(const char* fname, const char* mode = "r+")
>       { if ((fp = fopen(fname, mode)) == NULL) perror( "open" ); }
>    ~CharFile()
>       { if (fclose(fp)) perror( "close" ); }
>    CharFile& operator[](int i)
>       { if (fseek(fp, i, 0)) perror( "fseek" ); return *this; }
>    char operator=(char c)
>       { if (c) fputc(c, fp); return c; }
>    CharFile& operator=(CharFile& otherfile)  // Note I am using the overloaded =
>       { char c = (char)otherfile; if (c) fputc(c, fp); return *this; }
>    operator char()
>       { int c = fgetc(fp); return (c == EOF) ? 0 : c; }
> };

> int main(int argc, char *argv[])
> {
>   CharFile a( argv[1] ), b( argv[2] );

>   for (int i = 0; b[i] = (char)a[i]; i++)
>     ;
> }
> (2) uranus% gcc -o testFile testFile.C
> (3) uranus% echo 0123456789 >! foo
> (4) uranus% echo xxxxxxxxxx >! bar
> (5) uranus% cat foo
> 0123456789
> (6) uranus% cat bar
> xxxxxxxxxx
> (7) uranus% ./testFile foo bar
> (8) uranus% cat foo
> 0123456789
> (9) uranus% cat bar
> 0123456789
> (10) uranus% exit
> exit

> Script done on Tue May 14 15:07:11 1996

> ---------------------------------------------------------------

> The second contains the same bug.

> so the following code:

> >   for (int i = 0; b[i] = a[i]; i++)
> >     ;

> which copies a to b, and fp should also be copied acrossed.
> However, there is no operator= for fstream defined,
> then there is no fit for the operation. The compiler
> has a look and find a cast (char)() and convert
> a[i] (which is a CharIO&) to a char, and
> use the cast operator=(char) to cast the second
> CharIO to char. And then use the overloaded
> operator=(char) and therefore the program behave as
> you expected.

> However, in the first program, fp is a pointer and
> there is a default operator for copying a pointer.
> Hence, the operator involked is (CharFile&) = (CharFile &)
> which (again, the default is used) one object to and other.

> A simple illustration:

> -------------------------------------------------------

> Script started on Tue May 14 17:10:28 1996
> (1) skynet% cat t3.cc
> #include <fstream.h>

> class a
> {
>    fstream x;
> };

> int main ()
> {
>    class a A;
>    class a B;

>    A = B;
> }
> (2) skynet% gcc -c t3.cc
> t3.cc: In function `int main()':
> t3.cc:13: `a' does not define operator=

> -----------> [ here, byte copy class A to B, which involvs A.x = B.x
>                but there is no fsteram = fstream operator defined
>                hence compilation failed ]

> (3) skynet% cat t4.cc
> #include <fstream.h>

> class a
> {
>    fstream *x;
> };

> int main ()
> {
>    class a A;
>    class a B;

>    A = B;
> }
> (4) skynet% gcc -c t4.cc
> (5) skynet% ls -lrt
> total 344
> -rw-r--r--   1 cwhk     phd           99 May 14 17:09 t4.cc
> -rw-r--r--   1 cwhk     phd           98 May 14 17:09 t3.cc
> -rw-r--r--   1 cwhk     phd           43 May 14 17:10 typescript
> -rw-r--r--   1 cwhk     phd          544 May 14 17:10 t4.o

> -----------> [ here, byte copy class A to B, which involvs A.x = B.x
>                which is valid ]
> (6) skynet% exit
> exit

> script done on Tue May 14 17:11:09 1996

> -----------------------------------------------------------

> So, it is a bit more complicated than what one might think,
> unfortunately. When it comes down to overloading,
> and user defined casts, things can get really out of hands
> if one is not careful.

> I am sorry if this is a bit long. However, I think
> it does clear some of the problems for you.

> However, I am still baffled by the original poster's
> problem in which a simple "hello world" fails
> to work.

> Regards.

> Hansel

> --
> Hansel Kwok                                  Telephone: (0171) 5946309    
> Digi. Comms. Section, Dept. of E&E Eng.,         Email: h.k...@ic.ac.uk
> Imperial College of Science,                          : han...@gih.com
> Technology and Medicine, London.                      : han...@gih.co.uk

--

    Igor Shpigelman               "The opposite of a profound truth
    i...@isgtec.com                may well be another profound truth"

 
 
 

Weird g++/stdio bug

Post by H.J. L » Thu, 16 May 1996 04:00:00



> Under Linux, it would die complitely on gcc2.6.3 (well, broken iostream?)
> but, with gcc2.7.0/libc5.0.9/libg++?.?.?, which can produce
> mixed stdio/iostream output without any problems (I'm using RedHat2.1),
> my CharFile still bombs whereas CharIO works.

> Corey Brenner and Mike Romberg in the responce to my followup to
> "No output from c++ program", suggested that I (and original poster?)
> used the newest gcc2.7.2/libc5.3.12/libg2.7.1.4 which I did,
> (Many thanks, guys!), however, =my= bug was still there ...

> Ok, here is the output of the test runs of CharFile and FileIO.
> Note, that as the result of the run the file 'bar' must be identical
> to the file 'foo', which didn't happen in case of CharFile.

> And some answers to the questions likely to come:
> 1. Yes, as I said, CharFile worked perfectly well at least on one system.

That is what I put into the Linux C library to check if something
like this may happen. Per, Ulrich, that is why I use the
strong CHECK_FILE for Linux.

This is a typical C++ bug. Unfortunately, you
are not warned on other systems :-(.

- Show quoted text -

> 2. Yes, SEEK_SET is defined 0 in unistd.h and stdio.h.
> 3. No, fgetc and fputc are not implemented as macros.
> 4. 'close: invalid argument' comes from the second file 'bar'.
> 5. Kernel 1.2.13 (ELF), RedHat 2.1, packages used:
>         gcc272-no-sr-bug.lbin.tgz
>         libc-5.3.12.bin.tar.gz
>         libg++-2.7.1.4.bin.tar.gz

> And here, finally, the typescript file:

> Script started on Mon May 13 23:20:44 1996
> $ cat CharFile.h

> // Description: in a[i] = b[j] to read j-th byte from b
> //    and write io i-th of a;
> //    accept a[i] = 'c' and char c = b[i];
> // See also:  B.Stroustrup, C++, 2nd edition, p. 359.

> #include <stdio.h>
> #include <stdlib.h>

> class CharFile {
>    FILE *fp;
> public:
>    CharFile(const char* fname, const char* mode = "r+")
>       { if ((fp = fopen(fname, mode)) == NULL) perror( "open" ); }
>    ~CharFile()
>       { if (fclose(fp)) perror( "close" ); }

Please add

CharFile& operator= (const CharFile &);

to see what happens. The other bug is left as an exercise.

- Show quoted text -

>    CharFile& operator[](int i)
>       { if (fseek(fp, i, 0)) perror( "fseek" ); return *this; }
>    char operator=(char c)
>       { if (c) fputc(c, fp); return c; }
>    operator char()
>       { int c = fgetc(fp); return (c == EOF) ? 0 : c; }
> };
> $ cat testFile.C
> #include "CharFile.h"

> int main(int argc, char *argv[])
> {
>   CharFile a( argv[1] ), b( argv[2] );

>   for (int i = 0; b[i] = a[i]; i++)
>     ;
> }
> $ c++ testFile.C -o testFile
> $ echo 0123456789 >foo
> $ echo XXXXXXXXXX >bar
> $ testFile foo bar
> close: Invalid argument
> $ cat foo
> 0123456789
> $ cat bar
> XXXXXXXXXX
> $ cat CharIO.h

> // Description: in a[i] = b[j] to read j-th byte from b
> //        and write io i-th of a;
> //        accept a[i] = 'c' and char c = b[i];
> // Notes:   This is a new, kosher implementation of CharFile.h
> //        which uses only C++ i/o.
> //        Not that I'm so much into purism, it's just that
> //        my gcc-2.6.3 goes wild on any C i/o in C++ code.
> // See also:  B.Stroustrup, C++, 2nd edition, p. 359.

> #include <fstream.h>

> class CharIO {
>   fstream fp;
>   long pos;

> public:
>   CharIO( const char* fname )
>     { fp.open( fname, ios::in | ios::out ); }
>   ~CharIO()
>     { fp.close(); }
>   CharIO& operator[]( int i )
>     { pos = i; return *this; }
>   char operator=( char c )
>     { fp.seekp( pos, ios::beg ); if ( c ) fp.put( c ); return ( c ); }
>   operator char()
>     { fp.seekg( pos, ios::beg ); char c = 0; fp.get( c ); return ( c ); }
> };
> $ cat testIO.C
> #include "CharIO.h"

> int main(int argc, char *argv[])
> {
>   CharIO a( argv[1] ), b( argv[2] );

>   for (int i = 0; b[i] = a[i]; i++)
>     ;
> }
> $ c++ testIO.C -o testIO
> $ cat foo
> 0123456789
> $ cat bar
> XXXXXXXXXX
> $ testIO foo bar
> $ cat foo
> 0123456789
> $ cat bar
> 0123456789
> $ exit
> Script done on Mon May 13 23:24:49 1996

> Thanks for your patience, guys :-)

> --

>     Igor Shpigelman               "The opposite of a profound truth


 
 
 

Weird g++/stdio bug

Post by Ralf W. Steph » Fri, 17 May 1996 04:00:00


Quote:H.J. Lu writes:
> Please add
> CharFile& operator= (const CharFile &);
> to see what happens. The other bug is left as an exercise.

Cline's Law Of The Big Three (from memory):

   If a class has one of the following it should have all three:
   - a non-trivial destructor
   - a copy constructor
   - an assignment operator.

Now that was easy,
ralf

 
 
 

1. Possilbe bug in stdio fopen a+/rewind/lseek

#include <stdio.h>

/*
 * Following program seems to go wrong on bog standard system 5
 *
 * It has caused me much hair pulling and swearing.
 *
 * I have tryied this program under solaris 2.2 (Sunos 5.2 )
 * and  version of sco unix (I don't have the release number)
 *
 *  This program opens a file (a+)
 *
 *      rewinds the string to the being,
 *
 *      Then writes a string and closes the file
 *
 *      This operation is repeated TWICE,  the second time
 *      hello world is written
 *
 *      If stdio is correctly opening/rewind files only the
 *      line Hello world should appear in the output, on my system
 *      the following appears
 *

I am a bug
Hello world
 *      
 *
 */
main(){
        FILE * bug;

        if((bug=fopen("bug","a+"))==NULL){
                fprintf(stderr,"Can create file\n");
                exit(0);
        }
        rewind(bug);            /* go to the being of file */
                                /* print a message */
        fprintf(bug,"I am a bug\n");
        fclose(bug);            /* close file */

                                /* reopen */

        if((bug=fopen("bug","a+"))==NULL){
                fprintf(bug,"Can create file\n");
                exit(0);
        }
                                /* goto begining of file */
        rewind(bug);
        fprintf(bug,"Hello world\n");
        fclose(bug);

        /* Have a look at the output, should conaint one line saying
         * hello world
         */

Any options ?? Is this a bug or just a badly written bit of code ?/

--
   _/_/_/     _/_/   _/    _/ _/_/_/_/
  _/    _/ _/    _/ _/    _/ _/_/         D A V E     P O T T S

_/_/_/   _/    _/     _/   _/_/_/_/

2. solo on 2.2.12

3. possible STDIO bug in libc 5.0.9

4. New or Revised TAs on websco, 970925

5. amusing stdio buffering bug in Solaris 2.3

6. writinh an usb driver for custom hardware

7. Bug in stdio ?

8. Gateway 2000 video compatibility

9. stdio on a socket bug in SCO

10. libc5 stdio bug

11. Bug in stdio library - Problems with sc

12. A bug in stdio? Or my immaturity?

13. stdio bugs