fclose(0)

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

    #46
    Re: fclose(0)

    CBFalconer wrote:
    Ian Collins wrote:
    >CBFalconer wrote:
    >>
    ... snip ...
    >>
    >>However fclose doesn't crash on receiving a NULL. It returns EOF.
    >>
    >Says who? The behaviour is undefined.
    >
    Says the standard.
    >
    7.19.5.1 The fclose function
    >
    Synopsis
    [#1]
    #include <stdio.h>
    int fclose(FILE *stream);
    >
    Description
    >
    [#2] The fclose function causes the stream pointed to by
    stream to be flushed and the associated file to be closed.
    Any unwritten buffered data for the stream are delivered to
    the host environment to be written to the file; any unread
    buffered data are discarded. The stream is disassociated
    from the file. If the associated buffer was automatically
    allocated, it is deallocated.
    >
    Returns
    >
    [#3] The fclose function returns zero if the stream was
    successfully closed, or EOF if any errors were detected.
    >
    Note the phrase "any errors" in the line above.
    Yes. But is it an "error" to pass NULL to fclose? Elsewhere Richard
    Tobin says that undefined behaviour is invoked when NULL is passed to a
    library function whose definition does not *explicitly* accept NULL as
    a valid parameter. The above description of fclose says nothing about a
    call with NULL as argument, so presumably, undefined behaviour is
    invoked at the point fclose(0) is called. One outcome would be to check
    for NULL and return EOF (which DigitalMars seems to do), another would
    be to blindly process the argument leading to God knows what.

    Comment

    • Ben Bacarisse

      #47
      Re: fclose(0)

      CBFalconer <cbfalconer@yah oo.comwrites:
      Ben Bacarisse wrote:
      >>
      ... snip ...
      >>
      >It's normal. Have you tried strlen(0), strcpy(0, 0) or fopen(0, 0)?
      >Luck is another matter. In a way you were lucky that at least one
      >implementati on flagged up the call (with a crash). If you'd used
      >one that just returns EOF (which is allowed), you'd have no warning
      >that the construct is not portable.
      >
      Sure you would. The EOF is not a normal return value. Something
      failed.
      So, the poor user writes (and I *know* this is a fragment):

      FILE *fp = fopen(argv[1], "r");
      if (fp) {
      /* ...processing.. . */
      }
      else fprintf(stderr, "Failed to open %s\n", argv[1]);
      if (flose(fp) == EOF)
      fprintf(stderr, "Error closing %s\n", argv[1]);

      How can they tell, from the EOF return, that their code is not
      portable? Note that that is what I claimed. Sure, they get the two
      error messages, but they expect that, surely? How does the expected
      error return help then to see the non-portability of the construct?

      --
      Ben.

      Comment

      • Bartc

        #48
        Re: fclose(0)


        "Eric Sosman" <esosman@ieee-dot-org.invalidwrot e in message
        news:i--dnZ85CdjKOo7VnZ 2dnUVZ_uGdnZ2d@ comcast.com...
        Bartc wrote:
        >If this was the case then it would be better to admit it rather than
        >suggest, as a few people have, that crashing on passing a null pointer is
        >actually a good idea.
        >
        The good idea is not to pass a null pointer in the first place.
        If you want a hand-holding language (and there's no shame in wanting
        such a thing), you can find plenty of them.
        I don't think so. My projects require a low-level high-level mainstream
        language like C. But there seem to be very few about other than C.

        And I'm not going to change language because of some unexpected behaviour in
        some library functions, that can be easily fixed with a few lines of code in
        wrapper functions that already exist anyway.

        I was just surprised at fclose() for example not already doing such a simple
        check even if the standard doesn't require it to do so. But clearly it
        would upset a lot of people if it were to suddenly behave sensibly.

        Pointer values can be roughly grouped into these kinds:

        (1) Pointing at the right thing
        (2) Pointing at the wrong thing
        (3) Containing an illegal address other than NULL
        (4) Containing NULL

        Of these, I would say (4) is the easiest to verify, and could easily be
        placed in a library function. And I would also say it is a common error (to
        have NULL where (1) is expected).

        (3) is a little more difficult to check, and would probably be unreasonable
        to expect most library functions to do so. (Although on some platforms, the
        address range 0..N might be known to be invalid, and can be combined with a
        check for NULL. This would trap many pointer errors like p+k where p has a
        NULL value and k<=N.)

        (2) might also be easily checkable in a few cases, for example in a FILE*
        value where the beginning of a FILE struct is expected to contain some value
        or other.


        --
        Bartc


        Comment

        • pete

          #49
          Re: fclose(0)

          Bartc wrote:
          Pointer values can be roughly grouped into these kinds:
          >
          (1) Pointing at the right thing
          (2) Pointing at the wrong thing
          (3) Containing an illegal address other than NULL
          (4) Containing NULL
          I consider object pointer values into a different four groups:
          1 address of an object
          2 one past the address of an object
          3 null pointer
          4 indeterminate

          --
          pete

          Comment

          • Bartc

            #50
            Re: fclose(0)


            "pete" <pfiland@mindsp ring.comwrote in message
            news:RpSdnQ0Ysa NN74nVnZ2dnUVZ_ v-hnZ2d@earthlink .com...
            Bartc wrote:
            >
            >Pointer values can be roughly grouped into these kinds:
            >>
            >(1) Pointing at the right thing
            >(2) Pointing at the wrong thing
            >(3) Containing an illegal address other than NULL
            >(4) Containing NULL
            >
            I consider object pointer values into a different four groups:
            1 address of an object
            2 one past the address of an object
            3 null pointer
            4 indeterminate
            I was thinking in terms of verifying pointer values passed to functions.

            (4) of my list is easy. (3) and (2) are progressively more difficult. (1)
            might be impossible (for the function to determine anyway).

            3 on your list is again easy. But I wouldn't know how to test the others,
            and if I did, the object in question might be the wrong one.

            --
            Bart


            Comment

            • CBFalconer

              #51
              Re: fclose(0)

              pete wrote:
              Bartc wrote:
              >
              >Pointer values can be roughly grouped into these kinds:
              >>
              >(1) Pointing at the right thing
              >(2) Pointing at the wrong thing
              >(3) Containing an illegal address other than NULL
              >(4) Containing NULL
              >
              I consider object pointer values into a different four groups:
              1a address of an object if provided by malloc
              1b " " " " not provided by malloc
              2 one past the address of an object
              3 null pointer
              4 indeterminate
              Note my modification to 1a and 1b above. This is the cause of most
              of the address checking impossibilities in C, and at the same time
              much of the addressing flexibility in C.

              --
              [mail]: Chuck F (cbfalconer at maineline dot net)
              [page]: <http://cbfalconer.home .att.net>
              Try the download section.


              ** Posted from http://www.teranews.com **

              Comment

              • CBFalconer

                #52
                Re: fclose(0)

                Ben Bacarisse wrote:
                >
                .... snip ...
                >
                So, the poor user writes (and I *know* this is a fragment):
                >
                FILE *fp = fopen(argv[1], "r");
                if (fp) {
                /* ...processing.. . */
                }
                else fprintf(stderr, "Failed to open %s\n", argv[1]);
                if (flose(fp) == EOF)
                fprintf(stderr, "Error closing %s\n", argv[1]);
                >
                How can they tell, from the EOF return, that their code is not
                portable? Note that that is what I claimed. Sure, they get the two
                error messages, but they expect that, surely? How does the expected
                error return help then to see the non-portability of the construct?
                They write:

                FILE *fp = fopen(argv[1], "r");

                if (!fp) fprintf(stderr, "Failed to open %s\n", argv[1]);
                else {
                /* ...processing.. . */
                if (flose(fp) == EOF)
                fprintf(stderr, "Error closing %s\n", argv[1]);
                }

                Notice the inversion of if and else clauses. I think it is
                clearer.

                --
                [mail]: Chuck F (cbfalconer at maineline dot net)
                [page]: <http://cbfalconer.home .att.net>
                Try the download section.


                ** Posted from http://www.teranews.com **

                Comment

                • Ben Bacarisse

                  #53
                  Re: fclose(0)

                  CBFalconer <cbfalconer@yah oo.comwrites:
                  Ben Bacarisse wrote:
                  >>
                  ... snip ...
                  >>
                  >So, the poor user writes (and I *know* this is a fragment):
                  >>
                  > FILE *fp = fopen(argv[1], "r");
                  > if (fp) {
                  > /* ...processing.. . */
                  > }
                  > else fprintf(stderr, "Failed to open %s\n", argv[1]);
                  > if (flose(fp) == EOF)
                  > fprintf(stderr, "Error closing %s\n", argv[1]);
                  >>
                  >How can they tell, from the EOF return, that their code is not
                  >portable? Note that that is what I claimed. Sure, they get the two
                  >error messages, but they expect that, surely? How does the expected
                  >error return help then to see the non-portability of the construct?
                  >
                  They write:
                  >
                  FILE *fp = fopen(argv[1], "r");
                  >
                  if (!fp) fprintf(stderr, "Failed to open %s\n", argv[1]);
                  else {
                  /* ...processing.. . */
                  if (flose(fp) == EOF)
                  fprintf(stderr, "Error closing %s\n", argv[1]);
                  }
                  >
                  Notice the inversion of if and else clauses. I think it is
                  clearer.
                  <sigh Forget it.

                  --
                  Ben.

                  Comment

                  • pete

                    #54
                    Re: fclose(0)

                    Bartc wrote:
                    "pete" <pfiland@mindsp ring.comwrote in message
                    news:RpSdnQ0Ysa NN74nVnZ2dnUVZ_ v-hnZ2d@earthlink .com...
                    >Bartc wrote:
                    >>
                    >>Pointer values can be roughly grouped into these kinds:
                    >>>
                    >>(1) Pointing at the right thing
                    >>(2) Pointing at the wrong thing
                    >>(3) Containing an illegal address other than NULL
                    >>(4) Containing NULL
                    >I consider object pointer values into a different four groups:
                    >1 address of an object
                    >2 one past the address of an object
                    >3 null pointer
                    >4 indeterminate
                    >
                    I was thinking in terms of verifying pointer values passed to functions.
                    >
                    (4) of my list is easy. (3) and (2) are progressively more difficult. (1)
                    might be impossible (for the function to determine anyway).
                    >
                    3 on your list is again easy. But I wouldn't know how to test the others,
                    and if I did, the object in question might be the wrong one.
                    There is no portable C code way
                    to examine an indeterminate pointer value.

                    If an indeterminate pointer value is an argument to a function call,
                    then you're on your own.
                    The rules of C no longer apply to what your program will do.

                    --
                    pete

                    Comment

                    Working...