From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29250 invoked by alias); 8 Feb 2007 17:41:43 -0000 Received: (qmail 29230 invoked by uid 22791); 8 Feb 2007 17:41:42 -0000 X-Spam-Check-By: sourceware.org Received: from sunsite.ms.mff.cuni.cz (HELO sunsite.mff.cuni.cz) (195.113.15.26) by sourceware.org (qpsmtpd/0.31) with ESMTP; Thu, 08 Feb 2007 17:41:32 +0000 Received: from sunsite.mff.cuni.cz (localhost.localdomain [127.0.0.1]) by sunsite.mff.cuni.cz (8.13.8/8.13.8) with ESMTP id l18HgD20021149; Thu, 8 Feb 2007 18:42:13 +0100 Received: (from jakub@localhost) by sunsite.mff.cuni.cz (8.13.8/8.13.8/Submit) id l18HgCQb021148; Thu, 8 Feb 2007 18:42:12 +0100 Date: Thu, 08 Feb 2007 17:41:00 -0000 From: Jakub Jelinek To: Ulrich Drepper Cc: Glibc hackers Subject: [PATCH] Fix strptime (BZ #3944) Message-ID: <20070208174212.GB4219@sunsite.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.2.2i Mailing-List: contact libc-hacker-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sourceware.org X-SW-Source: 2007-02/txt/msg00002.txt.bz2 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 [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 +#include +#include +#include + + +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