diff --git a/ChangeLog b/ChangeLog index 064feaefb..fbf6eb7f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2012-01-29 Richard Frith-Macdonald + + * configure.ac: + * Headers/GNUstepBase/config.h.in: + * Source/GSFFIInvocation.m: + * Source/GSPrivate.h: + * Source/NSInvocation.m: + If modern ffi is available, use ffi_prep_closure_loc and ffi closure + memory management so we get the benefit of ffi library code to work + around restrictions of selinux etc. + 2012-01-29 Richard Frith-Macdonald * Source/NSUserDefaults.m: Try to deal with the case where a language diff --git a/Headers/GNUstepBase/config.h.in b/Headers/GNUstepBase/config.h.in index c020cfda9..ad6528a11 100644 --- a/Headers/GNUstepBase/config.h.in +++ b/Headers/GNUstepBase/config.h.in @@ -205,6 +205,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H +/* Define to 1 if you have the `ffi_prep_closure_loc' function. */ +#undef HAVE_FFI_PREP_CLOSURE_LOC + /* Define to 1 if you have the header file. */ #undef HAVE_FLOAT_H diff --git a/Source/GSFFIInvocation.m b/Source/GSFFIInvocation.m index 8e5360fcc..487d2b06b 100644 --- a/Source/GSFFIInvocation.m +++ b/Source/GSFFIInvocation.m @@ -148,6 +148,7 @@ static IMP gs_objc_msg_forward2 (id receiver, SEL sel) NSMutableData *frame; cifframe_t *cframe; ffi_closure *cclosure; + void *executable; NSMethodSignature *sig = nil; GSCodeBuffer *memory; const char *types; @@ -207,18 +208,28 @@ static IMP gs_objc_msg_forward2 (id receiver, SEL sel) memory = [GSCodeBuffer memoryWithSize: sizeof(ffi_closure)]; cclosure = [memory buffer]; + executable = [memory executable]; if (cframe == NULL || cclosure == NULL) { [NSException raise: NSMallocException format: @"Allocating closure"]; } +#if HAVE_FFI_PREP_CLOSURE_LOC + if (ffi_prep_closure_loc(cclosure, &(cframe->cif), + GSFFIInvocationCallback, frame, executable) != FFI_OK) + { + [NSException raise: NSGenericException format: @"Preping closure"]; + } +#else + executable = (void*)cclosure; if (ffi_prep_closure(cclosure, &(cframe->cif), GSFFIInvocationCallback, frame) != FFI_OK) { [NSException raise: NSGenericException format: @"Preping closure"]; } +#endif [memory protect]; - return (IMP)cclosure; + return (IMP)executable; } static __attribute__ ((__unused__)) diff --git a/Source/GSPrivate.h b/Source/GSPrivate.h index 533b387fc..bb7f601a7 100644 --- a/Source/GSPrivate.h +++ b/Source/GSPrivate.h @@ -526,9 +526,11 @@ GSPrivateUnloadModule(FILE *errorStream, { unsigned size; void *buffer; + void *executable; } + (GSCodeBuffer*) memoryWithSize: (NSUInteger)_size; - (void*) buffer; +- (void*) executable; - (id) initWithSize: (NSUInteger)_size; - (void) protect; @end diff --git a/Source/NSInvocation.m b/Source/NSInvocation.m index 895068dbb..31454cc8e 100644 --- a/Source/NSInvocation.m +++ b/Source/NSInvocation.m @@ -73,6 +73,9 @@ { if (size > 0) { +#if defined(HAVE_FFI_PREP_CLOSURE_LOC) + ffi_closure_free(buffer); +#else #if defined(HAVE_MMAP) munmap(buffer, size); #else @@ -84,14 +87,34 @@ #endif NSDeallocateMemoryPages(buffer, NSPageSize()); #endif +#endif + buffer = 0; + executable = 0; + size = 0; } [super dealloc]; } +- (void*) executable +{ + return executable; +} + - (id) initWithSize: (NSUInteger)_size { NSAssert(_size > 0, @"Tried to allocate zero length buffer."); NSAssert(_size <= NSPageSize(), @"Tried to allocate more than one page."); +#if defined(HAVE_FFI_PREP_CLOSURE_LOC) + buffer = ffi_closure_alloc(_size, &executable); + if (0 == buffer) + { + executable = 0; + } + else + { + size = _size; + } +#else #if defined(HAVE_MMAP) #if defined(HAVE_MPROTECT) /* We have mprotect, so we create memory as writable and change it to @@ -117,13 +140,16 @@ NSLog(@"Failed to map %"PRIuPTR " bytes for execute: %@", _size, [NSError _last]); buffer = 0; + executable = 0; [self dealloc]; self = nil; } else { + executable = buffer; size = _size; } +#endif /* USE_LIBFFI */ return self; } @@ -132,7 +158,8 @@ */ - (void) protect { -#if defined(__MINGW__) +#if !defined(HAVE_FFI_PREP_CLOSURE_LOC) +#if defined(__MINGW__) DWORD old; if (VirtualProtect(buffer, size, PAGE_EXECUTE, &old) == 0) { @@ -144,6 +171,7 @@ NSLog(@"Failed to protect memory as executable: %@", [NSError _last]); } #endif +#endif } @end diff --git a/configure b/configure index 018f844f1..098e26e0e 100755 --- a/configure +++ b/configure @@ -22392,6 +22392,107 @@ $as_echo "libffi" >&6; } { $as_echo "$as_me:$LINENO: WARNING: ffi may be broken on this system ... try enabling ffcall" >&5 $as_echo "$as_me: WARNING: ffi may be broken on this system ... try enabling ffcall" >&2;} fi + +for ac_func in ffi_prep_closure_loc +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + else { { $as_echo "$as_me:$LINENO: error: The ffi library (libffi) does not appear to be working. Perhaps it's missing or you need a more recent version. Version 3.0.9 or later should work, and you can find a link to it n the list of packages for download at http://www.gnustep.org/resources/sources.html" >&5 $as_echo "$as_me: error: The ffi library (libffi) does not appear to be working. Perhaps it's missing or you need a more recent version. Version 3.0.9 or later should work, and you can find a link to it n the list of packages for download at http://www.gnustep.org/resources/sources.html" >&2;} @@ -23005,8 +23106,6 @@ fi sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` xml_config_micro_version=`$XML_CONFIG $xml_config_args --version | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` - # Strip '-L/usr/lib' off since this is always in the link path. - XML_LIBS=`echo $XML_LIBS | sed -e 's|-L/usr/lib||'` if test "x$enable_xmltest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" @@ -23781,8 +23880,6 @@ fi sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` tls_config_micro_version=`$TLS_CONFIG $tls_config_args --version | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` - # Strip '-L/usr/lib' off since this is always in the link path. - TLS_LIBS=`echo $TLS_LIBS | sed -e 's|-L/usr/lib||'` if test "x$enable_tlstest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" diff --git a/configure.ac b/configure.ac index 2be17d467..70ae97c77 100644 --- a/configure.ac +++ b/configure.ac @@ -2631,6 +2631,7 @@ if test $enable_libffi = yes; then if test $do_broken_libffi = yes; then AC_MSG_WARN([ffi may be broken on this system ... try enabling ffcall]) fi + AC_CHECK_FUNCS(ffi_prep_closure_loc) else AC_MSG_ERROR([The ffi library (libffi) does not appear to be working. Perhaps it's missing or you need a more recent version. Version 3.0.9 or later should work, and you can find a link to it n the list of packages for download at http://www.gnustep.org/resources/sources.html]) fi