Skip to content

Commit 17a294c

Browse files
committed
Replace remaining PHP errors with PHP exceptions
`SWIG_ErrorCode()`, `SWIG_ErrorMsg()`, `SWIG_FAIL()` and `goto thrown;` are no longer supported (these are really all internal implementation details and none are documented aside from brief mentions in CHANGES for the first three). I wasn't able to find any uses at least in FOSS code via code search tools. If you are using these: Use `SWIG_PHP_Error(code,msg);` instead of `SWIG_ErrorCode(code); SWIG_ErrorMsg(msg);` (which will throw a PHP exception in SWIG >= 4.1 and do the same as the individual calls in older SWIG). `SWIG_FAIL();` and `goto thrown;` can typically be replaced with `SWIG_fail;`. This will probably also work with older SWIG, but please test with your wrappers if this is important to you. Fixes swig#2014
1 parent cdc69f9 commit 17a294c

File tree

7 files changed

+41
-68
lines changed

7 files changed

+41
-68
lines changed

CHANGES.current

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,33 @@ Version 4.1.0 (in progress)
88
===========================
99

1010
2021-05-04: olly
11-
[PHP] #2014 Throw exceptions instead of using errors
11+
[PHP] #2014 Throw PHP exceptions instead of using PHP errors
1212

13-
Parameter type errors and some other cases in SWIG-generated wrappers
14-
now throw a PHP exception, which is how PHP's native parameter handling
15-
deals with similar situations.
13+
PHP exceptions can be caught and handled if desired, but if they
14+
aren't caught then PHP exits in much the same way as it does for a
15+
PHP error.
16+
17+
In particular this means parameter type errors and some other cases
18+
in SWIG-generated wrappers now throw a PHP exception, which matches
19+
how PHP's native parameter handling deals with similar situations.
20+
21+
`SWIG_ErrorCode()`, `SWIG_ErrorMsg()`, `SWIG_FAIL()` and `goto thrown;`
22+
are no longer supported (these are really all internal implementation
23+
details and none are documented aside from brief mentions in CHANGES
24+
for the first three). I wasn't able to find any uses in user interface
25+
files at least in FOSS code via code search tools.
26+
27+
If you are using these:
28+
29+
Use `SWIG_PHP_Error(code,msg);` instead of `SWIG_ErrorCode(code);
30+
SWIG_ErrorMsg(msg);` (which will throw a PHP exception in SWIG >= 4.1
31+
and do the same as the individual calls in older SWIG).
32+
33+
`SWIG_FAIL();` and `goto thrown;` can typically be replaced with
34+
`SWIG_fail;`. This will probably also work with older SWIG, but
35+
please test with your wrappers if this is important to you.
36+
37+
*** POTENTIAL INCOMPATIBILITY ***
1638

1739
2021-05-17: adr26
1840
[Python] #1985 Fix memory leaks:

Lib/exception.i

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
code == SWIG_DivisionByZero ? zend_ce_division_by_zero_error : \
2626
code == SWIG_SyntaxError ? zend_ce_parse_error : \
2727
code == SWIG_OverflowError ? zend_ce_arithmetic_error : \
28-
NULL, msg, code); goto thrown; } while (0)
28+
NULL, msg, code); SWIG_fail; } while (0)
2929
%}
3030
#endif
3131

Lib/php/director.swg

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ namespace Swig {
137137
swig_msg += " ";
138138
swig_msg += msg;
139139
}
140-
SWIG_ErrorCode() = code;
141-
SWIG_ErrorMsg() = swig_msg.c_str();
140+
// Don't replace an already active PHP exception.
141+
if (!EG(exception)) zend_throw_exception(NULL, swig_msg.c_str(), code);
142142
}
143143

