summaryrefslogtreecommitdiff
path: root/Lib/php
diff options
context:
space:
mode:
authorOlly Betts <olly@survex.com>2022-01-20 14:42:02 +1300
committerOlly Betts <olly@survex.com>2022-01-20 14:42:02 +1300
commitc417250b4ef8c945b602722642ab3b7c82acb7ca (patch)
tree67853e698564fac861677d5903a720a9a282518d /Lib/php
parent0cfc750d44cb9b4efe40b7bdaec44b930c7f4a9d (diff)
downloadswig-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.swg19
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;