I'm wondering if someone else ever wanted to do this...

Deep inside my XS module I create an object and pass it to
a function (which may pass it to other functions and so on).
However, any of these functions may call Perl_croak(), and
if they do, I need to destroy the object if I don't want to
leak memory. Here's an excerpt of the original code:

  tag = tag_new(tagid, gs_TagTbl[tagid].vtbl);
  rv = gs_TagTbl[tagid].set(aTHX_ ptti, tag, val);
  insert_tag(ptl, tag);

Calling the 'set' method in the second line may eventually
call croak(). If it does, I just want to throw away the tag
object and croak() again.

I didn't find anything in perl(xs|guts|call|api), so I looked
at how "eval" does it, and came up with the following macros:

  #define dXCPT             dJMPENV; int rEtV = 0
  
  #define XCPT_TRY_START    JMPENV_PUSH(rEtV); \
                            if (rEtV == 0)
  
  #define XCPT_TRY_END      JMPENV_POP;
  
  #define XCPT_CATCH        if (rEtV != 0)
  
  #define XCPT_RETHROW      JMPENV_JUMP(rEtV)

With these macros, I can rewrite the above code as:

  dXCPT;

  tag = tag_new(tagid, gs_TagTbl[tagid].vtbl);

  XCPT_TRY_START {
    rv = gs_TagTbl[tagid].set(aTHX_ ptti, tag, val);
  } XCPT_TRY_END

  XCPT_CATCH
  {
    tag_delete(tag);
    XCPT_RETHROW;
  }

  insert_tag(ptl, tag);

This seems to work fine, but makes use of internal API.

Is this the way to do it?
Or is there any other/better way?

If it turns out to be correct, would it make sense to document
it and/or add some public interface for this purpose?

Marcus

-- 
Bender: "Like most of life's problems, this one can be solved with bending." 

Reply via email to