Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Argument "123abc" treated as 0 in increment is actually treated as 123 #13788

Closed
p5pRT opened this issue Apr 30, 2014 · 13 comments
Closed

Argument "123abc" treated as 0 in increment is actually treated as 123 #13788

p5pRT opened this issue Apr 30, 2014 · 13 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 30, 2014

Migrated from rt.perl.org#121771 (status was 'resolved')

Searchable as RT121771$

@p5pRT
Copy link
Author

p5pRT commented Apr 30, 2014

From @ilmari

Created by @ilmari

When the argument to ++ starts with a number, but contains trailing
crap, the warning is wrong, since the value is actually treated as the
leading numerical part.

$ perl -wE 'my $x = "123abc"; $x++; say $x'
Argument "123abc" treated as 0 in increment (++) at -e line 1.
124

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl 5.19.9:

Configured by ilmari at Fri Feb 21 14:38:49 GMT 2014.

Summary of my perl5 (revision 5 version 19 subversion 9) configuration:
   
  Platform:
    osname=linux, osvers=3.2.0-58-generic, archname=x86_64-linux
    uname='linux zarquon 3.2.0-58-generic #88-ubuntu smp tue dec 3 17:37:58 utc 2013 x86_64 x86_64 x86_64 gnulinux '
    config_args='-de -Dprefix=/home/ilmari/perl5/perlbrew/perls/19.9 -Dman1dir=none -Dman3dir=none -Dcc=ccache cc -Dusedevel -Aeval:scriptdir=/home/ilmari/perl5/perlbrew/perls/19.9/bin'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='ccache cc', ccflags ='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2',
    cppflags='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.6.3', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='ccache cc', ldflags =' -fstack-protector -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed /usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib
    libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
    libc=, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.15'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector'



@INC for perl 5.19.9:
    /home/ilmari/.perlbrew/libs/19.9@std/lib/perl5/x86_64-linux
    /home/ilmari/.perlbrew/libs/19.9@std/lib/perl5
    /home/ilmari/perl5/perlbrew/perls/19.9/lib/site_perl/5.19.9/x86_64-linux
    /home/ilmari/perl5/perlbrew/perls/19.9/lib/site_perl/5.19.9
    /home/ilmari/perl5/perlbrew/perls/19.9/lib/5.19.9/x86_64-linux
    /home/ilmari/perl5/perlbrew/perls/19.9/lib/5.19.9
    .


Environment for perl 5.19.9:
    HOME=/home/ilmari
    LANG=en_GB.UTF-8
    LANGUAGE=en_GB:en
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/ilmari/.perlbrew/libs/19.9@std/bin:/home/ilmari/perl5/perlbrew/bin:/home/ilmari/perl5/perlbrew/perls/19.9/bin:/home/ilmari/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
    PERL5LIB=/home/ilmari/.perlbrew/libs/19.9@std/lib/perl5
    PERLBREW_BASHRC_VERSION=0.64
    PERLBREW_HOME=/home/ilmari/.perlbrew
    PERLBREW_LIB=std
    PERLBREW_MANPATH=/home/ilmari/.perlbrew/libs/19.9@std/man:/home/ilmari/perl5/perlbrew/perls/19.9/man
    PERLBREW_PATH=/home/ilmari/.perlbrew/libs/19.9@std/bin:/home/ilmari/perl5/perlbrew/bin:/home/ilmari/perl5/perlbrew/perls/19.9/bin
    PERLBREW_PERL=19.9
    PERLBREW_ROOT=/home/ilmari/perl5/perlbrew
    PERLBREW_VERSION=0.64
    PERL_BADLANG (unset)
    PERL_LOCAL_LIB_ROOT=/home/ilmari/.perlbrew/libs/19.9@std
    PERL_MB_OPT=--install_base /home/ilmari/.perlbrew/libs/19.9@std
    PERL_MM_OPT=INSTALL_BASE=/home/ilmari/.perlbrew/libs/19.9@std
    SHELL=/bin/bash

-- 
"I use RMS as a guide in the same way that a boat captain would use
 a lighthouse.  It's good to know where it is, but you generally
 don't want to find yourself in the same spot." - Tollef Fog Heen

@p5pRT
Copy link
Author

p5pRT commented Apr 30, 2014

From @iabyn

On Wed, Apr 30, 2014 at 06​:55​:09AM -0700, Dagfinn Ilmari Mannsåker wrote​:

When the argument to ++ starts with a number, but contains trailing
crap, the warning is wrong, since the value is actually treated as the
leading numerical part.

$ perl -wE 'my $x = "123abc"; $x++; say $x'
Argument "123abc" treated as 0 in increment (++) at -e line 1.
124

Bisects to this​:

