By default, SWIG's runtime argument validation for Perl produces error messages like this:
ValueError invalid null reference in method 'new_Test2', argument 1 of type 'Test1 &'By using SWIG code insertion directives to override the default behavior, it's possible to produce more useful error messages that include the file and line number:
ValueError invalid null reference in method 'new_Test2', argument 1 of type 'Test1 &' at ./test line 15This is accomplished by having SWIG's runtime argument validation code call Carp::croak to report the error. The following code insertion directives work for C++ code wrapped using SWIG 2.0.1 for Perl v5.10.1 on Ubuntu 10.04.1 Lucid:
%header %{ #undef SWIG_Error // if placed in %wrapper it will be at th +e end, too late for the wrapper code #define SWIG_Error(code, msg) call_perl_carp +((char *) SWIG_ErrorType(code), (char *) msg) __BEGIN_DECLS static void call_perl_carp(char *a, char *b); __END_DECLS %} %wrapper %{ static void call_perl_carp(char *a, char *b) { std::string *errstr = new std::string; errstr->append(a); errstr->append(" "); errstr->append(b); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(errstr->c_str(), 0))); PUTBACK; call_pv("Carp::croak", G_VOID | G_DISCARD); FREETMPS; LEAVE; } %} %perlcode %{ use Carp; # ensure Carp.pm is available for wrap +per argument validation %}
The code in the %header directive redefines the SWIG_Error macro to call the function call_perl_carp which is included below in the %wrapper directive. It also pre-declares call_perl_carp.
The %wrapper directive contains the call_perl_carp function, which concatenates its two string arguments and calls Carp::croak.
The %perlcode directive ensures that Carp::croak gets loaded and will be available to call_perl_carp when needed, for the cases when it's not loaded by the script using the wrapped code. Carp::croak has been a core module since perl 5.7.3, so it's sure to be present. Carp::croak suffices even for deeply-nested calls to the wrapped code, as anyone needing a full backtrace can refer to the Forcing a Stack Trace section of the Carp.pm documentation.
Note: The normal operation of the SWIG_Error macro is changed since call_perl_carp never regains control from the call to Carp::croak and thus never returns.
I think this is okay, since most SWIG_Error calls are from the SWIG_exception_fail macro, where SWIG_Error is followed by SWIG_fail which expands to goto fail, where SWIG_croak_null is called, expanding to croak(Nullch) and then Perl_croak_nocontext.
The only other uses of SWIG_Error are:
#define SWIG_croak(x) { SWIG_Error(SWIG_RuntimeError, x); SWIG_fail +; } #define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG +_RuntimeError, msg); SWIG_fail; } else #define SWIG_SetError(str) SWIG_Error(SWI +G_RuntimeError, str)
Since SWIG_croak and SWIG_contract_assert resemble SWIG_exception_fail in calling SWIG_fail after SWIG_Error, they should be fine as well. SWIG_SetError might pose a problem except that it's never used after being defined.
While I've not tried this error reporting technique with C code or Perl versions other than v5.10.1, I hope this information proves useful to anyone wrapping code with SWIG for use from Perl.
Original node text follows
I've written some C++ code and used SWIG to interface it to Perl.
While it's worked pretty well for the most part, SWIG produces a ton of wrapper code that performs extensive runtime argument validation.
The error messages produced by the default wrappers look like:
ValueError invalid null reference in method 'new_Foo', argument 2 of type 'Bar &'Note what's missing: there is no indication of the line number that triggered the problem. This complicates debugging large scripts.
Is there anyone familiar with SWIG and the error-reporting internals of Perl who can give me an idea how hard it would be to add Perl script line numbers to SWIG's runtime error reporting?
The error is apparently generated by this code in the _perlwrap.cxx file:
if (!argp2) { SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Foo" "', argument " "2"" of type '" "Bar &""'"); }
Wouldn't it be a matter of substituting a new SWIG_exception_fail routine which formats the error string and then calls the Perl error handler to print and exit?
Can this be done on a per-language basis in SWIG, or do all SWIG-supported languages have this issue with runtime error reporting?
Update Yes, SWIG uses preprocessor macros (both its own and Perl's) in the argument validation error handling:
As sundialsvc4 pointed out in his response, what's really needed is something similar to the functions in Carp.pm. So the problem comes down a generic one: Carp.pm (actually Carp::Heavy) is written entirely in Perl, so how does one call it from XS code?#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWI +G_fail; } while(0) #define SWIG_Error(code, msg) sv_setpvf(GvSV +(PL_errgv),"%s %s\n", SWIG_ErrorType(code), msg) #define SWIG_ErrorType(code) SWIG_Perl_Erro +rType(code) SWIG_Perl_ErrorType(int code) { C code that returns a string describin +g the error code } #define SWIG_fail goto fail #define SWIG_croak_null() croak(Nullch)
Looking at 'man perlcall'
End Update
If lack of script line numbers in runtime errors is specific to Perl, I'm willing to do the work needed to patch SWIG to bring error support up to par with other languages. All I need is for someone to point me in the right direction. A Google search for the two terms Perl_croak and SWIG_exception_fail gives three results.
When I tried adding an exception handler, the exception handling code showed up in the wrapper, but not around the argument validation stuff with the calls to SWIG_exception_fail. It appears that argument validation errors aren't catchable with SWIG exception mechanism.
(Note: After getting frustrated with this issue in the SWIG version 1.3.4 packaged with Ubuntu I downloaded the brand-new SWIG 2.0.1 which includes "Numerous fixes in reporting file and line numbers in error and warning messages". Alas, no change in runtime errors, at least in Perl. Apparently the improvements are in the swig program itself when generating the wrapper code.
I posted a similar question to the swig-user mailing list but got no response. Perhaps the question is too Perl-specific.)
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Better runtime error messages from SWIG-wrapped code?
by locked_user sundialsvc4 (Abbot) on Oct 15, 2010 at 14:30 UTC | |
by tod222 (Pilgrim) on Oct 15, 2010 at 14:58 UTC |