public inbox for libc-hacker@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Fix strptime (BZ #3944)
@ 2007-02-08 17:41 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2007-02-08 17:41 UTC (permalink / raw)
  To: Ulrich Drepper; +Cc: Glibc hackers

Hi!

strptime as described in info libc doesn't change fields not set in
the format (or not recomputed from the values) and allows several
consecutive strptime calls on the same struct tm to gradually fill
it (in POSIX that's unspecified).  This patch guards against crashes
when tm_mon hasn't been intialized yet, but tm_wday or tm_yday is
being recomputed (e.g. because tm_year or tm_day was set).

2007-02-08  Jakub Jelinek  <jakub@redhat.com>

	[BZ #3944]
	* time/strptime_l.c (__strptime_internal): Set have_mon for
	%b/%B/%h.  Set have_mon and have_mday if tm_mon and tm_mday
	have been computed from tm_yday and tm_year.  Don't crash
	in day_of_the_week or day_of_the_year if not have_mon
	and tm_mon contains bogus value.
	* time/Makefile (tests): Add tst-strptime3.
	* time/tst-strptime3.c: New test.

--- libc/time/strptime_l.c.jj	2005-04-27 06:30:10.000000000 +0200
+++ libc/time/strptime_l.c	2007-02-08 17:11:04.000000000 +0100
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -400,6 +400,7 @@ __strptime_internal (rp, fmt, tm, decide
 	    /* Does not match a month name.  */
 	    return NULL;
 	  tm->tm_mon = cnt;
+	  have_mon = 1;
 	  want_xday = 1;
 	  break;
 	case 'c':
@@ -1085,11 +1086,15 @@ __strptime_internal (rp, fmt, tm, decide
 	      tm->tm_mday =
 		(tm->tm_yday
 		 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
+	  have_mon = 1;
+	  have_mday = 1;
 	}
-      day_of_the_week (tm);
+      /* Don't crash in day_of_the_week if tm_mon is uninitialized.  */
+      if (have_mon || (unsigned) tm->tm_mon <= 11)
+	day_of_the_week (tm);
     }
 
-  if (want_xday && !have_yday)
+  if (want_xday && !have_yday && (have_mon || (unsigned) tm->tm_mon <= 11))
     day_of_the_year (tm);
 
   if ((have_uweek || have_wweek) && have_wday)
--- libc/time/tst-strptime3.c.jj	2007-02-08 17:11:47.000000000 +0100
+++ libc/time/tst-strptime3.c	2007-02-08 18:26:02.000000000 +0100
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+int
+main (void)
+{
+  int result = 0;
+  struct tm tm;
+
+  memset (&tm, 0xaa, sizeof (tm));
+
+  /* Test we don't crash on uninitialized struct tm.
+     Some fields might contain bogus values until everything
+     needed is initialized, but we shouldn't crash.  */
+  if (strptime ("2007", "%Y", &tm) == NULL
+      || strptime ("12", "%d", &tm) == NULL
+      || strptime ("Feb", "%b", &tm) == NULL
+      || strptime ("13", "%M", &tm) == NULL
+      || strptime ("21", "%S", &tm) == NULL
+      || strptime ("16", "%H", &tm) == NULL)
+    {
+      puts ("strptimes failed");
+      result = 1;
+    }
+
+  if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
+      || tm.tm_mday != 12 || tm.tm_mon != 1 || tm.tm_year != 107
+      || tm.tm_wday != 1 || tm.tm_yday != 42)
+    {
+      puts ("unexpected tm content");
+      result = 1;
+    }
+
+  if (strptime ("8", "%d", &tm) == NULL)
+    {
+      puts ("strptime failed");
+      result = 1;
+    }
+
+  if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
+      || tm.tm_mday != 8 || tm.tm_mon != 1 || tm.tm_year != 107
+      || tm.tm_wday != 4 || tm.tm_yday != 38)
+    {
+      puts ("unexpected tm content");
+      result = 1;
+    }
+
+  if (result == 0)
+    puts ("all OK");
+
+  return 0;
+}
--- libc/time/Makefile.jj	2006-09-09 18:54:49.000000000 +0200
+++ libc/time/Makefile	2007-02-08 18:25:51.000000000 +0100
@@ -1,4 +1,4 @@
-# Copyright (C) 1991-2003, 2004, 2005 Free Software Foundation, Inc.
+# Copyright (C) 1991-2003, 2004, 2005, 2007 Free Software Foundation, Inc.
 # This file is part of the GNU C Library.
 
 # The GNU C Library is free software; you can redistribute it and/or
@@ -35,7 +35,8 @@ distribute := datemsk
 
 tests	:= test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
 	   tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
-	   tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1
+	   tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
+	   tst-strptime3
 
 include ../Rules
 

	Jakub

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2007-02-08 17:41 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-02-08 17:41 [PATCH] Fix strptime (BZ #3944) Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).