php: Throw exceptions instead of using 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.

See #2014, but not closing yet as there may be more cases to convert.
This commit is contained in:
Olly Betts 2021-05-25 16:37:21 +12:00
commit cdc69f9843
5 changed files with 52 additions and 22 deletions

View file

@ -7,6 +7,13 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.1.0 (in progress) Version 4.1.0 (in progress)
=========================== ===========================
2021-05-04: olly
[PHP] #2014 Throw exceptions instead of using 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.
2021-05-17: adr26 2021-05-17: adr26
[Python] #1985 Fix memory leaks: [Python] #1985 Fix memory leaks:

View file

@ -86,7 +86,8 @@
%typemap(in) SWIGTYPE ($&1_ltype tmp) %typemap(in) SWIGTYPE ($&1_ltype tmp)
%{ %{
if (SWIG_ConvertPtr(&$input, (void **) &tmp, $&1_descriptor, 0) < 0 || tmp == NULL) { if (SWIG_ConvertPtr(&$input, (void **) &tmp, $&1_descriptor, 0) < 0 || tmp == NULL) {
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $&1_descriptor"); zend_type_error("Expected $&1_descriptor for argument $argnum of $symname");
return;
} }
$1 = *tmp; $1 = *tmp;
%} %}
@ -94,7 +95,8 @@
%typemap(directorout) SWIGTYPE ($&1_ltype tmp) %typemap(directorout) SWIGTYPE ($&1_ltype tmp)
%{ %{
if (SWIG_ConvertPtr($input, (void **) &tmp, $&1_descriptor, 0) < 0 || tmp == NULL) { if (SWIG_ConvertPtr($input, (void **) &tmp, $&1_descriptor, 0) < 0 || tmp == NULL) {
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $&1_descriptor"); zend_type_error("Expected $&1_descriptor for argument $argnum of $symname");
goto thrown;
} }
$result = *tmp; $result = *tmp;
%} %}
@ -103,7 +105,8 @@
SWIGTYPE [] SWIGTYPE []
%{ %{
if (SWIG_ConvertPtr(&$input, (void **) &$1, $1_descriptor, 0) < 0) { if (SWIG_ConvertPtr(&$input, (void **) &$1, $1_descriptor, 0) < 0) {
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $1_descriptor"); zend_type_error("Expected $1_descriptor for argument $argnum of $symname");
return;
} }
%} %}
@ -111,7 +114,8 @@
SWIGTYPE [] (swig_owntype own) SWIGTYPE [] (swig_owntype own)
%{ %{
if (SWIG_ConvertPtrAndOwn($input, (void **)&$result, $1_descriptor, SWIG_POINTER_DISOWN, &own) < 0) { if (SWIG_ConvertPtrAndOwn($input, (void **)&$result, $1_descriptor, SWIG_POINTER_DISOWN, &own) < 0) {
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $1_descriptor"); zend_type_error("Expected $1_descriptor for argument $argnum of $symname");
goto thrown;
} }
swig_acquire_ownership_obj((void*)$result, own); swig_acquire_ownership_obj((void*)$result, own);
%} %}
@ -120,7 +124,8 @@
SWIGTYPE && SWIGTYPE &&
%{ %{
if (SWIG_ConvertPtr(&$input, (void **) &$1, $1_descriptor, 0) < 0 || $1 == NULL) { if (SWIG_ConvertPtr(&$input, (void **) &$1, $1_descriptor, 0) < 0 || $1 == NULL) {
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $1_descriptor"); zend_type_error("Expected $1_descriptor for argument $argnum of $symname");
return;
} }
%} %}
@ -128,7 +133,8 @@
SWIGTYPE && ($1_ltype tmp) SWIGTYPE && ($1_ltype tmp)
%{ %{
if (SWIG_ConvertPtr($input, (void **) &tmp, $1_descriptor, 0) < 0 || tmp == NULL) { if (SWIG_ConvertPtr($input, (void **) &tmp, $1_descriptor, 0) < 0 || tmp == NULL) {
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $1_descriptor"); zend_type_error("Expected $1_descriptor for argument $argnum of $symname");
goto thrown;
} }
$result = tmp; $result = tmp;
%} %}
@ -136,7 +142,8 @@
%typemap(in) SWIGTYPE *const& ($*ltype temp) %typemap(in) SWIGTYPE *const& ($*ltype temp)
%{ %{
if (SWIG_ConvertPtr(&$input, (void **) &temp, $*1_descriptor, 0) < 0) { if (SWIG_ConvertPtr(&$input, (void **) &temp, $*1_descriptor, 0) < 0) {
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $*1_descriptor"); zend_type_error("Expected $*1_descriptor for argument $argnum of $symname");
return;
} }
$1 = ($1_ltype)&temp; $1 = ($1_ltype)&temp;
%} %}
@ -144,7 +151,8 @@
%typemap(in) SWIGTYPE *DISOWN %typemap(in) SWIGTYPE *DISOWN
%{ %{
if (SWIG_ConvertPtr(&$input, (void **) &$1, $1_descriptor, SWIG_POINTER_DISOWN) < 0) { if (SWIG_ConvertPtr(&$input, (void **) &$1, $1_descriptor, SWIG_POINTER_DISOWN) < 0) {
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $1_descriptor"); zend_type_error("Expected $1_descriptor for argument $argnum of $symname");
return;
} }
%} %}
@ -157,10 +165,12 @@
%{ %{
if (SWIG_ConvertPtr(&$input, (void **) &$1, 0, 0) < 0) { if (SWIG_ConvertPtr(&$input, (void **) &$1, 0, 0) < 0) {
/* Allow NULL from php for void* */ /* Allow NULL from php for void* */
if (Z_ISNULL($input)) if (Z_ISNULL($input)) {
$1=0; $1=0;
else } else {
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $1_descriptor"); zend_type_error("Expected $1_descriptor for argument $argnum of $symname");
return;
}
} }
%} %}
@ -175,7 +185,8 @@
/* So... we didn't get a ref or ptr, but we'll accept NULL by reference */ /* So... we didn't get a ref or ptr, but we'll accept NULL by reference */
if (!(Z_ISREF($input) && Z_ISNULL_P(Z_REFVAL($input)))) { if (!(Z_ISREF($input) && Z_ISNULL_P(Z_REFVAL($input)))) {
/* wasn't a pre/ref/thing, OR anything like an int thing */ /* wasn't a pre/ref/thing, OR anything like an int thing */
SWIG_PHP_Error(E_ERROR, "Type error in argument $arg of $symname."); zend_throw_exception(zend_ce_type_error, "Type error in argument $arg of $symname", 0);
return;
} }
} }
force=0; force=0;