144144
virtual ~DirectorException() throw() {

Lib/php/php.swg

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
%{
9797
if (SWIG_ConvertPtr($input, (void **) &tmp, $&1_descriptor, 0) < 0 || tmp == NULL) {
9898
zend_type_error("Expected $&1_descriptor for argument $argnum of $symname");
99-
goto thrown;
99+
SWIG_fail;
100100
}
101101
$result = *tmp;
102102
%}
@@ -115,7 +115,7 @@
115115
%{
116116
if (SWIG_ConvertPtrAndOwn($input, (void **)&$result, $1_descriptor, SWIG_POINTER_DISOWN, &own) < 0) {
117117
zend_type_error("Expected $1_descriptor for argument $argnum of $symname");
118-
goto thrown;
118+
SWIG_fail;
119119
}
120120
swig_acquire_ownership_obj((void*)$result, own);
121121
%}
@@ -134,7 +134,7 @@
134134
%{
135135
if (SWIG_ConvertPtr($input, (void **) &tmp, $1_descriptor, 0) < 0 || tmp == NULL) {
136136
zend_type_error("Expected $1_descriptor for argument $argnum of $symname");
137-
goto thrown;
137+
SWIG_fail;
138138
}
139139
$result = tmp;
140140
%}

Lib/php/phprun.swg

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,12 @@ static zend_always_inline void *zend_object_alloc(size_t obj_size, zend_class_en
5858

5959
#define SWIG_fail goto fail
6060

61-
// If there's an active PHP exception, just return so it can propagate.
62-
#define SWIG_FAIL() do { if (!EG(exception)) zend_error_noreturn(SWIG_ErrorCode(), "%s", SWIG_ErrorMsg()); goto thrown; } while (0)
63-
6461
static const char *default_error_msg = "Unknown error occurred";
6562
static int default_error_code = E_ERROR;
6663

6764
#define SWIG_PHP_Arg_Error_Msg(argnum,extramsg) "Error in argument " #argnum " "#extramsg
6865

69-
#define SWIG_PHP_Error(code,msg) do { SWIG_ErrorCode() = code; SWIG_ErrorMsg() = msg; SWIG_fail; } while (0)
66+
#define SWIG_PHP_Error(code,msg) do { zend_throw_exception(NULL, msg, code); SWIG_fail; } while (0)
7067

7168
#define SWIG_contract_assert(expr,msg) \
7269
do { if (!(expr)) zend_printf("Contract Assert Failed %s\n", msg); } while (0)
@@ -102,7 +99,7 @@ SWIG_SetPointerZval(zval *z, void *ptr, swig_type_info *type, int newobject) {
10299
}
103100

104101
if (!type->clientdata) {
105-
zend_error(E_ERROR, "Type: %s not registered with zend", type->name);
102+
zend_type_error("Type: %s not registered with zend", type->name);
106103
return;
107104
}
108105

Lib/php/typemaps.i

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ INT_TYPEMAP(unsigned long long);
277277
if (!(Z_ISREF($input) && Z_ISNULL_P(Z_REFVAL($input)))) {
278278
/* wasn't a pre/ref/thing, OR anything like an int thing */
279279
zend_type_error("Expected reference or NULL for argument $arg of $symname");
280-
SWIG_FAIL;
280+
return;
281281
}
282282
}
283283
force=0;

Source/Modules/php.cxx

Lines changed: 6 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -359,29 +359,7 @@ class PHP : public Language {
359359

360360
/* Initialize the rest of the module */
361361

362-
Printf(s_oinit, " ZEND_INIT_MODULE_GLOBALS(%s, %s_init_globals, NULL);\n", module, module);
363-
364362
/* start the header section */
365-
Printf(s_header, "ZEND_BEGIN_MODULE_GLOBALS(%s)\n", module);
366-
Printf(s_header, "const char *error_msg;\n");
367-
Printf(s_header, "int error_code;\n");
368-
Printf(s_header, "ZEND_END_MODULE_GLOBALS(%s)\n", module);
369-
Printf(s_header, "ZEND_DECLARE_MODULE_GLOBALS(%s)\n", module);
370-
Printf(s_header, "#define SWIG_ErrorMsg() ZEND_MODULE_GLOBALS_ACCESSOR(%s, error_msg)\n", module);
371-
Printf(s_header, "#define SWIG_ErrorCode() ZEND_MODULE_GLOBALS_ACCESSOR(%s, error_code)\n", module);
372-
373-
Printf(s_header, "static void %s_init_globals(zend_%s_globals *globals ) {\n", module, module);
374-
Printf(s_header, " globals->error_msg = default_error_msg;\n");
375-
Printf(s_header, " globals->error_code = default_error_code;\n");
376-
Printf(s_header, "}\n");
377-
378-
Printf(s_header, "static void SWIG_ResetError(void) {\n");
379-
Printf(s_header, " SWIG_ErrorMsg() = default_error_msg;\n");
380-
Printf(s_header, " SWIG_ErrorCode() = default_error_code;\n");
381-
Printf(s_header, "}\n");
382-
383-
Append(s_header, "\n");
384-
385363
Printf(s_header, "#define SWIG_name \"%s\"\n", module);
386364
Printf(s_header, "#ifdef __cplusplus\n");
387365
Printf(s_header, "extern \"C\" {\n");
@@ -831,7 +809,7 @@ class PHP : public Language {
831809
Printv(f->code, dispatch, "\n", NIL);
832810

833811
Printf(f->code, "zend_throw_exception(zend_ce_type_error, \"No matching function for overloaded '%s'\", 0);\n", symname);
834-
Printv(f->code, "thrown:\n", NIL);
812+
Printv(f->code, "fail:\n", NIL);
835813
Printv(f->code, "return;\n", NIL);
836814
Printv(f->code, "}\n", NIL);
837815
Wrapper_print(f, s_wrappers);
@@ -947,12 +925,8 @@ class PHP : public Language {
947925
Printf(f->code, "add_property_zval_ex(ZEND_THIS, ZSTR_VAL(arg2), ZSTR_LEN(arg2), &args[1]);\n}\n");
948926
}
949927

950-
Printf(f->code, "thrown:\n");
951-
Printf(f->code, "return;\n");
952-
953-
/* Error handling code */
954928
Printf(f->code, "fail:\n");
955-
Append(f->code, "SWIG_FAIL();\n");
929+
Printf(f->code, "return;\n");
956930
Printf(f->code, "}\n\n\n");
957931

958932

@@ -984,12 +958,8 @@ class PHP : public Language {
984958
Printf(f->code, "RETVAL_NULL();\n}\n");
985959
}
986960

987-
Printf(f->code, "thrown:\n");
988-
Printf(f->code, "return;\n");
989-
990-
/* Error handling code */
991961
Printf(f->code, "fail:\n");
992-
Append(f->code, "SWIG_FAIL();\n");
962+
Printf(f->code, "return;\n");
993963
Printf(f->code, "}\n\n\n");
994964

995965

@@ -1020,12 +990,8 @@ class PHP : public Language {
1020990
Printf(f->code, "RETVAL_FALSE;\n}\n");
1021991
}
1022992

1023-
Printf(f->code, "thrown:\n");
1024-
Printf(f->code, "return;\n");
1025-
1026-
/* Error handling code */
1027993
Printf(f->code, "fail:\n");
1028-
Append(f->code, "SWIG_FAIL();\n");
994+
Printf(f->code, "return;\n");
1029995
Printf(f->code, "}\n\n\n");
1030996

1031997
Wrapper_print(f, s_wrappers);
@@ -1243,8 +1209,6 @@ class PHP : public Language {
12431209

12441210
// NOTE: possible we ignore this_ptr as a param for native constructor
12451211

1246-
Printf(f->code, "SWIG_ResetError();\n");
1247-
12481212
if (numopt > 0) { // membervariable wrappers do not have optional args
12491213
Wrapper_add_local(f, "arg_count", "int arg_count");
12501214
Printf(f->code, "arg_count = ZEND_NUM_ARGS();\n");
@@ -1420,14 +1384,9 @@ class PHP : public Language {
14201384
}
14211385

14221386
if (!static_setter) {
1423-
Printf(f->code, "thrown:\n");
1424-
Printf(f->code, "return;\n");
1425-
1426-
/* Error handling code */
14271387
Printf(f->code, "fail:\n");
14281388
Printv(f->code, cleanup, NIL);
1429-
Append(f->code, "SWIG_FAIL();\n");
1430-
1389+
Printf(f->code, "return;\n");
14311390
Printf(f->code, "}\n");
14321391
}
14331392

@@ -2186,7 +2145,7 @@ class PHP : public Language {
21862145
Delete(outarg);
21872146
}
21882147

2189-
Append(w->code, "thrown:\n");
2148+
Append(w->code, "fail: ;\n");
21902149
if (!is_void) {
21912150
if (!(ignored_method && !pure_virtual)) {
21922151
String *rettype = SwigType_str(returntype, 0);
@@ -2197,12 +2156,7 @@ class PHP : public Language {
21972156
}
21982157
Delete(rettype);
21992158
}
2200-
} else {
2201-
Append(w->code, "return;\n");
22022159
}
2203-
2204-
Append(w->code, "fail:\n");
2205-
Append(w->code, "SWIG_FAIL();\n");
22062160
Append(w->code, "}\n");
22072161

22082162
// We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method

0 commit comments

Comments
 (0)