commit 8140a7a
Author​: Tony Cook <tony@​develop-help.com>
Date​: Mon Aug 12 12​:02​:51 2013 +1000

  [perl #3330] warn on increment of an non number/non-magically incable value

--
In economics, the exam questions are the same every year.
They just change the answers.

@p5pRT
Copy link
Author

p5pRT commented Apr 30, 2014

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented May 1, 2014

From @tonycoz

On Wed Apr 30 09​:26​:37 2014, davem wrote​:

On Wed, Apr 30, 2014 at 06​:55​:09AM -0700, Dagfinn Ilmari Mannsåker
wrote​:

When the argument to ++ starts with a number, but contains trailing
crap, the warning is wrong, since the value is actually treated as
the
leading numerical part.

$ perl -wE 'my $x = "123abc"; $x++; say $x'
Argument "123abc" treated as 0 in increment (++) at -e line 1.
124

Bisects to this​:

commit 8140a7a
Author​: Tony Cook <tony@​develop-help.com>
Date​: Mon Aug 12 12​:02​:51 2013 +1000

[perl #3330] warn on increment of an non number/non-magically incable
value

I think the simplest solution would be to rename grok_number() to grok_number_flags() with a PERL_SCAN_TRAILING which allows for trailing trash.

Patch attached, along with some extra tests for grok_number().

Alternatively we could just revert the offending commit, since it's not a critical change.

Tony

@p5pRT
Copy link
Author

p5pRT commented May 1, 2014

From @tonycoz

0001-perl-121771-warn-correctly-about-on-123abc.patch
From 665d8b701105a26728f6ada939e6c2499a03d6fd Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Thu, 1 May 2014 15:36:52 +1000
Subject: [perl #121771] warn correctly about ++ on "123abc"

---
 embed.fnc         |    1 +
 embed.h           |    1 +
 numeric.c         |   35 +++++++++++++++++++++++++++++------
 perl.h            |    4 ++++
 proto.h           |    5 +++++
 sv.c              |    2 +-
 t/lib/warnings/sv |    4 ++++
 7 files changed, 45 insertions(+), 7 deletions(-)

diff --git a/embed.fnc b/embed.fnc
index 567e587..70fc84e 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -785,6 +785,7 @@ EMsPR	|char*|form_short_octal_warning|NN const char * const s  \
 #endif
 Apd	|UV	|grok_hex	|NN const char* start|NN STRLEN* len_p|NN I32* flags|NULLOK NV *result
 Apd	|int	|grok_number	|NN const char *pv|STRLEN len|NULLOK UV *valuep
+Apd	|int	|grok_number_flags|NN const char *pv|STRLEN len|NULLOK UV *valuep|U32 flags
 ApdR	|bool	|grok_numeric_radix|NN const char **sp|NN const char *send
 Apd	|UV	|grok_oct	|NN const char* start|NN STRLEN* len_p|NN I32* flags|NULLOK NV *result
 : These are all indirectly referenced by globals.c. This is somewhat annoying.
diff --git a/embed.h b/embed.h
index 0ddaca7..20d6581 100644
--- a/embed.h
+++ b/embed.h
@@ -171,6 +171,7 @@
 #define grok_bin(a,b,c,d)	Perl_grok_bin(aTHX_ a,b,c,d)
 #define grok_hex(a,b,c,d)	Perl_grok_hex(aTHX_ a,b,c,d)
 #define grok_number(a,b,c)	Perl_grok_number(aTHX_ a,b,c)
+#define grok_number_flags(a,b,c,d)	Perl_grok_number_flags(aTHX_ a,b,c,d)
 #define grok_numeric_radix(a,b)	Perl_grok_numeric_radix(aTHX_ a,b)
 #define grok_oct(a,b,c,d)	Perl_grok_oct(aTHX_ a,b,c,d)
 #define gv_add_by_type(a,b)	Perl_gv_add_by_type(aTHX_ a,b)
diff --git a/numeric.c b/numeric.c
index d431728..e4a750d 100644
--- a/numeric.c
+++ b/numeric.c
@@ -550,7 +550,7 @@ Perl_grok_numeric_radix(pTHX_ const char **sp, const char *send)
 }
 
 /*
-=for apidoc grok_number
+=for apidoc grok_number_flags
 
 Recognise (or not) a number.  The type of the number is returned
 (0 if unrecognised), otherwise it is a bit-ORed combination of
@@ -570,11 +570,27 @@ IS_NUMBER_NEG if the number is negative (in which case *valuep holds the
 absolute value).  IS_NUMBER_IN_UV is not set if e notation was used or the
 number is larger than a UV.
 
+C<flags> allows only C<PERL_SCAN_TRAILING>, which allows for trailing
+non-numeric text on an otherwise successful I<grok>, setting
+C<IS_NUMBER_TRAILING> on the result.
+
+=for apidoc grok_number
+
+Identical to grok_number_flags() with flags set to zero.
+
 =cut
  */
 int
 Perl_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
 {
+    PERL_ARGS_ASSERT_GROK_NUMBER;
+
+    return grok_number_flags(pv, len, valuep, 0);
+}
+
+int
+Perl_grok_number_flags(pTHX_ const char *pv, STRLEN len, UV *valuep, U32 flags)
+{
   const char *s = pv;
   const char * const send = pv + len;
   const UV max_div_10 = UV_MAX / 10;
@@ -583,7 +599,7 @@ Perl_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
   int sawinf = 0;
   int sawnan = 0;
 
-  PERL_ARGS_ASSERT_GROK_NUMBER;
+  PERL_ARGS_ASSERT_GROK_NUMBER_FLAGS;
 
   while (s < send && isSPACE(*s))
     s++;
@@ -738,9 +754,6 @@ Perl_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
   } else if (s < send) {
     /* we can have an optional exponent part */
     if (*s == 'e' || *s == 'E') {
-      /* The only flag we keep is sign.  Blow away any "it's UV"  */
-      numtype &= IS_NUMBER_NEG;
-      numtype |= IS_NUMBER_NOT_INT;
       s++;
       if (s < send && (*s == '-' || *s == '+'))
         s++;
@@ -749,8 +762,14 @@ Perl_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
           s++;
         } while (s < send && isDIGIT(*s));
       }
+      else if (flags & PERL_SCAN_TRAILING)
+        return numtype | IS_NUMBER_TRAILING;
       else
-      return 0;
+        return 0;
+
+      /* The only flag we keep is sign.  Blow away any "it's UV"  */
+      numtype &= IS_NUMBER_NEG;
+      numtype |= IS_NUMBER_NOT_INT;
     }
   }
   while (s < send && isSPACE(*s))
