Re: Static global - bug? (Re: Two valgrind warningsinOpenSSL-possible bug???)

2008-01-29 Thread Brad House

void foo(void)
{
 static int *my_errno=NULL;
 if(my_errno==NULL) my_errno=errno;
 // code that uses 'my_errno' as if it were 'errno'
}



No, this is not legal code under the POSIX standard at all.


Since this code is single-threaded only, what POSIX standard are you talking
about? The pthreads standard doesn't apply.

In any event, provided the code is compiled single-threaded and
thread-safety has not been asked for, it's a perfectly legal compiler
optimization under the 'as-if' rule. No compliant code could ever tell the
difference.

Remember, I was not suggesting anyone actually write this code. I was
suggesting it was a legal compiler optimization so long as the code was not
compiled multi-threaded.

My point is very similar, nothing requires the platform to generate
thread-safe code if you don't ask it to. If it just happens to, it's purely
by accident.


Well, I'm late to this discussion, but it would seem to me that quite
a few things are wrong with that ...
First, my_errno=errno;  might be more appropriate, after all, you need
to reference the address of errno, not the current value, right? But that
would also assume errno is declared as an int.  Some implementations,
like glibc, in bits/errno.h define errno as  #define errno (*__errno_location())
... so doing what you suggest wouldn't exactly be legal.

So assuming your system really declares errno as an int, and not a
define to a function, you wouldn't just be able to use 'my_errno'
instead of errno ... maybe (*my_errno), since obviously, you can't
forget to dereference it, right?

-Brad
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: Static global - bug? (Re: Two valgrind warningsinOpenSSL-possible bug???)

2008-01-29 Thread David Schwartz

 void foo(void)
 {
  static int *my_errno=NULL;
  if(my_errno==NULL) my_errno=errno;
  // code that uses 'my_errno' as if it were 'errno'
 }

 No, this is not legal code under the POSIX standard at all.

Since this code is single-threaded only, what POSIX standard are you talking
about? The pthreads standard doesn't apply.

In any event, provided the code is compiled single-threaded and
thread-safety has not been asked for, it's a perfectly legal compiler
optimization under the 'as-if' rule. No compliant code could ever tell the
difference.

Remember, I was not suggesting anyone actually write this code. I was
suggesting it was a legal compiler optimization so long as the code was not
compiled multi-threaded.

My point is very similar, nothing requires the platform to generate
thread-safe code if you don't ask it to. If it just happens to, it's purely
by accident.

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: Static global - bug? (Re: Two valgrind warningsinOpenSSL-possible bug???)

2008-01-29 Thread David Schwartz

 Well, I'm late to this discussion, but it would seem to me that quite
 a few things are wrong with that ...
 First, my_errno=errno;  might be more appropriate, after all, you need
 to reference the address of errno, not the current value, right? But that
 would also assume errno is declared as an int.  Some implementations,
 like glibc, in bits/errno.h define errno as  #define errno
 (*__errno_location())
 ... so doing what you suggest wouldn't exactly be legal.

The errno was a typo. As for the second part, the platform knows its
definition of 'errno', so it doesn't have to worry about it being different.

 So assuming your system really declares errno as an int, and not a
 define to a function, you wouldn't just be able to use 'my_errno'
 instead of errno ... maybe (*my_errno), since obviously, you can't
 forget to dereference it, right?

Right. Again, I'm talking about an internal optimization. It wasn't mean to
be runnable code.

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.

If you break the rules, optimizations and internal translations may turn
your code into something other than you meant it to be. If you follow the
rules and that happens, the optimization is broken. If you don't follow the
rules, then you get shown by the platform where you should have.

The literature is full of examples of code that broke the rules, seemed to
work, and then failed in horrible ways in production. We can either learn
from the literature or ignore it.

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: Static global - bug? (Re: Two valgrind warningsinOpenSSL-possible bug???)

2008-01-29 Thread David Schwartz

  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
movl8(%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