[LTP] [RFC] [PATCH 2/2] tst_timer.h: Make time conversions saturated
Cyril Hrubis
chrubis@suse.cz
Tue Jun 13 18:00:34 CEST 2017
The conversions of struct timeval and struct timespec to us and ms are
now saturated so instead of overflowing/underflowing long long these
return LLONG_MAX/LLONG_MIN.
This commit also adds tst_us_to_timespec(), tst_ms_to_timespec() and
newlib_tests/tst_timer test to assert that the saturated conversion
actually works.
Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
include/tst_timer.h | 129 ++++++++++++++++++++++++++++++++++++++++---
lib/newlib_tests/.gitignore | 1 +
lib/newlib_tests/tst_timer.c | 126 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 248 insertions(+), 8 deletions(-)
create mode 100644 lib/newlib_tests/tst_timer.c
diff --git a/include/tst_timer.h b/include/tst_timer.h
index f294b0eb7..b1f595bd4 100644
--- a/include/tst_timer.h
+++ b/include/tst_timer.h
@@ -33,37 +33,124 @@
#include <sys/time.h>
#include <time.h>
+#include <limits.h>
+
+#define LLONG_MAX_USEC_OVERFLOW(sec, usec) \
+ (sizeof(time_t) == 8 && ((sec == LLONG_MAX/1000000 && usec > LLONG_MAX%1000000) \
+ || (sec > LLONG_MAX/1000000)))
+
+#define LLONG_MIN_USEC_UNDERFLOW(sec, usec) \
+ ((sec == LLONG_MIN/1000000 && usec < LLONG_MIN%1000000) \
+ || (sec < LLONG_MIN/1000000))
+
+#define LLONG_MAX_MSEC_OVERFLOW(sec, msec) \
+ ((sec == LLONG_MAX/1000 && msec > LLONG_MAX%1000) \
+ || (sec > LLONG_MAX/1000))
+
+#define LLONG_MIN_MSEC_UNDERFLOW(sec, msec) \
+ ((sec == LLONG_MIN/1000 && msec < LLONG_MIN%1000) \
+ || (sec < LLONG_MIN/1000))
+
+/*
+ * Normalize timespec so that abs(tv_nsec) is smaller than 1s.
+ */
+static inline struct timespec tst_normalize_timespec(struct timespec t)
+{
+ t.tv_sec += t.tv_nsec / 1000000000;
+ t.tv_nsec %= 1000000000;
+
+ return t;
+}
+
+/*
+ * Normalize timeval so that abs(tv_usec) is smaller than 1s.
+ */
+static inline struct timeval tst_normalize_timeval(struct timeval t)
+{
+ t.tv_sec += t.tv_usec / 1000000;
+ t.tv_usec %= 1000000;
+
+ return t;
+}
/*
- * Converts timespec to microseconds.
+ * Saturated conversion from timespec to microseconds.
*/
static inline long long tst_timespec_to_us(struct timespec t)
{
- return t.tv_sec * 1000000 + (t.tv_nsec + 500) / 1000;
+ t = tst_normalize_timespec(t);
+
+ long long usec = (t.tv_nsec + 500) / 1000;
+
+#if LONG_MAX > 0xffffffff
+ if (LLONG_MAX_USEC_OVERFLOW(t.tv_sec, usec))
+ return LLONG_MAX;
+
+ if (LLONG_MIN_USEC_UNDERFLOW(t.tv_sec, usec))
+ return LLONG_MIN;
+#endif
+
+ return t.tv_sec * 1000000 + usec;
}
/*
- * Converts timespec to miliseconds.
+ * Saturated conversion from timespec to miliseconds.
*/
static inline long long tst_timespec_to_ms(struct timespec t)
{
- return t.tv_sec * 1000 + (t.tv_nsec + 500000) / 1000000;
+ t = tst_normalize_timespec(t);
+
+ long long msec = (t.tv_nsec + 500000) / 1000000;
+
+#if LONG_MAX > 0xffffffff
+ if (LLONG_MAX_MSEC_OVERFLOW(t.tv_sec, msec))
+ return LLONG_MAX;
+
+ if (LLONG_MIN_MSEC_UNDERFLOW(t.tv_sec, msec))
+ return LLONG_MIN;
+#endif
+
+ return t.tv_sec * 1000 + msec;
}
/*
- * Converts timeval to microseconds.
+ * Saturated conversion from timeval to microseconds.
*/
static inline long long tst_timeval_to_us(struct timeval t)
{
- return t.tv_sec * 1000000 + t.tv_usec;
+ t = tst_normalize_timeval(t);
+
+ long long usec = t.tv_usec;
+
+#if LONG_MAX > 0xffffffff
+ if (LLONG_MAX_USEC_OVERFLOW(t.tv_sec, usec))
+ return LLONG_MAX;
+
+ if (LLONG_MIN_USEC_UNDERFLOW(t.tv_sec, usec))
+ return LLONG_MIN;
+#endif
+
+ return t.tv_sec * 1000000 + usec;
}
/*
- * Converts timeval to miliseconds.
+ * Saturated conversion from timeval to miliseconds.
*/
static inline long long tst_timeval_to_ms(struct timeval t)
{
- return t.tv_sec * 1000 + (t.tv_usec + 500) / 1000;
+ t = tst_normalize_timeval(t);
+
+ long long msec = (t.tv_usec + 500) / 1000;
+
+#if LONG_MAX > 0xffffffff
+ if (LLONG_MAX_MSEC_OVERFLOW(t.tv_sec, msec))
+ return LLONG_MAX;
+
+ if (LLONG_MIN_MSEC_UNDERFLOW(t.tv_sec, msec))
+ return LLONG_MIN;
+#endif
+
+ return t.tv_sec * 1000 + msec;
}
/*
@@ -93,6 +180,32 @@ static inline struct timeval tst_us_to_timeval(long long us)
}
/*
+ * Converts ms to struct timespec
+ */
+static inline struct timespec tst_ms_to_timespec(long long ms)
+{
+ struct timespec ret;
+
+ ret.tv_sec = ms / 1000;
+ ret.tv_nsec = (ms % 1000) * 1000000;
+
+ return ret;
+}
+
+/*
+ * Converts us to struct timespec
+ */
+static inline struct timespec tst_us_to_timespec(long long us)
+{
+ struct timespec ret;
+
+ ret.tv_sec = us / 1000000;
+ ret.tv_nsec = (us % 1000000) * 1000;
+
+ return ret;
+}
+
+/*
* Comparsions
*/
static inline int tst_timespec_lt(struct timespec t1, struct timespec t2)
diff --git a/lib/newlib_tests/.gitignore b/lib/newlib_tests/.gitignore
index 8e120074e..0405c3e2e 100644
--- a/lib/newlib_tests/.gitignore
+++ b/lib/newlib_tests/.gitignore
@@ -15,3 +15,4 @@ test14
tst_device
tst_safe_fileops
tst_res_hexd
+tst_timer
diff --git a/lib/newlib_tests/tst_timer.c b/lib/newlib_tests/tst_timer.c
new file mode 100644
index 000000000..d29ac263b
--- /dev/null
+++ b/lib/newlib_tests/tst_timer.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ /*
+ * Tests saturated timeval and timespec to us and ms conversions.
+ */
+
+#include "tst_test.h"
+#include "tst_timer.h"
+
+static void timeval_overflow_us_test(long long us_add)
+{
+ struct timeval tv;
+ long long us;
+
+ tst_res(TINFO, "Testing for timeval overflow by %llius", us_add);
+
+ tv = tst_us_to_timeval(LLONG_MAX);
+ tv.tv_usec += us_add;
+
+ tst_res(TINFO, "tv_sec=%li tv_usec=%li", tv.tv_sec, tv.tv_usec);
+
+ us = tst_timeval_to_us(tv);
+
+ long long expected = LLONG_MAX;
+
+ if (us_add < 0)
+ expected = LLONG_MAX + us_add;
+
+ if (us != expected)
+ tst_res(TFAIL, "Got %lli, expected %lli", us, expected);
+ else
+ tst_res(TPASS, "Got %lli", expected);
+}
+
+static void timeval_underflow_us_test(long long us_add)
+{
+ struct timeval tv;
+ long long us;
+
+ tst_res(TINFO, "Testing for timeval underflow by %llius", us_add);
+
+ tv = tst_us_to_timeval(LLONG_MIN);
+ tv.tv_usec += us_add;
+
+ tst_res(TINFO, "tv_sec=%li tv_usec=%li", tv.tv_sec, tv.tv_usec);
+
+ us = tst_timeval_to_us(tv);
+
+ long long expected = LLONG_MIN;
+
+ if (us_add > 0)
+ expected = LLONG_MIN + us_add;
+
+ if (us != expected)
+ tst_res(TFAIL, "Got %lli, expected %lli", us, expected);
+ else
+ tst_res(TPASS, "Got %lli", expected);
+}
+
+static void timespec_overflow_us_test(long long us_add)
+{
+ struct timespec ts;
+ long long us;
+
+ tst_res(TINFO, "Testing for timespec overflow by %llius", us_add);
+
+ ts = tst_us_to_timespec(LLONG_MAX);
+ ts.tv_nsec += us_add * 1000;
+
+ tst_res(TINFO, "tv_sec=%li tv_nsec=%li", ts.tv_sec, ts.tv_nsec);
+
+ us = tst_timespec_to_us(ts);
+
+ long long expected = LLONG_MAX;
+
+ if (us_add < 0)
+ expected = LLONG_MAX + us_add;
+
+ if (us != expected)
+ tst_res(TFAIL, "Got %lli, expected %lli", us, expected);
+ else
+ tst_res(TPASS, "Got %lli", expected);
+}
+
+static void do_test(void)
+{
+ if (sizeof(time_t) == 4)
+ tst_brk(TCONF, "sizeof(time_t) == 4");
+
+ timeval_overflow_us_test(0);
+ timeval_overflow_us_test(1);
+ timeval_overflow_us_test(-1);
+ timeval_overflow_us_test(1000000);
+ timeval_overflow_us_test(-1000000);
+
+ timeval_underflow_us_test(0);
+ timeval_underflow_us_test(1);
+ timeval_underflow_us_test(-1);
+ timeval_underflow_us_test(1000000);
+ timeval_underflow_us_test(-1000000);
+
+ timespec_overflow_us_test(0);
+ timespec_overflow_us_test(1);
+ timespec_overflow_us_test(-1);
+ timespec_overflow_us_test(100000);
+ timespec_overflow_us_test(-100000);
+}
+
+static struct tst_test test = {
+ .test_all = do_test,
+};
--
2.13.0
More information about the ltp
mailing list