@@ -762,6 +781,10 @@ Perl_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
       *valuep = 0;
     return IS_NUMBER_IN_UV;
   }
+  else if (flags & PERL_SCAN_TRAILING) {
+    return numtype | IS_NUMBER_TRAILING;
+  }
+
   return 0;
 }
 
diff --git a/perl.h b/perl.h
index 6da39f3..f08fc70 100644
--- a/perl.h
+++ b/perl.h
@@ -5671,6 +5671,7 @@ int flock(int fd, int op);
 #define IS_NUMBER_NEG		      0x08 /* leading minus sign */
 #define IS_NUMBER_INFINITY	      0x10 /* this is big */
 #define IS_NUMBER_NAN                 0x20 /* this is not */
+#define IS_NUMBER_TRAILING            0x40 /* number has trailing trash */
 
 #define GROK_NUMERIC_RADIX(sp, send) grok_numeric_radix(sp, send)
 
@@ -5680,6 +5681,9 @@ int flock(int fd, int op);
 #define PERL_SCAN_SILENT_ILLDIGIT     0x04 /* grok_??? not warn about illegal digits */
 #define PERL_SCAN_SILENT_NON_PORTABLE 0x08 /* grok_??? not warn about very large
 					      numbers which are <= UV_MAX */
+#define PERL_SCAN_TRAILING            0x10 /* grok_number_flags() allow trailing
+                                              and set IS_NUMBER_TRAILING */
+
 /* Output flags: */
 #define PERL_SCAN_GREATER_THAN_UV_MAX 0x02 /* should this merge with above? */
 
diff --git a/proto.h b/proto.h
index dd5edde..e55ba7a 100644
--- a/proto.h
+++ b/proto.h
@@ -1284,6 +1284,11 @@ PERL_CALLCONV int	Perl_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
 #define PERL_ARGS_ASSERT_GROK_NUMBER	\
 	assert(pv)
 
+PERL_CALLCONV int	Perl_grok_number_flags(pTHX_ const char *pv, STRLEN len, UV *valuep, U32 flags)
+			__attribute__nonnull__(pTHX_1);
+#define PERL_ARGS_ASSERT_GROK_NUMBER_FLAGS	\
+	assert(pv)
+
 PERL_CALLCONV bool	Perl_grok_numeric_radix(pTHX_ const char **sp, const char *send)
 			__attribute__warn_unused_result__
 			__attribute__nonnull__(pTHX_1)
