Menu

#1308 SWIG_exception / SWIG_fail compile failure

open
nobody
None
5
2022-08-04
2013-03-06
dstndstn
No

Hi,

With the SWIG below, I get a compile failure: it looks like SWIG_fail is expanding to "goto fail", but the "fail:" label is in the wrong function (the calling function).

This is with swig 2.0.9, and my target is python, though I think the problem is language-independent.

%module test

%include <exception.i>

%inline %{

    typedef struct {
    } s;

    %}

%extend s {

    s(int x) {
        // option A
        SWIG_exception(SWIG_RuntimeError, "Msg");

        // option B
        PyErr_SetString(PyExc_RuntimeError, "Msg");
        SWIG_fail;

        return NULL;
    }

 }

Produces:

#define SWIG_fail       goto fail                      
// [snip]
SWIGINTERN s *new_s(int x){
        SWIG_exception(SWIG_RuntimeError, "Msg");
        PyErr_SetString(PyExc_RuntimeError, "Msg");
        SWIG_fail;
        return NULL;
    }

SWIGINTERN PyObject *_wrap_new_s(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
/// [snip]
  result = (s *)new_s(arg1);
  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_s, SWIG_POINTER_NEW |  0 );
  return resultobj;
fail:
  return NULL;
}

Notice that 'SWIG_fail', ie, 'goto fail' is in 'new_s()', but the 'fail:' label is in '_wrap_new_s'.

Thanks,
dustin

Discussion

  • Olly Betts

    Olly Betts - 2022-03-09

    Still the case with git master.

    You can probably workaround by adding a fail: label before the return NULL; in your %extend constructor. With -builtin it looks like that would work; without -builtin I'm not so sure.

     
  • Olly Betts

    Olly Betts - 2022-08-04

    Looking at the SWIG manual they don't seem to describe SWIG_fail in a common place, but where target-language-specific docs describe what it's for they always seem to say things like (this particular quote is from Python.html):

    SWIG_fail is a C macro which when called within the context of SWIG wrapper function, will jump to the error handler code.

    I've added emphasis - my point here is that use in %extend isn't within such a context so SWIG_fail shouldn't be expected to work there.

    So how should one raise a target language exception from a %extend method?

    I suppose %extend effectively adds a method to the C++ class and then wraps it for SWIG, so this is best done in the same way you'd raise a target language exception from a method actually in the wrapped API - i.e. you throw a C++ exception from the %extend which is then caught using a %exception block which does SWIG_exception(SWIG_RuntimeError, "Msg"); SWIG_fail; or similar.

    I don't really see how else this could be solved without SWIG inlining the %extend code into the wrapper function, which seems likely to cause other problems (for example, clashes between variables in the wrapper function and those in the %extend function). Also SWIG.html currently explicitly notes:

    The only exception to this rule are methods defined with %extend. In this case, the added code is contained in a separate function.

    So I think the best resolution here is to explicitly clarify that SWIG_fail isn't for use in %extend. Really Typemaps.html ought to document SWIG_fail instead of leaving it to the target-language-specific docs - Typemaps.html already has many examples using it so that seems a good place to document it, and then we can add the note about %extend there.

     

Log in to post a comment.