summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlly Betts <olly@survex.com>2023-05-08 15:39:53 +1200
committerOlly Betts <olly@survex.com>2023-05-08 15:44:24 +1200
commit15b739d60e9586025b665c19a85a09280d4ff9ad (patch)
tree0d7458e7afd14699fc0e3146cb0e46c8452cc0d0
parent281af00437752e4340bfb6c8ca6bb97434bea5a4 (diff)
downloadswig-15b739d60e9586025b665c19a85a09280d4ff9ad.tar.gz
[PHP] Wrap method with both static and non-static overloads
We now wrap this as a non-static method in PHP, which means the static form only callable via an object. Previously this case could end up wrapped as static or non-static in PHP. If it was wrapped as static, attempting to call non-static overloaded forms would crash with a segmentation fault. See #2544
-rw-r--r--CHANGES.current9
-rw-r--r--Examples/test-suite/php/smart_pointer_static_runme.php18
-rw-r--r--Source/Modules/php.cxx19
3 files changed, 45 insertions, 1 deletions
diff --git a/CHANGES.current b/CHANGES.current
index f76519d31..4a4304545 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -7,6 +7,15 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.2.0 (in progress)
===========================
+2023-05-08: olly
+ [PHP] #2544 Wrap overloaded method with both static and non-static
+ forms. We now wrap this as a non-static method in PHP, which means
+ the static form only callable via an object.
+
+ Previously this case could end up wrapped as static or non-static
+ in PHP. If it was wrapped as static, attempting to call non-static
+ overloaded forms would crash with a segmentation fault.
+
2023-05-06: mmomtchev, wsfulton
#2550 Fix typedef/using declarations to a typedef struct/class.
diff --git a/Examples/test-suite/php/smart_pointer_static_runme.php b/Examples/test-suite/php/smart_pointer_static_runme.php
new file mode 100644
index 000000000..71f7a74ee
--- /dev/null
+++ b/Examples/test-suite/php/smart_pointer_static_runme.php
@@ -0,0 +1,18 @@
+<?php
+
+require "tests.php";
+
+check::classes(array("Foo2","MyHandle_Foo2"));
+
+// This doesn't actually test any smart pointer stuff, just that static
+// vs non-static overloading is wrapped suitable (fixed in SWIG 4.2.0).
+//
+// We can't make the same wrapped method both static and non-static in PHP
+// so we make it non-static, and that at least allows the static version
+// to be called via an object.
+$foo2=new Foo2();
+check::classname("foo2",$foo2);
+check::equal($foo2->sum(1,2), 3);
+check::equal($foo2->sum(1,2,3), 6);
+
+check::done();
diff --git a/Source/Modules/php.cxx b/Source/Modules/php.cxx
index b272aab81..c2b19367d 100644
--- a/Source/Modules/php.cxx
+++ b/Source/Modules/php.cxx
@@ -239,6 +239,15 @@ class PHPTypes {
// Does the node for this have directorNode set?
bool has_director_node;
+ // Track if all the overloads of a method are static.
+ //
+ // We should only flag a dispatch method as ACC_STATIC if all the dispatched
+ // to methods are static. If we have both static and non-static methods in
+ // the overloaded set we omit ACC_STATIC, and then all the methods are
+ // callable (though the static ones only via an object). If we set
+ // ACC_STATIC we get a crash on an attempt to call a non-static method.
+ bool all_overloads_static;
+
// Used to clamp the required number of parameters in the arginfo to be
// compatible with any parent class version of the method.
int num_required;
@@ -332,6 +341,7 @@ public:
}
arginfo_id = Copy(Getattr(n, "sym:name"));
has_director_node = (Getattr(n, "directorNode") != NULL);
+ all_overloads_static = true;
}
~PHPTypes() {
@@ -339,6 +349,10 @@ public:
Delete(byref);
}
+ void not_all_static() { all_overloads_static = false; }
+
+ bool get_all_static() const { return all_overloads_static; }
+
void adjust(int num_required_, bool php_constructor) {
num_required = std::min(num_required, num_required_);
if (php_constructor) {
@@ -1021,7 +1035,7 @@ public:
if (constructorRenameOverload) {
Append(modes, " | ZEND_ACC_STATIC");
}
- } else if (wrapperType == staticmemberfn || Cmp(Getattr(n, "storage"), "static") == 0) {
+ } else if (phptypes->get_all_static()) {
modes = NewString("ZEND_ACC_PUBLIC | ZEND_ACC_STATIC");
} else {
modes = NewString("ZEND_ACC_PUBLIC");
@@ -1365,6 +1379,9 @@ public:
phptypes = new PHPTypes(n);
SetVoid(all_phptypes, key, phptypes);
}
+ if (!(wrapperType == staticmemberfn || Cmp(Getattr(n, "storage"), "static") == 0)) {
+ phptypes->not_all_static();
+ }
}
f = NewWrapper();