Warn about using an unsafe +initialize

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@32455 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2011-03-05 13:11:47 +00:00
parent 360e28f269
commit 03233198f7
7 changed files with 7932 additions and 7227 deletions

View file

@ -1,3 +1,13 @@
2011-03-05 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSUserDefaults.m: Small optimisation suggested by Fred.
* config/config.initialize.m: Test for working +initialize
* configure.ac: Use test for +initialize thread safety
* Headers/Additions/GNUstepBase/config.h.in: regenerate
* configure: regenerate
* Source/NSThread.m: Log warning when going multithreaded without
a reliable runtime.
2011-03-05 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSNumberFormatter.m: Make error text compatible with OSX

View file

@ -1,5 +1,8 @@
/* Headers/Additions/GNUstepBase/config.h.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
/* The normal alignment of `pthread_cond_t', in bytes. */
#undef ALIGNOF_PTHREAD_COND_T
@ -283,6 +286,9 @@
/* Define to 1 if you have the `inet_pton' function. */
#undef HAVE_INET_PTON
/* Define if libobjc has thread-safe +initialize support */
#undef HAVE_INITIALIZE
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
@ -723,26 +729,44 @@
/* Define if using the libffi library for invocations */
#undef USE_LIBFFI
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Define if vasprintf returns the length printed */
#undef VASPRINTF_RETURNS_LENGTH
/* Define if vsprintf returns the length printed */
#undef VSPRINTF_RETURNS_LENGTH
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
#undef WORDS_BIGENDIAN
/* Define to 1 if on AIX 3.
System headers sometimes define this.
We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
# undef WORDS_BIGENDIAN
# endif
#endif
/* Define to 1 if on MINIX. */
@ -755,17 +779,6 @@
/* Define to 1 if you need to in order for `stat' and other things to work. */
#undef _POSIX_SOURCE
/* Enable extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus

View file

@ -380,15 +380,13 @@ gnustep_base_thread_callback(void)
* Won't work properly if threads are not all created
* by this class, but it's better than nothing.
*/
// FIXME: This code is complete nonsense; this can be called from
// any thread (and is when adding new foreign threads), so this
// will often be called from the wrong thread, delivering
// notifications to the wrong thread, and generally doing the
// wrong thing..
if (nc == nil)
{
nc = RETAIN([NSNotificationCenter defaultCenter]);
}
#if !defined(HAVE_INITIALIZE)
NSLog(@"WARNING your program is becoming multi-threaded, but you are using an ObjectiveC runtime library which does not have a thread-safe implementation of the +initialize method. This means that any classes not already used may be incorrectly initialised, potentially causing strange behaviors and crashes. Please build/run GNUstep-base with a runtime which supports the +initialize method.");
#endif
[nc postNotificationName: NSWillBecomeMultiThreadedNotification
object: nil
userInfo: nil];
@ -536,11 +534,7 @@ unregisterActiveThread(NSThread *thread)
* if we have become multi-threaded due to a call to the runtime directly
* rather than via the NSThread class.
*/
#if defined(__GNUSTEP_RUNTIME__) || defined(NeXT_RUNTIME)
gnustep_base_thread_callback();
#else
objc_set_thread_callback(gnustep_base_thread_callback);
#endif
}
}

View file

@ -783,15 +783,15 @@ newLanguages(NSArray *oldNames)
+ (NSArray*) userLanguages
{
return [[NSUserDefaults standardUserDefaults]
stringArrayForKey: @"NSLanguages"];
return [[self standardUserDefaults] stringArrayForKey: @"NSLanguages"];
}
+ (void) setUserLanguages: (NSArray*)languages
{
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSUserDefaults *defs;
NSMutableDictionary *dict;
defs = [self standardUserDefaults];
dict = [[defs volatileDomainForName: GSPrimaryDomain] mutableCopy];
if (languages == nil) // Remove the entry
{

View file

@ -0,0 +1,82 @@
/* Test whether Objective-C runtime +initialize support is thread-safe
*/
#include "objc-common.g"
#include <pthread.h>
static unsigned initialize_entered = 0;
static unsigned initialize_exited = 0;
static unsigned class_entered = 0;
static BOOL may_proceed = NO;
@interface MyClass : NSObject
@end
@implementation MyClass
+ (void) initialize
{
initialize_entered++;
while (NO == may_proceed)
sleep(1);
initialize_exited++;
}
+ (Class) class
{
class_entered++;
return self;
}
@end
static void test(void *arg)
{
[MyClass class];
}
int
main()
{
pthread_t t1;
pthread_t t2;
if (0 == pthread_create(&t1, 0, test, 0))
{
unsigned counter = 0;
while (0 == initialize_entered && counter++ < 3)
{
sleep(1);
}
if (0 == initialize_entered)
{
fprintf(stderr, "Failed to initialize\n");
return 1;
}
if (0 == pthread_create(&t1, 0, test, 0))
{
sleep(1);
if (class_entered > 0)
{
fprintf(stderr, "class entered prematurely\n");
return 1;
}
may_proceed = YES;
sleep(1);
if (2 == class_entered)
{
return 0; // OK
}
fprintf(stderr, "problem with initialize\n");
return 1;
}
else
{
fprintf(stderr, "failed to create t2\n");
return 1;
}
}
else
{
fprintf(stderr, "failed to create t1\n");
return 1;
}
}

14844
configure vendored

File diff suppressed because it is too large Load diff

View file

@ -1457,6 +1457,66 @@ OBJC_SYS_DYNAMIC_LINKER()
# NOTE: libdl should be in LIBS now if it's available.
AC_CHECK_FUNCS(dladdr)
#--------------------------------------------------------------------
# Check for pthread.h
#--------------------------------------------------------------------
AC_CHECK_HEADERS(pthread.h)
if test $ac_cv_header_pthread_h = yes ; then
AC_CHECK_SIZEOF(pthread_mutex_t,,[AC_INCLUDES_DEFAULT
#include <pthread.h>])
GS_SIZEOF_MUTEX_T=$ac_cv_sizeof_pthread_mutex_t
if test $ac_cv_sizeof_pthread_mutex_t = 0 ; then
AC_MSG_ERROR([Unable to find size of pthread_mutex_t (required).])
fi
AC_SUBST(GS_SIZEOF_MUTEX_T)
AC_CHECK_SIZEOF(pthread_cond_t,,[AC_INCLUDES_DEFAULT
#include <pthread.h>])
if test $ac_cv_sizeof_pthread_cond_t = 0 ; then
AC_MSG_ERROR([Unable to find size of pthread_cond_t (required).])
fi
GS_SIZEOF_COND_T=$ac_cv_sizeof_pthread_cond_t
AC_SUBST(GS_SIZEOF_COND_T)
AC_CHECK_ALIGNOF(pthread_mutex_t,[AC_INCLUDES_DEFAULT
#include <pthread.h>])
GS_ALIGNOF_MUTEX_T=$ac_cv_alignof_pthread_mutex_t
if test $ac_cv_alignof_pthread_mutex_t = 0 ; then
AC_MSG_ERROR([Unable to find align of pthread_mutex_t (required).])
fi
AC_SUBST(GS_ALIGNOF_MUTEX_T)
AC_CHECK_ALIGNOF(pthread_cond_t,[AC_INCLUDES_DEFAULT
#include <pthread.h>])
if test $ac_cv_alignof_pthread_cond_t = 0 ; then
AC_MSG_ERROR([Unable to find align of pthread_cond_t (required).])
fi
GS_ALIGNOF_COND_T=$ac_cv_alignof_pthread_cond_t
AC_SUBST(GS_ALIGNOF_COND_T)
else
AC_MSG_ERROR([Unable to find pthread.h (needed for thread support).])
fi
AC_CHECK_LIB(pthread, pthread_join, pthread_ok=yes, pthread_ok=no)
ismingw=no
case "$target_os" in
mingw*) ismingw=yes;;
esac
if test $pthread_ok = yes ; then
LIBS="$LIBS -lpthread"
else
if test $ismingw = yes ; then
AC_CHECK_LIB(pthreadGC2, pthread_join, pthread_ok=yes, pthread_ok=no)
if test $pthread_ok = yes ; then
LIBS="$LIBS -lpthreadGC2"
fi
fi
fi
if test $pthread_ok = no ; then
AC_MSG_ERROR([Unable to find pthread library (needed for thread support).])
fi
# Typically need librt on Solaris for sched_yield
AC_CHECK_LIB(rt, sched_yield)
#--------------------------------------------------------------------
# Check whether Objective-C /really/ works
#--------------------------------------------------------------------
@ -1570,6 +1630,8 @@ else
fi
AC_SUBST(OBJCSYNC)
# Don't revert any Objective-C flags as they are used in the next test
#--------------------------------------------------------------------
# Check for ObjC2 support in runtime
#--------------------------------------------------------------------
@ -1581,6 +1643,8 @@ else
fi
AC_SUBST(OBJC2RUNTIME)
# Don't revert any Objective-C flags as they are used in the next test
GS_NONFRAGILE=0
GS_MIXEDABI=0
if test "$nonfragile" = "yes"; then
@ -1632,6 +1696,8 @@ if test $have_set_uncaught_exception_handler = yes; then
fi
AC_MSG_RESULT($have_set_uncaught_exception_handler)
# Don't revert any Objective-C flags as they are used in the next test
AC_MSG_CHECKING(for objc_set_unexpected() in runtime)
AC_LINK_IFELSE([#include "$srcdir/config/config.set_unexpected.m"],
have_set_unexpected=yes, have_set_unexpected=no)
@ -1641,6 +1707,8 @@ if test $have_set_unexpected = yes; then
fi
AC_MSG_RESULT($have_set_unexpected)
# Don't revert any Objective-C flags as they are used in the next test
AC_MSG_CHECKING(for _objc_unexpected_exception in runtime)
AC_RUN_IFELSE([#include "$srcdir/config/config.unexpected.m"],
have_unexpected=yes, have_unexpected=no)
@ -1671,6 +1739,19 @@ if test $ac_cv_func_objc_sync_enter = yes ; then
fi
AC_SUBST(HAVE_OBJC_SYNC_ENTER)
# Don't revert any Objective-C flags as they are used in the next test
AC_MSG_CHECKING(for thread-safe +initialize in runtime)
AC_RUN_IFELSE([#include "$srcdir/config/config.initialize.m"],
safe_initialize=yes, safe_initialize=no)
if test $safe_initialize = yes; then
AC_DEFINE(HAVE_INITIALIZE,1,
[Define if libobjc has thread-safe +initialize support])
else
AC_MSG_WARN([Your ObjectiveC runtime does not support thread-safe class initialisation. Please use a different runtime if you intend to use threads.])
fi
AC_MSG_RESULT($safe_initialize)
LIBS="$saved_LIBS"
CPPFLAGS="$saved_CPPFLAGS"
@ -1805,64 +1886,6 @@ if test $ac_cv_header_poll_h = yes; then
fi
fi
#--------------------------------------------------------------------
# Check for pthread.h
#--------------------------------------------------------------------
AC_CHECK_HEADERS(pthread.h)
if test $ac_cv_header_pthread_h = yes ; then
AC_CHECK_SIZEOF(pthread_mutex_t,,[AC_INCLUDES_DEFAULT
#include <pthread.h>])
GS_SIZEOF_MUTEX_T=$ac_cv_sizeof_pthread_mutex_t
if test $ac_cv_sizeof_pthread_mutex_t = 0 ; then
AC_MSG_ERROR([Unable to find size of pthread_mutex_t (required).])
fi
AC_SUBST(GS_SIZEOF_MUTEX_T)
AC_CHECK_SIZEOF(pthread_cond_t,,[AC_INCLUDES_DEFAULT
#include <pthread.h>])
if test $ac_cv_sizeof_pthread_cond_t = 0 ; then
AC_MSG_ERROR([Unable to find size of pthread_cond_t (required).])
fi
GS_SIZEOF_COND_T=$ac_cv_sizeof_pthread_cond_t
AC_SUBST(GS_SIZEOF_COND_T)
AC_CHECK_ALIGNOF(pthread_mutex_t,[AC_INCLUDES_DEFAULT
#include <pthread.h>])
GS_ALIGNOF_MUTEX_T=$ac_cv_alignof_pthread_mutex_t
if test $ac_cv_alignof_pthread_mutex_t = 0 ; then
AC_MSG_ERROR([Unable to find align of pthread_mutex_t (required).])
fi
AC_SUBST(GS_ALIGNOF_MUTEX_T)
AC_CHECK_ALIGNOF(pthread_cond_t,[AC_INCLUDES_DEFAULT
#include <pthread.h>])
if test $ac_cv_alignof_pthread_cond_t = 0 ; then
AC_MSG_ERROR([Unable to find align of pthread_cond_t (required).])
fi
GS_ALIGNOF_COND_T=$ac_cv_alignof_pthread_cond_t
AC_SUBST(GS_ALIGNOF_COND_T)
else
AC_MSG_ERROR([Unable to find pthread.h (needed for thread support).])
fi
AC_CHECK_LIB(pthread, pthread_join, pthread_ok=yes, pthread_ok=no)
ismingw=no
case "$target_os" in
mingw*) ismingw=yes;;
esac
if test $pthread_ok = yes ; then
LIBS="$LIBS -lpthread"
else
if test $ismingw = yes ; then
AC_CHECK_LIB(pthreadGC2, pthread_join, pthread_ok=yes, pthread_ok=no)
if test $pthread_ok = yes ; then
LIBS="$LIBS -lpthreadGC2"
fi
fi
fi
if test $pthread_ok = no ; then
AC_MSG_ERROR([Unable to find pthread library (needed for thread support).])
fi
# Typically need librt on Solaris for sched_yield
AC_CHECK_LIB(rt, sched_yield)
#--------------------------------------------------------------------
# This function needed by StdioStream.m
#--------------------------------------------------------------------
@ -2212,8 +2235,7 @@ elif test "$enable_pass_arguments" = "no"; then
if test "$objc_load_method_worked" = yes -a \( "$ac_cv_sys_procfs" = yes -o "$have_kvm_env" = 1 -o "$ac_cv_sys_procfs_psinfo" = yes \); then
GS_FAKE_MAIN=0
if test "$have_kvm_env" = "1"; then
echo "WARNING ... using libkvm which is known to be buggy on some systems"
echo "consider configuring with --enable-fake-main instead."
AC_MSG_WARN([Using libkvm which is known to be buggy on some systems consider configuring with --enable-fake-main instead.])
fi
else
GS_FAKE_MAIN=1