From nobody@FreeBSD.org  Sat Mar 31 22:01:42 2007
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id 73A1216A406
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 31 Mar 2007 22:01:42 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [69.147.83.33])
	by mx1.freebsd.org (Postfix) with ESMTP id 659FA13C448
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 31 Mar 2007 22:01:42 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.13.1/8.13.1) with ESMTP id l2VM1gLM000237
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 31 Mar 2007 22:01:42 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.13.1/8.13.1/Submit) id l2VLueOU099159;
	Sat, 31 Mar 2007 21:56:40 GMT
	(envelope-from nobody)
Message-Id: <200703312156.l2VLueOU099159@www.freebsd.org>
Date: Sat, 31 Mar 2007 21:56:40 GMT
From: Ryan Pavely<paradox@nac.net>
To: freebsd-gnats-submit@FreeBSD.org
Subject: /bin/date -j -f "%b %Y" "Feb 2007" +%m returns 03 for Feb!!
X-Send-Pr-Version: www-3.0

>Number:         111077
>Category:       bin
>Synopsis:       date(1): /bin/date -j -f "%b %Y" "Feb 2007" +%m returns 03 for Feb!!
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Mar 31 22:10:05 GMT 2007
>Closed-Date:    
>Last-Modified:  Sun Jul 01 04:30:12 GMT 2007
>Originator:     Ryan Pavely
>Release:        4.6, 4.8, 4.9, 5.3, 5.4, 5.5, 6.0, 6.1, 6.2
>Organization:
Net Access Corporation
>Environment:
FreeBSD #####.nac.net 4.6-STABLE FreeBSD 4.6-STABLE #0
FreeBSD #####.nac.net 4.8-RELEASE FreeBSD 4.8-RELEASE
FreeBSD #####.nac.net 4.9-RELEASE FreeBSD 4.9-RELEASE
FreeBSD #####.nac.net 5.2.1-RELEASE FreeBSD 5.2.1-RELEASE
FreeBSD #####.nac.net 5.3-RELEASE FreeBSD 5.3-RELEASE
FreeBSD #####.nac.net 5.4-RELEASE FreeBSD 5.4-RELEASE
FreeBSD #####.nac.net 5.5-RELEASE FreeBSD 5.5-RELEASE
FreeBSD #####.nac.net 6.0-RELEASE FreeBSD 6.0-RELEASE
FreeBSD #####.nac.net 6.1-RELEASE FreeBSD 6.1-RELEASE
FreeBSD #####.nac.net 6.2-RELEASE FreeBSD 6.2-RELEASE
>Description:
Date input of "mmm yyyy" for Feb always returns 03.

Flaw exists across all know bsd versions, intel, amd, 64bit, not, etc.


>How-To-Repeat:
> # /bin/date -j -f "%b %Y" "Jan 2007" +%m
> 01
> # /bin/date -j -f "%b %Y" "Feb 2007" +%m
> 03
> # /bin/date -j -f "%m %Y" "02 2007" +%m
> 03
> # /bin/date -j -f "%m %Y" "02 2007" +%m-%b
> 03-Mar
>Fix:
Got me :>
>Release-Note:
>Audit-Trail:

From: Giorgos Keramidas <keramida@freebsd.org>
To: Ryan Pavely <paradox@nac.net>
Cc: bug-followup@freebsd.org
Subject: Re: bin/111077: /bin/date -j -f "%b %Y" "Feb 2007" +%m returns 03
	for Feb!!
Date: Mon, 2 Apr 2007 05:07:05 +0300

 Hmmm, not that we are in the 2nd of April, I cannot seem to reproduce
 this by running /bin/date on the command line, on a 6.2-RELEASE or a
 7.0-CURRENT system:
 
   $ date -j -f '%b %Y' 'Feb 2007' '+%m'
   02
   $
 
 As I found out, this happens when the current value of %d when /bin/date
 runs is larger than the number of days February has.  Then date(1) gets
 the value of %d from the current time, and this overflows from February
 into March (i.e. if you ran the tests on the same day that you submitted
 this bug report, the value of %d was 31, which is clearly not a valid %d
 value for any February).
 
 The date utility initializes a `struct tm' structure in setthetime()
 with the current value of date/time using localtime().  Then strptime()
 is called with the format specified and it parses *only* the parts which
 are explicitly mentioned in the format string "%b %Y".  The value of the
 current day-of-the-month should be left untouched by strptime(), and it
 is.  But I think that strptime() tries to rationalize an invalid value,
 when it finds one.  It's easy to reproduce this by setting a breakpoint
 in setthetime() while /bin/date runs, and tweaking the value of "day of
 the month" which is returned by localtime() in place:
 
 % keramida@kobe:/home/keramida/tmp/date$ gdb date
 % GNU gdb 6.1.1 [FreeBSD]
 % Copyright 2004 Free Software Foundation, Inc.
 % GDB is free software, covered by the GNU General Public License, and you are
 % welcome to change it and/or distribute copies of it under certain conditions.
 % Type "show copying" to see the conditions.
 % There is absolutely no warranty for GDB.  Type "show warranty" for details.
 % This GDB was configured as "i386-marcel-freebsd"...No symbol table is loaded.  Use the "file" command.
 %
 % (gdb) b setthetime
 % Breakpoint 1 at 0x8049213: file date.c, line 189.
 % (gdb) run -j -f "%b %Y" "Feb 2007" +%m
 % Starting program: /home/keramida/tmp/date/date -j -f "%b %Y" "Feb 2007" +%m
 %
 % Breakpoint 1, setthetime (fmt=0xbfbfe9a7 "%b %Y", \
 %     p=0xbfbfe9ad "Feb 2007", jflag=1, nflag=0) at date.c:189
 % 189             if (fmt != NULL) {
 % (gdb) n
 % 190                     lt = localtime(&tval);
 % (gdb)
 % 191                     t = strptime(p, fmt, lt);
 % (gdb) print *lt
 % $1 = {tm_sec = 12, tm_min = 54, tm_hour = 4, tm_mday = 2, tm_mon = 3,
 %       tm_year = 107, tm_wday = 1, tm_yday = 91, tm_isdst = 1,
 %       tm_gmtoff = 10800, tm_zone = 0x28184270 "EEST"}
 % (gdb) print lt->tm_mday =31
 % $2 = 31
 % (gdb) print *lt
 % $3 = {tm_sec = 12, tm_min = 54, tm_hour = 4, tm_mday = 31, tm_mon = 3,
 %       tm_year = 107, tm_wday = 1, tm_yday = 91, tm_isdst = 1,
 %       tm_gmtoff = 10800, tm_zone = 0x28184270 "EEST"}
 % (gdb) n
 % 192                     if (t == NULL) {
 % (gdb) c
 % Continuing.
 % 03
 %
 % Program exited normally.
 % (gdb)
 
 By asking strptime() to parse a struct tm which contains tm_mday set to
 31 with a format specifier of "%b" and an input string which says "Feb"
 we get "03" in the output (i.e. "March").
 
 I don't know if strptime() should return an error in this case, instead
 of trying to "overflow" into the next calendar month.  Both cases have,
 arguably, a logical explanation, but the overflow case is surprising.
 
 My own personal preference would be that strptime() returns an error in
 this case.  This will certainly cause a mild disturbance when users run
 /bin/date in the case you tried and get an error if the current day of
 the month is more than 28 (or 29 on leap years), but when /bin/date is
 used without an explicit %d value in both the format string of -j and
 the input data, it runs with an underspecified input value.  Giving
 input which is underspecified and getting an error is, IMHO, slightly
 better than getting surprising results.
 
 - Giorgos
 
>Unformatted:
