Skip to content

Commit 1707d6b

Browse files
committed
[PHP] Fix cleanup code handling issues
Fix to call cleanup code in exception situations and not to invoke the freearg typemap twice in certain situations. Fixes https://sourceforge.net/p/swig/bugs/1211/
1 parent dffa74b commit 1707d6b

File tree

9 files changed

+54
-16
lines changed

9 files changed

+54
-16
lines changed

CHANGES.current

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
77
Version 4.1.0 (in progress)
88
===========================
99

10+
2022-02-17: olly
11+
[PHP] https://sourceforge.net/p/swig/bugs/1211/
12+
Fix to call cleanup code in exception situations and not to invoke
13+
the freearg typemap twice in certain situations.
14+
1015
2022-02-15: olly
1116
#300 #368 Improve parser handling of % followed immediately by
1217
an identifier. If it's not a recognised directive the scanner

Examples/test-suite/common.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ CPP_TEST_CASES += \
234234
evil_diamond_ns \
235235
evil_diamond_prop \
236236
exception_classname \
237+
exception_memory_leak \
237238
exception_order \
238239
extend \
239240
extend_constructor_destructor \
Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
%module r_memory_leak
1+
%module exception_memory_leak
22

33
%include <std_string.i>
44

@@ -8,33 +8,38 @@
88
}
99
%typemap(freearg) Foo* foo
1010
{
11-
printf(" \" Object deleted\"\n");
11+
Foo::inc_freearg_count();
1212
delete $1;
1313
}
1414
%typemap(out) Foo* verify_no_memory_leak
1515
{
1616
if ($1 == NULL)
1717
SWIG_exception_fail(SWIG_RuntimeError, "Let's see how the bindings manage this exception!");
18+
$1 = NULL;
1819
}
19-
%typemap(scoerceout) Foo*
20-
%{ if (!is.null($result) && !is.logical($result)) {$result <- new("$R_class", ref=$result) ;}; %}
2120

2221
%inline %{
2322
#include <string>
2423

2524
class Foo {
2625
static unsigned count;
26+
static unsigned freearg_count;
2727
public:
2828
Foo() { ++count; }
2929
~Foo() { --count; }
3030
static unsigned get_count() { return count; }
31+
static unsigned get_freearg_count() { return freearg_count; }
32+
#ifndef SWIG
33+
static void inc_freearg_count() { ++freearg_count; }
34+
#endif
3135
};
3236

3337
unsigned Foo::count = 0;
38+
unsigned Foo::freearg_count = 0;
3439

3540
static Foo* trigger_internal_swig_exception(const std::string& message, Foo* foo)
3641
{
3742
return (message == "null") ? NULL : foo;
38-
};
43+
}
3944

4045
%}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
require "tests.php";
4+
5+
check::functions(array('trigger_internal_swig_exception'));
6+
check::classes(array('Foo', 'exception_memory_leak'));
7+
// No new vars
8+
check::globals(array());
9+
10+
$a = new Foo();
11+
check::equal(Foo::get_count(), 1, "Should have 1 Foo objects");
12+
$b = new Foo();
13+
check::equal(Foo::get_count(), 2, "Should have 2 Foo objects");
14+
15+
// Normal behaviour
16+
trigger_internal_swig_exception("no problem", $a);
17+
check::equal(Foo::get_count(), 2, "Should have 2 Foo objects");
18+
check::equal(Foo::get_freearg_count(), 1, "freearg should have been used once");
19+
20+
// SWIG exception triggered and handled.
21+
trigger_internal_swig_exception("null", $b);
22+
check::equal(Foo::get_count(), 2, "Should have 2 Foo objects");
23+
check::equal(Foo::get_freearg_count(), 2, "freearg should have been used twice");

Examples/test-suite/r/Makefile.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ C_TEST_CASES += \
1818

1919
CPP_TEST_CASES += \
2020
r_double_delete \
21-
r_memory_leak \
2221
r_overload_array \
2322
r_sexp \
2423
r_overload_comma \

Examples/test-suite/r/r_memory_leak_runme.R renamed to Examples/test-suite/r/exception_memory_leak_runme.R

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
clargs <- commandArgs(trailing=TRUE)
22
source(file.path(clargs[1], "unittest.R"))
33

