By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,952 Members | 1,091 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,952 IT Pros & Developers. It's quick & easy.

fclose(0)

P: n/a
This short program:

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

int main(void) {
int status;

status=fclose(0);

printf("fclose(0) status: %d\n",status);

}

crashes on the first two implementations I tried. Then I tried DMC and that
gave the expected EOF status.

Given the emphasis on error-checking in this group, it seems astonishing
that a library function (executed at most once per file) cannot do this
elementary check on it's parameter.

(It's possible a zero FILE* handle is returned by fopen() but the file has
to be closed for other reasons before it can checked by the application.)

Was I unlucky or is it normal for C library functions to be so fragile?

-- Bart
Jun 27 '08 #1
Share this Question
Share on Google+
53 Replies


P: n/a
Bartc said:
This short program:

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

int main(void) {
int status;

status=fclose(0);

printf("fclose(0) status: %d\n",status);

}

crashes on the first two implementations I tried.
The Standard requires that you pass to fclose a pointer to a stream object
of type FILE. You did not do this. (0 doesn't point to any object at all,
let alone a stream object.) You broke the rules, so all bets are off.

<snip>
Given the emphasis on error-checking in this group, it seems astonishing
that a library function (executed at most once per file) cannot do this
elementary check on it's parameter.
Well, of course it could, but it isn't obliged to. One of the ways an
implementation can hand you astounding performance is to keep the
error-checking down to an absolute minimum, trusting you to do any
necessary checks yourself (because the alternative is to do the checks,
even when *you* know they're not needed).
Was I unlucky or is it normal for C library functions to be so fragile?
C trusts you. Be worthy of that trust, or use a different language.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #2

P: n/a
Bartc wrote:
This short program:

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

int main(void) {
int status;

status=fclose(0);

printf("fclose(0) status: %d\n",status);

}

crashes on the first two implementations I tried. Then I tried DMC and
that gave the expected EOF status.

Given the emphasis on error-checking in this group, it seems
astonishing that a library function (executed at most once per file)
cannot do this elementary check on it's parameter.

(It's possible a zero FILE* handle is returned by fopen() but the file
has to be closed for other reasons before it can checked by the
application.)

Was I unlucky or is it normal for C library functions to be so
fragile?
According to the standard fclose must return EOF if "errors were
detected". However it says nothing about the range of possible errors.
Is it an error if the operation fails to close a file with an otherwise
perfectly valid FILE * parameter? According to the standard the answer
is a clear yes. Is it also an error if the argument to fclose is an
illegal or invalid pointer value? The standard doesn't explicitly
address this issue, but I think the intent is to treat an illegal
pointer value (basically NULL and other trap representations) as a
failure, and hence return EOF. OTOH an invalid pointer value cannot be
detected by most implementations of fclose and I think it invokes
undefined behaviour, whose result might be anything from a crash to
returning EOF.

So for the code in question I'd say that conforming compilers are
allowed to do anything since the behaviour is undefined (not explicitly
stated in the standard, but inferred) upon giving fclose an illegal
argument. So it becomes a QoI issue and it seems that DigitalMars has
the best behaviour of your test set.

Jun 27 '08 #3

P: n/a
"Bartc" <bc@freeuk.comwrites:
This short program:

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

int main(void) {
int status;

status=fclose(0);

printf("fclose(0) status: %d\n",status);

}

crashes on the first two implementations I tried. Then I tried DMC and that
gave the expected EOF status.

Given the emphasis on error-checking in this group, it seems
astonishing
that a library function (executed at most once per file) cannot do this
elementary check on it's parameter.

(It's possible a zero FILE* handle is returned by fopen() but the file has
to be closed for other reasons before it can checked by the
application.)
Error. Read the manual.
>
Was I unlucky or is it normal for C library functions to be so fragile?

-- Bart
I like it when they crash. It means I dont have to check the return code
for error conditions and my debugger tells me straightaway where it
broke.

Why would I want the libraries to cover up my sloppy mistakes?

Excessive error checking to cover for lazy programmers might well add
unnecessary overheads.
Jun 27 '08 #4

P: n/a
"Bartc" <bc@freeuk.comwrites:
This short program:

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

int main(void) {
int status;

status=fclose(0);

printf("fclose(0) status: %d\n",status);

}

crashes on the first two implementations I tried. Then I tried DMC and that
gave the expected EOF status.
Not everyone will expect the same thing!
Given the emphasis on error-checking in this group, it seems astonishing
that a library function (executed at most once per file) cannot do this
elementary check on it's parameter.
Of course it can. The behaviour is undefined so it may check (or not
check) anything it likes in this case. What has the emphasis of this
group got to do with what a standard library function does?
(It's possible a zero FILE* handle is returned by fopen() but the file has
to be closed for other reasons before it can checked by the
application.)
Yes, I agree that it is annoying that one can't fclose the result of
fopen (like one can free the result of malloc) but such is C.
Was I unlucky or is it normal for C library functions to be so
fragile?
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
implementation 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.

--
Ben.
Jun 27 '08 #5

P: n/a

"Richard Heathfield" <rj*@see.sig.invalidwrote in message
news:dZ******************************@bt.com...
Bartc said:
>This short program:

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

int main(void) {
int status;

status=fclose(0);

printf("fclose(0) status: %d\n",status);

}

crashes on the first two implementations I tried.

The Standard requires that you pass to fclose a pointer to a stream object
of type FILE. You did not do this. (0 doesn't point to any object at all,
let alone a stream object.) You broke the rules, so all bets are off.
fopen() returns a FILE* value, which can include NULL. So it's argueable
that NULL (or (FILE*)NULL) is acceptable, type-wise, to fclose().
>One of the ways an
implementation can hand you astounding performance is to keep the
error-checking down to an absolute minimum
This is a /file/ operation. The cost of the check is negligible compared to
the file processing time.
C trusts you. Be worthy of that trust, or use a different language.
I was. But I was interpreting it using a C program. I will have to put in
extra checks for possible uses of NULL file handles that can crash C, to
keep that other language robust.

--
Bartc
Jun 27 '08 #6

P: n/a

"Ben Bacarisse" <be********@bsb.me.ukwrote in message
news:87************@bsb.me.uk...
"Bartc" <bc@freeuk.comwrites:
>status=fclose(0);
>crashes on the first two implementations I tried. Then I tried DMC and
that
gave the expected EOF status.

Not everyone will expect the same thing!
>Given the emphasis on error-checking in this group, it seems astonishing
that a library function (executed at most once per file) cannot do this
elementary check on it's parameter.

Of course it can. The behaviour is undefined so it may check (or not
check) anything it likes in this case. What has the emphasis of this
group got to do with what a standard library function does?
Something to do with setting an example?

If a writer of a library function can't check a handle (for a common error
like NULL, in a non-speed-critical function) why should anybody else?
It's normal. Have you tried strlen(0), strcpy(0, 0) or fopen(0, 0)?
I know about null string pointers. I'd prefer the library to be tolerant of
them.
Luck is another matter. In a way you were lucky that at least one
implementation 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.
That's true. And if I did have a file that needed closing then fclose(0)
returning EOF wouldn't tell me there was a problem (although I would find
out in due course).

