Subj : Re: Non-strictly-conforming and unspecified versus undefined behavior To : comp.programming.threads,comp.std.c From : David Hopwood Date : Sat Feb 19 2005 07:07 am Douglas A. Gwyn wrote: > David Hopwood wrote: >>David Schwartz wrote: >>>"Alexander Terekhov" wrote... >>> >>>>Under C/POSIX different objects just can't have the same address. >>>>And threads share the entire address space. By definition. >>> >>> That's ridiculous. Providing no strictly-conforming code can tell the >>>difference, POSIX is silent. >> >>I keep hearing this idea that POSIX (or Standard C) only imposes >>requirements for strictly-conforming code. Where does it come from? > > All such standards have an "escape clause" to the effect > that if your program does not follow certain specified > rules, its behavior is no longer guaranteed by the standard. > > The category of "strictly conforming program" means for C > several things, essentially that the output of the program > does not depend on any unspecified or implementation-defined > properties and does not invoke undefined behavior. Since > the C host model does not include platform-specific interfaces, > in particular that means that no POSIX-specific functions can > be used. The purpose of strict conformance can be seen in the > requirement that *every* conforming C implementation "accept" > every s.c. program. (Whether the program will "work" depends > on whether it exceeds resource limits.) Thus, a s.c. program > is in a specific sense "maximally portable" across different > platforms. All of that is beside the point. The claims I am making are: A. C99 imposes requirements for programs that are not strictly conforming. B. POSIX imposes requirements for programs that are not Strictly Conforming POSIX Applications. Therefore, it is incorrect to say that "Providing no strictly-conforming code can tell the difference, POSIX is silent." Nothing that Doug has said above contradicts this. Note that it was David Schwartz' statement that introduced the term "strictly-conforming code" in the context of POSIX, when "Strictly Conforming POSIX Application" was meant. Perhaps some confusion could have been avoided if I had corrected that error first. In any case, there is no possibility that statement A above could be false while B is true, or vice versa, because the argument for both statements is the same. It goes like this: In each environment, the appropriate definition of "strictly conforming" code excludes behaviour that is unspecified or implementation-defined in that environment. C99 4 #5: # A strictly conforming program shall use only those features of the # language and library specified in this International Standard.2) It # shall not produce output dependent on any unspecified, undefined, or # implementation-defined behavior [...] POSIX XBD 2.2.1 #6: # For the C programming language, [a Strictly Conforming POSIX # Application] shall not produce any output dependent on any behavior # described in the ISO/IEC 9899:1999 standard as unspecified, undefined, # or implementation-defined, unless the System Interfaces volume of # IEEE Std 1003.1-2001 specifies the behavior (As a result, the categories of strictly conforming C99 programs and Strictly Conforming POSIX C-language Applications both exclude essentially all useful, non-trivial programs.) However, C99 4 #3 applies in both cases (it is incorporated in POSIX by reference to C99): # 2 If a "shall" or "shall not" requirement that appears outside of a # constraint is violated, the behavior is undefined. [...] # 3 A program that is correct in all other aspects, operating on correct # data, containing unspecified behavior shall be a correct program and # act in accordance with 5.1.2.3. In context, "other aspects" refers to aspects other than having undefined behaviour. "Correct data" is unfortunately not defined, but what is clear is that there must be *some* programs that contain unspecified behaviour and for which the implementation must "act in accordance with 5.1.2.3." This is the clause defining "Program execution" -- i.e. essentially all of the runtime behaviour of a C program. Doug Gwyn argues that the "strictly conforming" category is needed to define implementation conformance. If his argument were correct it would also apply to both plain C99 and POSIX C99. However it is not correct: the requirements imposed by C99 4 #3 are a *strict superset* of those imposed for strictly conforming programs. Apart from its definition, the only other use of the term "strictly conforming" in C99 is in clause 4 #6, which says that "A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any strictly conforming program." However, it appears that the intent was that extensions should also not alter the set of *possible* behaviours of programs covered by 4 #3 (otherwise, 4 #3 would have no force at all). [For instance, it is clearly not intended that an implementation extension could alter the behaviour of 'puts("foo" == "foo" ? "same" : "different")' so that it might no longer print either "same" or "different".] IOW, the "strictly conforming" category could be removed from the standard and 4 #6 corrected appropriately, without any ill effects. For POSIX, while the current definition of "Strictly Conforming POSIX Application" is equally as useless as "strictly conforming C99 program", it would probably be preferable to fix it rather than to eliminate it, since the problem appears only to be with paragraph 6: > POSIX conformance is somewhat different, but amounts to an > extension of the Standard C environment to include support > for the headers, functions, etc. specified by POSIX. The > POSIX *thread* specification adds yet another set of functions > and rules for their use. pthreads is a mandatory part of POSIX. There is no need to make this more complicated than it needs to be. >>This is quite relevant to c.p.threads, BTW. Not imposing any requirements >>for code that has nondeterministic, i.e. unspecified, behaviour would make >>POSIX useless for multithreaded programming. > > POSIX certainly requires that Standard C rules apply within > a single thread. More precisely, the Standard C rules have to be interpreted somehow as applying to single threads, even though the entities being manipulated by each thread can only be properly defined in a language model that takes concurrency into account. This is one of the weakest areas of the POSIX specification -- hence the interminable arguments about volatile, and the problems described in . > Because a POSIX thread is created within a > particular function invocation, the only way threads can > validly share data is via globals (extern data) or pointers. Actually there are other ways (e.g. pthread_setspecific etc.), but that's not worth quibbling about. > There was a lot of dispute in a thread a few months ago about > whether volatile qualification is necessary for accesses to > shared objects. My reading of the POSIX thread spec says yes, > others say no. In any case, you'd better interlock such > accesses using the functions POSIX provides for that purpose. > (The specific argument was whether such interlock functions > also flushed any cached values. I find it hard to believe > that that could be the intent, since it's not obvious that > such a requirement could be met on many reasonable platforms.) As I pointed out at the time, it cannot have anything to do with "flushing cached values", since POSIX and C99 have no concept of "caching" values. It is one thing to understand how a possible class of implementations would work, and quite another to understand what the semantic requirements are; you seem to be confusing one for the other. -- David Hopwood .