Skip to content

Commit 289822d

Browse files
pirastcmb69
authored andcommitted
Add a proper error message for ffi load
We call dlerror when a library failed to load properly. Closes GH-9913.
1 parent 0109aa6 commit 289822d

File tree

3 files changed

+55
-3
lines changed

3 files changed

+55
-3
lines changed

ext/ffi/ffi.c

+38-3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@
3232
#include <sys/stat.h>
3333
#include <fcntl.h>
3434

35+
#ifdef HAVE_LIBDL
36+
#ifdef PHP_WIN32
37+
#include "win32/param.h"
38+
#include "win32/winutil.h"
39+
#define GET_DL_ERROR() php_win_err()
40+
#else
41+
#include <sys/param.h>
42+
#define GET_DL_ERROR() DL_ERROR()
43+
#endif
44+
#endif
45+
3546
#ifdef HAVE_GLOB
3647
#ifdef PHP_WIN32
3748
#include "win32/glob.h"
@@ -2934,6 +2945,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
29342945
zend_string *lib = NULL;
29352946
zend_ffi *ffi = NULL;
29362947
DL_HANDLE handle = NULL;
2948+
char *err;
29372949
void *addr;
29382950

29392951
ZEND_FFI_VALIDATE_API_RESTRICTION();
@@ -2946,9 +2958,21 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
29462958
if (lib) {
29472959
handle = DL_LOAD(ZSTR_VAL(lib));
29482960
if (!handle) {
2949-
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", ZSTR_VAL(lib));
2961+
err = GET_DL_ERROR();
2962+
#ifdef PHP_WIN32
2963+
if (err && err[0]) {
2964+
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", ZSTR_VAL(lib), err);
2965+
php_win32_error_msg_free(err);
2966+
} else {
2967+
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (Unknown reason)", ZSTR_VAL(lib));
2968+
}
2969+
#else
2970+
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", ZSTR_VAL(lib), err);
2971+
GET_DL_ERROR(); /* free the buffer storing the error */
2972+
#endif
29502973
RETURN_THROWS();
29512974
}
2975+
29522976
#ifdef RTLD_DEFAULT
29532977
} else if (1) {
29542978
// TODO: this might need to be disabled or protected ???
@@ -3201,7 +3225,7 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */
32013225
{
32023226
struct stat buf;
32033227
int fd;
3204-
char *code, *code_pos, *scope_name, *lib;
3228+
char *code, *code_pos, *scope_name, *lib, *err;
32053229
size_t code_size, scope_name_len;
32063230
zend_ffi *ffi;
32073231
DL_HANDLE handle = NULL;
@@ -3278,7 +3302,18 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */
32783302
if (preload) {
32793303
zend_error(E_WARNING, "FFI: Failed pre-loading '%s'", lib);
32803304
} else {
3281-
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", lib);
3305+
err = GET_DL_ERROR();
3306+
#ifdef PHP_WIN32
3307+
if (err && err[0]) {
3308+
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", lib, err);
3309+
php_win32_error_msg_free(err);
3310+
} else {
3311+
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (Unknown reason)", lib);
3312+
}
3313+
#else
3314+
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", lib, err);
3315+
GET_DL_ERROR(); /* free the buffer storing the error */
3316+
#endif
32823317
}
32833318
goto cleanup;
32843319
}

ext/ffi/tests/ffi_load_error.h

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#define FFI_LIB "./donotexist.so"

ext/ffi/tests/ffi_load_error.phpt

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Test that FFI::load returns a detailed error when failling to load a shared library
3+
--EXTENSIONS--
4+
ffi
5+
--INI--
6+
ffi.enable=1
7+
--FILE--
8+
<?php
9+
try {
10+
FFI::load(__DIR__ . "/ffi_load_error.h");
11+
} catch (FFI\Exception $ex) {
12+
printf($ex->getMessage());
13+
}
14+
?>
15+
--EXPECTF--
16+
Failed loading '%s' (%s)

0 commit comments

Comments
 (0)