Nick Ing-Simmons wrote:

>Steve Hay <[EMAIL PROTECTED]> writes:
>  
>
>>Revised version (attached) now passes the SV itself again.  Then I can 
>>check that mg->mg_obj == sv after using mg_find() to see if I've found 
>>the right MAGIC *.  Am I kidding myself here, or does that work OK?  
>>    
>>
>
>It will work, but adding SV as mg_obj is quite common.
>Only 100% fool proof scheme I can think of is to store the MAGIC *
>back into "your struct" - but then you don't need to use mg_find anyway ;-)
>
[...]

>>Not sure I like that since behaviour when namelen < 0 isn't documented.  
>>So I've added an I32 signature member to my struct and check that it has 
>>the correct value after retrieving the magic when it is being used later.
>>    
>>
>
>If you use the MAGIC * as the "signature" it can't fail ;-)
>
An excellent idea.

So attached is hopefully my final take.

Using sv_magic(), I've dropped the re-use of the SV in the 2nd arg since 
(a) I couldn't pull that trick if I actually wanted to use mg_obj for 
something else and (b) the subsequent mg_find() call is always 
_immediately_ after sv_magic() anyway so no other magic could have been 
added.  the MAGIC * is then stored within the struct itself.  Later on 
(and possibly in another part of the code, when mg_find() wouldn't be 
"safe"), the pointer stored with the struct is used to verify that the 
correct MAGIC * was found.

Using sv_magicext() is even easier since it returns the MAGIC * for us.

Thanks (once again!) for your help.

- Steve


------------------------------------------------
Radan Computational Ltd.

The information contained in this message and any files transmitted with it are 
confidential and intended for the addressee(s) only.  If you have received this 
message in error or there are any problems, please notify the sender immediately.  The 
unauthorized use, disclosure, copying or alteration of this message is strictly 
forbidden.  Note that any views or opinions presented in this email are solely those 
of the author and do not necessarily represent those of Radan Computational Ltd.  The 
recipient(s) of this message should check it and any attached files for viruses: Radan 
Computational will accept no liability for any damage caused by any virus transmitted 
by this email.
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"

typedef struct {
  MAGIC *mg;
  char *buf;
} Foo;

static Foo *FooAlloc(pTHX);
static void FooFree(pTHX_ Foo *foo);
static int MagicFooFree(pTHX_ SV *sv, MAGIC *mg);

static MGVTBL Foo_vtbl = {
  NULL,
  NULL,
  NULL,
  NULL,
  MagicFooFree
};

static Foo *FooAlloc(pTHX) {
  Foo *foo;
  Newz(0, foo, 1, Foo);
  Newz(0, foo->buf, 1024, char);
  strcpy(foo->buf, "Hello, world.");
  return foo;
}

static void FooFree(pTHX_ Foo *foo) {
  Safefree(foo->buf);
  Safefree(foo);
}

static int MagicFooFree(pTHX_ SV *sv, MAGIC *mg) {
  FooFree(aTHX_ (Foo *)mg->mg_ptr);
  return 1;
}

MODULE = Foo            PACKAGE = Foo           

void
magicfoo()
PPCODE:
{
  SV *sv;
  Foo *foo;
  MAGIC *mg;
  // Initialise
  foo = FooAlloc(aTHX);
  sv = NEWSV(0, 0);
  sv_magic(sv, NULL, PERL_MAGIC_ext, (char *)foo, 0);
  // This mg_find() can't fail since we're doing it straight away.
  if (!(mg = mg_find(sv, PERL_MAGIC_ext)))
    croak("Can't find new magic");
  foo->mg = mg;
  mg->mg_virtual = &Foo_vtbl;
  SvREADONLY_on(sv);
  // Use it.  This could be much later in another function, so we
  // need to check that mg_find() found the right magic.
  if (!(mg = mg_find(sv, PERL_MAGIC_ext)))
    croak("Can't find magic");
  if (!(foo = (Foo *)(mg->mg_ptr)))
    croak("Can't find magic pointer");
  if (foo->mg != mg)
    croak("Found wrong magic pointer");
  //printf("%s\n", foo->buf);
  // Clean up
  SvREFCNT_dec(sv);
}

void
magicextfoo()
PPCODE:
{
  SV *sv;
  Foo *foo;
  MAGIC *mg;
  // Initialise
  foo = FooAlloc(aTHX);
  sv = NEWSV(0, 0);
  if (!(mg = sv_magicext(sv, NULL, PERL_MAGIC_ext, &Foo_vtbl, (char *)foo, 0)))
    croak("Can't add magic");
  foo->mg = mg;
  SvREADONLY_on(sv);
  // Use it.  This could be much later in another function, so we
  // need to check that mg_find() found the right magic.
  if (!(mg = mg_find(sv, PERL_MAGIC_ext)))
    croak("Can't find magic");
  if (!(foo = (Foo *)(mg->mg_ptr)))
    croak("Can't find magic pointer");
  if (foo->mg != mg)
    croak("Found wrong magic pointer");
  //printf("%s\n", foo->buf);
  // Clean up
  SvREFCNT_dec(sv);
}

Reply via email to