View file

@ -6,7 +6,7 @@
CONVERT_IN(tmp, $*1_ltype, $input); CONVERT_IN(tmp, $*1_ltype, $input);
$1 = &tmp; $1 = &tmp;
} else { } else {
SWIG_PHP_Error(E_ERROR, SWIG_PHP_Arg_Error_Msg($argnum, Expected a reference)); zend_type_error(SWIG_PHP_Arg_Error_Msg($argnum, Expected a reference));
} }
%} %}
%typemap(argout) TYPE *REF, %typemap(argout) TYPE *REF,

View file

@ -276,7 +276,8 @@ INT_TYPEMAP(unsigned long long);
/* So... we didn't get a ref or ptr, but we'll accept NULL by reference */ /* So... we didn't get a ref or ptr, but we'll accept NULL by reference */
if (!(Z_ISREF($input) && Z_ISNULL_P(Z_REFVAL($input)))) { if (!(Z_ISREF($input) && Z_ISNULL_P(Z_REFVAL($input)))) {
/* wasn't a pre/ref/thing, OR anything like an int thing */ /* wasn't a pre/ref/thing, OR anything like an int thing */
SWIG_PHP_Error(E_ERROR, "Type error in argument $arg of $symname."); zend_type_error("Expected reference or NULL for argument $arg of $symname");
SWIG_FAIL;
} }
} }
force=0; force=0;

View file

