Correct the rounding behavior on tv_mdiff.

Fix for bug 19428.
This commit is contained in:
Nick Mathewson 2016-06-16 10:16:04 -04:00
parent f05a213fe1
commit 41cb26c169
3 changed files with 16 additions and 5 deletions

5
changes/bug19428 Normal file
View File

@ -0,0 +1,5 @@
- Minor bugfixes (timing):
o When computing the difference between two times in milliseconds,
we now round to the nearest millisecond correctly. Previously,
we could sometimes round in the wrong direction. Fixes bug 19428;
bugfix on 0.2.2.2-alpha.

View File

@ -1386,7 +1386,7 @@ tv_udiff(const struct timeval *start, const struct timeval *end)
long udiff;
long secdiff = end->tv_sec - start->tv_sec;
if (labs(secdiff+1) > LONG_MAX/1000000) {
if (labs(secdiff)+1 > LONG_MAX/1000000) {
log_warn(LD_GENERAL, "comparing times on microsecond detail too far "
"apart: %ld seconds", secdiff);
return LONG_MAX;
@ -1404,7 +1404,7 @@ tv_mdiff(const struct timeval *start, const struct timeval *end)
long mdiff;
long secdiff = end->tv_sec - start->tv_sec;
if (labs(secdiff+1) > LONG_MAX/1000) {
if (labs(secdiff)+1 > LONG_MAX/1000) {
log_warn(LD_GENERAL, "comparing times on millisecond detail too far "
"apart: %ld seconds", secdiff);
return LONG_MAX;
@ -1412,7 +1412,13 @@ tv_mdiff(const struct timeval *start, const struct timeval *end)
/* Subtract and round */
mdiff = secdiff*1000L +
((long)end->tv_usec - (long)start->tv_usec + 500L) / 1000L;
/* We add a million usec here to ensure that the result is positive,
* so that the round-towards-zero behavior of the division will give
* the right result for rounding to the nearest msec. Later we subtract
* 1000 in order to get the correct result.
*/
((long)end->tv_usec - (long)start->tv_usec + 500L + 1000000L) / 1000L
- 1000;
return mdiff;
}

View File

@ -286,12 +286,12 @@ test_util_time(void *arg)
end.tv_usec = 0;
tt_int_op(995000L,OP_EQ, tv_udiff(&start, &end));
// tt_int_op(996L,OP_EQ, tv_mdiff(&start, &end)); // XXXX fails
tt_int_op(995L,OP_EQ, tv_mdiff(&start, &end));
end.tv_sec = 4;
tt_int_op(-1005000L,OP_EQ, tv_udiff(&start, &end));
// tt_int_op(-1005L,OP_EQ, tv_udiff(&start, &end)); // XXXX Fails
tt_int_op(-1005L,OP_EQ, tv_mdiff(&start, &end));
end.tv_sec = TIME_MAX;
tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end));