# zdump loop problem

Robbin Kawabata Robbin.Kawabata at sun.com
Mon Nov 24 16:36:15 UTC 2008

```This sounds like a problem we encountered too.
zdump.c uses behavior of integer overflow on L.358 to detect when newt
has reached or exceeded the maximum time_t value.  When newt exceeds the
maximum time_t value from L.356, it overflows to a negative number, so
the L.358 check for newt less than t succeeds.

However according to the C Standard, the behavior of integer overflow is
undefined (see below).  The Sun Studio 11 compiler with -O flag optimizes
L.358 out, because it detects the check is not needed, because for the
valid range of time_t, newt will never be > t, since from L.355 newt is t
plus a positive number.  With L.358 optimized out, the for loop at L.352
executes infinitely.

zdump.c:
...
249          time_t                  t;
250          time_t                  newt;
...
352                  for ( ; ; ) {
353                          if (t >= cuthitime)
354                                  break;
355                          newt = t + SECSPERHOUR * 12;	<--
356                          if (newt >= cuthitime)
357                                  break;
358                          if (newt <= t)			<--
359                                  break;
360                          newtmp = localtime(&newt);
...

376                          t = newt;
377                          tm = newtm;
378                          tmp = newtmp;
379                  }

A possible fix is to instead check whether t plus delta (delta =
SECSPERHOUR * 12) is greater than the maximum time_t:

(time + delta) > max_time_t
or:
time > max_time_t - delta   /* avoids time+delta overflow */

------- zdump.c -------
@@ -314,11 +314,12 @@
for (;;) {
if (t >= cuthitime)
break;
+                       /* check if newt will overrun maximum time_t value */
+                       if (t > LONG_MAX - (SECSPERHOUR * 12))
+                               break;
newt = t + SECSPERHOUR * 12;
if (newt >= cuthitime)
break;
-                       if (newt <= t)
-                               break;
newtmp = localtime(&newt);
if (newtmp != NULL)
newtm = *newtmp;

The C Standard says (for signed integer):

ISO/IEC 9899:1999:

6.5 p5:
If an exceptional condition occurs during the evaluation of an
expression (that is, if the result is not mathematically defined or not
in the range of representable values for its type), the behavior is
undefined.

3.4.3 p3:
EXAMPLE: An example of undefined behavior is the behavior on integer
overflow.

> Date: Mon, 24 Nov 2008 09:09:13 -0500
> From: "Olson, Arthur David (NIH/NCI) [E]" <olsona at dc37a.nci.nih.gov>
> Subject: FW: mail to tz list bounced
> To: tz at lecserver.nci.nih.gov
>
> I'm forwarding this message from Andreas Radke; while Andreas is on the
> time zone mailing list, the message bounced when he tried to send it
> directly.
>
>
> Datum: Wed, 19 Nov 2008 21:47:05 +0100
> An: tz at lecserver.nci.nih.gov
> Betreff: optimization -O2 broken?
>
> I'm the ArchLinux package maintainer for tzdata. We are using gcc
> 4.3.2/glibc2.8- We have run into a small problem with compiler
> optimizations.
>
> Using our default CFLAGS="-march=i686 -mtune=generic -O2 -pipe" the
> zdump binary is built in broken way on i686 architecture. I have to
> apply -O1 to make zdump work. See our bugreport:
>
> I could confirm this when running zdump -v EUROPE/BERLIN it stuck after
> two printing first two lines.
>
> x86_64 architecture doesn't seem to be affected. Any idea why this
> happens and how to fix it?
>
> -Andy
>

```