Re: [perl #18872] File::Basename example misleading
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index cc6b5c3..0a15c74 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -1,6 +1,6 @@
 /*    pp.c
  *
- *    Copyright (c) 1991-2002, Larry Wall
+ *    Copyright (c) 1991-2003, Larry Wall
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -211,6 +211,7 @@ PP(pp_rv2gv)
 
 PP(pp_rv2sv)
 {
+    GV *gv = Nullgv;
     dSP; dTOPss;
 
     if (SvROK(sv)) {
@@ -226,9 +227,9 @@ PP(pp_rv2sv)
        }
     }
     else {
-       GV *gv = (GV*)sv;
        char *sym;
        STRLEN len;
+       gv = (GV*)sv;
 
        if (SvTYPE(gv) != SVt_PVGV) {
            if (SvGMAGICAL(sv)) {
@@ -265,8 +266,14 @@ PP(pp_rv2sv)
        sv = GvSV(gv);
     }
     if (PL_op->op_flags & OPf_MOD) {
-       if (PL_op->op_private & OPpLVAL_INTRO)
-           sv = save_scalar((GV*)TOPs);
+       if (PL_op->op_private & OPpLVAL_INTRO) {
+           if (cUNOP->op_first->op_type == OP_NULL)
+               sv = save_scalar((GV*)TOPs);
+           else if (gv)
+               sv = save_scalar(gv);
+           else
+               Perl_croak(aTHX_ PL_no_localize_ref);
+       }
        else if (PL_op->op_private & OPpDEREF)
            vivify_ref(sv, PL_op->op_private & OPpDEREF);
     }
@@ -2450,16 +2457,79 @@ PP(pp_i_divide)
     }
 }
 
+STATIC
+PP(pp_i_modulo_0)
+{
+     /* This is the vanilla old i_modulo. */
+     dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
+     {
+         dPOPTOPiirl;
+         if (!right)
+              DIE(aTHX_ "Illegal modulus zero");
+         SETi( left % right );
+         RETURN;
+     }
+}
+
+STATIC
+PP(pp_i_modulo_1)
+{
+#ifdef __GLIBC__
+     /* This is the i_modulo with the workaround for the _moddi3 bug
+      * in (at least) glibc 2.2.5 (the "right = -right" is the workaround).
+      * See below for pp_i_modulo. */
+     dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
+     {
+         dPOPTOPiirl;
+         if (!right)
+              DIE(aTHX_ "Illegal modulus zero");
+         if (right < 0)
+              right = -right;
+         SETi( left % right );
+         RETURN;
+     }
+#endif
+}
+
 PP(pp_i_modulo)
 {
-    dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
-    {
-      dPOPTOPiirl;
-      if (!right)
-       DIE(aTHX_ "Illegal modulus zero");
-      SETi( left % right );
-      RETURN;
-    }
+     dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
+     {
+         dPOPTOPiirl;
+         if (!right)
+              DIE(aTHX_ "Illegal modulus zero");
+         /* The assumption is to use hereafter the old vanilla version... */
+         PL_op->op_ppaddr =
+              PL_ppaddr[OP_I_MODULO] =
+                  &Perl_pp_i_modulo_0;
+         /* .. but if we have glibc, we might have a buggy _moddi3
+          * (at least glicb 2.2.5 is known to have this bug), in other
+          * words our integer modulus with negative quad as the second
+          * argument might be broken.  Test for this and re-patch the
+          * opcode dispatch table if that is the case, remembering to
+          * also apply the workaround so that this first round works
+          * right, too.  See [perl #9402] for more information. */
+#if defined(__GLIBC__) && IVSIZE == 8
+         {
+              IV l =   3;
+              IV r = -10;
+              /* Cannot do this check with inlined IV constants since
+               * that seems to work correctly even with the buggy glibc. */
+              if (l % r == -3) {
+                   /* Yikes, we have the bug.
+                    * Patch in the workaround version. */
+                   PL_op->op_ppaddr =
+                        PL_ppaddr[OP_I_MODULO] =
+                            &Perl_pp_i_modulo_1;
+                   /* Make certain we work right this time, too. */
+                   if (right < 0)
+                        right = -right;
+              }
+         }
+#endif
+         SETi( left % right );
+         RETURN;
+     }
 }
 
 PP(pp_i_add)
@@ -4625,6 +4695,7 @@ PP(pp_split)
                }
            }
            s = rx->endp[0] + orig;
+           PUTBACK;
        }
     }