changeset 22804:33a2b955ea19

lib: time-util: Fix timeval_cmp_margin() to correctly handle a margin crossing the second boundary. The timeval_cmp_margin() function incorrectly assumed that the margin is irrelevent when the tv_sec values are different.
author Stephan Bosch <stephan.bosch@dovecot.fi>
date Tue, 06 Feb 2018 15:50:19 +0100
parents 766e2da35883
children dbb45b0865be
files src/lib/test-time-util.c src/lib/time-util.c
diffstat 2 files changed, 162 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/test-time-util.c	Tue Feb 06 16:51:23 2018 +0100
+++ b/src/lib/test-time-util.c	Tue Feb 06 15:50:19 2018 +0100
@@ -54,6 +54,143 @@
 	test_end();
 }
 
+static void test_timeval_cmp_margin(void)
+{
+	static const struct {
+		struct timeval tv1, tv2;
+		unsigned int margin;
+		int output;
+	} tests[] = {
+		{
+			.tv1 = { 0, 0 },
+			.tv2 = { 0, 0 },
+			.output = 0,
+		},{
+			.tv1 = { INT_MAX, 999999 },
+			.tv2 = { INT_MAX, 999999 },
+			.output = 0,
+
+		},{
+			.tv1 = { 0, 0 },
+			.tv2 = { 0, 1 },
+			.output = -1,
+		},{
+			.tv1 = { 0, 0 },
+			.tv2 = { 1, 0 },
+			.output = -1,
+		},{
+			.tv1 = { 0, 999999 },
+			.tv2 = { 1, 0 },
+			.output = -1,
+		},{
+			.tv1 = { 1, 0 },
+			.tv2 = { 1, 1 },
+			.output = -1,
+		},{
+			.tv1 = { -INT_MAX, 0 },
+			.tv2 = { INT_MAX, 0 },
+			.output = -1,
+		},{
+			.tv1 = { 0, 999999 },
+			.tv2 = { 1, 0 },
+			.margin = 1,
+			.output = 0,
+		},{
+			.tv1 = { 1, 0 },
+			.tv2 = { 1, 1 },
+			.margin = 1,
+			.output = 0,
+		},{
+			.tv1 = { 0, 999998 },
+			.tv2 = { 1, 0 },
+			.margin = 1,
+			.output = -1,
+		},{
+			.tv1 = { 1, 0 },
+			.tv2 = { 1, 2 },
+			.margin = 1,
+			.output = -1,
+		},{
+			.tv1 = { 0, 998000 },
+			.tv2 = { 1, 0 },
+			.margin = 2000,
+			.output = 0,
+		},{
+			.tv1 = { 1, 0 },
+			.tv2 = { 1, 2000 },
+			.margin = 2000,
+			.output = 0,
+		},{
+			.tv1 = { 0, 997999 },
+			.tv2 = { 1, 0 },
+			.margin = 2000,
+			.output = -1,
+		},{
+			.tv1 = { 1, 0 },
+			.tv2 = { 1, 2001 },
+			.margin = 2000,
+			.output = -1,
+		},{
+			.tv1 = { 0, 1 },
+			.tv2 = { 1, 0 },
+			.margin = 999999,
+			.output = 0,
+		},{
+			.tv1 = { 1, 0 },
+			.tv2 = { 1, 999999 },
+			.margin = 999999,
+			.output = 0,
+		},{
+			.tv1 = { 0, 0 },
+			.tv2 = { 1, 0 },
+			.margin = 999999,
+			.output = -1,
+		},{
+			.tv1 = { 1, 0 },
+			.tv2 = { 2, 0 },
+			.margin = 999999,
+			.output = -1,
+		},{
+			.tv1 = { 10, 0 },
+			.tv2 = { 11, 500000 },
+			.margin = 1500000,
+			.output = 0,
+		},{
+			.tv1 = { 8, 500000 },
+			.tv2 = { 10, 0 },
+			.margin = 1500000,
+			.output = 0,
+		},{
+			.tv1 = { 10, 0 },
+			.tv2 = { 11, 500001 },
+			.margin = 1500000,
+			.output = -1,
+		},{
+			.tv1 = { 8, 499999 },
+			.tv2 = { 10, 0 },
+			.margin = 1500000,
+			.output = -1,
+		},{
+			.tv1 = { 1517925358, 999989 },
+			.tv2 = { 1517925359, 753 },
+			.margin = 2000,
+			.output = 0,
+		}
+	};
+	unsigned int i;
+
+	test_begin("timeval_cmp_margin()");
+	for (i = 0; i < N_ELEMENTS(tests); i++) {
+		const struct timeval *tv1 = &tests[i].tv1, *tv2 = &tests[i].tv2;
+		unsigned int margin = tests[i].margin;
+		int output = tests[i].output;
+
+		test_assert(timeval_cmp_margin(tv1, tv2, margin) == output);
+		test_assert(timeval_cmp_margin(tv2, tv1, margin) == -output);
+	}
+	test_end();
+}
+
 static void test_timeval_diff(void)
 {
 	static struct timeval input[] = {
@@ -201,6 +338,7 @@
 void test_time_util(void)
 {
 	test_timeval_cmp();
+	test_timeval_cmp_margin();
 	test_timeval_diff();
 	test_time_to_local_day_start();
 	test_strftime_now();
--- a/src/lib/time-util.c	Tue Feb 06 16:51:23 2018 +0100
+++ b/src/lib/time-util.c	Tue Feb 06 15:50:19 2018 +0100
@@ -23,16 +23,31 @@
 int timeval_cmp_margin(const struct timeval *tv1, const struct timeval *tv2,
 	unsigned int usec_margin)
 {
-	if (tv1->tv_sec < tv2->tv_sec)
-		return -1;
-	if (tv1->tv_sec > tv2->tv_sec)
-		return 1;
+	unsigned long long usecs_diff;
+	int sec_margin, ret;
 
-	if ((tv2->tv_usec - tv1->tv_usec) > (int)usec_margin)
-		return -1;
-	if ((tv1->tv_usec - tv2->tv_usec) > (int)usec_margin)
-		return 1;
-	return 0;
+	if (tv1->tv_sec < tv2->tv_sec) {
+		sec_margin = ((int)usec_margin / 1000000) + 1;
+		if ((tv2->tv_sec - tv1->tv_sec) > sec_margin)
+			return -1;
+		usecs_diff = (tv2->tv_sec - tv1->tv_sec) * 1000000ULL +
+			(tv2->tv_usec - tv1->tv_usec);
+		ret = -1;
+	} else if (tv1->tv_sec > tv2->tv_sec) {
+		sec_margin = ((int)usec_margin / 1000000) + 1;
+		if ((tv1->tv_sec - tv2->tv_sec) > sec_margin)
+			return 1;
+		usecs_diff = (tv1->tv_sec - tv2->tv_sec) * 1000000ULL +
+			(tv1->tv_usec - tv2->tv_usec);
+		ret = 1;
+	} else if (tv1->tv_usec < tv2->tv_usec) {
+		usecs_diff = tv2->tv_usec - tv1->tv_usec;
+		ret = -1;
+	} else {
+		usecs_diff = tv1->tv_usec - tv2->tv_usec;
+		ret = 1;
+	}
+	return usecs_diff > usec_margin ? ret : 0;
 }
 
 int timeval_diff_msecs(const struct timeval *tv1, const struct timeval *tv2)