diff --git a/sv.c b/sv.c
index 85f91f1..8cb4bab 100644
--- a/sv.c
+++ b/sv.c
@@ -8446,7 +8446,7 @@ Perl_sv_inc_nomg(pTHX_ SV *const sv)
     while (isALPHA(*d)) d++;
     while (isDIGIT(*d)) d++;
     if (d < SvEND(sv)) {
-	const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), NULL);
+	const int numtype = grok_number_flags(SvPVX_const(sv), SvCUR(sv), NULL, PERL_SCAN_TRAILING);
 #ifdef PERL_PRESERVE_IVUV
 	/* Got to punt this as an integer if needs be, but we don't issue
 	   warnings. Probably ought to make the sv_iv_please() that does
diff --git a/t/lib/warnings/sv b/t/lib/warnings/sv
index 87bc368..f09a97c 100644
--- a/t/lib/warnings/sv
+++ b/t/lib/warnings/sv
@@ -404,6 +404,8 @@ my $x = "a_c";
 use warnings "numeric";
 $x = "a_c"; ++$x;
 $x = ${ qr/abc/ }; ++$x;
+$x = "123x"; ++$x;
+$x = "123e"; ++$x;
 $x = 0; ++$x; # none of these should warn
 $x = "ABC"; ++$x;
 $x = "ABC123"; ++$x;
@@ -411,3 +413,5 @@ $x = " +10"; ++$x;
 EXPECT
 Argument "a_c" treated as 0 in increment (++) at - line 5.
 Argument "(?^:abc)" treated as 0 in increment (++) at - line 6.
+Argument "123x" isn't numeric in preincrement (++) at - line 7.
+Argument "123e" isn't numeric in preincrement (++) at - line 8.
-- 
1.7.10.4

@p5pRT
Copy link
Author

p5pRT commented May 1, 2014

From @tonycoz

0002-extra-tests-for-grok_number-_flags.patch
From f1595057a14b19b6e993d61e60ae9c90dfd4e36e Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Thu, 1 May 2014 15:37:08 +1000
Subject: extra tests for grok_number(_flags)()

---
 ext/XS-APItest/APItest.pm  |    2 +-
 ext/XS-APItest/Makefile.PL |    2 +-
 ext/XS-APItest/numeric.xs  |   16 ++++++++++++++++
 ext/XS-APItest/t/grok.t    |   35 +++++++++++++++++++++++++++++++++++
 4 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/ext/XS-APItest/APItest.pm b/ext/XS-APItest/APItest.pm
index 8c72b35..e17e263 100644
--- a/ext/XS-APItest/APItest.pm
+++ b/ext/XS-APItest/APItest.pm
@@ -5,7 +5,7 @@ use strict;
 use warnings;
 use Carp;
 
-our $VERSION = '0.60';
+our $VERSION = '0.61';
 
 require XSLoader;
 
diff --git a/ext/XS-APItest/Makefile.PL b/ext/XS-APItest/Makefile.PL
index 031ce8a..173e5c9 100644
--- a/ext/XS-APItest/Makefile.PL
+++ b/ext/XS-APItest/Makefile.PL
@@ -24,7 +24,7 @@ my @names = (qw(HV_DELETE HV_DISABLE_UVAR_XKEY HV_FETCH_ISSTORE
 		G_KEEPERR G_NODEBUG G_METHOD G_FAKINGEVAL
 		IS_NUMBER_IN_UV IS_NUMBER_GREATER_THAN_UV_MAX
 		IS_NUMBER_NOT_INT IS_NUMBER_NEG IS_NUMBER_INFINITY
-		IS_NUMBER_NAN
+		IS_NUMBER_NAN IS_NUMBER_TRAILING PERL_SCAN_TRAILING
 		),
 	     {name=>"G_WANT", default=>["IV", "G_ARRAY|G_VOID"]});
 
diff --git a/ext/XS-APItest/numeric.xs b/ext/XS-APItest/numeric.xs
index b06258d..ab48dba 100644
--- a/ext/XS-APItest/numeric.xs
+++ b/ext/XS-APItest/numeric.xs
@@ -14,3 +14,19 @@ grok_number(number)
 	PUSHs(sv_2mortal(newSViv(result)));
 	if (result & IS_NUMBER_IN_UV)
 	    PUSHs(sv_2mortal(newSVuv(value)));
+
+void
+grok_number_flags(number, flags)
+	SV *number
+	U32 flags
+    PREINIT:
+	STRLEN len;
+	const char *pv = SvPV(number, len);
+	UV value;
+	int result;
+    PPCODE:
+	EXTEND(SP,2);
+	result = grok_number_flags(pv, len, &value, flags);
+	PUSHs(sv_2mortal(newSViv(result)));
+	if (result & IS_NUMBER_IN_UV)
+	    PUSHs(sv_2mortal(newSVuv(value)));
diff --git a/ext/XS-APItest/t/grok.t b/ext/XS-APItest/t/grok.t
index 99fbc5d..2e035ee 100644
--- a/ext/XS-APItest/t/grok.t
+++ b/ext/XS-APItest/t/grok.t
@@ -74,4 +74,39 @@ foreach my $leader ('', ' ', '  ') {
     }
 }
 
+# format tests
+my @groks =
+  (
+   # input, in flags, out uv, out flags
+   [ "1",    0,                  1,     IS_NUMBER_IN_UV ],
+   [ "1x",   0,                  undef, 0 ],
+   [ "1x",   PERL_SCAN_TRAILING, 1,     IS_NUMBER_IN_UV | IS_NUMBER_TRAILING ],
+   [ "3.1",  0,                  3,     IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT ],
+   [ "3.1a", 0,                  undef, 0 ],
+   [ "3.1a", PERL_SCAN_TRAILING, 3,
+     IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT | IS_NUMBER_TRAILING ],
+   [ "3e5",  0,                  undef, IS_NUMBER_NOT_INT ],
+   [ "3e",   0,                  undef, 0 ],
+   [ "3e",   PERL_SCAN_TRAILING, 3,     IS_NUMBER_IN_UV | IS_NUMBER_TRAILING ],
+   [ "3e+",  0,                  undef, 0 ],
+   [ "3e+",  PERL_SCAN_TRAILING, 3,     IS_NUMBER_IN_UV | IS_NUMBER_TRAILING ],
+   [ "Inf",  0,                  undef,
+     IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT ],
+   [ "In",   0,                  undef, 0 ],
+   [ "Infin",0,                  undef, 0 ],
+   # this doesn't work and hasn't been needed yet
+   #[ "Infin",PERL_SCAN_TRAILING, undef,
+   #  IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT | IS_NUMBER_TRAILING ],
+   [ "nan",  0,                  undef, IS_NUMBER_NAN | IS_NUMBER_NOT_INT ],
+   [ "nanx", 0,                  undef, 0 ],
+   [ "nanx", PERL_SCAN_TRAILING, undef,
+     IS_NUMBER_NAN | IS_NUMBER_NOT_INT | IS_NUMBER_TRAILING],
+  );
+
+for my $grok (@groks) {
+  my ($out_flags, $out_uv) = grok_number_flags($grok->[0], $grok->[1]);
+  is($out_uv,    $grok->[2], "'$grok->[0]' flags $grok->[1] - check number");
+  is($out_flags, $grok->[3], "'$grok->[0]' flags $grok->[1] - check flags");
+}
+
 done_testing();
-- 
1.7.10.4

@p5pRT
Copy link
Author

p5pRT commented May 1, 2014

From @nwc10

On Wed, Apr 30, 2014 at 10​:46​:23PM -0700, Tony Cook via RT wrote​:

On Wed Apr 30 09​:26​:37 2014, davem wrote​:

On Wed, Apr 30, 2014 at 06​:55​:09AM -0700, Dagfinn Ilmari Mannsåker
wrote​:

When the argument to ++ starts with a number, but contains trailing
crap, the warning is wrong, since the value is actually treated as
the
leading numerical part.

$ perl -wE 'my $x = "123abc"; $x++; say $x'
Argument "123abc" treated as 0 in increment (++) at -e line 1.
124

Bisects to this​:

commit 8140a7a
Author​: Tony Cook <tony@​develop-help.com>
Date​: Mon Aug 12 12​:02​:51 2013 +1000

[perl #3330] warn on increment of an non number/non-magically incable
value

I think the simplest solution would be to rename grok_number() to grok_number_flags() with a PERL_SCAN_TRAILING which allows for trailing trash.

Patch attached, along with some extra tests for grok_number().

Alternatively we could just revert the offending commit, since it's not a critical change.

I think revert the guilty commit for now, and re-instate it with more
tests for the corner cases in v5.21.0.

Partly because we might find another bug, and partly because it seems a bit
tight adding new visible functions this close to a release​:

diff --git a/embed.fnc b/embed.fnc
index 567e587..70fc84e 100644
--- a/embed.fnc
+++ b/embed.fnc
@​@​ -785,6 +785,7 @​@​ EMsPR |char*|form_short_octal_warning|NN const char * const s \
#endif
Apd |UV |grok_hex |NN const char* start|NN STRLEN* len_p|NN I32* flags|NULLOK NV *result
Apd |int |grok_number |NN const char *pv|STRLEN len|NULLOK UV *valuep
+Apd |int |grok_number_flags|NN const char *pv|STRLEN len|NULLOK UV *valuep|U32 flags
ApdR |bool |grok_numeric_radix|NN const char **sp|NN const char *send
Apd |UV |grok_oct |NN const char* start|NN STRLEN* len_p|NN I32* flags|NULLOK NV *result
: These are all indirectly referenced by globals.c. This is somewhat annoying.

Nicholas Clark

@p5pRT
Copy link
Author

p5pRT commented May 1, 2014

From @epa

Wouldn't the least invasive fix immediately before a release be to leave the
code alone but change the error string? It could just say 'Argument "123abc"
treated as numeric in increment', without being drawn on what the numeric
value is.

--
Ed Avis <eda@​waniasset.com>

@p5pRT
Copy link
Author

p5pRT commented May 5, 2014

From @tonycoz

On Wed Apr 30 23​:51​:10 2014, nicholas wrote​:

On Wed, Apr 30, 2014 at 10​:46​:23PM -0700, Tony Cook via RT wrote​:

Patch attached, along with some extra tests for grok_number().

Alternatively we could just revert the offending commit, since it's
not a critical change.

I think revert the guilty commit for now, and re-instate it with more
tests for the corner cases in v5.21.0.

Partly because we might find another bug, and partly because it seems
a bit
tight adding new visible functions this close to a release​:

Reverting was my initial inclination.

Attached, a patch to do the revert.

Tony

@p5pRT
Copy link
Author

p5pRT commented May 5, 2014

From @tonycoz

0001-perl-121771-Revert-the-new-warning-for-on-non-A-a-zA.patch
From 4c1186ae1ccd18d04fd3028725fe4a2196803af3 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Mon, 5 May 2014 11:58:56 +1000
Subject: [perl #121771] Revert the new warning for ++ on non-
 /\A[a-zA-Z]+[0-9]*\z/

This failed as in it was producing:

  Argument "123abc" treated as 0 in increment (++) at -e line 1.

when the user incremented that value (which is a lie).

This reverts commits 8140a7a801e37d147db0e5a8d89551d9d77666e0 and
2cd5095e471e1d84dc9e0b79900ebfd66aabc909.

I expect to revert this commit, and add fixes, after 5.20 is released.

Conflicts:
	pod/perldiag.pod
---
 embed.fnc         |    2 --
 embed.h           |    2 --
 lib/diagnostics.t |    3 +++
 pod/perldiag.pod  |    7 -------
 proto.h           |   11 ----------
 sv.c              |   58 ++++++++++++-----------------------------------------
 t/lib/warnings/sv |   14 -------------
 t/op/inc.t        |    9 +++------
 8 files changed, 19 insertions(+), 87 deletions(-)

diff --git a/embed.fnc b/embed.fnc
index 567e587..1545bd2 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -2245,9 +2245,7 @@ pX	|void	|sv_del_backref	|NN SV *const tsv|NN SV *const sv
 #if defined(PERL_IN_SV_C)
 nsR	|char *	|uiv_2buf	|NN char *const buf|const IV iv|UV uv|const int is_uv|NN char **const peob
 i	|void	|sv_unglob	|NN SV *const sv|U32 flags
-s	|const char *|sv_display	|NN SV *const sv|NN char *tmpbuf|STRLEN tmpbuf_size
 s	|void	|not_a_number	|NN SV *const sv
-s	|void	|not_incrementable	|NN SV *const sv
 s	|I32	|visit		|NN SVFUNC_t f|const U32 flags|const U32 mask
 #  ifdef DEBUGGING
 s	|void	|del_sv	|NN SV *p
diff --git a/embed.h b/embed.h
index 0ddaca7..d4b1752 100644
--- a/embed.h
+++ b/embed.h
@@ -1612,11 +1612,9 @@
 #define glob_assign_ref(a,b)	S_glob_assign_ref(aTHX_ a,b)
 #define more_sv()		S_more_sv(aTHX)
 #define not_a_number(a)		S_not_a_number(aTHX_ a)
-#define not_incrementable(a)	S_not_incrementable(aTHX_ a)
 #define ptr_table_find		S_ptr_table_find
 #define sv_2iuv_common(a)	S_sv_2iuv_common(aTHX_ a)
 #define sv_add_arena(a,b,c)	S_sv_add_arena(aTHX_ a,b,c)
-#define sv_display(a,b,c)	S_sv_display(aTHX_ a,b,c)
 #define sv_pos_b2u_midway(a,b,c,d)	S_sv_pos_b2u_midway(aTHX_ a,b,c,d)
 #define sv_pos_u2b_cached(a,b,c,d,e,f,g)	S_sv_pos_u2b_cached(aTHX_ a,b,c,d,e,f,g)
 #define sv_pos_u2b_forwards	S_sv_pos_u2b_forwards
diff --git a/lib/diagnostics.t b/lib/diagnostics.t
index 367424e..8868eda 100644
--- a/lib/diagnostics.t
+++ b/lib/diagnostics.t
@@ -134,12 +134,15 @@ like $warning,
     'spaces in warnings with periods at the end are matched lightly';
 
 # Wrapped links
+SKIP: {
+skip("We no longer have any multi-line links", 1);
 seek STDERR, 0,0;
 $warning = '';
 warn "Argument \"%s\" treated as 0 in increment (++)";
 like $warning,
     qr/Auto-increment.*Auto-decrement/s,
     'multiline links are not truncated';
+}
 
 {
 # Find last warning in perldiag.pod, and last items if any
diff --git a/pod/perldiag.pod b/pod/perldiag.pod
index bca95e2..f87ca9c 100644
--- a/pod/perldiag.pod
+++ b/pod/perldiag.pod
@@ -186,13 +186,6 @@ point and did not attempt to push this layer.  If your program
 didn't explicitly request the failing operation, it may be the
 result of the value of the environment variable PERLIO.
 
-=item Argument "%s" treated as 0 in increment (++)
-
-(W numeric) The indicated string was fed as an argument to the C<++>
-operator which expects either a number or a string matching
-C</^[a-zA-Z]*[0-9]*\z/>.  See L<perlop/Auto-increment and
-Auto-decrement> for details.
-
 =item Array @%s missing the @ in argument %d of %s()
 
 (D deprecated) Really old Perl let you omit the @ on array names in some
diff --git a/proto.h b/proto.h
index dd5edde..a553202 100644
--- a/proto.h
+++ b/proto.h
@@ -7345,11 +7345,6 @@ STATIC void	S_not_a_number(pTHX_ SV *const sv)
 #define PERL_ARGS_ASSERT_NOT_A_NUMBER	\
 	assert(sv)
 
-STATIC void	S_not_incrementable(pTHX_ SV *const sv)
-			__attribute__nonnull__(pTHX_1);
-#define PERL_ARGS_ASSERT_NOT_INCREMENTABLE	\
-	assert(sv)
-
 STATIC PTR_TBL_ENT_t *	S_ptr_table_find(PTR_TBL_t *const tbl, const void *const sv)
 			__attribute__warn_unused_result__
 			__attribute__nonnull__(1);
@@ -7366,12 +7361,6 @@ STATIC void	S_sv_add_arena(pTHX_ char *const ptr, const U32 size, const U32 flag
 #define PERL_ARGS_ASSERT_SV_ADD_ARENA	\
 	assert(ptr)
 
-STATIC const char *	S_sv_display(pTHX_ SV *const sv, char *tmpbuf, STRLEN tmpbuf_size)
-			__attribute__nonnull__(pTHX_1)
-			__attribute__nonnull__(pTHX_2);
-#define PERL_ARGS_ASSERT_SV_DISPLAY	\
-	assert(sv); assert(tmpbuf)
-
 STATIC STRLEN	S_sv_pos_b2u_midway(pTHX_ const U8 *const s, const U8 *const target, const U8 *end, STRLEN endu)
 			__attribute__nonnull__(pTHX_1)
 			__attribute__nonnull__(pTHX_2)
diff --git a/sv.c b/sv.c
index 85f91f1..395431a 100644
--- a/sv.c
+++ b/sv.c
@@ -1722,24 +1722,26 @@ Perl_sv_setnv_mg(pTHX_ SV *const sv, const NV num)
     SvSETMAGIC(sv);
 }
 
-/* Return a cleaned-up, printable version of sv, for non-numeric, or
- * not incrementable warning display.
- * Originally part of S_not_a_number().
- * The return value may be != tmpbuf.
+/* Print an "isn't numeric" warning, using a cleaned-up,
+ * printable version of the offending string
  */
 
