Extent of the "as-if" rule

A

August Derleth

Michael said:
However, it's entirely possible to imagine an implementation where a
conforming program could indirectly detect an effect of opening a
file for reading.

For example, consider an implementation which creates a file (in the
sense of "a filesystem object which can be opened using fopen") in a
temporary area for each file a program opens. These temporary files
are named using a predictable convention. A conforming program
could potentially determine how many files it had opened by attempting
to fopen (and then immediately fclose) these temporary files and seeing
how many such fopens succeeded.

Which could be a good way of doing it...
That ought to work on a Linux system with the proc filesystem mounted,
for example, though I haven't actually tried it.

[OT]
....except here. In /proc, the directories (which are named after
currently existant PIDs and contain files and directories containing
info relative to those processes) are created and destroyed along with
the processes. Which means that in a system with an uptime of more than
a few moments, they wouldn't exist in sequential order. In fact, the
`array' is quite sparse most of the time.

There are, of course, ways to work around this. But that would drag this
comment even further from the topic (of the thread and the newsgroup). ;)
[/OT]
Such a program would get a different result before and after the
hypothetical fopen if that fopen were not optimized away. If it were
optimized away, of course, the program would get the same result
before and after the fopen.
(Unless the implementation were clever
enough to understand the operation of the count-my-open-files
function and simulate the correct result - that is, extend the as-if
behavior to cover this aspect as well.)

Heh. Any compiler that smart could phone in sick and spend the day
goofing off on Usenet. ;)
Such a program would not be strictly conforming, since (to be useful)
it would have to produce output that depended on unspecified behavior,
but it could be conforming, as far as I can tell.

Well, I suppose that your notion of `conforming' is different from my
own. If a program implicitly makes use of a highly system-specific
property, I'd consider it nonconformant and I wouldn't expect it to work
/at all/ in another system context. That fopen() trick is at the mercy
of all parts of the system, apparently including the compiler.

I would, however, want a compiler flag to tell the thing not to optimize
certain ways, or even not to optimize at all. But that's pure QoI.
 
J

Jack Klein

It is purely pedantic because no existing compiler will remove the call
to fopen ().

On the other hand: If you are a compiler writer and you want to remove
this kind of call, then you have to _prove_ that the C Standard allows
it. If you are an application programmer and you want to make sure that
the call is not removed, then you could write

