diff options
author | Olly Betts <olly@survex.com> | 2022-01-20 14:42:02 +1300 |
---|---|---|
committer | Olly Betts <olly@survex.com> | 2022-01-20 14:42:02 +1300 |
commit | c417250b4ef8c945b602722642ab3b7c82acb7ca (patch) | |
tree | 67853e698564fac861677d5903a720a9a282518d /Lib/php | |
parent | 0cfc750d44cb9b4efe40b7bdaec44b930c7f4a9d (diff) | |
download | swig-c417250b4ef8c945b602722642ab3b7c82acb7ca.tar.gz |
[php] Allow testing if an object is SWIG-wrapped
Since the switch to wrapping classes using PHP's C API, we now
internally need to be able to tell if a PHP object is of or derived
from a class that is wrapped by SWIG so we know if we can offset the
zend_object pointer to get to the swig_object_wrapper. If we try to
do this to an object which isn't wrapped by SWIG then we invoke C/C++
undefined behaviour (and typically get a segmentation fault).
This check is implemented by having a SWIG\wrapped empty interface which
we make all SWIG-wrapped classes implement simply so we can test for it
to detect such classes.
Fixes #2125
Diffstat (limited to 'Lib/php')
-rw-r--r-- | Lib/php/phprun.swg | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/Lib/php/phprun.swg b/Lib/php/phprun.swg index a24b2551c..97d17d9ca 100644 --- a/Lib/php/phprun.swg +++ b/Lib/php/phprun.swg @@ -93,6 +93,12 @@ static int default_error_code = E_ERROR; #define SWIG_GetModule(clientdata) SWIG_Php_GetModule() #define SWIG_SetModule(clientdata, pointer) SWIG_Php_SetModule(pointer, *(int*)clientdata) +static zend_class_entry SWIG_Php_swig_wrapped_interface_ce; + +#if PHP_MAJOR_VERSION == 7 +# define zend_class_implements_interface(C, I) instanceof_function_ex(C, I, 1) +#endif + /* used to wrap returned objects in so we know whether they are newobject and need freeing, or not */ typedef struct { @@ -156,7 +162,18 @@ SWIG_ConvertPtrAndOwn(zval *z, void **ptr, swig_type_info *ty, int flags, swig_o switch (Z_TYPE_P(z)) { case IS_OBJECT: { - swig_object_wrapper *value = SWIG_Z_FETCH_OBJ_P(z); + zend_object *obj = Z_OBJ_P(z); + swig_object_wrapper *value; + if (ty && ty->clientdata == (void*)obj->ce) { + // Object is exactly the class asked for - this handles common cases cheaply, + // and in particular the PHP classes we use to wrap a pointer to a non-class. + } else if (!zend_class_implements_interface(obj->ce, &SWIG_Php_swig_wrapped_interface_ce)) { + // Not an object we've wrapped. + return -1; + } + + /* convert and cast value->ptr from value->type to ptr as ty. */ + value = swig_php_fetch_object(obj); if (!ty) { /* They don't care about the target type, so just pass on the pointer! */ *ptr = value->ptr; |