But then, it may crash quietly.

What's wrong with fclose() doing something like: "ABORTING: Invalid handle
to fclose()".

--
Bartc
Jun 27 '08 #7

P: n/a
"Bartc" <bc@freeuk.comwrites:
"Ben Bacarisse" <be********@bsb.me.ukwrote in message
news:87************@bsb.me.uk...
>"Bartc" <bc@freeuk.comwrites:
>>status=fclose(0);
>>crashes on the first two implementations I tried. Then I tried DMC and
that
gave the expected EOF status.

Not everyone will expect the same thing!
>>Given the emphasis on error-checking in this group, it seems astonishing
that a library function (executed at most once per file) cannot do this
elementary check on it's parameter.

Of course it can. The behaviour is undefined so it may check (or not
check) anything it likes in this case. What has the emphasis of this
group got to do with what a standard library function does?

Something to do with setting an example?

If a writer of a library function can't check a handle (for a common error
like NULL, in a non-speed-critical function) why should anybody else?
Because it has a documented range of inputs. Why waste time? This is not
ADA. It is C.
Jun 27 '08 #8

P: n/a
"Bartc" <bc@freeuk.comwrites:
"Ben Bacarisse" <be********@bsb.me.ukwrote in message
news:87************@bsb.me.uk...
>"Bartc" <bc@freeuk.comwrites:
>>status=fclose(0);
>>crashes on the first two implementations I tried. Then I tried DMC and
that
gave the expected EOF status.

Not everyone will expect the same thing!
>>Given the emphasis on error-checking in this group, it seems astonishing
that a library function (executed at most once per file) cannot do this
elementary check on it's parameter.

Of course it can. The behaviour is undefined so it may check (or not
check) anything it likes in this case. What has the emphasis of this
group got to do with what a standard library function does?

Something to do with setting an example?
I am confused as to which way round the example should be set. Maybe
you are surprised by how keen we are on error checking, given how lax
the library is? I don't know, but I don't think that is your main
point.

Anyway, I don't think there *is* an emphasis on functions checking their
input. There certainly is on checking the results, but that is not
the same. I think most regulars here will have caught the C bug of
doing rather minimal checking *in* a function. See, for example, the
recent posts about K&R solutions -- most of the examples posted ensure
that a function is called correctly and don't re-check inside.
If a writer of a library function can't check a handle (for a common error
like NULL, in a non-speed-critical function) why should anybody else?
>It's normal. Have you tried strlen(0), strcpy(0, 0) or fopen(0, 0)?

I know about null string pointers. I'd prefer the library to be tolerant of
them.
Then you'll have to write a set of wrappers.
>Luck is another matter. In a way you were lucky that at least one
implementation 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.

That's true. And if I did have a file that needed closing then fclose(0)
returning EOF wouldn't tell me there was a problem (although I would find
out in due course).

But then, it may crash quietly.

What's wrong with fclose() doing something like: "ABORTING: Invalid handle
to fclose()".
Nothing, except that there is an assumption that the library does not
write error messages. I don't think it is forbidden, it is just not
expected (at least on the systems I am used to).

--
Ben.
Jun 27 '08 #9

P: n/a
Bartc wrote:

printf("fclose(0) status: %d\n",status);
Was I unlucky or is it normal for C library functions to be so
fragile?

There is no defined behavior for Undefined Behavior.


Brian
Jun 27 '08 #10

P: n/a
On 26 Apr 2008 at 15:06, Bartc wrote:
int status;

status=fclose(0);
fclose takes a pointer argument, so this is the same as
status=fclose(NULL);
which is obviously not a good idea.

[guess] Instead of fclose, did you mean close, which takes a file
descriptor as an argument? Are you wondering about whether it's OK to
close(0) (i.e. close the stdin stream)? If so, the answer is yes: it's
useful for piping data between parent and child processes. (You can use
dup() to bind the output of a pipe back to stdin.)

Jun 27 '08 #11

P: n/a

"Antoninus Twink" <no****@nospam.invalidwrote in message
news:sl*******************@nospam.invalid...
On 26 Apr 2008 at 15:06, Bartc wrote:
>int status;

status=fclose(0);

fclose takes a pointer argument, so this is the same as
status=fclose(NULL);
which is obviously not a good idea.

[guess] Instead of fclose, did you mean close, which takes a file
descriptor as an argument? Are you wondering about whether it's OK to
close(0) (i.e. close the stdin stream)? If so, the answer is yes: it's
useful for piping data between parent and child processes. (You can use
dup() to bind the output of a pipe back to stdin.)
No, it came up in something like:

f=fopen(...);
fclose(f);

where the fopen failed. I would just have expected fclose to do nothing
given a null file handle (as I tend to do in my own functions that use
handles).

No big deal, I already use wrappers and it's a one-line fix. Was just mildly
surprised that that one line isn't already there.

--
Bartc
Jun 27 '08 #12

P: n/a
"Bartc" <bc@freeuk.comwrites:
status=fclose(0);
This yields undefined behavior. Are you thinking of
fflush(NULL), which is well-defined?
--
"Given that computing power increases exponentially with time,
algorithms with exponential or better O-notations
are actually linear with a large constant."
--Mike Lee
Jun 27 '08 #13

P: n/a
Bartc said:
>
"Richard Heathfield" <rj*@see.sig.invalidwrote in message
news:dZ******************************@bt.com...
>Bartc said:
>>This short program:

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

int main(void) {
int status;

status=fclose(0);

printf("fclose(0) status: %d\n",status);

}

crashes on the first two implementations I tried.

The Standard requires that you pass to fclose a pointer to a stream
object of type FILE. You did not do this. (0 doesn't point to any object
at all, let alone a stream object.) You broke the rules, so all bets are
off.

fopen() returns a FILE* value, which can include NULL. So it's argueable
that NULL (or (FILE*)NULL) is acceptable, type-wise, to fclose().
No, it isn't, because the Standard doesn't say so. The Standard says that,
if you call fclose, you must pass to it a pointer to a stream object of
type FILE that has a file associated with it. You didn't do this.

<snip>

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #14

P: n/a
"Bartc" <bc@freeuk.comwrites:
[...]
>On 26 Apr 2008 at 15:06, Bartc wrote:
>>int status;

status=fclose(0);
[...]
>
No, it came up in something like:

f=fopen(...);
fclose(f);

where the fopen failed. I would just have expected fclose to do nothing
given a null file handle (as I tend to do in my own functions that use
handles).
In that case, it's probably just as easy to avoid calling fclose if
the fopen failed than to call it. You have to test whether fopen
succeeded anyway; if it doesn't, you don't attempt to read any input
from the file, right? So you have to do something like this:

f = fopen(...);
if (f != NULL) {
fread(...);
fclose(...);
}
else {
/* Report that you couldn't open the file */
}
No big deal, I already use wrappers and it's a one-line fix. Was just mildly
surprised that that one line isn't already there.
Yeah, most standard libary functions don't check for invalid input.
free(NULL) is a rare exception.

Note that, in the case of fclose(), checking for a null pointer
argument would just handle one failure case. There are plenty of
other errors that can't reasonably be caught, such as calling fclose()
with an uninitialized pointer.

--
Keith Thompson (The_Other_Keith) <ks***@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 27 '08 #15

P: n/a
Bartc wrote:
"Richard Heathfield" <rj*@see.sig.invalidwrote
>>
The Standard requires that you pass to fclose a pointer to a stream object
of type FILE. You did not do this. (0 doesn't point to any object at all,
let alone a stream object.) You broke the rules, so all bets are off.

fopen() returns a FILE* value, which can include NULL. So it's argueable
that NULL (or (FILE*)NULL) is acceptable, type-wise, to fclose().
The type is acceptable, but the value is not. Would
you expect `fprintf (NULL, "Hello, world!\n");' to work?
How about `fprintf (NULL, NULL);'?

The relevant passage is Section 7.1.4 paragraph 1:

"Each of the following statements applies unless
explicitly stated otherwise [...]: If an argument to
a function has an invalid value (such as [...] a null
pointer, [...]) [...]the behavior is undefined. [...]"

--
Eric Sosman
es*****@ieee-dot-org.invalid
Jun 27 '08 #16

P: n/a
Bartc wrote:
[...]
What's wrong with fclose() doing something like: "ABORTING: Invalid handle
to fclose()".
It does! The spelling of the error message differs somewhat
implementation to implementation; on one I'm familiar with, the
message is spelled "SIGSEGV" ...

--
Eric Sosman
es*****@ieee-dot-org.invalid
Jun 27 '08 #17

P: n/a
In comp.lang.c, Eric Sosman wrote:
Bartc wrote:
>[...]
What's wrong with fclose() doing something like: "ABORTING: Invalid
handle to fclose()".

It does! The spelling of the error message differs somewhat
implementation to implementation; on one I'm familiar with, the
message is spelled "SIGSEGV" ...
and I've seen that message, but spelled as "S0C4"
--
Lew Pitcher

Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by request
---------- Slackware - Because I know what I'm doing. ------
Jun 27 '08 #18

P: n/a

"Eric Sosman" <es*****@ieee-dot-org.invalidwrote in message
news:XI******************************@comcast.com. ..
Bartc wrote:
>"Richard Heathfield" <rj*@see.sig.invalidwrote
>>>
The Standard requires that you pass to fclose a pointer to a stream
object
of type FILE. You did not do this. (0 doesn't point to any object at
all,
let alone a stream object.) You broke the rules, so all bets are off.
The relevant passage is Section 7.1.4 paragraph 1:

"Each of the following statements applies unless
explicitly stated otherwise [...]: If an argument to
a function has an invalid value (such as [...] a null
pointer, [...]) [...]the behavior is undefined. [...]"
I suspect this was written when there were already many implementations that
behaved this way.

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.

--
Bartc


Jun 27 '08 #19

P: n/a
Bartc said:

<snip>
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.
Crashing is not an idea - either good or bad. It is merely a consequence.

If a programmer is dense enough to break the contract between himself and
the implementation, he has no business complaining when something happens
that he doesn't like. If you don't want a crash or some other bad
consequence of passing an invalid argument (and neither do I), the answer
is simple: ***don't pass an invalid argument***.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #20

P: n/a
Richard Heathfield wrote:
Bartc said:

<snip>
>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.

Crashing is not an idea - either good or bad. It is merely a consequence.

If a programmer is dense enough to break the contract between himself and
the implementation, he has no business complaining when something happens
that he doesn't like. If you don't want a crash or some other bad
consequence of passing an invalid argument (and neither do I), the answer
is simple: ***don't pass an invalid argument***.
I'm not sure it's invalid. Consider..

FILE *fp = fopen("file", "r");

which fails for some reason. Later in the program we do..

int stat = fclose(fp);

The fclose finds that fp does not point to an open file and returns EOF.

No crash, no problem.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Jun 27 '08 #21

P: n/a
Joe Wright said:
Richard Heathfield wrote:
<snip>
>If you don't want a crash or some other
bad consequence of passing an invalid argument (and neither do I), the
answer is simple: ***don't pass an invalid argument***.
I'm not sure it's invalid. Consider..

FILE *fp = fopen("file", "r");

which fails for some reason. Later in the program we do..

int stat = fclose(fp);
If fp is a null pointer, the argument *is* invalid, because fclose requires
fp to be a pointer to a stream that is associated with a file. A null
pointer doesn't qualify, since it is guaranteed not to point to any
object.
The fclose finds that fp does not point to an open file and returns EOF.
That is one legitimate outcome of undefined behaviour, yes. As you know,
there are plenty of others.
No crash, no problem.
I'm not sure I agree about the "no problem" part.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #22

P: n/a
Richard Heathfield wrote:
Joe Wright said:
>Richard Heathfield wrote:

<snip>
>>If you don't want a crash or some other
bad consequence of passing an invalid argument (and neither do I), the
answer is simple: ***don't pass an invalid argument***.
I'm not sure it's invalid. Consider..

FILE *fp = fopen("file", "r");

which fails for some reason. Later in the program we do..

int stat = fclose(fp);

If fp is a null pointer, the argument *is* invalid, because fclose requires
fp to be a pointer to a stream that is associated with a file. A null
pointer doesn't qualify, since it is guaranteed not to point to any
object.
It's a pity that case isn't specified in the way malloc/free is.

It is always safe to call free with the result of malloc, so it would be
consistent to always be a able to call any resource freeing function
with the result of its corresponding allocation function.

--
Ian Collins.
Jun 27 '08 #23

P: n/a
Bartc wrote:
"Eric Sosman" <es*****@ieee-dot-org.invalidwrote in message
news:XI******************************@comcast.com. ..
>Bartc wrote:
>>"Richard Heathfield" <rj*@see.sig.invalidwrote
The Standard requires that you pass to fclose a pointer to a stream
object
of type FILE. You did not do this. (0 doesn't point to any object at
all,
let alone a stream object.) You broke the rules, so all bets are off.
> The relevant passage is Section 7.1.4 paragraph 1:

"Each of the following statements applies unless
explicitly stated otherwise [...]: If an argument to
a function has an invalid value (such as [...] a null
pointer, [...]) [...]the behavior is undefined. [...]"

I suspect this was written when there were already many implementations that
behaved this way.
The Committee's mandate was not to invent a new programming
language from whole cloth, but to codify existing practice insofar
as practical.

In the Rationale, the Committee laid out the principles that
it tried to apply when making decisions about the language. One
of these was "Keep the spirit of C," and the very first point in
the short list of facets that constitute that spirit is "Trust
the programmer." As Richard Heathfield pointed out earlier, trust
is not a one-sided relationship; the trusted party bears a burden
arising from the fact of being trusted.
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.

--
Eric Sosman
es*****@ieee-dot-org.invalid
Jun 27 '08 #24

P: n/a
In article <i-******************************@comcast.com>
Eric Sosman <es*****@ieee-dot-org.invalidwrote:
In the Rationale, the Committee laid out the principles that
it tried to apply when making decisions about the language. One
of these was "Keep the spirit of C," and the very first point in
the short list of facets that constitute that spirit is "Trust
the programmer." As Richard Heathfield pointed out earlier, trust
is not a one-sided relationship; the trusted party bears a burden
arising from the fact of being trusted.
A burden and a benefit, simultaneously. :-)
The good idea is not to pass a null pointer in the first place.
And yet, if this is the case, why does free() accept NULL? The
same argument holds here, and -- historically speaking -- at the
time the C89 standard was being created, actual implementations
actually crashed if you called free(NULL). So the committee have
attempted to have it both ways: "We trust you (putting the burden
of checking for NULL first) when you call fclose(), but we do not
trust you (removing the burden of checking for NULL first) when
you call free()".

It is not consistent. But it is C. :-)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: gmail (figure it out) http://web.torek.net/torek/index.html
Jun 27 '08 #25

P: n/a
In article <67*************@mid.individual.net>,
Ian Collins <ia******@hotmail.comwrote:
>If fp is a null pointer, the argument *is* invalid, because fclose requires
fp to be a pointer to a stream that is associated with a file. A null
pointer doesn't qualify, since it is guaranteed not to point to any
object.
>It's a pity that case isn't specified in the way malloc/free is.
The case is different with malloc(). Malloc() can return null
when it succeeds, if its argument is 0.

I believe the requirement for free(0) to work was added at the same
time that malloc(0) was required to work and allowed to return a null
pointer.

-- Richard
--
:wq
Jun 27 '08 #26

P: n/a
In article <fu**********@registered.motzarella.org>,
santosh <sa*********@gmail.comwrote:
>So for the code in question I'd say that conforming compilers are
allowed to do anything since the behaviour is undefined (not explicitly
stated in the standard, but inferred) upon giving fclose an illegal
argument.
The standard *does* say that you get undefined behaviour if you pass
null to a library function expecting a pointer unless it explicitly
says you can. So the behaviour is certainly undefined.

-- Richard
--
:wq
Jun 27 '08 #27

P: n/a
On Sat, 26 Apr 2008 16:21:13 GMT, "Bartc" <bc@freeuk.comwrote in
comp.lang.c:
>
"Richard Heathfield" <rj*@see.sig.invalidwrote in message
news:dZ******************************@bt.com...
Bartc said:
This short program:

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

int main(void) {
int status;

status=fclose(0);

printf("fclose(0) status: %d\n",status);

}

crashes on the first two implementations I tried.
The Standard requires that you pass to fclose a pointer to a stream object
of type FILE. You did not do this. (0 doesn't point to any object at all,
let alone a stream object.) You broke the rules, so all bets are off.

fopen() returns a FILE* value, which can include NULL. So it's argueable
that NULL (or (FILE*)NULL) is acceptable, type-wise, to fclose().
There are a large number of standard library functions that accept a
pointer to char, expecting it to be the first character of a '\0'
terminated string. There are also functions in the C standard library
that return a pointer to char on success, but could return NULL,
strchr(), for one. Your suggestion, by analogy, could extend to
saying that all functions expecting a pointer to char should accept a
null pointer.

On the other hand, I think it would have been convenient to specify
that fclose(NULL) would be a no-op, not for the reason that you
mention, but for parity with free(NULL) being defined as a no-op.

As is it, at the end of an operation that allocates one or more
dynamic memory block, and opens one or more files, in a clean up
section that might be reached prematurely if any of the resource
allocations failed, you just have to write:

free (mem1);
free (mem2);
if (file1) fclose(file1);
if (file2) fclose(files):

....which makes the fclose() checking inelegant by comparison. But
such is life.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
Jun 27 '08 #28

P: n/a
Chris Torek wrote:
Eric Sosman <es*****@ieee-dot-org.invalidwrote:
.... snip ...
>
A burden and a benefit, simultaneously. :-)
>The good idea is not to pass a null pointer in the first place.

