> > The answer is that if you're compiled single-threaded, it's > > perfectly legal. > > If you're multi-threaded, it's not. > > I guess by "legal" you mean that it has defined behaviour.
Yes, that's correct. > Both the C99 standard and SUS have this nice warning in it. In C99: > > errno > > which expands to a modifiable lvalue that has type int, > the value of which is set to a positive error number by > several library functions. It is unspecified whether errno > is a macro or an identifier declared with external linkage. > If a macro definition is suppressed in order to access an > actual object, or a program defines an identifier with the > name errno, the behavior is undefined. > > SUS v3: > It is unspecified whether errno is a macro or an identifier declared > with external linkage. If a macro definition is suppressed in order > to access an actual object, or a program defines an identifier with > the name errno, the behavior is undefined. This isn't relevent. The platform's *IMPLEMENTATION* of SUS and C99 cannot and does not have to itself be defined under those very standards. It's impossible to implement C99 in strictly-compliant C99 code. > I read your example, after fixing it's problems, as "suppressing > the macro definition", and so would have undefined behaviour. That's absolute craziness. If I take the part of glibc that calls 'clone', would you argue that that has undefined behavior too since SUS and C99 don't say anything about 'clone'?! We're talking about the platform's *implementation* of those very standards. It doesn't have to comply with the standards the same way code written to use it does. > Compiler people are very good in finding things that are undefined, > and they might do things with it you don't expect. That doesn't mean > everything is undefined. Compiler people also internally define things that are normally undefined. > In the case the macro is expanded to a function call, there is > nothing that tell the compiler that that function always returns > the same value. I don't see how the compiler could do such an > optimization. And yet compilers do precisely this optimization with all kinds of other functions. For example, 'strcpy' may be magically optimized by the compiler based on secret knowledge of the length of the string where it is known. For example, if I take: #include <string.h> void foo(char *k) { strcpy(k, "hello"); } And I compile it on Linux, I get: foo: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax movl $1819043176, (%eax) movw $111, 4(%eax) popl %ebp ret Where did the call to 'strcpy' go? Obviously there was something to tell the compiler what 'strcpy' did and allow the compiler to replace it with two moves. The compiler clearly 'somehow' knew that in this case, semantically, 'strcpy' had to copy six bytes every time. There is no reason why, on Linux, code compiled without the '-pthread' option couldn't internally 'optimize' errno to save the TLS dereference. If such an optimization were added to the platform tomorrow, on what grounds would you object to it? (Breaks working code, I suppose, but that's not an excuse to write more 'working by accident' code.) I should point out that there's a history of such gcc optimizations, even if they break large amounts of working code. So long as the working code is breaking the rules and the optimization actually provides a benefit, it's fair game to the gcc developers. The aliasing fiasco was an example of this. Lots of code broke C aliasing rules but always worked because no compiler was smart enough to optimize the code such that it mattered. They added those optimizations and enabled them by default. A lot of working code broke. The next optimization could be caching the address of 'errno' in code not compiled with thread-safety requested on platforms where there is a documented way to request thread-safety. > > Really, it's an extraneous example. The point I'm trying to > > make is really > > simple -- you cannot expect threat safety if the platform > > provides a way to > > ask for it and you choose not to do so. > As far as I know there actually isn't a _compiler_ (cc1) option to make > something thread safe. There are only preprocessor and linker options. This is an implementation detail on a particular platform. On most Linux platforms, the '-pthread' option only has preprocessor and linker effects. But preprocessor changes can cause code to compile very differently. Some header files have '#ifdef _REENTRANT' sections which are conditioned on the preprocessor options. In any event, it doesn't matter. You can't justify optimizations based on implementation details, which is what these are. > > > Let's assume for a moment that openssl is not "compiled for multi > > > thread", whatever you mean with that exactly. Even when the > > > application > > > is using threads, when openssl tries to use errno it will get > the one for > > > > > the current thread. > > Really? Even if it's coded like my 'foo' above? It will > > magically always get > > the right 'errno'? How?! > Not in case of your example, which you said yourself wasn't legal in > multi-threaded applications. It's also not using errno, it's using > some other variable. If you go and add something that has > undefined behaviour, lots of things might not work as you expect. You missed the point of the example which was that this was an optimization done by some element of the system. It's not undefined behavior because the platform knows that it will comply with the 'as-if' rule for all compliant code. DS ______________________________________________________________________ OpenSSL Project http://www.openssl.org Development Mailing List openssl-dev@openssl.org Automated List Manager [EMAIL PROTECTED]