bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [bug-gnulib] PING: strftime bugs


From: Eric Blake
Subject: Re: [bug-gnulib] PING: strftime bugs
Date: Sat, 19 Feb 2005 10:44:13 -0700
User-agent: Mozilla Thunderbird 1.0 (Windows/20041206)

According to Paul Eggert on 2/16/2005 12:52 PM:
> 
> Here's my current patch.  It is completely untested and unreviewed and
> quite possibly wrong, but I thought I'd give you a snapshot to let you
> know what sort of issues are involved.  Perhaps you can review it
> and/or test it with your test cases?
> 
> --- strftime.c.~1.78.~        2004-11-10 21:32:43 -0800
> +++ strftime.c        2005-02-16 11:51:30 -0800
> @@ -974,7 +992,7 @@ my_strftime (CHAR_T *s, size_t maxsize, 
>         if (modifier == L_('E'))
>           goto bad_format;
>  
> -       DO_NUMBER (3, 1 + tp->tm_yday);
> +       DO_SIGNED_NUMBER (3, tp->tm_yday < -1, tp->tm_yday + 1U);

Per the POSIX specification of <time.h>, tp->tm_yday is restricted to be
between 0 and 365 in a compliant program, so the user passing in a
negative tm_yday evokes unspecified behavior.  The existing behavior did
not crash on illegal input, so why add another comparison in the
instruction stream to format the illegal input nicely?  (Similarly to a
couple of other modifiers that you converted to DO_SIGNED_NUMBER - only
tm_year and tm_isdst are unrestricted in value.)

> @@ -1131,24 +1149,25 @@ my_strftime (CHAR_T *s, size_t maxsize, 
>         if (modifier == L_('E'))
>           goto bad_format;
>         {
> -         int year = tp->tm_year + TM_YEAR_BASE;
> +         int days_in_year = 365 + leapyear (tp->tm_year);
> +         int year_adjust = 0;
>           int days = iso_week_days (tp->tm_yday, tp->tm_wday);
>  
>           if (days < 0)
>             {
>               /* This ISO week belongs to the previous year.  */
> -             year--;
> -             days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
> +             year_adjust = -1;
> +             days = iso_week_days (tp->tm_yday + days_in_year,
>                                     tp->tm_wday);

The old formula was checking if the PREVIOUS year was a leap year, you
changed it to check if the current year is leap year.  That will break %V
(Jan 1 is week 53 if the previous year ended on Thursday, or if the
previous year was leap year and ended on Friday; otherwise Jan 1 is week
52 if it belongs to the previous year).

>             case L_('G'):
> -             DO_NUMBER (1, year);
> +             DO_SIGNED_NUMBER (4, tp->tm_year < -TM_YEAR_BASE - year_adjust,
> +                               (tp->tm_year + (unsigned int) TM_YEAR_BASE
> +                                + year_adjust));

You just switched %G from 1-character minimum to 4-character minimum; I
guess that is okay since no spec calls out the minimum width, and this
will make %G consistent with %Y.

> @@ -1201,7 +1229,8 @@ my_strftime (CHAR_T *s, size_t maxsize, 
>         if (modifier == L_('O'))
>           goto bad_format;
>         else
> -         DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
> +         DO_SIGNED_NUMBER (4, tp->tm_year < -TM_YEAR_BASE,
> +                           tp->tm_year + (unsigned int) TM_YEAR_BASE);

In this case, your approach is much better than mine - it still allows
width and padding formatting to take place on a single number rather than
adding recursion, and I'm okay with your use of guaranteed 2's complement
unsigned math avoiding overflow, although a comment might be helpful.

Overall, your patch seems pretty good to me, as a nice improvement on my
initial ideas.  Attached is a test program I wrote for my use when fixing
the same strftime bugs in newlib (admittedly it doesn't test everything,
since newlib is hardcoded to the "C" locale and does not support width, -,
or _ modifiers, but it helps).

-- 
Life is short - so eat dessert first!

Eric Blake             address@hidden




reply via email to

[Prev in Thread] Current Thread [Next in Thread]