And yet, if this is the case, why does free() accept NULL? The
same argument holds here, and -- historically speaking -- at the
time the C89 standard was being created, actual implementations
actually crashed if you called free(NULL). So the committee have
attempted to have it both ways: "We trust you (putting the burden
of checking for NULL first) when you call fclose(), but we do not
trust you (removing the burden of checking for NULL first) when
you call free()".
However fclose doesn't crash on receiving a NULL. It returns EOF.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
** Posted from http://www.teranews.com **
Jun 27 '08 #29

P: n/a
Joe Wright wrote:
>
.... snip ...
>
I'm not sure it's invalid. Consider..

FILE *fp = fopen("file", "r");

which fails for some reason. Later in the program we do..

int stat = fclose(fp);

The fclose finds that fp does not point to an open file and
returns EOF.
And between fopen and fclose you use the file. If fopen failed it
is not usable, and it does not need closing. The standard says:

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.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
** Posted from http://www.teranews.com **
Jun 27 '08 #30

P: n/a
Bartc wrote:
>
This short program:

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

int main(void) {
int status;

status=fclose(0);

printf("fclose(0) status: %d\n",status);
}

crashes on the first two implementations I tried. Then I tried
DMC and that gave the expected EOF status.
Of course. fclose requires a non-NULL FILE* parameter.
Given the emphasis on error-checking in this group, it seems
astonishing that a library function (executed at most once per
file) cannot do this elementary check on it's parameter.

(It's possible a zero FILE* handle is returned by fopen() but
the file has to be closed for other reasons before it can
checked by the application.)
No, because if fopen returns a NULL (not a zero) it means the file
has not opened.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
** Posted from http://www.teranews.com **
Jun 27 '08 #31

P: n/a
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
implementation 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.

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

** Posted from http://www.teranews.com **
Jun 27 '08 #32

P: n/a
Bartc <bc@freeuk.comwrote:
>
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.
It *is* a good idea: it forces programmers to fix their defective code.

-Larry Jones

I don't NEED to compromise my principles, because they don't have
the slightest bearing on what happens to me anyway. -- Calvin
Jun 27 '08 #33

P: n/a
CBFalconer wrote:
Chris Torek wrote:
>Eric Sosman <es*****@ieee-dot-org.invalidwrote:
.... snip ...
>A burden and a benefit, simultaneously. :-)
>>The good idea is not to pass a null pointer in the first place.
And yet, if this is the case, why does free() accept NULL? The
same argument holds here, and -- historically speaking -- at the
time the C89 standard was being created, actual implementations
actually crashed if you called free(NULL). So the committee have
attempted to have it both ways: "We trust you (putting the burden
of checking for NULL first) when you call fclose(), but we do not
trust you (removing the burden of checking for NULL first) when
you call free()".

However fclose doesn't crash on receiving a NULL. It returns EOF.
Says who? The behaviour is undefined.

--
Ian Collins.
Jun 27 '08 #34

P: n/a
la************@siemens.com said:
Bartc <bc@freeuk.comwrote:
>>
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.

It *is* a good idea:
No, it's merely a useful consequence.
it forces programmers to fix their defective code.
If that were true, it would be a pity that it isn't guaranteed by the
Standard. But it isn't true, of course. Some programmers never even see
the crashes, let alone fix their causes. For example, I have a web browser
written by someone else, which crashes whenever I accidentally click on a
PDF link and then click "cancel" on the subsequent dialog asking if I want
to hand over my firstborn to Adobe. Clearly the programmer never bothered
to test this execution path, so he has /not/ been forced to fix his
defective code.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #35

P: n/a
CBFalconer said:

<snip>
However fclose doesn't crash on receiving a NULL. It returns EOF.
$ cat foo.c
#include <stdio.h>

int main(void)
{
fclose(NULL);
printf("Hello, world!\n");
return 0;
}

$ ./foo
Segmentation fault (core dumped)

Undefined behaviour need not have the same effect on my system as it does
on yours. I was under the impression that you already knew that.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #36

P: n/a
Richard Heathfield wrote:
la************@siemens.com said:
>Bartc <bc@freeuk.comwrote:
>>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.
It *is* a good idea:

No, it's merely a useful consequence.
>it forces programmers to fix their defective code.

If that were true, it would be a pity that it isn't guaranteed by the
Standard. But it isn't true, of course. Some programmers never even see
the crashes, let alone fix their causes. For example, I have a web browser
written by someone else, which crashes whenever I accidentally click on a
PDF link and then click "cancel" on the subsequent dialog asking if I want
to hand over my firstborn to Adobe. Clearly the programmer never bothered
to test this execution path, so he has /not/ been forced to fix his
defective code.
But he or she would if a paying customer filed a bug report. That is,
unless he or she works for a well known supplier of non-compliant browsers.

--
Ian Collins.
Jun 27 '08 #37

P: n/a
Ian Collins said:
Richard Heathfield wrote:
>la************@siemens.com said:
>>Bartc <bc@freeuk.comwrote:
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.
It *is* a good idea:

No, it's merely a useful consequence.
>>it forces programmers to fix their defective code.

If that were true, it would be a pity that it isn't guaranteed by the
Standard. But it isn't true, of course. Some programmers never even see
the crashes, let alone fix their causes. [example snipped] Clearly the
programmer never bothered to test this execution path, so he has /not/
been forced to fix his defective code.
But he or she would if a paying customer filed a bug report.
So what you're saying is that the crash in itself is not sufficient to
force the programmer to fix the defective code. This doesn't appear to
contradict anything I said above.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #38

P: n/a
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.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
** Posted from http://www.teranews.com **
Jun 27 '08 #39

P: n/a
Richard Heathfield wrote:
>
.... snip ...
>
Undefined behaviour need not have the same effect on my system as
it does on yours. I was under the impression that you already
knew that.
See my reply to Ian.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
** Posted from http://www.teranews.com **
Jun 27 '08 #40

P: n/a
CBFalconer said:
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.
<snip>
>
[#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.
Note that the implementation is not *obliged* to detect the error of
passing NULL to this function. The Standard merely documents the result if
such an error /is/ detected. The behaviour if you pass NULL to fclose
remains undefined.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #41

P: n/a
CBFalconer said:
Richard Heathfield wrote:
>>
... snip ...
>>
Undefined behaviour need not have the same effect on my system as
it does on yours. I was under the impression that you already
knew that.

See my reply to Ian.
See my reply to your reply to Ian.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #42

P: n/a
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.

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.
See Richard's reply to your reply to my reply.

--
Ian Collins.
Jun 27 '08 #43

P: n/a
Richard Tobin wrote:
In article <fu**********@registered.motzarella.org>,
santosh <sa*********@gmail.comwrote:
>>So for the code in question I'd say that conforming compilers are
allowed to do anything since the behaviour is undefined (not
explicitly stated in the standard, but inferred) upon giving fclose an
illegal argument.

The standard *does* say that you get undefined behaviour if you pass
null to a library function expecting a pointer unless it explicitly
says you can. So the behaviour is certainly undefined.
Okay. I guess it says this somewhere else. IMHO, it should also have
been added to the description of fclose and other functions that are
not defined for a null pointer parameter.

Jun 27 '08 #44

P: n/a
Richard Heathfield wrote:
Ian Collins said:
>Richard Heathfield wrote:
>>la************@siemens.com said:

Bartc <bc@freeuk.comwrote:
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.
It *is* a good idea:

No, it's merely a useful consequence.

it forces programmers to fix their defective code.

If that were true, it would be a pity that it isn't guaranteed by
the Standard. But it isn't true, of course. Some programmers never
even see the crashes, let alone fix their causes. [example snipped]
Clearly the programmer never bothered to test this execution path,
so he has /not/ been forced to fix his defective code.
But he or she would if a paying customer filed a bug report.

So what you're saying is that the crash in itself is not sufficient to
force the programmer to fix the defective code. This doesn't appear to
contradict anything I said above.
I suppose Larry implied crashes during development and in-house testing.
But a crash isn't guaranteed even in this case. It's merely an outcome
on several common platforms.

Jun 27 '08 #45

P: n/a
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.

Jun 27 '08 #46

P: n/a
CBFalconer <cb********@yahoo.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
implementation 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.
Jun 27 '08 #47

P: n/a

"Eric Sosman" <es*****@ieee-dot-org.invalidwrote in message
news:i-******************************@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
Jun 27 '08 #48

P: n/a
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
Jun 27 '08 #49

P: n/a

"pete" <pf*****@mindspring.comwrote in message
news:Rp******************************@earthlink.co m...
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
Jun 27 '08 #50

53 Replies

This discussion thread is closed

Replies have been disabled for this discussion.