undefined behaviour?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Friedrich Dominicus

    undefined behaviour?

    I stumbled upon the following code (stripped to the minimum)
    #include <stdio.h>
    #include <stdlib.h>

    int main(void){

    char *file_name = "t1.txt";
    char ch;
    FILE *pf = fopen(file_name , "r+");
    fputs("bla", pf);
    ungetc('z', pf);
    ch = getc(pf);
    printf("ch = %c\n", ch);
    fclose(pf);
    return 0;
    }

    Now I'm wondering if this is defined behaviour or not, and if it's
    defined should there be a problem with the close at the end?

    Thanks in advance
    Friedrich

    --
    Please remove just-for-news- to reply via e-mail.
  • santosh

    #2
    Re: undefined behaviour?

    Friedrich Dominicus wrote:[color=blue]
    > I stumbled upon the following code (stripped to the minimum)
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > int main(void){
    >
    > char *file_name = "t1.txt";[/color]
    An uninitialised pointer is being used here.
    [color=blue]
    > char ch;
    > FILE *pf = fopen(file_name , "r+");[/color]
    fopen() is not checked for errors.
    [color=blue]
    > fputs("bla", pf);[/color]
    Again, fputs() is not checked for failure.
    [color=blue]
    > ungetc('z', pf);[/color]
    The first parameter of ungetc() is an int.
    Again, no checking for failure.
    [color=blue]
    > ch = getc(pf);[/color]
    getc() returns an int, but may also return EOF on error.
    [color=blue]
    > printf("ch = %c\n", ch);
    > fclose(pf);[/color]
    fclose() isn't being checked for error.
    [color=blue]
    > return 0;
    > }
    >
    > Now I'm wondering if this is defined behaviour or not, and if it's
    > defined should there be a problem with the close at the end?[/color]
    AFAICS, there should be no problems with fclose().
    The problem in this program is with the use of a uninitialised
    pointer at the start.

    I tested it here and it crashes. It because of the uninitialised
    pointer.
    Either use a string literal or allocate space via malloc or use an
    array
    to hold the file name.

    Comment

    • Pieter Droogendijk

      #3
      Re: undefined behaviour?

      On Thu, 15 Dec 2005 14:19:26 +0100, Friedrich Dominicus wrote:
      [color=blue]
      > #include <stdio.h>
      > #include <stdlib.h>
      >
      > int main(void){
      >
      > char *file_name = "t1.txt";
      > char ch;
      > FILE *pf = fopen(file_name , "r+");
      > fputs("bla", pf);[/color]

      Definitely undefined behaviour if fopen() failed. Other than that, no.
      [color=blue]
      > ungetc('z', pf);[/color]

      One ungetc() is guaranteed to work. So, no problem.
      [color=blue]
      > ch = getc(pf);[/color]

      getc() returns an int. Implementation-defined behaviour might arise if
      getc() fails and if a char is signed.

      This because getc() returns EOF if it fails, which might not fit in
      a char.
      If chars are unsigned, the value will be EOF with CHAR_MAX+1 added to it
      until the value can be represented in a char.
      If chars are signed, and EOF cannot be represented in it, the resulting
      value is implementation-defined. Part of the behaviour might be a raised
      signal.

      However, I don't know if getc() is allowed to fail if you just called
      ungetc(). I don't think the standard makes any guarantees about this.
      [color=blue]
      > printf("ch = %c\n", ch);[/color]

      printf() expects an unsigned char converted to an int. The conversion to
      int is done automatically thanks to the default integer promotion rules,
      but char is not guaranteed to be unsigned.

      I believe this is undefined behaviour.
      [color=blue]
      > fclose(pf);[/color]

      No problem with this.
      [color=blue]
      > return 0;
      > }[/color]

      --
      Pieter Droogendijk <pieter at binky dot org dot uk>
      PGP/1E92DBBC [ Make way for the Emperor's Finest. ] binky.org.uk

      Comment

      • Jordan Abel

        #4
        Re: undefined behaviour?

        On 2005-12-15, Friedrich Dominicus <just-for-news-frido@q-software-solutions.de> wrote:[color=blue]
        > I stumbled upon the following code (stripped to the minimum)
        > #include <stdio.h>
        > #include <stdlib.h>
        >
        > int main(void){
        > char *file_name = "t1.txt";
        > char ch;
        > FILE *pf = fopen(file_name , "r+");[/color]

        Whether it is possible to open a text file for updating is
        implementation-defined. that said, this could have been "r+b" without
        changing the essential meaning of your question.
        [color=blue]
        > fputs("bla", pf);
        > ungetc('z', pf);
        > ch = getc(pf);
        > printf("ch = %c\n", ch);
        > fclose(pf);
        > return 0;
        >}
        >
        > Now I'm wondering if this is defined behaviour or not, and if it's
        > defined should there be a problem with the close at the end?[/color]

        I can't think of a single line in there that invokes undefined
        behavior... however, it's not clear to me whether the contents of the
        file are well-defined afterwards.

        Comment

        • Jordan Abel

          #5
          Re: undefined behaviour?

          On 2005-12-15, Pieter Droogendijk <pieterNO@binky SPAM.orgFOR.ukM E> wrote:[color=blue]
          > On Thu, 15 Dec 2005 14:19:26 +0100, Friedrich Dominicus wrote:
          >[color=green]
          >> #include <stdio.h>
          >> #include <stdlib.h>
          >>
          >> int main(void){
          >>
          >> char *file_name = "t1.txt";
          >> char ch;
          >> FILE *pf = fopen(file_name , "r+");
          >> fputs("bla", pf);[/color]
          >
          > Definitely undefined behaviour if fopen() failed. Other than that, no.
          >[color=green]
          >> ungetc('z', pf);
          >> ch = getc(pf);
          >> printf("ch = %c\n", ch);[/color]
          >
          > printf() expects an unsigned char converted to an int. The conversion to
          > int is done automatically thanks to the default integer promotion rules,
          > but char is not guaranteed to be unsigned.[/color]

          'z' is guaranteed to be positive, as are all members of the basic
          execution character set. In any case, it's not the issue he was looking
          for an answer on.
          [color=blue]
          > I believe this is undefined behaviour.[/color]

          You believe incorrectly.
          [color=blue][color=green]
          >> fclose(pf);
          >> return 0;
          >> }[/color][/color]

          so what about the contents of the file afterwards? I suspect this is
          what he was wondering about.

          Comment

          • Jordan Abel

            #6
            Re: undefined behaviour?

            On 2005-12-15, santosh <santosh.k83@gm ail.com> wrote:[color=blue][color=green]
            >> char *file_name = "t1.txt";[/color]
            > An uninitialised pointer is being used here.[/color]

            The line you are responding to is a declaration, and, moreover, one with
            an initializer.

            You claim that on your implementation the program crashes on that line.
            Either you're lying, or you have a very crappy [and non-conforming]
            implementation.

            Comment

            • Robert Gamble

              #7
              Re: undefined behaviour?

              Friedrich Dominicus wrote:[color=blue]
              > I stumbled upon the following code (stripped to the minimum)
              > #include <stdio.h>
              > #include <stdlib.h>
              >
              > int main(void){
              >
              > char *file_name = "t1.txt";
              > char ch;
              > FILE *pf = fopen(file_name , "r+");[/color]

              Undefined behavior for all following operations that use pf if fopen
              returns NULL.
              [color=blue]
              > fputs("bla", pf);
              > ungetc('z', pf);[/color]

              Undefined behavior for not calling fflush on a stream after performing
              an output operation and before performing an input operation.
              [color=blue]
              > ch = getc(pf);[/color]

              getc returns int.
              [color=blue]
              > printf("ch = %c\n", ch);
              > fclose(pf);
              > return 0;
              > }
              >
              > Now I'm wondering if this is defined behaviour or not, and if it's
              > defined should there be a problem with the close at the end?[/color]

              Check the return value of fopen and fflush(pf) after the call to fputs
              and you should be alright.

              Robert Gamble

              Comment

              • Antonio Contreras

                #8
                Re: undefined behaviour?

                santosh wrote:[color=blue]
                > Friedrich Dominicus wrote:[color=green]
                > > I stumbled upon the following code (stripped to the minimum)
                > > #include <stdio.h>
                > > #include <stdlib.h>
                > >
                > > int main(void){
                > >
                > > char *file_name = "t1.txt";[/color]
                > An uninitialised pointer is being used here.[/color]

                <snip part of the answer>
                [color=blue]
                > I tested it here and it crashes. It because of the uninitialised
                > pointer.
                > Either use a string literal or allocate space via malloc or use an
                > array
                > to hold the file name.[/color]

                That line declares a pointer to char and initializes it to point to a
                string literal. How does this constitute a use of an uninitialized
                pointer?

                Comment

                • santosh

                  #9
                  Re: undefined behaviour?

                  Friedrich Dominicus wrote:[color=blue]
                  > I stumbled upon the following code (stripped to the minimum)[/color]

                  Well, the following modified version of the code you posted works
                  here for me.
                  The output is:
                  ch = z

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

                  int main(void){

                  int ch;
                  FILE *pf;
                  if((pf = fopen("t1.txt", "w+"))==NUL L)
                  {
                  puts("fopen() returned NULL...");
                  exit(EXIT_FAILU RE);
                  }
                  if((fputs("bla" , pf))==EOF)
                  {
                  puts("fputs() returned EOF...");
                  exit(EXIT_FAILU RE);
                  }
                  ch = 'z';
                  fflush(pf);
                  if((ungetc(ch, pf))==EOF)
                  {
                  puts("ungetc() returned EOF...");
                  exit(EXIT_FAILU RE);
                  }

                  ch = getc(pf);
                  if(ch==EOF)
                  {
                  puts("getc() returned EOF...");
                  exit(EXIT_FAILU RE);
                  }

                  printf("ch = %c\n", ch);
                  if((fclose(pf)) ==-1)
                  {
                  puts("fclose() returned -1...");
                  exit(EXIT_FAILU RE);
                  }
                  return 0;

                  }

                  Comment

                  • Richard Bos

                    #10
                    Re: undefined behaviour?

                    Friedrich Dominicus <just-for-news-frido@q-software-solutions.de> wrote:
                    [color=blue]
                    > I stumbled upon the following code (stripped to the minimum)
                    > #include <stdio.h>
                    > #include <stdlib.h>
                    >
                    > int main(void){
                    >
                    > char *file_name = "t1.txt";
                    > char ch;
                    > FILE *pf = fopen(file_name , "r+");
                    > fputs("bla", pf);
                    > ungetc('z', pf);[/color]

                    Yes, undefined behaviour. You just wrote (using fputs()) to an update
                    stream, causing it to be set to output mode. ungetc() expects an input
                    stream. You cannot use ungetc() on an output-oriented update stream
                    without first using fflush() or a file positioning function.

                    This raises the question of what happens when you fflush() between
                    fputs() and ungetc(). AFAICT, that should work, not cause UB, cause the
                    'z' to be read by the following getc(), and as the Standard says about
                    ungetc(): "The external storage corresponding to the stream is
                    unchanged".

                    Richard

                    Comment

                    • Robert Gamble

                      #11
                      Re: undefined behaviour?

                      santosh wrote:[color=blue]
                      > Friedrich Dominicus wrote:[color=green]
                      > > I stumbled upon the following code (stripped to the minimum)
                      > > #include <stdio.h>
                      > > #include <stdlib.h>
                      > >
                      > > int main(void){
                      > >
                      > > char *file_name = "t1.txt";[/color]
                      > An uninitialised pointer is being used here.[/color]

                      What is your definition of initialized?

                      Robert Gamble

                      Comment

                      • santosh

                        #12
                        Re: undefined behaviour?

                        Jordan Abel wrote:[color=blue]
                        > On 2005-12-15, santosh <santosh.k83@gm ail.com> wrote:[color=green][color=darkred]
                        > >> char *file_name = "t1.txt";[/color]
                        > > An uninitialised pointer is being used here.[/color]
                        >
                        > The line you are responding to is a declaration, and, moreover, one with
                        > an initializer.
                        >
                        > You claim that on your implementation the program crashes on that line.
                        > Either you're lying, or you have a very crappy [and non-conforming]
                        > implementation.[/color]

                        Your right. I'm sorry. It was an incredible oversight on my part.

                        That being said, the code as was posted did crash over here.
                        The compiler is gcc (mingw).
                        After I introduced error checking for each function call I found that
                        the
                        first error was with foen().
                        I modified "r+" to "w+" which succeeded, but then ungetc() returned
                        EOF.
                        I corrected that by inserting a 'fflush(pf)' before calling ungetc().
                        Then it was getc()'s turn to return EOF.
                        After I changed 'ch' from char to int the program finally executed as
                        it
                        should. The contents of the file after running the code is:
                        bla [Hex dump = 626c 610d 0a]

                        Comment

                        • Friedrich Dominicus

                          #13
                          Re: undefined behaviour?

                          rlb@hoekstra-uitgeverij.nl (Richard Bos) writes:
                          [color=blue]
                          > Friedrich Dominicus <just-for-news-frido@q-software-solutions.de> wrote:
                          >[color=green]
                          >> I stumbled upon the following code (stripped to the minimum)
                          >> #include <stdio.h>
                          >> #include <stdlib.h>
                          >>
                          >> int main(void){
                          >>
                          >> char *file_name = "t1.txt";
                          >> char ch;
                          >> FILE *pf = fopen(file_name , "r+");
                          >> fputs("bla", pf);
                          >> ungetc('z', pf);[/color]
                          >
                          > Yes, undefined behaviour. You just wrote (using fputs()) to an update
                          > stream, causing it to be set to output mode. ungetc() expects an input
                          > stream.[/color]
                          Well that's what the 'r' is for or not? So for me it's an input stream
                          in first line and writable also.
                          [color=blue]
                          > You cannot use ungetc() on an output-oriented update stream
                          > without first using fflush() or a file positioning function.[/color]
                          As posted before I can understand this argument, and as said before I
                          have found it out there, but was puzzling about its validity.

                          Regards
                          Friedrich
                          --
                          Please remove just-for-news- to reply via e-mail.

                          Comment

                          • Friedrich Dominicus

                            #14
                            Re: undefined behaviour?

                            rlb@hoekstra-uitgeverij.nl (Richard Bos) writes:
                            [color=blue]
                            >
                            > This raises the question of what happens when you fflush() between
                            > fputs() and ungetc(). AFAICT, that should work, not cause UB, cause the
                            > 'z' to be read by the following getc(), and as the Standard says about
                            > ungetc(): "The external storage corresponding to the stream is
                            > unchanged".[/color]
                            So I'd argue it's defined if there is an fflush between the fputs and
                            ungetc, and undefined without it. That's sounds reasonable

                            Regards
                            Friedrich


                            --
                            Please remove just-for-news- to reply via e-mail.

                            Comment

                            • Robert Gamble

                              #15
                              Re: undefined behaviour?


                              Friedrich Dominicus wrote:[color=blue]
                              > rlb@hoekstra-uitgeverij.nl (Richard Bos) writes:
                              >[color=green]
                              > > Friedrich Dominicus <just-for-news-frido@q-software-solutions.de> wrote:
                              > >[color=darkred]
                              > >> I stumbled upon the following code (stripped to the minimum)
                              > >> #include <stdio.h>
                              > >> #include <stdlib.h>
                              > >>
                              > >> int main(void){
                              > >>
                              > >> char *file_name = "t1.txt";
                              > >> char ch;
                              > >> FILE *pf = fopen(file_name , "r+");
                              > >> fputs("bla", pf);
                              > >> ungetc('z', pf);[/color]
                              > >
                              > > Yes, undefined behaviour. You just wrote (using fputs()) to an update
                              > > stream, causing it to be set to output mode. ungetc() expects an input
                              > > stream.[/color]
                              > Well that's what the 'r' is for or not? So for me it's an input stream
                              > in first line and writable also.
                              >[color=green]
                              > > You cannot use ungetc() on an output-oriented update stream
                              > > without first using fflush() or a file positioning function.[/color]
                              > As posted before I can understand this argument, and as said before I
                              > have found it out there, but was puzzling about its validity.[/color]

                              Here is the appropriate section of the Standard (n1124 to be exact):

                              7.19.5.3p6

                              When a file is opened with update mode ('+' as the second or third
                              character in the
                              above list of mode argument values), both input and output may be
                              performed on the
                              associated stream. However, output shall not be directly followed by
                              input without an
                              intervening call to the fflush function or to a file positioning
                              function (fseek,
                              fsetpos, or rewind), and input shall not be directly followed by output
                              without an
                              intervening call to a file positioning function, unless the input
                              operation encounters endof-
                              file. Opening (or creating) a text file with update mode may instead
                              open (or create) a
                              binary stream in some implementations .

                              I hope that relieves any doubt you had about the validity of the
                              statements made to that effect here.

                              Robert Gamble

                              Comment

                              Working...