Bugzilla Bug 322422: fixed a negative integer division truncation direction
authorwtchang%redhat.com
Mon, 09 Jan 2006 22:48:25 +0000
changeset 3542 3c265df58a5e9d6da13b21715b37e8772655bf87
parent 3540 77f911a5a3cb3ad8a46ae454fed4049218856d38
child 3551 3f795764998f6d6c4bff7ba9bafb0343a02db263
push idunknown
push userunknown
push dateunknown
bugs322422
Bugzilla Bug 322422: fixed a negative integer division truncation direction error, which resulted in a negative PRTime with fractional seconds being converted to PRExplodedTime off by one second. Thanks to Aleksey Sanin <aleksey@aleksey.com> for reporting and investigating the bug and reviewing the patch. r=aleskey.
pr/src/misc/prtime.c
--- a/pr/src/misc/prtime.c
+++ b/pr/src/misc/prtime.c
@@ -612,16 +612,17 @@ PR_IMPLEMENT(PRTimeParameters)
 PR_LocalTimeParameters(const PRExplodedTime *gmt)
 {
 
     PRTimeParameters retVal;
     struct tm localTime;
     time_t secs;
     PRTime secs64;
     PRInt64 usecPerSec;
+    PRInt64 usecPerSec_1;
     PRInt64 maxInt32;
     PRInt64 minInt32;
     PRInt32 dayOffset;
     PRInt32 offset2Jan1970;
     PRInt32 offsetNew;
     int isdst2Jan1970;
 
     /*
@@ -658,17 +659,26 @@ PR_LocalTimeParameters(const PRExplodedT
      * the dst offset.
      *     overall_offset = local_time - GMT
      *     overall_offset = gmt_offset + dst_offset
      * ==> dst_offset = local_time - GMT - gmt_offset
      */
 
     secs64 = PR_ImplodeTime(gmt);    /* This is still in microseconds */
     LL_I2L(usecPerSec, PR_USEC_PER_SEC);
-    LL_DIV(secs64, secs64, usecPerSec);   /* Convert to seconds */
+    LL_I2L(usecPerSec_1, PR_USEC_PER_SEC - 1);
+    /* Convert to seconds, truncating down (3.1 -> 3 and -3.1 -> -4) */
+    if (LL_GE_ZERO(secs64)) {
+        LL_DIV(secs64, secs64, usecPerSec);
+    } else {
+        LL_NEG(secs64, secs64);
+        LL_ADD(secs64, secs64, usecPerSec_1);
+        LL_DIV(secs64, secs64, usecPerSec);
+        LL_NEG(secs64, secs64);
+    }
     LL_I2L(maxInt32, PR_INT32_MAX);
     LL_I2L(minInt32, PR_INT32_MIN);
     if (LL_CMP(secs64, >, maxInt32) || LL_CMP(secs64, <, minInt32)) {
         /* secs64 is too large or too small for time_t (32-bit integer) */
         retVal.tp_gmt_offset = offset2Jan1970;
         retVal.tp_dst_offset = 0;
         return retVal;
     }