From: Dave Hart Date: Wed, 26 Jan 2011 16:50:03 +0000 (+0000) Subject: Fix off-by-one bug in format_time_fraction() introduced by hart@ntp.org. X-Git-Tag: NTP_4_2_7P126~2^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dc9cf4e5a72d8ac99433950847be4e9ebf3d413c;p=thirdparty%2Fntp.git Fix off-by-one bug in format_time_fraction() introduced by hart@ntp.org. Remove abs(prec) <= 9 requirement from format_time_fraction(). Add more time{spec|val}_tostr() tests. bk: 4d4050bbhFJeWxtWxx9_y5W7N_xN3A --- diff --git a/include/timetoa.h b/include/timetoa.h index e766d1300..686928ab4 100644 --- a/include/timetoa.h +++ b/include/timetoa.h @@ -65,12 +65,10 @@ typedef unsigned long long u_time; * * secs - integral seconds of time stamp * frac - fractional units - * prec - log10 of units per second (3=miliseconds, 6=microseconds,..) + * prec - log10 of units per second (3=milliseconds, 6=microseconds,..) * or in other words: the number decimal digits required. - * If prec is < 0, abs(prec) is taken and for the precision - * and 'secs' is treated as an unsigned value. - * - * abs(prec) must be in [1 .. 9], or only the seconds are formatted. + * If prec is < 0, abs(prec) is taken for the precision and secs + * is treated as an unsigned value. * * The function will eventually normalise the fraction and adjust the * seconds accordingly. diff --git a/libntp/timetoa.c b/libntp/timetoa.c index bcacf095d..2f0a7daa3 100644 --- a/libntp/timetoa.c +++ b/libntp/timetoa.c @@ -20,9 +20,11 @@ #include "config.h" +#include #include #include "timetoa.h" +#include "ntp_assert.h" #include "lib_strbuf.h" /* @@ -49,19 +51,16 @@ format_time_fraction( int prec ) { - static const long limit[10] = { - 1, - 10, 100, 1000, - 10000, 100000, 1000000, - 10000000, 100000000, 1000000000 - }; - char * cp; u_time ttmp; /* unsigned storage for seconds */ + int i; + long fraclimit; int notneg; /* flag for non-negative value */ const char * fmt; ldiv_t qr; + DEBUG_REQUIRE(prec != 0); + LIB_GETBUF(cp); ttmp = (u_time)secs; fmt = "-%" UTIME_FORMAT ".%0*ld"; @@ -69,43 +68,36 @@ format_time_fraction( /* check if we need signed or unsigned mode */ notneg = (prec < 0); prec = abs(prec); - if (prec <= 0 || prec > COUNTOF(limit)) { - if (notneg) - fmt = "%" UTIME_FORMAT; - else - fmt = "%" TIME_FORMAT; - snprintf(cp, LIB_BUFLENGTH, fmt, secs); - - return cp; - } + /* fraclimit = (long)pow(10, prec); */ + for (fraclimit = 10, i = 1; i < prec; i++) + fraclimit *= 10; + DEBUG_INSIST(fraclimit > 0); /* * Since conversion to string uses lots of divisions anyway, * there's no big extra penalty for normalisation. We do it for * consistency. */ - if (frac < 0 || frac >= limit[prec]) { - qr = ldiv(frac, limit[prec]); + if (frac < 0 || frac >= fraclimit) { + qr = ldiv(frac, fraclimit); if (qr.rem < 0) { qr.quot--; - qr.rem += limit[prec]; + qr.rem += fraclimit; } ttmp += (time_t)qr.quot; frac = qr.rem; } - /* - * Get the absolute value of the time stamp. - */ + /* Get the absolute value of the time stamp. */ notneg = notneg || ((time_t)ttmp >= 0); - if (!notneg) { + if (notneg) { + fmt++; /* skip sign char in format string */ + } else { ttmp = ~ttmp; if (frac != 0) - frac = limit[prec] - frac; + frac = fraclimit - frac; else ttmp += 1; - } else { - fmt++; /* skip sign char in format string */ } /* finally format the data and return the result */ diff --git a/tests/libntp/tspecops.cpp b/tests/libntp/tspecops.cpp index 9a57b4550..008349298 100644 --- a/tests/libntp/tspecops.cpp +++ b/tests/libntp/tspecops.cpp @@ -347,8 +347,10 @@ TEST_F(timespecTest, ToString) { { 2, 0, "2.000000000" }, {-2, 0, "-2.000000000" }, { 0, 1, "0.000000001" }, + { 0,-1, "-0.000000001" }, { 1,-1, "0.999999999" }, - {-1, 1, "-0.999999999" } + {-1, 1, "-0.999999999" }, + {-1,-1, "-1.000000001" }, }; for (int i = 0; i < COUNTOF(data); i++) { TSPEC a(data[i].sec, data[i].nsec); diff --git a/tests/libntp/tvalops.cpp b/tests/libntp/tvalops.cpp index 4ca17cd6b..cb43123af 100644 --- a/tests/libntp/tvalops.cpp +++ b/tests/libntp/tvalops.cpp @@ -382,8 +382,10 @@ TEST_F(timevalTest, ToString) { { 2, 0, "2.000000" }, {-2, 0, "-2.000000" }, { 0, 1, "0.000001" }, + { 0,-1, "-0.000001" }, { 1,-1, "0.999999" }, - {-1, 1, "-0.999999" } + {-1, 1, "-0.999999" }, + {-1,-1, "-1.000001" }, }; for (int i = 0; i < COUNTOF(data); ++i) { timeval_wrap a(data[i].sec, data[i].usec);