This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Uninitialized tmbuf.
authorJarkko Hietaniemi <jhi@iki.fi>
Wed, 7 May 2014 13:26:52 +0000 (09:26 -0400)
committerTony Cook <tony@develop-help.com>
Thu, 29 May 2014 04:50:11 +0000 (14:50 +1000)
Fix for Coverity perl5 CID 29088: Uninitialized scalar variable (UNINIT)
uninit_use: Using uninitialized value tmbuf.tm_year.

There is a code path that can lead to accessing uninitialized tmbuf:
when the too-small or too-large time inputs to gmtime/localtime
happen.

- make it so that the tm_year is used only on successful code path:
  pp_sys.c
- add the gmtime failed / localtime failed errors to perldiag:
  pod/perldiag.pod
- test those errors: t/op/time.t

pod/perldiag.pod
pp_sys.c
t/op/time.t

index f87ca9c..530bc47 100644 (file)
@@ -2121,6 +2121,11 @@ a term, so it's looking for the corresponding right angle bracket, and
 not finding it.  Chances are you left some needed parentheses out
 earlier in the line, and you really meant a "less than".
 
+=item gmtime(%f) failed
+
+(W overflow) You called C<gmtime> with a number that it could not handle:
+too large, too small, or NaN.  The returned value is C<undef>.
+
 =item gmtime(%f) too large
 
 (W overflow) You called C<gmtime> with a number that was larger than
@@ -2780,6 +2785,11 @@ L<perlfunc/listen>.
 form of C<open> does not support pipes, such as C<open($pipe, '|-', @args)>.
 Use the two-argument C<open($pipe, '|prog arg1 arg2...')> form instead.
 
+=item localtime(%f) failed
+
+(W overflow) You called C<localtime> with a number that it could not handle:
+too large, too small, or NaN.  The returned value is C<undef>.
+
 =item localtime(%f) too large
 
 (W overflow) You called C<localtime> with a number that was larger
index 671a9c0..d954f8b 100644 (file)
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -4485,30 +4485,29 @@ PP(pp_gmtime)
     }
 
     if (err == NULL) {
+       /* diag_listed_as: gmtime(%f) failed */
        /* XXX %lld broken for quads */
        Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW),
                       "%s(%.0" NVff ") failed", opname, when);
     }
 
     if (GIMME != G_ARRAY) {    /* scalar context */
-       SV *tsv;
-       /* XXX newSVpvf()'s %lld type is broken, so cheat with a double */
-       double year = (double)tmbuf.tm_year + 1900;
-
         EXTEND(SP, 1);
         EXTEND_MORTAL(1);
        if (err == NULL)
            RETPUSHUNDEF;
-
-       tsv = Perl_newSVpvf(aTHX_ "%s %s %2d %02d:%02d:%02d %.0f",
-                           dayname[tmbuf.tm_wday],
-                           monname[tmbuf.tm_mon],
-                           tmbuf.tm_mday,
-                           tmbuf.tm_hour,
-                           tmbuf.tm_min,
-                           tmbuf.tm_sec,
-                           year);
-       mPUSHs(tsv);
+       else {
+           mPUSHs(Perl_newSVpvf(aTHX_ "%s %s %2d %02d:%02d:%02d %.0f",
+                                dayname[tmbuf.tm_wday],
+                                monname[tmbuf.tm_mon],
+                                tmbuf.tm_mday,
+                                tmbuf.tm_hour,
+                                tmbuf.tm_min,
+                                tmbuf.tm_sec,
+                                /* XXX newSVpvf()'s %lld type is broken,
+                                 * so cheat with a double */
+                                (double)tmbuf.tm_year + 1900));
+        }
     }
     else {                     /* list context */
        if ( err == NULL )
index 4ac7f5b..734b838 100644 (file)
@@ -6,7 +6,7 @@ BEGIN {
     require './test.pl';
 }
 
-plan tests => 66;
+plan tests => 70;
 
 # These tests make sure, among other things, that we don't end up
 # burning tons of CPU for dates far in the future.
@@ -210,7 +210,7 @@ SKIP: { #rt #73040
        || $small_time == $smallest
         || $big_time - 200 != $biggest
        || $big_time == $biggest) {
-       skip "Can't represent test values", 4;
+       skip "Can't represent test values", 8;
     }
     my $small_time_f = sprintf("%.0f", $small_time);
     my $big_time_f = sprintf("%.0f", $big_time);
@@ -221,17 +221,20 @@ SKIP: { #rt #73040
     $warning = '';
     my $date = gmtime($big_time);
     like $warning, qr/^gmtime\($big_time_f\) too large/;
+    like $warning, qr/^gmtime\($big_time_f\) failed/m;
 
     $warning = '';
     $date = localtime($big_time);
     like $warning, qr/^localtime\($big_time_f\) too large/;
+    like $warning, qr/^localtime\($big_time_f\) failed/m;
 
     $warning = '';
     $date = gmtime($small_time);
     like $warning, qr/^gmtime\($small_time_f\) too small/;
+    like $warning, qr/^gmtime\($small_time_f\) failed/m;
 
     $warning = '';
     $date = localtime($small_time);
     like $warning, qr/^localtime\($small_time_f\) too small/;
-  
+    like $warning, qr/^localtime\($small_time_f\) failed/m;
 }