summaryrefslogtreecommitdiff
path: root/Source
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 /Source
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
Diffstat (limited to 'Source')
-rw-r--r--Source/Modules/php.cxx19
1 files changed, 18 insertions, 1 deletions
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();