-STATIC const char *
-S_sv_display(pTHX_ SV *const sv, char *tmpbuf, STRLEN tmpbuf_size) {
-    const char *pv;
+STATIC void
+S_not_a_number(pTHX_ SV *const sv)
+{
+     dVAR;
+     SV *dsv;
+     char tmpbuf[64];
+     const char *pv;
 
-     PERL_ARGS_ASSERT_SV_DISPLAY;
+     PERL_ARGS_ASSERT_NOT_A_NUMBER;
 
      if (DO_UTF8(sv)) {
-          SV *dsv = newSVpvs_flags("", SVs_TEMP);
+          dsv = newSVpvs_flags("", SVs_TEMP);
           pv = sv_uni_display(dsv, sv, 10, UNI_DISPLAY_ISPRINT);
      } else {
 	  char *d = tmpbuf;
-	  const char * const limit = tmpbuf + tmpbuf_size - 8;
+	  const char * const limit = tmpbuf + sizeof(tmpbuf) - 8;
 	  /* each *s can expand to 4 chars + "...\0",
 	     i.e. need room for 8 chars */
 	
@@ -1790,24 +1792,6 @@ S_sv_display(pTHX_ SV *const sv, char *tmpbuf, STRLEN tmpbuf_size) {
 	  pv = tmpbuf;
     }
 
-    return pv;
-}
-
-/* Print an "isn't numeric" warning, using a cleaned-up,
- * printable version of the offending string
- */
-
-STATIC void
-S_not_a_number(pTHX_ SV *const sv)
-{
-     dVAR;
-     char tmpbuf[64];
-     const char *pv;
-
-     PERL_ARGS_ASSERT_NOT_A_NUMBER;
-
-     pv = sv_display(sv, tmpbuf, sizeof(tmpbuf));
-
     if (PL_op)
 	Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
 		    /* diag_listed_as: Argument "%s" isn't numeric%s */
@@ -1819,20 +1803,6 @@ S_not_a_number(pTHX_ SV *const sv)
 		    "Argument \"%s\" isn't numeric", pv);
 }
 
-STATIC void
-S_not_incrementable(pTHX_ SV *const sv) {
-     dVAR;
-     char tmpbuf[64];
-     const char *pv;
-
-     PERL_ARGS_ASSERT_NOT_INCREMENTABLE;
-
-     pv = sv_display(sv, tmpbuf, sizeof(tmpbuf));
-
-     Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
-                 "Argument \"%s\" treated as 0 in increment (++)", pv);
-}
-
 /*
 =for apidoc looks_like_number
 
@@ -8446,11 +8416,11 @@ Perl_sv_inc_nomg(pTHX_ SV *const sv)
     while (isALPHA(*d)) d++;
     while (isDIGIT(*d)) d++;
     if (d < SvEND(sv)) {
-	const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), NULL);
 #ifdef PERL_PRESERVE_IVUV
 	/* Got to punt this as an integer if needs be, but we don't issue
 	   warnings. Probably ought to make the sv_iv_please() that does
 	   the conversion if possible, and silently.  */