@ -830,9 +830,7 @@ public:
Printv(f->code, dispatch, "\n", NIL); Printv(f->code, dispatch, "\n", NIL);
Printf(f->code, "SWIG_ErrorCode() = E_ERROR;\n"); Printf(f->code, "zend_throw_exception(zend_ce_type_error, \"No matching function for overloaded '%s'\", 0);\n", symname);
Printf(f->code, "SWIG_ErrorMsg() = \"No matching function for overloaded '%s'\";\n", symname);
Printv(f->code, "SWIG_FAIL();\n", NIL);
Printv(f->code, "thrown:\n", NIL); Printv(f->code, "thrown:\n", NIL);
Printv(f->code, "return;\n", NIL); Printv(f->code, "return;\n", NIL);
Printv(f->code, "}\n", NIL); Printv(f->code, "}\n", NIL);
@ -924,7 +922,10 @@ public:
Printf(f->code, " zval args[2];\n zval tempZval;\n zend_string *arg2 = 0;\n\n"); Printf(f->code, " zval args[2];\n zval tempZval;\n zend_string *arg2 = 0;\n\n");
Printf(f->code, " if(ZEND_NUM_ARGS() != 2 || zend_get_parameters_array_ex(2, args) != SUCCESS) {\n"); Printf(f->code, " if(ZEND_NUM_ARGS() != 2 || zend_get_parameters_array_ex(2, args) != SUCCESS) {\n");
Printf(f->code, "\tWRONG_PARAM_COUNT;\n}\n\n"); Printf(f->code, "\tWRONG_PARAM_COUNT;\n}\n\n");
Printf(f->code, " if(!arg) SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");\n\n"); Printf(f->code, " if (!arg) {\n");
Printf(f->code, " zend_throw_exception(zend_ce_type_error, \"this pointer is NULL\", 0);\n");
Printf(f->code, " return;\n");
Printf(f->code, " }\n");
Printf(f->code, " arg2 = Z_STR(args[0]);\n\n"); Printf(f->code, " arg2 = Z_STR(args[0]);\n\n");
Printf(f->code, "if (!arg2) {\n RETVAL_NULL();\n}\n"); Printf(f->code, "if (!arg2) {\n RETVAL_NULL();\n}\n");
@ -963,7 +964,10 @@ public:
Printf(f->code, " zval args[1];\n zval tempZval;\n zend_string *arg2 = 0;\n\n"); Printf(f->code, " zval args[1];\n zval tempZval;\n zend_string *arg2 = 0;\n\n");
Printf(f->code, " if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, args) != SUCCESS) {\n"); Printf(f->code, " if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, args) != SUCCESS) {\n");
Printf(f->code, "\tWRONG_PARAM_COUNT;\n}\n\n"); Printf(f->code, "\tWRONG_PARAM_COUNT;\n}\n\n");
Printf(f->code, " if(!arg) SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");\n\n"); Printf(f->code, " if (!arg) {\n");
Printf(f->code, " zend_throw_exception(zend_ce_type_error, \"this pointer is NULL\", 0);\n");
Printf(f->code, " return;\n");
Printf(f->code, " }\n");
Printf(f->code, " arg2 = Z_STR(args[0]);\n\n"); Printf(f->code, " arg2 = Z_STR(args[0]);\n\n");
Printf(f->code, "if (!arg2) {\n RETVAL_NULL();\n}\n"); Printf(f->code, "if (!arg2) {\n RETVAL_NULL();\n}\n");
@ -997,7 +1001,9 @@ public:
Printf(f->code, " zval args[1];\n zend_string *arg2 = 0;\n\n"); Printf(f->code, " zval args[1];\n zend_string *arg2 = 0;\n\n");
Printf(f->code, " if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, args) != SUCCESS) {\n"); Printf(f->code, " if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, args) != SUCCESS) {\n");
Printf(f->code, "\tWRONG_PARAM_COUNT;\n}\n\n"); Printf(f->code, "\tWRONG_PARAM_COUNT;\n}\n\n");
Printf(f->code, " if(!arg) SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");\n\n"); Printf(f->code, " if(!arg) {\n");
Printf(f->code, " zend_throw_exception(zend_ce_type_error, \"this pointer is NULL\", 0);\n");
Printf(f->code, " }\n");
Printf(f->code, " arg2 = Z_STR(args[0]);\n\n"); Printf(f->code, " arg2 = Z_STR(args[0]);\n\n");
Printf(f->code, "if (!arg2) {\n RETVAL_FALSE;\n}\n"); Printf(f->code, "if (!arg2) {\n RETVAL_FALSE;\n}\n");
@ -1301,7 +1307,10 @@ public:
Setattr(p, "emit:input", source); Setattr(p, "emit:input", source);
Printf(f->code, "%s\n", tm); Printf(f->code, "%s\n", tm);
if (i == 0 && Getattr(p, "self")) { if (i == 0 && Getattr(p, "self")) {
Printf(f->code, "\tif(!arg1) SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");\n"); Printf(f->code, "\tif(!arg1) {\n");
Printf(f->code, "\t zend_throw_exception(zend_ce_type_error, \"this pointer is NULL\", 0);\n");
Printf(f->code, "\t return;\n");
Printf(f->code, "\t}\n");
} }
p = Getattr(p, "tmap:in:next"); p = Getattr(p, "tmap:in:next");
if (i >= num_required) { if (i >= num_required) {
@ -1820,7 +1829,9 @@ public:
Printf(director_ctor_code, "if (Swig::Director::swig_is_overridden_method(\"%s\", arg0)) { /* not subclassed */\n", class_name); Printf(director_ctor_code, "if (Swig::Director::swig_is_overridden_method(\"%s\", arg0)) { /* not subclassed */\n", class_name);
Printf(director_prot_ctor_code, "if (Swig::Director::swig_is_overridden_method(\"%s\", arg0)) { /* not subclassed */\n", class_name); Printf(director_prot_ctor_code, "if (Swig::Director::swig_is_overridden_method(\"%s\", arg0)) { /* not subclassed */\n", class_name);
Printf(director_ctor_code, " %s = new %s(%s);\n", Swig_cresult_name(), ctype, args); Printf(director_ctor_code, " %s = new %s(%s);\n", Swig_cresult_name(), ctype, args);
Printf(director_prot_ctor_code, " SWIG_PHP_Error(E_ERROR, \"accessing abstract class or protected constructor\");\n"); Printf(director_prot_ctor_code,
" zend_throw_exception(zend_ce_type_error, \"accessing abstract class or protected constructor\", 0);\n"
" return;\n");
if (i) { if (i) {
Insert(args, 0, ", "); Insert(args, 0, ", ");
} }