David Brown said:
On 12/04/2013 02:44 AM, David Brown wrote:
...
That's not quite the right way to think about it. In general,
the reason why the committee chose to leave the behavior of a C
construct undefined was that doing so gives the implementation
the freedom needed to do whatever it considers is most
appropriate. In the particular, if the behavior of a call to
waitpid() were well-defined, that would force the implementor to
make sure that the call had precisely the behavior defined for it
by the C standard (whatever that might be), whether or not the OS
provided a function of the same name, and it would have to do so
even if the behavior specified by the C standard were different
from the behavior provided by the OS function of the same name.
Because the behavior is undefined, an implementation of C is free
to implement the call as simply conforming to the calling
conventions of the corresponding platform, and leaving the details
of what happens when it is called up to the library containing the
corresponding function.
This means that a compiler implementer could theoretical produce
nasal daemons when the programmer calls waitpid(), just because the
writer thought that is "most appropriate" ? He would not even have
to document it (as would be the case for "implementation-defined
behaviour")? Obviously no sane compiler implementer /would/ do such
a thing, but there seems to me to be a loophole there. [snip
elaboration]
The previous responses here haven't been very illuminating, and I
believe have steered the conclusions in a bad direction. First,
when something is "undefined behavior" (as with the "unspecified"
or "implementation-defined" labels) that is not a description of
behavior but rather a specification of what behaviors are
permissible. Also, something people often forget, what's being
addressed is not the behavior of /programs/ but the behavior of
/implementations/. Of course it is common to talk about how a
certain program construct must behave, but that's only a shorthand
for saying the implementation must produce an executable which
when run will act according to the semantic descriptions given in
the Standard. That may be a subtle difference, but here it is an
important one.
Upon encountering a call to waitpid(), what is an implementation
obliged to do? The answer is mostly found in 5.1.1.1 p1 and
5.1.1.2 p1. Each translation unit must be processed, linked with
library functions and also other TU's, and ultimately an executable
produced. During translation a call to waitpid() must be
processed just like any other function call. Similarly during
link time the linkage must be done just the way it would for
any other link-time connection. What does this mean for how
waitpid() behaves? There are two possibilities.
One is that there is a "magic" object file (magic in the sense
that its origins are unknown, but accepted by the linker even
though the compiler didn't produce it) that defines an external
reference for waitpid(), so the hookup is complete. A call to
waitpid() happens in the same way that other function calls do
(ie, the implementation is obliged to do that), but what
waitpid() does is outside the domain of the implementation.
Whatever happens is not defined behavior, unspecified behavior,
implementation-defined behavior, or undefined behavior, because
these terms make sense only in the context of a C implementation
processing (all or part of) a C program. Here that hasn't
happened. Probably the best term for this situation is
"extra-linguistic behavior" - it is simply outside the realm of
what the C standard considers. The call must be done normally;
after that some other set of rules is in charge.
The other possibility is that waitpid() is supplied by one of
the implementation's library components, ie, a component the
implementation knows about. In this case such a function would
count as an extension in the sense of 4 p6. This in turn says
something about the behavior - in section 4 p8, the Standard
requires implementations to defined (among other things) all
extensions. So what waitpid() does must be defined explicitly
(under this scenario) by the implementation, even though it does
not fall under the heading of 'implementation-defined'.
So perhaps you can rest easier now, knowing that in neither case
is the implementation off the hook for what happens when making
a call to waitpid() - after the call is made, maybe, but not
before.