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 #2014
This commit is contained in:
Olly Betts 2021-05-26 08:56:41 +12:00
commit 17a294cec4
7 changed files with 41 additions and 68 deletions

View file

@ -8,11 +8,33 @@ Version 4.1.0 (in progress)
===========================
2021-05-04: olly
[PHP] #2014 Throw exceptions instead of using errors
[PHP] #2014 Throw PHP exceptions instead of using PHP errors
Parameter type errors and some other cases in SWIG-generated wrappers
now throw a PHP exception, which is how PHP's native parameter handling
deals with similar situations.
PHP exceptions can be caught and handled if desired, but if they
aren't caught then PHP exits in much the same way as it does for a
PHP error.
In particular this means parameter type errors and some other cases
in SWIG-generated wrappers now throw a PHP exception, which matches
how PHP's native parameter handling deals with similar situations.
`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 in user interface
files 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.
*** POTENTIAL INCOMPATIBILITY ***
2021-05-17: adr26
[Python] #1985 Fix memory leaks:

View file

@ -25,7 +25,7 @@
code == SWIG_DivisionByZero ? zend_ce_division_by_zero_error : \
code == SWIG_SyntaxError ? zend_ce_parse_error : \
code == SWIG_OverflowError ? zend_ce_arithmetic_error : \
NULL, msg, code); goto thrown; } while (0)
NULL, msg, code); SWIG_fail; } while (0)
%}
#endif

View file

@ -137,8 +137,8 @@ namespace Swig {
swig_msg += " ";
swig_msg += msg;
}
SWIG_ErrorCode() = code;
SWIG_ErrorMsg() = swig_msg.c_str();
// Don't replace an already active PHP exception.
if (!EG(exception)) zend_throw_exception(NULL, swig_msg.c_str(), code);
}
virtual ~DirectorException() throw() {

View file

@ -96,7 +96,7 @@
%{
if (SWIG_ConvertPtr($input, (void **) &tmp, $&1_descriptor, 0) < 0 || tmp == NULL) {
zend_type_error("Expected $&1_descriptor for argument $argnum of $symname");
goto thrown;
SWIG_fail;
}
$result = *tmp;
%}
@ -115,7 +115,7 @@
%{
if (SWIG_ConvertPtrAndOwn($input, (void **)&$result, $1_descriptor, SWIG_POINTER_DISOWN, &own) < 0) {
zend_type_error("Expected $1_descriptor for argument $argnum of $symname");
goto thrown;
SWIG_fail;
}
swig_acquire_ownership_obj((void*)$result, own);
%}
@ -134,7 +134,7 @@
%{
if (SWIG_ConvertPtr($input, (void **) &tmp, $1_descriptor, 0) < 0 || tmp == NULL) {
zend_type_error("Expected $1_descriptor for argument $argnum of $symname");
goto thrown;
SWIG_fail;
}
$result = tmp;
%}

View file

@ -58,15 +58,12 @@ static zend_always_inline void *zend_object_alloc(size_t obj_size, zend_class_en
#define SWIG_fail goto fail
// If there's an active PHP exception, just return so it can propagate.
#define SWIG_FAIL() do { if (!EG(exception)) zend_error_noreturn(SWIG_ErrorCode(), "%s", SWIG_ErrorMsg()); goto thrown; } while (0)
static const char *default_error_msg = "Unknown error occurred";
static int default_error_code = E_ERROR;
#define SWIG_PHP_Arg_Error_Msg(argnum,extramsg) "Error in argument " #argnum " "#extramsg
#define SWIG_PHP_Error(code,msg) do { SWIG_ErrorCode() = code; SWIG_ErrorMsg() = msg; SWIG_fail; } while (0)
#define SWIG_PHP_Error(code,msg) do { zend_throw_exception(NULL, msg, code); SWIG_fail; } while (0)
#define SWIG_contract_assert(expr,msg) \
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) {
}
if (!type->clientdata) {
zend_error(E_ERROR, "Type: %s not registered with zend", type->name);
zend_type_error("Type: %s not registered with zend", type->name);
return;
}

View file

@ -277,7 +277,7 @@ INT_TYPEMAP(unsigned long long);
if (!(Z_ISREF($input) && Z_ISNULL_P(Z_REFVAL($input)))) {
/* wasn't a pre/ref/thing, OR anything like an int thing */
zend_type_error("Expected reference or NULL for argument $arg of $symname");
SWIG_FAIL;
return;
}
}
force=0;

View file

@ -359,29 +359,7 @@ public:
/* Initialize the rest of the module */
Printf(s_oinit, " ZEND_INIT_MODULE_GLOBALS(%s, %s_init_globals, NULL);\n", module, module);
/* start the header section */
Printf(s_header, "ZEND_BEGIN_MODULE_GLOBALS(%s)\n", module);
Printf(s_header, "const char *error_msg;\n");
Printf(s_header, "int error_code;\n");
Printf(s_header, "ZEND_END_MODULE_GLOBALS(%s)\n", module);
Printf(s_header, "ZEND_DECLARE_MODULE_GLOBALS(%s)\n", module);
Printf(s_header, "#define SWIG_ErrorMsg() ZEND_MODULE_GLOBALS_ACCESSOR(%s, error_msg)\n", module);
Printf(s_header, "#define SWIG_ErrorCode() ZEND_MODULE_GLOBALS_ACCESSOR(%s, error_code)\n", module);
Printf(s_header, "static void %s_init_globals(zend_%s_globals *globals ) {\n", module, module);
Printf(s_header, " globals->error_msg = default_error_msg;\n");
Printf(s_header, " globals->error_code = default_error_code;\n");
Printf(s_header, "}\n");
Printf(s_header, "static void SWIG_ResetError(void) {\n");
Printf(s_header, " SWIG_ErrorMsg() = default_error_msg;\n");
Printf(s_header, " SWIG_ErrorCode() = default_error_code;\n");
Printf(s_header, "}\n");
Append(s_header, "\n");
Printf(s_header, "#define SWIG_name \"%s\"\n", module);
Printf(s_header, "#ifdef __cplusplus\n");
Printf(s_header, "extern \"C\" {\n");
@ -831,7 +809,7 @@ public:
Printv(f->code, dispatch, "\n", NIL);
Printf(f->code, "zend_throw_exception(zend_ce_type_error, \"No matching function for overloaded '%s'\", 0);\n", symname);
Printv(f->code, "thrown:\n", NIL);
Printv(f->code, "fail:\n", NIL);
Printv(f->code, "return;\n", NIL);
Printv(f->code, "}\n", NIL);
Wrapper_print(f, s_wrappers);
@ -947,12 +925,8 @@ public:
Printf(f->code, "add_property_zval_ex(ZEND_THIS, ZSTR_VAL(arg2), ZSTR_LEN(arg2), &args[1]);\n}\n");
}
Printf(f->code, "thrown:\n");
Printf(f->code, "return;\n");
/* Error handling code */
Printf(f->code, "fail:\n");
Append(f->code, "SWIG_FAIL();\n");
Printf(f->code, "return;\n");
Printf(f->code, "}\n\n\n");
@ -984,12 +958,8 @@ public:
Printf(f->code, "RETVAL_NULL();\n}\n");
}
Printf(f->code, "thrown:\n");
Printf(f->code, "return;\n");
/* Error handling code */
Printf(f->code, "fail:\n");
Append(f->code, "SWIG_FAIL();\n");
Printf(f->code, "return;\n");
Printf(f->code, "}\n\n\n");
@ -1020,12 +990,8 @@ public:
Printf(f->code, "RETVAL_FALSE;\n}\n");
}
Printf(f->code, "thrown:\n");
Printf(f->code, "return;\n");
/* Error handling code */
Printf(f->code, "fail:\n");
Append(f->code, "SWIG_FAIL();\n");
Printf(f->code, "return;\n");
Printf(f->code, "}\n\n\n");
Wrapper_print(f, s_wrappers);
@ -1243,8 +1209,6 @@ public:
// NOTE: possible we ignore this_ptr as a param for native constructor
Printf(f->code, "SWIG_ResetError();\n");
if (numopt > 0) { // membervariable wrappers do not have optional args
Wrapper_add_local(f, "arg_count", "int arg_count");
Printf(f->code, "arg_count = ZEND_NUM_ARGS();\n");
@ -1420,14 +1384,9 @@ public:
}
if (!static_setter) {
Printf(f->code, "thrown:\n");
Printf(f->code, "return;\n");
/* Error handling code */
Printf(f->code, "fail:\n");
Printv(f->code, cleanup, NIL);
Append(f->code, "SWIG_FAIL();\n");
Printf(f->code, "return;\n");
Printf(f->code, "}\n");
}
@ -2186,7 +2145,7 @@ public:
Delete(outarg);
}
Append(w->code, "thrown:\n");
Append(w->code, "fail: ;\n");
if (!is_void) {
if (!(ignored_method && !pure_virtual)) {
String *rettype = SwigType_str(returntype, 0);
@ -2197,12 +2156,7 @@ public:
}
Delete(rettype);
}
} else {
Append(w->code, "return;\n");
}
Append(w->code, "fail:\n");
Append(w->code, "SWIG_FAIL();\n");
Append(w->code, "}\n");
// We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method