fclose(0)

B

Bartc

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
 
S

santosh

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

Richard

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

Ben Bacarisse

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

Bartc

Richard Heathfield said:
Bartc said:


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

Bartc

Ben Bacarisse said:
Not everyone will expect the same thing!


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()".
 
R

Richard

Bartc said:
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.
 
B

Ben Bacarisse

Bartc said:
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?


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.
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).
 
A

Antoninus Twink

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.)
 
B

Bartc

Antoninus Twink said:
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.
 
K

Keith Thompson

Bartc said:
[...]

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

Lew Pitcher

Bartc said:
[...]
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. ------
 
B

Bartc

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

Ian Collins

Richard said:
Joe Wright said:


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

Chris Torek

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. :)
 
L

lawrence.jones

Bartc said:
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
 
R

Richard Tobin

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.
[/QUOTE]
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
 
R

Richard Tobin

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Working with files 1
Command Line Arguments 0
code 34
[C language] Issue in the Lotka-Volterra model. 0
HELP:function at c returning (null) 4
please help a beginner 5
Problem with FCLOSE 11
comparison error 12

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top