diff --git a/ChangeLog b/ChangeLog index 0f74e9213..38f1144e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-06-28 Richard Frith-Macdonald + + * Source/GSFFIInvocation.m: + * configure.ac: + * configure: + * Headers/Additions/GNUstepBase/config.h.in: + Backport ffi fixes from trunk. + 2008-06-18 Richard Frith-Macdonald * Source/NSConnection.m: backport fix from trunk. diff --git a/Headers/Additions/GNUstepBase/config.h.in b/Headers/Additions/GNUstepBase/config.h.in index 9d0ff2787..49228303a 100644 --- a/Headers/Additions/GNUstepBase/config.h.in +++ b/Headers/Additions/GNUstepBase/config.h.in @@ -334,6 +334,9 @@ /* Define to 1 if you have the `mmap' function. */ #undef HAVE_MMAP +/* Define to 1 if you have the `mprotect' function. */ +#undef HAVE_MPROTECT + /* Define to 1 if you have the `nanosleep' function. */ #undef HAVE_NANOSLEEP @@ -467,6 +470,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MMAN_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MOUNT_H diff --git a/Source/GSFFIInvocation.m b/Source/GSFFIInvocation.m index 2fb3ebcfb..c000c2dcb 100644 --- a/Source/GSFFIInvocation.m +++ b/Source/GSFFIInvocation.m @@ -31,6 +31,86 @@ #import #import "cifframe.h" #import "mframe.h" +#import "GSPrivate.h" + +#if defined(HAVE_SYS_MMAN_H) +#include +#endif + +@interface GSMMapBuffer : NSObject +{ + unsigned size; + void *buffer; +} ++ (GSMMapBuffer*) memoryWithSize: (unsigned)_size; +- (void*) buffer; +- (id) initWithSize: (unsigned)_size; +- (void) protect; +@end + +@implementation GSMMapBuffer + ++ (GSMMapBuffer*) memoryWithSize: (unsigned)_size +{ + return [[[self alloc] initWithSize: _size] autorelease]; +} + +- (void*) buffer +{ + return buffer; +} + +- (void) dealloc +{ + if (size > 0) + { +#if defined(HAVE_MMAP) + munmap(buffer, size); +#else + free(buffer); +#endif + } + [super dealloc]; +} + +- (id) initWithSize: (unsigned)_size +{ +#if defined(HAVE_MMAP) + buffer = mmap (NULL, _size, PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (buffer == (void*)-1) +#else + buffer = malloc(_size); + if (buffer == (void*)0) +#endif + { + NSLog(@"Failed to map %u bytes for FFI: %@", _size, [NSError _last]); + buffer = 0; + [self dealloc]; + self = nil; + } + else + { + size = _size; + } + return self; +} + +/* Ensurre that the proterction on the buffer is such that it will execute + * on any architecture. + */ +- (void) protect +{ +#if defined(HAVE_MPROTECT) + if (mprotect(buffer, size, PROT_READ | PROT_EXEC) == -1) + { + NSLog(@"Failed to protect closure for FFI: %@", [NSError _last]); + } +#endif +} +@end + + #ifndef INLINE #define INLINE inline @@ -146,6 +226,7 @@ static IMP gs_objc_msg_forward2 (id receiver, SEL sel) cifframe_t *cframe; ffi_closure *cclosure; NSMethodSignature *sig; + GSMMapBuffer *memory; sig = [receiver methodSignatureForSelector: sel]; @@ -185,7 +266,9 @@ static IMP gs_objc_msg_forward2 (id receiver, SEL sel) worry about freeing it */ cframe = cifframe_from_info([sig methodInfo], [sig numberOfArguments], NULL); /* Autorelease the closure through GSAutoreleasedBuffer */ - cclosure = (ffi_closure *)GSAutoreleasedBuffer(sizeof(ffi_closure)); + + memory = [GSMMapBuffer memoryWithSize: sizeof(ffi_closure)]; + cclosure = [memory buffer]; if (cframe == NULL || cclosure == NULL) { [NSException raise: NSMallocException format: @"Allocating closure"]; @@ -195,6 +278,7 @@ static IMP gs_objc_msg_forward2 (id receiver, SEL sel) { [NSException raise: NSGenericException format: @"Preping closure"]; } + [memory protect]; return (IMP)cclosure; } diff --git a/configure b/configure index a15efc689..1af40f267 100755 --- a/configure +++ b/configure @@ -13140,7 +13140,7 @@ done #-------------------------------------------------------------------- -# These functions needed by NSData.m +# These functions needed by NSData.m and GSFFIInvocation.m #-------------------------------------------------------------------- for ac_func in mkstemp @@ -13425,6 +13425,240 @@ fi done +for ac_func in mprotect +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&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 "echo \"\$as_me:$LINENO: $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 + 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 && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +for ac_header in sys/mman.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + #-------------------------------------------------------------------- # These functions needed by NSTask.m #-------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index 15053807a..869732062 100644 --- a/configure.ac +++ b/configure.ac @@ -1496,11 +1496,13 @@ AC_CHECK_FUNCS(valloc) AC_CHECK_FUNCS(times) #-------------------------------------------------------------------- -# These functions needed by NSData.m +# These functions needed by NSData.m and GSFFIInvocation.m #-------------------------------------------------------------------- AC_CHECK_FUNCS(mkstemp) AC_CHECK_FUNCS(shmctl) AC_CHECK_FUNCS(mmap) +AC_CHECK_FUNCS(mprotect) +AC_CHECK_HEADERS(sys/mman.h) #-------------------------------------------------------------------- # These functions needed by NSTask.m