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

2008-01-29 Thread David Schwartz

 There is no global variable named errno, it only exist in the TLS.  You
 could say that because there is only 1 TLS, that it's global, and it
 acts that way.  But it's not really the same as a normal global
 variable.  You can't access the variables in the same manner you access
 other global variables.

Is the following code legal:

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'
}

The answer is that if you're compiled single-threaded, it's perfectly legal.
If you're multi-threaded, it's not.

This might be a perfectly sensible optimization to condition on '_REENTRANT'
not being defined. In principle, the compiler might do such a thing
automatically if the overhead of TLS were higher than the overhead of the
test.

 In case of errno on a glibc system with NPTL there is no difference in the
 compiled code.  You always get the same function call.

Exactly. The precise same code can have a very different semantic meaning
depending upon whether it is used in a multi-threaded or a single-threaded
process. That's why you *must* specify appropriate compilation flags. The
code may need to change so that it can produce *different* code to get the
*same* semantic meaning.

 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?!

  That these two different semantics are implemented by the same
  code doesn't
  change the fact that the semantics are different. In fact, it makes the
  important point that the semantics of code can be changed by whether the
  process is single-threaded or multi-threaded.

 I'm not at all saying that the semantics are the same.  All I'm saying
 is that in case of errno on a recent glibc there is no difference in the
 compiled code depending on wether your application or library is
 multi-threaded or not.

There is a huge difference. In the case of a single-threaded process, it
will get a process global 'errno' and optimizations such as my 'foo'
function above are perfectly legal. In the case of a multi-threaded process,
they're not.

  On many Linux distributions, it is perfectly acceptable to do
 the following:
 
  #ifdef _REENTRANT
  // inefficient thread-safe code
  #else
  // more efficient code that assumes 'errno' is process-global
  #endif

 On many Linux distributions it's required that if such code is in a
 library that it's compiled using -D_REENTRANT for the packages
 they ship.  With other words, if the library can be compiled
 reentrant, that's what we want.

Right, and the OP is saying he doesn't have to compile with -D_REENTRANT (or
whatever else is specified on his platform as required for multi-threaded
code) and he can still use the library in a multi-threaded process.

I'm saying he can't do this even if he thinks the code will be the same
because the same code can mean something different. Different code may be
needed to get the same *effect*.

Compiling code without the compilation flags your platform documents as
required to get thread-safety guarantees and then using that compiled code
in a multi-threaded process is simply off the map. Anything can happen. Here
be dragons. This is so even in the case of Linux, where all the flags do (at
least, on most Linux platforms, AFAICT) is add a single define to the
compilation and a library to the linking.

And it's a bad idea even if you know it's safe on a particular platform. 9
times out of 10, code winds up running on platforms you never expected. If
these assumptions are no longer true on that platform, you may get code that
appears to work but has subtle bugs that cause it to do the wrong thing
under load. This is precisely the type of issue that can cause information
intended for one client to go to another. Not a good think in an
encryption/security context.

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 warnings inOpenSSL-possible bug???)

2008-01-29 Thread Tomas Mraz
On Tue, 2008-01-29 at 07:54 -0800, David Schwartz wrote:
  There is no global variable named errno, it only exist in the TLS.
 You
  could say that because there is only 1 TLS, that it's global, and it
  acts that way.  But it's not really the same as a normal global
  variable.  You can't access the variables in the same manner you
 access
  other global variables.
 
 Is the following code legal:
 
 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'
 }
 
 The answer is that if you're compiled single-threaded, it's perfectly legal.
 If you're multi-threaded, it's not.

No, this is not legal code under the POSIX standard at all.
-- 
Tomas Mraz
No matter how far down the wrong road you've gone, turn back.
  Turkish proverb

__
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 warnings inOpenSSL-possible bug???)

2008-01-29 Thread Paul Sheer
 The answer is that if you're compiled single-threaded, it's perfectly
legal.
 If you're multi-threaded, it's not.

err, nobody codes like this

find me an example in real-life code that is being used.
better yet, find me an example in OpenSSL.

Your other points I agree with however.

  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.

Err? No.

Between the time that errno is set, and errno is read by the application,
ANOTHER thread could have changed errrno!! The very definition
of a race condition.

Furthermore, you might be reading 'errno', but the library call in
libpthread
that replaced the library call you thought you were using was actually
setting (*__the_errno()). So you MUST link with -lpthread when you define
_REENTRANT and visa versa to ensure the standard library and the app
are talking about the same errno!

My (possibly insane) usage of OpenSSL plugs in all my own OS routines,
just to avoid this problem.

-paul


On Jan 29, 2008 5:54 PM, David Schwartz [EMAIL PROTECTED] wrote:


  There is no global variable named errno, it only exist in the TLS.
  You
  could say that because there is only 1 TLS, that it's global, and it
  acts that way.  But it's not really the same as a normal global
  variable.  You can't access the variables in the same manner you access
  other global variables.

 Is the following code legal:

 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'
 }

 The answer is that if you're compiled single-threaded, it's perfectly
 legal.
 If you're multi-threaded, it's not.

 This might be a perfectly sensible optimization to condition on
 '_REENTRANT'
 not being defined. In principle, the compiler might do such a thing
 automatically if the overhead of TLS were higher than the overhead of the
 test.

  In case of errno on a glibc system with NPTL there is no difference in
 the
  compiled code.  You always get the same function call.

 Exactly. The precise same code can have a very different semantic meaning
 depending upon whether it is used in a multi-threaded or a single-threaded
 process. That's why you *must* specify appropriate compilation flags. The
 code may need to change so that it can produce *different* code to get the
 *same* semantic meaning.

  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?!

   That these two different semantics are implemented by the same
   code doesn't
   change the fact that the semantics are different. In fact, it makes
 the
   important point that the semantics of code can be changed by whether
 the
   process is single-threaded or multi-threaded.

  I'm not at all saying that the semantics are the same.  All I'm saying
  is that in case of errno on a recent glibc there is no difference in the
  compiled code depending on wether your application or library is
  multi-threaded or not.

 There is a huge difference. In the case of a single-threaded process, it
 will get a process global 'errno' and optimizations such as my 'foo'
 function above are perfectly legal. In the case of a multi-threaded
 process,
 they're not.

   On many Linux distributions, it is perfectly acceptable to do
  the following:
  
   #ifdef _REENTRANT
   // inefficient thread-safe code
   #else
   // more efficient code that assumes 'errno' is process-global
   #endif

  On many Linux distributions it's required that if such code is in a
  library that it's compiled using -D_REENTRANT for the packages
  they ship.  With other words, if the library can be compiled
  reentrant, that's what we want.

 Right, and the OP is saying he doesn't have to compile with -D_REENTRANT
 (or
 whatever else is specified on his platform as required for multi-threaded
 code) and he can still use the library in a multi-threaded process.

 I'm saying he can't do this even if he thinks the code will be the same
 because the same code can mean something different. Different code may
 be
 needed to get the same *effect*.

 Compiling code without the compilation flags your platform documents as
 required to get thread-safety guarantees and then using that compiled code
 in a multi-threaded process is simply off the map. Anything can happen.
 Here
 be dragons. This is so even in the case of Linux, where all the flags do
 (at
 least, on most Linux platforms, AFAICT) is add a single define to the
 compilation and a library to the linking.

 And it's a bad idea even if you know it's safe on a particular platform. 9
 times out of 10, code 

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

2008-01-29 Thread Kurt Roeckx
On Tue, Jan 29, 2008 at 07:54:54AM -0800, David Schwartz wrote:
 
  There is no global variable named errno, it only exist in the TLS.  You
  could say that because there is only 1 TLS, that it's global, and it
  acts that way.  But it's not really the same as a normal global
  variable.  You can't access the variables in the same manner you access
  other global variables.
 
 Is the following code legal:
 
 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'
 }
 
 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.

 This might be a perfectly sensible optimization to condition on '_REENTRANT'
 not being defined. In principle, the compiler might do such a thing
 automatically if the overhead of TLS were higher than the overhead of the
 test.

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.

I read your example, after fixing it's problems, as suppressing
the macro definition, and so would have undefined behaviour.

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.

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.

 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.

  In case of errno on a glibc system with NPTL there is no difference in the
  compiled code.  You always get the same function call.
 
 Exactly. The precise same code can have a very different semantic meaning
 depending upon whether it is used in a multi-threaded or a single-threaded
 process. That's why you *must* specify appropriate compilation flags. The
 code may need to change so that it can produce *different* code to get the
 *same* semantic meaning.
 
  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.

Like I said before, on a glibc system with NPTL errno is expanded to
a function call that that returns (the location of) errno.  That value
is stored per thread in the TLS.  That functions returns the value for
the current thread.

 Right, and the OP is saying he doesn't have to compile with -D_REENTRANT (or
 whatever else is specified on his platform as required for multi-threaded
 code) and he can still use the library in a multi-threaded process.
 
 I'm saying he can't do this even if he thinks the code will be the same
 because the same code can mean something different. Different code may be
 needed to get the same *effect*.
 
 Compiling code without the compilation flags your platform documents as
 required to get thread-safety guarantees and then using that compiled code
 in a multi-threaded process is simply off the map. Anything can happen. Here
 be dragons. This is so even in the case of Linux, where all the flags do (at
 least, on most Linux platforms, AFAICT) is add a single define to the
 compilation and a library to the linking.

As far as I know I've never said anything which suggest something else.
About the only thing I've claimed is that using errno on a recent glibc
with NPTL always gets your the errno for the current thread.


Kurt