[ previous ] [ next ] [ threads ]
 To :  yate@v...
 From :  Alexander Kovalenko <alexander.kovalenko@g...>
 Subject :  Wrong variables initialization order
 Date :  Mon, 21 Jun 2010 19:15:30 +0300
Greetings.

I run Yate-2.2.0-1 engine from Java program using JNI. Under Linux my 
program crashes with following stacktrace:
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, 
C=native code)
C  [libyate.so+0x2ddc9]  _ZN9TelEngine12MutexPrivate4lockEl+0x49
C  [libyate.so+0x2dfad]  _ZN9TelEngine5Mutex4lockEl+0x2d
C  [libyate.so+0x50ad7]  
_ZN9TelEngine14DataTranslator7installEPNS_17TranslatorFactoryE+0x37
C  [libyate.so+0x51820]
C  [libyate.so+0x80efd]
C  [libyate.so+0x27404]
C  [ld-linux.so.2+0xdc4c]
C  [ld-linux.so.2+0xdd69]
C  [ld-linux.so.2+0x11e39]
C  [ld-linux.so.2+0xd876]
C  [ld-linux.so.2+0x11676]
C  [libdl.so.2+0xc0b]
C  [ld-linux.so.2+0xd876]
C  [libdl.so.2+0x109c]
C  [libdl.so.2+0xb41]  dlopen+0x41

There are number of SimpleFactory static variables in DataFormat.cpp. 
During their initialization call to ThreadPrivate::current() appears. It 
uses current_key variable which is not initialized properly yet with 
ThreadPrivateKeyAlloc class in Thread.cpp. It seems during usual Yate 
initialization call to ::pthread_getspecific(current_key) returns NULL 
and all goes right even if current_key is not initialized. But when 
libyate.so is loaded using JNI call ::pthread_getspecific(current_key) 
returns some garbage value, then Yate casts this value to ThreadPrivate* 
and gets access violation when tries to use this pointer.
To avoid it I performed lazy initialization for current_key similar to 
getTls() method for windows version. Please see the patch against 
yate-2.2.0-1 in the attachment.

PS I also checked Yate-3 from svn. It seems the same error is present.

WBR, Alexander Kovalenko, www.ardas.dp.ua



diff -cbr yate-2.2.0-1/engine/Thread.cpp yate-2.2.0-1-patched/engine/Thread.cpp
*** yate-2.2.0-1/engine/Thread.cpp	2010-03-08 12:17:47.000000000 +0200
--- yate-2.2.0-1-patched/engine/Thread.cpp	2010-06-21 17:05:52.000000000 +0300
***************
*** 106,112 ****
      return tls_index;
  }
  #else /* _WINDOWS */
! static pthread_key_t current_key;
  
  class ThreadPrivateKeyAlloc
  {
--- 106,113 ----
      return tls_index;
  }
  #else /* _WINDOWS */
! #define CURRENT_KEY_NOT_SET 0xfeeb1e
! static pthread_key_t current_key = CURRENT_KEY_NOT_SET;
  
  class ThreadPrivateKeyAlloc
  {
***************
*** 120,126 ****
      }
  };
  
! static ThreadPrivateKeyAlloc keyAllocator;
  #endif /* _WINDOWS */
  
  static TokenDict s_prio[] = {
--- 121,133 ----
      }
  };
  
! pthread_key_t getCurrentKey() {
!     if (CURRENT_KEY_NOT_SET == current_key) {
! 	// volatile added to avoid unused variable optimization
! 	volatile ThreadPrivateKeyAlloc keyAllocator;
!     }
!     return current_key;
! }
  #endif /* _WINDOWS */
  
  static TokenDict s_prio[] = {
***************
*** 304,310 ****
  #ifdef _WINDOWS
      ::TlsSetValue(getTls(),this);
  #else
!     ::pthread_setspecific(current_key,this);
      pthread_cleanup_push(cleanupFunc,this);
  #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
      ::pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,0);
--- 311,317 ----
  #ifdef _WINDOWS
      ::TlsSetValue(getTls(),this);
  #else
!     ::pthread_setspecific(getCurrentKey(),this);
      pthread_cleanup_push(cleanupFunc,this);
  #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
      ::pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,0);
***************
*** 416,422 ****
  #ifdef _WINDOWS
      return reinterpret_cast(::TlsGetValue(getTls()));
  #else
!     return reinterpret_cast(::pthread_getspecific(current_key));
  #endif
  }
  
--- 423,429 ----
  #ifdef _WINDOWS
      return reinterpret_cast(::TlsGetValue(getTls()));
  #else
!     return reinterpret_cast(::pthread_getspecific(getCurrentKey()));
  #endif
  }