Subject: lib/5056: strptime(3) is broken
To: None <gnats-bugs@gnats.netbsd.org>
From: NAKAJIMA Yoshihiro <nakayosh@kcn.or.jp>
List: netbsd-bugs
Date: 02/24/1998 23:33:57
>Number:         5056
>Category:       lib
>Synopsis:       strptime(3) is broken
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    lib-bug-people (Library Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Feb 24 06:35:01 1998
>Last-Modified:
>Originator:     NAKAJIMA Yoshihiro
>Organization:
>Release:        NetBSD-current 98/02/23
>Environment:
System: NetBSD asura 1.3D NetBSD 1.3D (ASURA) #3: Tue Feb 24 21:15:07 JST 1998 nakayosh@asura:/usr/src/sys/arch/i386/compile/ASURA i386


>Description:

strptime(3) is broken.

1. `%m' assigns [1,12] to tm_mon.
2. `%I' requires [0,11].
3. `%S' requires [1,61].

>How-To-Repeat:

% cat test.c
#include <stdio.h>
#include <time.h>

int main(void)
{
    char *mon[] = { "Jan", "Feb" /* snip */ };

    struct tm tm;
    char *format, *buffer;

    printf("CASE 1:\t");
    format = "%m";
    buffer = "01";              /* Jan */
    strptime(buffer, format, &tm);
    printf("%s\n", mon[tm.tm_mon]);

    printf("CASE 2:\t");
    format = "%I";
    buffer = "12";
    if (strptime(buffer, format, &tm) == NULL)
        printf("ERROR\n");
    else
        printf("%02d\n", tm.tm_hour);

    printf("CASE 3:\t");
    format = "%S"; 
    buffer = "00";
    if (strptime(buffer, format, &tm) == NULL)
        printf("ERROR\n");
    else
        printf("%02d\n", tm.tm_sec);

    return 0;
}
% cc test.c
% ./a.out
CASE 1: Feb
CASE 2: ERROR
CASE 3: ERROR

>Fix:

diff -u src/lib/libc/time/strptime.c.orig src/lib/libc/time/strptime.c
--- src/lib/libc/time/strptime.c.orig	Wed Jan 21 21:16:48 1998
+++ src/lib/libc/time/strptime.c	Tue Feb 24 21:35:37 1998
@@ -240,7 +240,7 @@
 			/* FALLTHROUGH */
 		case 'I':
 			_LEGAL_ALT(_ALT_O);
-			if (!(_conv_num(&bp, &tm->tm_hour, 0, 11)))
+			if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
 				return (0);
 			break;
 
@@ -260,6 +260,7 @@
 			_LEGAL_ALT(_ALT_O);
 			if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
 				return (0);
+			tm->tm_mon--;
 			break;
 
 		case 'p':	/* The locale's equivalent of AM/PM. */
@@ -290,7 +291,7 @@
 
 		case 'S':	/* The seconds. */
 			_LEGAL_ALT(_ALT_O);
-			if (!(_conv_num(&bp, &tm->tm_sec, 1, 61)))
+			if (!(_conv_num(&bp, &tm->tm_sec, 0, 61)))
 				return (0);
 			break;
 

>Audit-Trail:
>Unformatted: