Add a proper error message for ffi load

We call dlerror when a library failed to load properly.

Closes GH-9913.
This commit is contained in:
Thomas PIRAS 2022-11-04 15:31:42 +01:00 committed by Christoph M. Becker
parent 0109aa62ec
commit 289822d3ad
No known key found for this signature in database
GPG key ID: D66C9593118BCCB6
3 changed files with 55 additions and 3 deletions

View file

@ -32,6 +32,17 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#ifdef HAVE_LIBDL
#ifdef PHP_WIN32
#include "win32/param.h"
#include "win32/winutil.h"
#define GET_DL_ERROR() php_win_err()
#else
#include <sys/param.h>
#define GET_DL_ERROR() DL_ERROR()
#endif
#endif
#ifdef HAVE_GLOB #ifdef HAVE_GLOB
#ifdef PHP_WIN32 #ifdef PHP_WIN32
#include "win32/glob.h" #include "win32/glob.h"
@ -2934,6 +2945,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
zend_string *lib = NULL; zend_string *lib = NULL;
zend_ffi *ffi = NULL; zend_ffi *ffi = NULL;
DL_HANDLE handle = NULL; DL_HANDLE handle = NULL;
char *err;
void *addr; void *addr;
ZEND_FFI_VALIDATE_API_RESTRICTION(); ZEND_FFI_VALIDATE_API_RESTRICTION();
@ -2946,9 +2958,21 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
if (lib) { if (lib) {
handle = DL_LOAD(ZSTR_VAL(lib)); handle = DL_LOAD(ZSTR_VAL(lib));
if (!handle) { if (!handle) {
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", ZSTR_VAL(lib)); err = GET_DL_ERROR();
#ifdef PHP_WIN32
if (err && err[0]) {
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", ZSTR_VAL(lib), err);
php_win32_error_msg_free(err);
} else {
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (Unknown reason)", ZSTR_VAL(lib));
}
#else
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", ZSTR_VAL(lib), err);
GET_DL_ERROR(); /* free the buffer storing the error */
#endif
RETURN_THROWS(); RETURN_THROWS();
} }
#ifdef RTLD_DEFAULT #ifdef RTLD_DEFAULT
} else if (1) { } else if (1) {
// TODO: this might need to be disabled or protected ??? // TODO: this might need to be disabled or protected ???
@ -3201,7 +3225,7 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */
{ {
struct stat buf; struct stat buf;
int fd; int fd;
char *code, *code_pos, *scope_name, *lib; char *code, *code_pos, *scope_name, *lib, *err;
size_t code_size, scope_name_len; size_t code_size, scope_name_len;
zend_ffi *ffi; zend_ffi *ffi;
DL_HANDLE handle = NULL; DL_HANDLE handle = NULL;
@ -3278,7 +3302,18 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */
if (preload) { if (preload) {
zend_error(E_WARNING, "FFI: Failed pre-loading '%s'", lib); zend_error(E_WARNING, "FFI: Failed pre-loading '%s'", lib);
} else { } else {
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", lib); err = GET_DL_ERROR();
#ifdef PHP_WIN32
if (err && err[0]) {
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", lib, err);
php_win32_error_msg_free(err);
} else {
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (Unknown reason)", lib);
}
#else
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", lib, err);
GET_DL_ERROR(); /* free the buffer storing the error */
#endif
} }
goto cleanup; goto cleanup;
} }

View file

@ -0,0 +1 @@
#define FFI_LIB "./donotexist.so"

View file

@ -0,0 +1,16 @@
--TEST--
Test that FFI::load returns a detailed error when failling to load a shared library
--EXTENSIONS--
ffi
--INI--
ffi.enable=1
--FILE--
<?php
try {
FFI::load(__DIR__ . "/ffi_load_error.h");
} catch (FFI\Exception $ex) {
printf($ex->getMessage());
}
?>
--EXPECTF--
Failed loading '%s' (%s)