From 14a9b0ac04c5b5d0becc7ca748a127aee107f342 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 13 May 2024 20:28:59 +0200 Subject: [PATCH 1/2] Fix GH-14215: Cannot use FFI::load on CRLF header file with apache2handler Some modules may reset _fmode, which causes mangling of line endings. Always be explicit like we do in other places where the native open call is used. --- ext/ffi/ffi.c | 3 +++ ext/ffi/tests/gh14215.h | 3 +++ ext/ffi/tests/gh14215.phpt | 23 +++++++++++++++++++++++ ext/zend_test/test.c | 12 ++++++++++++ ext/zend_test/test.stub.php | 4 ++++ ext/zend_test/test_arginfo.h | 14 +++++++++++++- 6 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 ext/ffi/tests/gh14215.h create mode 100644 ext/ffi/tests/gh14215.phpt diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 5c6ca05f96108..4eb977b9a6a80 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -3256,6 +3256,9 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */ code_size = buf.st_size; code = emalloc(code_size + 1); fd = open(filename, O_RDONLY, 0); +#ifdef PHP_WIN32 + _setmode(fd, _O_BINARY); +#endif if (fd < 0 || read(fd, code, code_size) != code_size) { if (preload) { zend_error(E_WARNING, "FFI: Failed pre-loading '%s', cannot read_file", filename); diff --git a/ext/ffi/tests/gh14215.h b/ext/ffi/tests/gh14215.h new file mode 100644 index 0000000000000..9a1245b891297 --- /dev/null +++ b/ext/ffi/tests/gh14215.h @@ -0,0 +1,3 @@ +#define FFI_LIB "Kernel32.dll" +typedef unsigned long DWORD; +DWORD GetLastError(void); diff --git a/ext/ffi/tests/gh14215.phpt b/ext/ffi/tests/gh14215.phpt new file mode 100644 index 0000000000000..e259621e7a596 --- /dev/null +++ b/ext/ffi/tests/gh14215.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-14215 (Cannot use FFI::load on CRLF header file with apache2handler) +--EXTENSIONS-- +ffi +zend_test +--SKIPIF-- + +--INI-- +ffi.enable=1 +--FILE-- +GetLastError()); +zend_test_set_fmode(true); +?> +--EXPECT-- +int(0) diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index d27b4543fcc01..8ae98eb106f58 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -584,6 +584,18 @@ static ZEND_FUNCTION(zend_test_is_pcre_bundled) #endif } +#ifdef PHP_WIN32 +static ZEND_FUNCTION(zend_test_set_fmode) +{ + bool binary; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_BOOL(binary) + ZEND_PARSE_PARAMETERS_END(); + + _fmode = binary ? _O_BINARY : _O_TEXT; +} +#endif + static zend_object *zend_test_class_new(zend_class_entry *class_type) { zend_object *obj = zend_objects_new(class_type); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index cf8ac50bd0629..0125b75f970ea 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -182,6 +182,10 @@ function zend_test_override_libxml_global_state(): void {} #endif function zend_test_is_pcre_bundled(): bool {} + +#if defined(PHP_WIN32) + function zend_test_set_fmode(bool $binary): void {} +#endif } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 70439ff726164..8f3bcb1bdfb6f 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 420711ec6f040d38bde450a169bf1186f8531191 */ + * Stub hash: b0964f7eabf91dc0fbffdee87257ee4e58dab303 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -112,6 +112,12 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_is_pcre_bundled, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() +#if defined(PHP_WIN32) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_set_fmode, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, binary, _IS_BOOL, 0) +ZEND_END_ARG_INFO() +#endif + #define arginfo_ZendTestNS2_namespaced_func arginfo_zend_test_is_pcre_bundled #define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_test_void_return @@ -216,6 +222,9 @@ static ZEND_FUNCTION(zend_test_crash); static ZEND_FUNCTION(zend_test_override_libxml_global_state); #endif static ZEND_FUNCTION(zend_test_is_pcre_bundled); +#if defined(PHP_WIN32) +static ZEND_FUNCTION(zend_test_set_fmode); +#endif static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); @@ -275,6 +284,9 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_test_override_libxml_global_state, arginfo_zend_test_override_libxml_global_state) #endif ZEND_FE(zend_test_is_pcre_bundled, arginfo_zend_test_is_pcre_bundled) +#if defined(PHP_WIN32) + ZEND_FE(zend_test_set_fmode, arginfo_zend_test_set_fmode) +#endif ZEND_NS_FALIAS("ZendTestNS2", namespaced_func, ZendTestNS2_namespaced_func, arginfo_ZendTestNS2_namespaced_func) ZEND_NS_DEP_FALIAS("ZendTestNS2", namespaced_deprecated_func, ZendTestNS2_namespaced_deprecated_func, arginfo_ZendTestNS2_namespaced_deprecated_func) ZEND_NS_FALIAS("ZendTestNS2", namespaced_aliased_func, zend_test_void_return, arginfo_ZendTestNS2_namespaced_aliased_func) From 1267d9ab8274e2bd7cc28f9cf62e745337465e81 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 13 May 2024 22:32:03 +0200 Subject: [PATCH 2/2] Directly set the binary flag in open --- ext/ffi/ffi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 4eb977b9a6a80..560338e71f335 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -3255,10 +3255,11 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */ code_size = buf.st_size; code = emalloc(code_size + 1); - fd = open(filename, O_RDONLY, 0); + int open_flags = O_RDONLY; #ifdef PHP_WIN32 - _setmode(fd, _O_BINARY); + open_flags |= _O_BINARY; #endif + fd = open(filename, open_flags, 0); if (fd < 0 || read(fd, code, code_size) != code_size) { if (preload) { zend_error(E_WARNING, "FFI: Failed pre-loading '%s', cannot read_file", filename);