+	const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), NULL);
 	if (numtype && !(numtype & IS_NUMBER_INFINITY)) {
 	    /* Need to try really hard to see if it's an integer.
 	       9.22337203685478e+18 is an integer.
@@ -8481,8 +8451,6 @@ Perl_sv_inc_nomg(pTHX_ SV *const sv)
 #endif
 	}
 #endif /* PERL_PRESERVE_IVUV */
-        if (!numtype && ckWARN(WARN_NUMERIC))
-            not_incrementable(sv);
 	sv_setnv(sv,Atof(SvPVX_const(sv)) + 1.0);
 	return;
     }
diff --git a/t/lib/warnings/sv b/t/lib/warnings/sv
index 87bc368..41a4fab 100644
--- a/t/lib/warnings/sv
+++ b/t/lib/warnings/sv
@@ -397,17 +397,3 @@ sprintf "%vd", new version v1.1_0;
 EXPECT
 vector argument not supported with alpha versions at - line 2.
 vector argument not supported with alpha versions at - line 4.
-########
-# sv.c
-my $x = "a_c";
-++$x;
-use warnings "numeric";
-$x = "a_c"; ++$x;
-$x = ${ qr/abc/ }; ++$x;
-$x = 0; ++$x; # none of these should warn
-$x = "ABC"; ++$x;
-$x = "ABC123"; ++$x;
-$x = " +10"; ++$x;
-EXPECT
-Argument "a_c" treated as 0 in increment (++) at - line 5.
-Argument "(?^:abc)" treated as 0 in increment (++) at - line 6.
diff --git a/t/op/inc.t b/t/op/inc.t
index 5135ab7..8db0660 100644
--- a/t/op/inc.t
+++ b/t/op/inc.t
@@ -274,12 +274,9 @@ isnt(scalar eval { my $pvbm = PVBM; --$pvbm }, undef, "predecrement defined");
 $_ = ${qr //};
 $_--;
 is($_, -1, 'regexp--');
-{
-    no warnings 'numeric';
-    $_ = ${qr //};
-    $_++;
-    is($_, 1, 'regexp++');
-}
+$_ = ${qr //};
+$_++;
+is($_, 1, 'regexp++');
 
 $_ = v97;
 $_++;
-- 
1.7.10.4

@p5pRT
Copy link
Author

p5pRT commented May 6, 2014

From @rjbs

* Tony Cook via RT <perlbug-followup@​perl.org> [2014-05-04T22​:08​:17]

Reverting was my initial inclination.

Attached, a patch to do the revert.

Reluctantly, I agree that this is the best way forward.

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented May 7, 2014

From @tonycoz

On Tue May 06 07​:40​:32 2014, perl.p5p@​rjbs.manxome.org wrote​:

* Tony Cook via RT <perlbug-followup@​perl.org> [2014-05-04T22​:08​:17]

Reverting was my initial inclination.

Attached, a patch to do the revert.

Reluctantly, I agree that this is the best way forward.

Revert applied as 2e6f7c2.

Ticket 3330 re-opened.

rjbs/perldelta updated to remove the diagnostic that has now been removed.

Hence closing this ticket (re-introduction is covered by 3330).

Tony

@p5pRT
Copy link
Author

p5pRT commented May 7, 2014

@tonycoz - Status changed from 'open' to 'resolved'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant