in reply to Re^4: Puzzled by value of $overload::ops{binary}
in thread Puzzled by value of $overload::ops{binary}

.... so I'll have another crack at it tomorrow ....

In GMPz.xs, in the bottom section of the file I have replaced:
SV * overload_add_eq (a, b, third) SV * a SV * b SV * third CODE: RETVAL = overload_add_eq (aTHX_ a, b, third); OUTPUT: RETVAL
with
void overload_add_eq (a, b, third) SV * a SV * b SV * third CODE: overload_add_eq (aTHX_ a, b, third); XSRETURN_EMPTY; /* return empty stack */
And in the top section of the file I have replaced:
SV * overload_add_eq(pTHX_ SV * a, SV * b, SV * third) { /* lengthy code snipped */ }
with
void overload_add_eq(pTHX_ SV * a, SV * b, SV * third) { PERL_UNUSED_ARG(third); /* UPDATE: This line can be removed as ir +relevant */ mpz_add_ui(*(INT2PTR(mpz_t *, SvIVX(SvRV(a)))), *(INT2PTR(mpz_t * +, SvIVX(SvRV(a)))), SvUV(b)); }
This means that we're always adding SvUV(b) to a, irrrespective of what b actually is.
This is good enough for demonstration purposes if we make sure that the second arg (b) is an IV, but we probably don't want to run make test.

On Windows 11, perl-5.38.0, I then run perl Makefile.PL, followed by make.
The build emits no warnings.
Then:
> perl -Mblib -MMath::GMPz -MDevel::Peek -wle "$x = Math::GMPz->new(12 +34); $x++;print $x; $x += 15; print $x; Dump($x);" 1235 Use of uninitialized value $x in print at -e line 1. SV = PVIV(0x1abd93865e0) at 0x1abdad3ae48 REFCNT = 1 FLAGS = () IV = 1837594613288 PV = 0
As you can see from that, the Math::GMPz object ($x) has been well and truly clobbered by the '+=' overloading.
Anyone interested can try this out by making the above alterations to GMPz.xs in https://cpan.metacpan.org/authors/id/S/SI/SISYPHUS/Math-GMPz-0.61.tar.gz.
Thoughts, observations, opinions and revelations are all most welcome.

UPDATE: I see the same behaviour on Cygwin, and also on Ubuntu-22.04.4-LTS.

UPDATE 2: I'll also point out that this altered version of overload_add_eq() works as expected when called as a function:
> perl -Mblib -MMath::GMPz -MDevel::Peek -wle "$x = Math::GMPz->new(12 +34); $x++; print $x; Math::GMPz::overload_add_eq($x, 15, 0); print $x +;" 1235 1250
UPDATE 3: Also, if I remove the '+=' overloading (by commenting out the appropriate line in GMPz.pm), then the '+=' overloading (which then uses the '+' overloading) works fine:
> perl -Mblib -MMath::GMPz -MDevel::Peek -wle "$x = Math::GMPz->new(12 +34); $x++;print $x; $x += 15; print $x; Dump($x);" 1235 1250 SV = IV(0x2bfffa61b78) at 0x2bfffa61b88 REFCNT = 1 FLAGS = (ROK) RV = 0x2bfff38aac8 SV = PVMG(0x2bfffa24a58) at 0x2bfff38aac8 REFCNT = 1 FLAGS = (OBJECT,IOK,READONLY,pIOK) IV = 3023652457216 NV = 0 PV = 0 STASH = 0x2bfffa5e5e8 "Math::GMPz"
Cheers,
Rob

Replies are listed 'Best First'.
Re^6: Puzzled by value of $overload::ops{binary}
by etj (Priest) on Jun 26, 2024 at 11:35 UTC
    I'd add some debugging checks in overload_add_eq to see what state the SVs are in when they arrive in it. Also, as a matter of good practice, I would keep all the SV-mangling stuff in the XS function, and just pass to your C function the mpz_t (or a pointer) values. If that meant the C functions you've shown here go away, then so be it.
      I keep looking at this piece of overload.pm documentation:
      * *Assignments* += -= *= /= %= **= <<= >>= x= .= &= |= ^= &.= |.= ^.= [snip] The subroutine for the assignment variant of an operator is required only to return the result of the operation.
      That seems to me to be asserting that these operations (unlike '++' and '--') do require a value to be returned.
      And it also looks to me that overload.pm is somehow enforcing that policy.

      This following rewrite of the simplified overload_add_eq C and XS functions works fine:
      void overload_add_eq(pTHX_ SV * a, SV * b, SV * third) { dXSARGS; PERL_UNUSED_ARG(third); mpz_add_ui(*(INT2PTR(mpz_t *, SvIVX(SvRV(a)))), *(INT2PTR(mpz_t * +, SvIVX(SvRV(a)))), SvUV(b)); XSRETURN(1); }
      and
      void overload_add_eq (a, b, third) SV * a SV * b SV * third CODE: overload_add_eq (aTHX_ a, b, third); XSRETURN(1);
      But I wonder if that achieves anything significant over the implementation that has been working fine for the last umpteen years.

      Anyway, I don't want to get too bogged down in this - though it's certainly interesting enough to encourage a bit more investigation.

      Cheers,
      Rob
        It definitely doesn't look right that you're doing
        dXSARGS; /* ... */ XSRETURN(1);
        in your alleged C function, which should either mutate things and let the XS function do all the Perl stack stuff, or return a value but strictly in C-land.