LCOV - code coverage report
Current view: top level - lib/time - tvdiff.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 38 42 90.5 %
Date: 2021-11-24 03:28:48 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /* Copyright (c) 2003-2004, Roger Dingledine
       2             :  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       3             :  * Copyright (c) 2007-2021, The Tor Project, Inc. */
       4             : /* See LICENSE for licensing information */
       5             : 
       6             : /**
       7             :  * \file tvdiff.c
       8             :  * \brief Compute the difference between timevals, in various units.
       9             :  **/
      10             : 
      11             : #include "lib/time/tvdiff.h"
      12             : 
      13             : #include "lib/cc/compat_compiler.h"
      14             : #include "lib/defs/time.h"
      15             : #include "lib/log/log.h"
      16             : 
      17             : #ifdef _WIN32
      18             : #include <winsock2.h>
      19             : #endif
      20             : #ifdef HAVE_SYS_TIME_H
      21             : #include <sys/time.h>
      22             : #endif
      23             : 
      24             : /** Return the difference between start->tv_sec and end->tv_sec.
      25             :  * Returns INT64_MAX on overflow and underflow.
      26             :  */
      27             : static int64_t
      28         125 : tv_secdiff_impl(const struct timeval *start, const struct timeval *end)
      29             : {
      30         125 :   const int64_t s = (int64_t)start->tv_sec;
      31         125 :   const int64_t e = (int64_t)end->tv_sec;
      32             : 
      33             :   /* This may not be the most efficient way of implementing this check,
      34             :    * but it's easy to see that it's correct and doesn't overflow */
      35             : 
      36         125 :   if (s > 0 && e < INT64_MIN + s) {
      37             :     /* s is positive: equivalent to e - s < INT64_MIN, but without any
      38             :      * overflow */
      39             :     return INT64_MAX;
      40         109 :   } else if (s < 0 && e > INT64_MAX + s) {
      41             :     /* s is negative: equivalent to e - s > INT64_MAX, but without any
      42             :      * overflow */
      43             :     return INT64_MAX;
      44             :   }
      45             : 
      46          89 :   return e - s;
      47             : }
      48             : 
      49             : /** Return the number of microseconds elapsed between *start and *end.
      50             :  * Returns LONG_MAX on overflow and underflow.
      51             :  */
      52             : long
      53          63 : tv_udiff(const struct timeval *start, const struct timeval *end)
      54             : {
      55             :   /* Sanity check tv_usec */
      56          63 :   if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) {
      57           3 :     log_warn(LD_GENERAL, "comparing times on microsecond detail with bad "
      58             :              "start tv_usec: %"PRId64 " microseconds",
      59             :              (int64_t)start->tv_usec);
      60           3 :     return LONG_MAX;
      61             :   }
      62             : 
      63          60 :   if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) {
      64           3 :     log_warn(LD_GENERAL, "comparing times on microsecond detail with bad "
      65             :              "end tv_usec: %"PRId64 " microseconds",
      66             :              (int64_t)end->tv_usec);
      67           3 :     return LONG_MAX;
      68             :   }
      69             : 
      70             :   /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit
      71             :    */
      72          57 :   int64_t udiff;
      73          57 :   const int64_t secdiff = tv_secdiff_impl(start, end);
      74             : 
      75             :   /* end->tv_usec - start->tv_usec can be up to 1 second either way */
      76          57 :   if (secdiff > (int64_t)(LONG_MAX/1000000 - 1) ||
      77             :       secdiff < (int64_t)(LONG_MIN/1000000 + 1)) {
      78          34 :     log_warn(LD_GENERAL, "comparing times on microsecond detail too far "
      79             :              "apart: %"PRId64 " seconds", (secdiff));
      80          34 :     return LONG_MAX;
      81             :   }
      82             : 
      83             :   /* we'll never get an overflow here, because we check that both usecs are
      84             :    * between 0 and TV_USEC_PER_SEC. */
      85          23 :   udiff = secdiff*1000000 + ((int64_t)end->tv_usec - (int64_t)start->tv_usec);
      86             : 
      87             :   /* Some compilers are smart enough to work out this is a no-op on L64 */
      88             : #if SIZEOF_LONG < 8
      89             :   if (udiff > (int64_t)LONG_MAX || udiff < (int64_t)LONG_MIN) {
      90             :     return LONG_MAX;
      91             :   }
      92             : #endif
      93             : 
      94          23 :   return (long)udiff;
      95             : }
      96             : 
      97             : /** Return the number of milliseconds elapsed between *start and *end.
      98             :  * If the tv_usec difference is 500, rounds away from zero.
      99             :  * Returns LONG_MAX on overflow and underflow.
     100             :  */
     101             : long
     102          74 : tv_mdiff(const struct timeval *start, const struct timeval *end)
     103             : {
     104             :   /* Sanity check tv_usec */
     105          74 :   if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) {
     106           3 :     log_warn(LD_GENERAL, "comparing times on millisecond detail with bad "
     107             :              "start tv_usec: %"PRId64 " microseconds",
     108             :              (int64_t)start->tv_usec);
     109           3 :     return LONG_MAX;
     110             :   }
     111             : 
     112          71 :   if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) {
     113           3 :     log_warn(LD_GENERAL, "comparing times on millisecond detail with bad "
     114             :              "end tv_usec: %"PRId64 " microseconds",
     115             :              (int64_t)end->tv_usec);
     116           3 :     return LONG_MAX;
     117             :   }
     118             : 
     119             :   /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit
     120             :    */
     121          68 :   int64_t mdiff;
     122          68 :   const int64_t secdiff = tv_secdiff_impl(start, end);
     123             : 
     124             :   /* end->tv_usec - start->tv_usec can be up to 1 second either way, but the
     125             :    * mdiff calculation may add another temporary second for rounding.
     126             :    * Whether this actually causes overflow depends on the compiler's constant
     127             :    * folding and order of operations. */
     128          68 :   if (secdiff > (int64_t)(LONG_MAX/1000 - 2) ||
     129             :       secdiff < (int64_t)(LONG_MIN/1000 + 1)) {
     130          28 :     log_warn(LD_GENERAL, "comparing times on millisecond detail too far "
     131             :              "apart: %"PRId64 " seconds", (int64_t)secdiff);
     132          28 :     return LONG_MAX;
     133             :   }
     134             : 
     135             :   /* Subtract and round */
     136          40 :   mdiff = secdiff*1000 +
     137             :       /* We add a million usec here to ensure that the result is positive,
     138             :        * so that the round-towards-zero behavior of the division will give
     139             :        * the right result for rounding to the nearest msec. Later we subtract
     140             :        * 1000 in order to get the correct result.
     141             :        * We'll never get an overflow here, because we check that both usecs are
     142             :        * between 0 and TV_USEC_PER_SEC. */
     143          40 :       ((int64_t)end->tv_usec - (int64_t)start->tv_usec + 500 + 1000000) / 1000
     144             :       - 1000;
     145             : 
     146             :   /* Some compilers are smart enough to work out this is a no-op on L64 */
     147             : #if SIZEOF_LONG < 8
     148             :   if (mdiff > (int64_t)LONG_MAX || mdiff < (int64_t)LONG_MIN) {
     149             :     return LONG_MAX;
     150             :   }
     151             : #endif
     152             : 
     153          40 :   return (long)mdiff;
     154             : }
     155             : 
     156             : /**
     157             :  * Converts timeval to milliseconds.
     158             :  */
     159             : int64_t
     160           0 : tv_to_msec(const struct timeval *tv)
     161             : {
     162           0 :   int64_t conv = ((int64_t)tv->tv_sec)*1000L;
     163             :   /* Round ghetto-style */
     164           0 :   conv += ((int64_t)tv->tv_usec+500)/1000L;
     165           0 :   return conv;
     166             : }
     167             : 
     168             : /**
     169             :  * Return duration in seconds between time_t values
     170             :  * <b>t1</b> and <b>t2</b> iff <b>t1</b> is numerically
     171             :  * less or equal than <b>t2</b>. Otherwise, return TIME_MAX.
     172             :  *
     173             :  * This provides a safe way to compute difference between
     174             :  * two UNIX timestamps (<b>t2</b> can be assumed by calling
     175             :  * code to be later than <b>t1</b>) or two durations measured
     176             :  * in seconds (<b>t2</b> can be assumed to be longer than
     177             :  * <b>t1</b>). Calling code is expected to check for TIME_MAX
     178             :  * return value and interpret that as error condition.
     179             :  */
     180             : time_t
     181         408 : time_diff(const time_t t1, const time_t t2)
     182             : {
     183         408 :   if (t1 <= t2)
     184         408 :     return t2 - t1;
     185             : 
     186             :   return TIME_MAX;
     187             : }
     188             : 

Generated by: LCOV version 1.14