volatile FILE* p = fopen ("my file", "options);

I think not, but perhaps:

FILE * volatile p = fopen (/*...*/);

....might.
 
J

Jack Klein

I have no intuition 'in the context of the C language' about files,
whatsoever. To me handling files is the job of the operating system and
the C standard ought to be non-explicit in what are and are not side
effects when doing /anything/ with a file.

A possible approach that just occurs to me would be to allow "volatile"
as a function attribute, meaning that the function is effectively
declared to communicate with the world outside the abstract machine,
with all bets off regarding side effects (no optimizations possible).


Dan Pop would probably argue that such a 'well-defined side effect' is
still not relevant to the compiler. C99 states exactly three things that
are side effects (for the compiler), and opening a file for reading is
not one of them, whether you do POSIX or not.

Best regards,

Sidney

No, because the meaning of at least one of those definitions, the one
relevant to this discussion, is debatable:

5.1.2.3 P2 states that "modifying a file" is a side effect. It does
not say writing to a file or changing the contents of a file.

If the fopen() call changes an entry in the system's file system that
pertains to that particular file, that modifies the file without
changing its contents.

Whether or not the "modifying a file" phrase in the standard includes
that type of modification as a side effect is not spelled out one way
or the other, and perhaps should be.
 
J

Jack Klein

in comp.std.c i read:

actually unices typically do record the time a file was opened. dan might
argue that by itself that isn't sufficient, and in some ways i agree, but
there remains a flaw: there's no way to know whether the FILE object
contains a volatile member or would call the environment since it's
implementation defined.

But that's exactly the point, the implementation should know what's in
its implementation-defined headers, shouldn't it?
 
K

Keith Thompson

A swap file or partition is not a file, in the sense of the C standard.

A swap file is a file if it has a name that can be used for a
successful call to fopen(). (Linux even has a "swapon" command that
causes an existing file to be used as a swap file.)
A program with no side effects can cause the contents of the swap file
to be changed by the mere fact that it is partly or totally swapped out.

Agreed -- and I agree that such a change should not be considered a
"side effect" as far as the C standard is concerned.
 
D

Dan Pop

In said:
A swap file is a file if it has a name that can be used for a
successful call to fopen(). (Linux even has a "swapon" command that
causes an existing file to be used as a swap file.)

Once you activate swapping on a certain file, this file no longer has
the semantics of standard C file, even if you can access it from a C
program.
Agreed -- and I agree that such a change should not be considered a
"side effect" as far as the C standard is concerned.

Then, what is your point?

Dan
 
D

Dan Pop

In said:
A compiler which optimized away opening a file for reading would not be
conforming to the POSIX standard.

Could you post the chapter and verse? I can't find any mention that
open() in read mode modifies anything in the file inode.

Dan
 
D

Dan Pop

In said:
As far as I can tell, the C standard does not define semantics of a
file.

Then, what does "7.19.3 Files" talk about?

Surprisingly, I don't see "file" defined either.

Which means that the definition must be taken from a normative reference,
such as ISO/IEC 2382-1:1993.
So why not view a file as 'contents' + 'attributes'; in that case,
opening a file which may change attributes counts as "modifying the file".

Where does the standard mention that fopen in read mode affects any
"file attributes"?

Where does the standard mention anything at all about "file attributes"?

Dan
 
P

pete

Sidney said:
As far as I can tell, the C standard does not define semantics of a
file. Surprisingly, I don't see "file" defined either.

N868 7.19.3 Files,
discusses files and their relationship to streams,
also uses "a terminal" and "a disk file" as two examples of files.
 
P

pete

If puts is defined this way:

#include <stdio.h>
int puts(const char *s)
{
return fputs(s, stdout) > -1 ? fputc('\n', stdout) : EOF;
}

.... is there any way that the call to fputc in the above definition,
could return EOF ?

I think that there isn't, because the operation of the standard
output stream has already been verified by the call to fputs,
and the '\n' argument shouldn't cause any problems either.

Is there anything else involved ?
 
J

James Kuyper

Wojtek Lerch wrote:
....
The compiler automatically replaces a return statement in main() with a call
to exit().

That's not correct - such a re-write would not handle correctly calls to
main() frome within user code (which are legal). It's more accurate to
say that the initial call to main() is essentially equivalent to

exit(main(argc,argv));
 
J

James Kuyper

pete said:
If puts is defined this way:

#include <stdio.h>
int puts(const char *s)
{
return fputs(s, stdout) > -1 ? fputc('\n', stdout) : EOF;
}

... is there any way that the call to fputc in the above definition,
could return EOF ?

I think that there isn't, because the operation of the standard
output stream has already been verified by the call to fputs,
and the '\n' argument shouldn't cause any problems either.

You're implying that the "operation" of the standard output stream can't
change between the fputs() call and the fputc() call. Offhand, I can't
see any reason why that would be true. If nothing else, a critical
hardware component could fail between the two calls.
 
D

Dan Pop

In said:
If puts is defined this way:

#include <stdio.h>
int puts(const char *s)
{
return fputs(s, stdout) > -1 ? fputc('\n', stdout) : EOF;
}

... is there any way that the call to fputc in the above definition,
could return EOF ?

I think that there isn't, because the operation of the standard
output stream has already been verified by the call to fputs,
and the '\n' argument shouldn't cause any problems either.

Is there anything else involved ?

Imagine that stdout is unbuffered and connected to a disk file
and the fputs call has written the last bytes available in the filesystem.
Where is the newline character going to be written by the fputc call?

As a general rule, if the standard doesn't guarantee that a certain
library function call will succeed, it can fail for unspecified reasons.
According to some committee members, even realloc(ptr, oldsize) is
allowed to fail, although it's logically a no-op.

Dan
 
P

pete

James said:
You're implying that the "operation" of the
standard output stream can't change between the fputs()
call and the fputc() call.

I'm asking, yes.
Offhand, I can't see any reason why that would be true.
If nothing else, a critical hardware component could fail
between the two calls.

Wouldn't such a failure disqualify the implementation from being a
conforming one, and thus no longer subject to the standard ?

Is an implementation which issues all the right diagnostics during
translation, but generates no output for any C program, conforming ?

(I changed the subject line, because I accidenatlly wrote fgets)
 
M

Michael Wojcik

Michael said:
[examining /proc/<pid>/fd/*]
That ought to work on a Linux system with the proc filesystem mounted,
for example, though I haven't actually tried it.

[OT]
...except here. In /proc, the directories (which are named after
currently existant PIDs and contain files and directories containing
info relative to those processes) are created and destroyed along with
the processes. Which means that in a system with an uptime of more than
a few moments, they wouldn't exist in sequential order. In fact, the
`array' is quite sparse most of the time.

#include <stdio.h>
int main(void)
{
FILE *fd = fopen("/proc/self/fd/0", "r");
if (fd) puts("This process has an open descriptor 0");
fclose(fd);
return 0;
}

appears to work on my Linux system, and does not appear to me to
be nonconforming; it uses only standard library calls. Extending
it to iterate through, say, the first 10 descriptor numbers to
find out how many files the process has open (up to 10) is trivial.
That in turn would allow it to detect the side effect of opening a
file for reading.

Of course, this is just intended as a real-world example of a
hypothetical implementation which would allow a program to detect
a side effect of such an fopen, and have output that depended on
it, resulting in a difference in program output if the fopen were
optimized away.
Well, I suppose that your notion of `conforming' is different from my
own. If a program implicitly makes use of a highly system-specific
property, I'd consider it nonconformant and I wouldn't expect it to work
/at all/ in another system context.

I believe it's conforming because it only uses standard language
constructs and library calls. It should be "acceptable to any
conforming implementation", which is how C90 defines conformance. It
won't *work* on all conforming implementations, certainly, in the
sense of doing what I'd like it to do; on many of them the fopens of
/proc/whatever will return NULL because that's not a valid filename.
But that doesn't make them nonconforming as defined in the standard.

Of course it's not strictly conforming, since its output depends on
implementation details.

Note that I'm not convinced myself that a conforming implementation
couldn't optimize away the "unused" fopen under the as-if rule. I
don't know if the standard's definition of side effect would include
the sort of thing I'm describing here. I only raise it because it
appears to be a side effect that can be detected by a conforming
program, unlike file timestamps and that sort of thing.
 
J

James Kuyper

pete said:
I'm asking, yes.


Wouldn't such a failure disqualify the implementation from being a
conforming one, and thus no longer subject to the standard ?

Every I/O function described by the standard has explicit permission to
fail, and the standard is deliberately unspecific about the reasons why
they might fail. If a system starts out with two working hard disks, and
looses one during the running of a program, do you think it would
thereby become non-conforming? If so, could you cite the relevant
section of the standard that would be violated?
Is an implementation which issues all the right diagnostics during
translation, but generates no output for any C program, conforming ?

I believe so, so long as all of the relevant function calls return the
required indications of I/O failures.
 
P

pete

James said:
Every I/O function described by the standard has explicit permission to
fail, and the standard is deliberately unspecific about the reasons why
they might fail. If a system starts out with two working hard disks, and
looses one during the running of a program, do you think it would
thereby become non-conforming? If so, could you cite the relevant
section of the standard that would be violated?

If the disk was the file that was associated with a stream,
then no more file, implies no more association.

N869
7.19.3 Files
[#1] A stream is associated with an external file (which may
be a physical device) by opening a file, which may involve
creating a new file.
I believe so, so long as all of the relevant function calls return the
required indications of I/O failures.

Thank you.
 
P

pete

Dan said:
Imagine that stdout is unbuffered and connected to a disk file
and the fputs call has written the last bytes available in the
filesystem.
Where is the newline character going to be written by the fputc call?

As a general rule, if the standard doesn't guarantee that a certain
library function call will succeed,
it can fail for unspecified reasons.
According to some committee members, even realloc(ptr, oldsize) is
allowed to fail, although it's logically a no-op.

Thank you.
 
K

Keith Thompson

Once you activate swapping on a certain file, this file no longer has
the semantics of standard C file, even if you can access it from a C
program.

Chapter and verse, please. C99 7.9.13 describes (in deliberately
vague terms) what a "file" is. It's clear that it can be a disk file
or a device (including a terminal). I see nothing in the description,
or anywhere else in the standard, that would exclude, for example, a
disk file or device to which the Linux "swapon" command has been
applied.
Then, what is your point?

My point is that, though common sense (at least mine) says that
updates to a swap file caused by updating a non-volatile variable
should not be considered side effects, I don't see that common sense
reflected in the wording of the standard (unless you can demonstrate
that a swap file is not a "file").

Perhaps it would suffice to add something to 5.1.2.3 saying that an
implementation may define that certain file updates are not side
effects. Or the phrase "modifying a file" could be changed to
"explicitly modifying a file".

Or (this is an interpretation I just thought of), we could decide that
it's the operating system, not the program, that modifies the swap
file, so it's not considered a side effect *of the program*, even
though it was indirectly caused by the execution of the program.

However it's interpreted and/or modified, I doubt that any
implementers will actually avoid optimizations just because they might
modify a swap file. The discussion, I think, is about wording, not
about intent.
 

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

Staff online

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,052
Latest member
LucyCarper

Latest Threads

Top