4-
dyn.load(paste("r_memory_leak", .Platform$dynlib.ext, sep=""))
5-
source("r_memory_leak.R")
4+
dyn.load(paste("exception_memory_leak", .Platform$dynlib.ext, sep=""))
5+
source("exception_memory_leak.R")
66
cacheMetaData(1)
77

88
a <- Foo();
@@ -13,6 +13,7 @@ unittest(Foo_get_count(), 2);
1313
# Normal behaviour
1414
invisible(trigger_internal_swig_exception("no problem", a));
1515
unittest(Foo_get_count(), 2);
16+
unittest(Foo_get_freearg_count(), 1);
1617
# SWIG exception introduced
1718
result <- tryCatch({
1819
trigger_internal_swig_exception("null", b);
@@ -24,3 +25,4 @@ result <- tryCatch({
2425
unittest(1,1);
2526
})
2627
unittest(Foo_get_count(), 2);
28+
unittest(Foo_get_freearg_count(), 2);

Lib/php/php.swg

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@
191191
if (!(Z_ISREF($input) && Z_ISNULL_P(Z_REFVAL($input)))) {
192192
/* wasn't a pre/ref/thing, OR anything like an int thing */
193193
zend_throw_exception(zend_ce_type_error, "Type error in argument $arg of $symname", 0);
194-
return;
194+
goto fail;
195195
}
196196
}
197197
force=0;
@@ -555,18 +555,18 @@
555555
unsigned long,
556556
unsigned short %{
557557
zend_throw_exception(NULL, "C++ $1_type exception thrown", $1);
558-
return;
558+
goto fail;
559559
%}
560560

561561
%typemap(throws) SWIGTYPE, SWIGTYPE &, SWIGTYPE &&, SWIGTYPE *, SWIGTYPE [], SWIGTYPE [ANY] %{
562562
(void)$1;
563563
zend_throw_exception(NULL, "C++ $1_type exception thrown", 0);
564-
return;
564+
goto fail;
565565
%}
566566

567567
%typemap(throws) char * %{
568568
zend_throw_exception(NULL, $1, 0);
569-
return;
569+
goto fail;
570570
%}
571571

572572
/* Array reference typemaps */

Lib/php/std_string.i

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ namespace std {
5151

5252
%typemap(throws) string, const string& %{
5353
zend_throw_exception(NULL, $1.c_str(), 0);
54-
return;
54+
goto fail;
5555
%}
5656

5757
%typemap(in, phptype="string") const string & ($*1_ltype temp) %{

Source/Modules/php.cxx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,7 @@ class PHP : public Language {
10311031
Printf(f->code, "\tWRONG_PARAM_COUNT;\n}\n\n");
10321032
Printf(f->code, " if(!arg) {\n");
10331033
Printf(f->code, " zend_throw_exception(zend_ce_type_error, \"this pointer is NULL\", 0);\n");
1034+
Printf(f->code, " return;\n");
10341035
Printf(f->code, " }\n");
10351036
Printf(f->code, " arg2 = Z_STR(args[0]);\n\n");
10361037

@@ -1405,7 +1406,7 @@ class PHP : public Language {
14051406
Printv(f->code, outarg, NIL);
14061407
}
14071408

1408-
if (cleanup) {
1409+
if (static_setter && cleanup) {
14091410
Printv(f->code, cleanup, NIL);
14101411
}
14111412

@@ -1698,8 +1699,10 @@ class PHP : public Language {
16981699
"#ifndef SWIG_PHP_INTERFACE_", interface, "_CE\n",
16991700
" {\n",
17001701
" zend_class_entry *swig_interface_ce = zend_lookup_class(zend_string_init(\"", interface, "\", sizeof(\"", interface, "\") - 1, 0));\n",
1701-
" if (!swig_interface_ce) zend_throw_exception(zend_ce_error, \"Interface \\\"", interface, "\\\" not found\", 0);\n",
1702-
" zend_do_implement_interface(SWIG_Php_ce_", class_name, ", swig_interface_ce);\n",
1702+
" if (swig_interface_ce)\n",
1703+
" zend_do_implement_interface(SWIG_Php_ce_", class_name, ", swig_interface_ce);\n",
1704+
" else\n",
1705+
" zend_throw_exception(zend_ce_error, \"Interface \\\"", interface, "\\\" not found\", 0);\n",
17031706
" }\n",
17041707
"#endif\n",
17051708
NIL);

0 commit comments

Comments
 (0)