diff options
author | glebius <glebius@FreeBSD.org> | 2015-10-22 19:42:57 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2015-10-22 19:42:57 +0000 |
commit | 9163b6ba3bf49312e356f13c0a8208d05a79e484 (patch) | |
tree | c69f4aae895073471547d394a727baaaa68d758b /contrib/ntp/libntp | |
parent | bb011941f0bd9e2ce1ade58a6f1f25eeb2141c9d (diff) | |
parent | aae1e7d66cee27b1a209ea5b8ca21ed12e129103 (diff) | |
download | FreeBSD-src-9163b6ba3bf49312e356f13c0a8208d05a79e484.zip FreeBSD-src-9163b6ba3bf49312e356f13c0a8208d05a79e484.tar.gz |
MFV ntp-4.2.8p4 (r289715)
Security: VuXML: c4a18a12-77fc-11e5-a687-206a8a720317
Security: CVE-2015-7871
Security: CVE-2015-7855
Security: CVE-2015-7854
Security: CVE-2015-7853
Security: CVE-2015-7852
Security: CVE-2015-7851
Security: CVE-2015-7850
Security: CVE-2015-7849
Security: CVE-2015-7848
Security: CVE-2015-7701
Security: CVE-2015-7703
Security: CVE-2015-7704, CVE-2015-7705
Security: CVE-2015-7691, CVE-2015-7692, CVE-2015-7702
Security: http://support.ntp.org/bin/view/Main/SecurityNotice#October_2015_NTP_Security_Vulner
Sponsored by: Nginx, Inc.
Diffstat (limited to 'contrib/ntp/libntp')
-rw-r--r-- | contrib/ntp/libntp/Makefile.in | 4 | ||||
-rw-r--r-- | contrib/ntp/libntp/atolfp.c | 2 | ||||
-rw-r--r-- | contrib/ntp/libntp/audio.c | 13 | ||||
-rw-r--r-- | contrib/ntp/libntp/authkeys.c | 12 | ||||
-rw-r--r-- | contrib/ntp/libntp/authreadkeys.c | 89 | ||||
-rw-r--r-- | contrib/ntp/libntp/caljulian.c | 2 | ||||
-rw-r--r-- | contrib/ntp/libntp/caltontp.c | 14 | ||||
-rw-r--r-- | contrib/ntp/libntp/decodenetnum.c | 9 | ||||
-rw-r--r-- | contrib/ntp/libntp/emalloc.c | 2 | ||||
-rw-r--r-- | contrib/ntp/libntp/icom.c | 28 | ||||
-rw-r--r-- | contrib/ntp/libntp/machines.c | 6 | ||||
-rw-r--r-- | contrib/ntp/libntp/msyslog.c | 24 | ||||
-rw-r--r-- | contrib/ntp/libntp/ntp_calendar.c | 786 | ||||
-rw-r--r-- | contrib/ntp/libntp/ntp_intres.c | 24 | ||||
-rw-r--r-- | contrib/ntp/libntp/ntp_lineedit.c | 2 | ||||
-rw-r--r-- | contrib/ntp/libntp/ntp_rfc2553.c | 2 | ||||
-rw-r--r-- | contrib/ntp/libntp/ntp_worker.c | 2 | ||||
-rw-r--r-- | contrib/ntp/libntp/prettydate.c | 2 | ||||
-rw-r--r-- | contrib/ntp/libntp/recvbuff.c | 2 | ||||
-rw-r--r-- | contrib/ntp/libntp/socket.c | 4 | ||||
-rw-r--r-- | contrib/ntp/libntp/socktohost.c | 2 | ||||
-rw-r--r-- | contrib/ntp/libntp/statestr.c | 2 |
22 files changed, 653 insertions, 380 deletions
diff --git a/contrib/ntp/libntp/Makefile.in b/contrib/ntp/libntp/Makefile.in index b4b1d81..6e40cd4 100644 --- a/contrib/ntp/libntp/Makefile.in +++ b/contrib/ntp/libntp/Makefile.in @@ -117,6 +117,7 @@ am__aclocal_m4_deps = $(top_srcdir)/sntp/libopts/m4/libopts.m4 \ $(top_srcdir)/sntp/m4/ntp_locinfo.m4 \ $(top_srcdir)/sntp/m4/ntp_openssl.m4 \ $(top_srcdir)/sntp/m4/ntp_pkg_config.m4 \ + $(top_srcdir)/sntp/m4/ntp_problemtests.m4 \ $(top_srcdir)/sntp/m4/ntp_prog_cc.m4 \ $(top_srcdir)/sntp/m4/ntp_rlimit.m4 \ $(top_srcdir)/sntp/m4/ntp_sntp.m4 \ @@ -345,6 +346,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BUILD_THREAD = @BUILD_THREAD@ CALC_TICKADJ_DB = @CALC_TICKADJ_DB@ CALC_TICKADJ_DL = @CALC_TICKADJ_DL@ CALC_TICKADJ_DS = @CALC_TICKADJ_DS@ @@ -353,6 +355,7 @@ CALC_TICKADJ_NI = @CALC_TICKADJ_NI@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ +CFLAGS_LIBEVENT = @CFLAGS_LIBEVENT@ CFLAGS_NTP = @CFLAGS_NTP@ CHUTEST = @CHUTEST@ CONFIG_SHELL = @CONFIG_SHELL@ @@ -414,6 +417,7 @@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LSCF = @LSCF@ +LTHREAD_LIBS = @LTHREAD_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MAKE_ADJTIMED = @MAKE_ADJTIMED@ diff --git a/contrib/ntp/libntp/atolfp.c b/contrib/ntp/libntp/atolfp.c index 3a65f6b..9a2f691 100644 --- a/contrib/ntp/libntp/atolfp.c +++ b/contrib/ntp/libntp/atolfp.c @@ -40,7 +40,7 @@ atolfp( int isneg; static const char *digits = "0123456789"; - NTP_REQUIRE(str != NULL); + REQUIRE(str != NULL); isneg = 0; dec_i = dec_f = 0; diff --git a/contrib/ntp/libntp/audio.c b/contrib/ntp/libntp/audio.c index 6f2262c..726dfa9 100644 --- a/contrib/ntp/libntp/audio.c +++ b/contrib/ntp/libntp/audio.c @@ -377,7 +377,9 @@ audio_gain( #ifdef PCM_STYLE_SOUND int l, r; - rval = 0; +# ifdef GCC + rval = 0; /* GCC thinks rval is used uninitialized */ +# endif r = l = 100 * gain / 255; /* Normalize to 0-100 */ # ifdef DEBUG @@ -392,10 +394,11 @@ audio_gain( if (cf_agc[0] != '\0') rval = ioctl(ctl_fd, agc, &l); else - if (2 == port) - rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_LINE, &l); - else - rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_MIC, &l); + rval = ioctl(ctl_fd + , (2 == port) + ? SOUND_MIXER_WRITE_LINE + : SOUND_MIXER_WRITE_MIC + , &l); if (-1 == rval) { printf("audio_gain: agc write: %s\n", strerror(errno)); return rval; diff --git a/contrib/ntp/libntp/authkeys.c b/contrib/ntp/libntp/authkeys.c index 68771ff..667ca29 100644 --- a/contrib/ntp/libntp/authkeys.c +++ b/contrib/ntp/libntp/authkeys.c @@ -534,6 +534,12 @@ MD5auth_setkey( bucket = &key_hash[KEYHASH(keyno)]; for (sk = *bucket; sk != NULL; sk = sk->hlink) { if (keyno == sk->keyid) { + /* TALOS-CAN-0054: make sure we have a new buffer! */ + if (NULL != sk->secret) { + memset(sk->secret, 0, sk->secretsize); + free(sk->secret); + } + sk->secret = emalloc(len); sk->type = (u_short)keytype; secretsize = len; sk->secretsize = (u_short)secretsize; @@ -593,12 +599,14 @@ auth_delkeys(void) } /* - * Don't lose info as to which keys are trusted. + * Don't lose info as to which keys are trusted. Make + * sure there are no dangling pointers! */ if (KEY_TRUSTED & sk->flags) { if (sk->secret != NULL) { - memset(sk->secret, '\0', sk->secretsize); + memset(sk->secret, 0, sk->secretsize); free(sk->secret); + sk->secret = NULL; /* TALOS-CAN-0054 */ } sk->secretsize = 0; sk->lifetime = 0; diff --git a/contrib/ntp/libntp/authreadkeys.c b/contrib/ntp/libntp/authreadkeys.c index e8ddc94..1c4c07c 100644 --- a/contrib/ntp/libntp/authreadkeys.c +++ b/contrib/ntp/libntp/authreadkeys.c @@ -62,6 +62,40 @@ nexttok( } +/* TALOS-CAN-0055: possibly DoS attack by setting the key file to the + * log file. This is hard to prevent (it would need to check two files + * to be the same on the inode level, which will not work so easily with + * Windows or VMS) but we can avoid the self-amplification loop: We only + * log the first 5 errors, silently ignore the next 10 errors, and give + * up when when we have found more than 15 errors. + * + * This avoids the endless file iteration we will end up with otherwise, + * and also avoids overflowing the log file. + * + * Nevertheless, once this happens, the keys are gone since this would + * require a save/swap strategy that is not easy to apply due to the + * data on global/static level. + */ + +static const size_t nerr_loglimit = 5u; +static const size_t nerr_maxlimit = 15; + +static void log_maybe(size_t*, const char*, ...) NTP_PRINTF(2, 3); + +static void +log_maybe( + size_t *pnerr, + const char *fmt , + ...) +{ + va_list ap; + if (++(*pnerr) <= nerr_loglimit) { + va_start(ap, fmt); + mvsyslog(LOG_ERR, fmt, ap); + va_end(ap); + } +} + /* * authreadkeys - (re)read keys from a file. */ @@ -79,7 +113,7 @@ authreadkeys( u_char keystr[32]; /* Bug 2537 */ size_t len; size_t j; - + size_t nerr; /* * Open file. Complain and return if it can't be opened. */ @@ -99,7 +133,10 @@ authreadkeys( /* * Now read lines from the file, looking for key entries */ + nerr = 0; while ((line = fgets(buf, sizeof buf, fp)) != NULL) { + if (nerr > nerr_maxlimit) + break; token = nexttok(&line); if (token == NULL) continue; @@ -109,15 +146,16 @@ authreadkeys( */ keyno = atoi(token); if (keyno == 0) { - msyslog(LOG_ERR, - "authreadkeys: cannot change key %s", token); + log_maybe(&nerr, + "authreadkeys: cannot change key %s", + token); continue; } if (keyno > NTP_MAXKEY) { - msyslog(LOG_ERR, - "authreadkeys: key %s > %d reserved for Autokey", - token, NTP_MAXKEY); + log_maybe(&nerr, + "authreadkeys: key %s > %d reserved for Autokey", + token, NTP_MAXKEY); continue; } @@ -126,8 +164,9 @@ authreadkeys( */ token = nexttok(&line); if (token == NULL) { - msyslog(LOG_ERR, - "authreadkeys: no key type for key %d", keyno); + log_maybe(&nerr, + "authreadkeys: no key type for key %d", + keyno); continue; } #ifdef OPENSSL @@ -139,13 +178,15 @@ authreadkeys( */ keytype = keytype_from_text(token, NULL); if (keytype == 0) { - msyslog(LOG_ERR, - "authreadkeys: invalid type for key %d", keyno); + log_maybe(&nerr, + "authreadkeys: invalid type for key %d", + keyno); continue; } if (EVP_get_digestbynid(keytype) == NULL) { - msyslog(LOG_ERR, - "authreadkeys: no algorithm for key %d", keyno); + log_maybe(&nerr, + "authreadkeys: no algorithm for key %d", + keyno); continue; } #else /* !OPENSSL follows */ @@ -155,8 +196,9 @@ authreadkeys( * 'm' for compatibility. */ if (!(*token == 'M' || *token == 'm')) { - msyslog(LOG_ERR, - "authreadkeys: invalid type for key %d", keyno); + log_maybe(&nerr, + "authreadkeys: invalid type for key %d", + keyno); continue; } keytype = KEY_TYPE_MD5; @@ -170,8 +212,8 @@ authreadkeys( */ token = nexttok(&line); if (token == NULL) { - msyslog(LOG_ERR, - "authreadkeys: no key for key %d", keyno); + log_maybe(&nerr, + "authreadkeys: no key for key %d", keyno); continue; } len = strlen(token); @@ -195,13 +237,24 @@ authreadkeys( keystr[j / 2] = temp << 4; } if (j < jlim) { - msyslog(LOG_ERR, - "authreadkeys: invalid hex digit for key %d", keyno); + log_maybe(&nerr, + "authreadkeys: invalid hex digit for key %d", + keyno); continue; } MD5auth_setkey(keyno, keytype, keystr, jlim / 2); } } fclose(fp); + if (nerr > nerr_maxlimit) { + msyslog(LOG_ERR, + "authreadkeys: emergency break after %u errors", + nerr); + return (0); + } else if (nerr > nerr_loglimit) { + msyslog(LOG_ERR, + "authreadkeys: found %u more error(s)", + nerr - nerr_loglimit); + } return (1); } diff --git a/contrib/ntp/libntp/caljulian.c b/contrib/ntp/libntp/caljulian.c index 6463699..4a30603 100644 --- a/contrib/ntp/libntp/caljulian.c +++ b/contrib/ntp/libntp/caljulian.c @@ -28,7 +28,7 @@ caljulian( ntpcal_split split; - NTP_INSIST(NULL != jt); + INSIST(NULL != jt); /* * Unfold ntp time around current time into NTP domain. Split diff --git a/contrib/ntp/libntp/caltontp.c b/contrib/ntp/libntp/caltontp.c index 4246a6a..808c94c 100644 --- a/contrib/ntp/libntp/caltontp.c +++ b/contrib/ntp/libntp/caltontp.c @@ -40,14 +40,14 @@ caltontp( int32_t eraday; /* CE Rata Die number */ vint64 ntptime;/* resulting NTP time */ - NTP_INSIST(jt != NULL); + REQUIRE(jt != NULL); - NTP_REQUIRE(jt->month <= 13); /* permit month 0..13! */ - NTP_REQUIRE(jt->monthday <= 32); - NTP_REQUIRE(jt->yearday <= 366); - NTP_REQUIRE(jt->hour <= 24); - NTP_REQUIRE(jt->minute <= MINSPERHR); - NTP_REQUIRE(jt->second <= SECSPERMIN); + REQUIRE(jt->month <= 13); /* permit month 0..13! */ + REQUIRE(jt->monthday <= 32); + REQUIRE(jt->yearday <= 366); + REQUIRE(jt->hour <= 24); + REQUIRE(jt->minute <= MINSPERHR); + REQUIRE(jt->second <= SECSPERMIN); /* * First convert the date to he corresponding RataDie diff --git a/contrib/ntp/libntp/decodenetnum.c b/contrib/ntp/libntp/decodenetnum.c index 187d5ca..35b908f 100644 --- a/contrib/ntp/libntp/decodenetnum.c +++ b/contrib/ntp/libntp/decodenetnum.c @@ -35,8 +35,11 @@ decodenetnum( char *np; char name[80]; - NTP_REQUIRE(num != NULL); - NTP_REQUIRE(strlen(num) < sizeof(name)); + REQUIRE(num != NULL); + + if (strlen(num) >= sizeof(name)) { + return 0; + } port_str = NULL; if ('[' != num[0]) { @@ -72,7 +75,7 @@ decodenetnum( err = getaddrinfo(cp, "ntp", &hints, &ai); if (err != 0) return 0; - NTP_INSIST(ai->ai_addrlen <= sizeof(*netnum)); + INSIST(ai->ai_addrlen <= sizeof(*netnum)); ZERO(*netnum); memcpy(netnum, ai->ai_addr, ai->ai_addrlen); freeaddrinfo(ai); diff --git a/contrib/ntp/libntp/emalloc.c b/contrib/ntp/libntp/emalloc.c index 95d293f..8b7ef99 100644 --- a/contrib/ntp/libntp/emalloc.c +++ b/contrib/ntp/libntp/emalloc.c @@ -76,8 +76,6 @@ ereallocz( * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <stdint.h> - /* * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW diff --git a/contrib/ntp/libntp/icom.c b/contrib/ntp/libntp/icom.c index 8070011..2e95db5 100644 --- a/contrib/ntp/libntp/icom.c +++ b/contrib/ntp/libntp/icom.c @@ -6,14 +6,16 @@ * frequency. All other parameters must be manually set before use. */ #include <config.h> -#include "icom.h" +#include <ntp_stdlib.h> +#include <ntp_tty.h> +#include <l_stdlib.h> +#include <icom.h> + #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <errno.h> -#include "ntp_tty.h" -#include "l_stdlib.h" #ifdef SYS_WINNT #undef write /* ports/winnt/include/config.h: #define write _write */ @@ -60,9 +62,14 @@ static void doublefreq (double, u_char *, int); /* * icom_freq(fd, ident, freq) - load radio frequency + * + * returns: + * 0 (ok) + * -1 (error) + * 1 (short write to device) */ int -icom_freq( /* returns 0 (ok), EIO (error) */ +icom_freq( int fd, /* file descriptor */ int ident, /* ICOM radio identifier */ double freq /* frequency (MHz) */ @@ -71,6 +78,7 @@ icom_freq( /* returns 0 (ok), EIO (error) */ u_char cmd[] = {PAD, PR, PR, 0, TX, V_SFREQ, 0, 0, 0, 0, FI, FI}; int temp; + int rc; cmd[3] = (char)ident; if (ident == IC735) @@ -78,9 +86,17 @@ icom_freq( /* returns 0 (ok), EIO (error) */ else temp = 5; doublefreq(freq * 1e6, &cmd[6], temp); - temp = write(fd, cmd, temp + 7); + rc = write(fd, cmd, temp + 7); + if (rc == -1) { + msyslog(LOG_ERR, "icom_freq: write() failed: %m"); + return -1; + } else if (rc != temp + 7) { + msyslog(LOG_ERR, "icom_freq: only wrote %d of %d bytes.", + rc, temp+7); + return 1; + } - return (0); + return 0; } diff --git a/contrib/ntp/libntp/machines.c b/contrib/ntp/libntp/machines.c index 43944f9..7a29ac0 100644 --- a/contrib/ntp/libntp/machines.c +++ b/contrib/ntp/libntp/machines.c @@ -40,7 +40,7 @@ struct hostent *gethostbyname(char *name) { struct hostent *host1; h_errno = 0; /* we are always successful!!! */ - host1 = (struct hostent *) malloc (sizeof(struct hostent)); + host1 = (struct hostent *) emalloc (sizeof(struct hostent)); host1->h_name = name; host1->h_addrtype = AF_INET; host1->h_aliases = name; @@ -54,7 +54,7 @@ struct hostent *gethostbyaddr(char *name, int size, int addr_type) { struct hostent *host1; h_errno = 0; /* we are always successful!!! */ - host1 = (struct hostent *) malloc (sizeof(struct hostent)); + host1 = (struct hostent *) emalloc (sizeof(struct hostent)); host1->h_name = name; host1->h_addrtype = AF_INET; host1->h_aliases = name; @@ -66,7 +66,7 @@ struct hostent *gethostbyaddr(char *name, int size, int addr_type) struct servent *getservbyname (char *name, char *type) { struct servent *serv1; - serv1 = (struct servent *) malloc (sizeof(struct servent)); + serv1 = (struct servent *) emalloc (sizeof(struct servent)); serv1->s_name = "ntp"; /* official service name */ serv1->s_aliases = NULL; /* alias list */ serv1->s_port = 123; /* port # */ diff --git a/contrib/ntp/libntp/msyslog.c b/contrib/ntp/libntp/msyslog.c index 283414d..cc8868f 100644 --- a/contrib/ntp/libntp/msyslog.c +++ b/contrib/ntp/libntp/msyslog.c @@ -38,7 +38,7 @@ char * syslog_abs_fname; #define INIT_NTP_SYSLOGMASK ~(u_int32)0 u_int32 ntp_syslogmask = INIT_NTP_SYSLOGMASK; -extern char * progname; +extern char const * progname; /* Declare the local functions */ void addto_syslog (int, const char *); @@ -145,8 +145,8 @@ addto_syslog( const char * msg ) { - static char * prevcall_progname; - static char * prog; + static char const * prevcall_progname; + static char const * prog; const char nl[] = "\n"; const char empty[] = ""; FILE * term_file; @@ -357,6 +357,18 @@ msyslog( addto_syslog(level, buf); } +void +mvsyslog( + int level, + const char * fmt, + va_list ap + ) +{ + char buf[1024]; + mvsnprintf(buf, sizeof(buf), fmt, ap); + addto_syslog(level, buf); +} + /* * Initialize the logging @@ -371,7 +383,7 @@ init_logging( ) { static int was_daemon; - const char * cp; + char * cp; const char * pname; /* @@ -402,7 +414,7 @@ init_logging( #ifdef SYS_WINNT /* strip ".exe" */ cp = strrchr(progname, '.'); if (NULL != cp && !strcasecmp(cp, ".exe")) - progname[cp - progname] = '\0'; + *cp = '\0'; #endif #if !defined(VMS) @@ -454,7 +466,7 @@ change_logfile( size_t octets; #endif /* POSIX */ - NTP_REQUIRE(fname != NULL); + REQUIRE(fname != NULL); log_fname = fname; /* diff --git a/contrib/ntp/libntp/ntp_calendar.c b/contrib/ntp/libntp/ntp_calendar.c index ff91fcf..ff6ead3 100644 --- a/contrib/ntp/libntp/ntp_calendar.c +++ b/contrib/ntp/libntp/ntp_calendar.c @@ -3,7 +3,55 @@ * * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project. * The contents of 'html/copyright.html' apply. + * + * -------------------------------------------------------------------- + * Some notes on the implementation: + * + * Calendar algorithms thrive on the division operation, which is one of + * the slowest numerical operations in any CPU. What saves us here from + * abysmal performance is the fact that all divisions are divisions by + * constant numbers, and most compilers can do this by a multiplication + * operation. But this might not work when using the div/ldiv/lldiv + * function family, because many compilers are not able to do inline + * expansion of the code with following optimisation for the + * constant-divider case. + * + * Also div/ldiv/lldiv are defined in terms of int/long/longlong, which + * are inherently target dependent. Nothing that could not be cured with + * autoconf, but still a mess... + * + * Furthermore, we need floor division in many places. C either leaves + * the division behaviour undefined (< C99) or demands truncation to + * zero (>= C99), so additional steps are required to make sure the + * algorithms work. The {l,ll}div function family is requested to + * truncate towards zero, which is also the wrong direction for our + * purpose. + * + * For all this, all divisions by constant are coded manually, even when + * there is a joined div/mod operation: The optimiser should sort that + * out, if possible. Most of the calculations are done with unsigned + * types, explicitely using two's complement arithmetics where + * necessary. This minimises the dependecies to compiler and target, + * while still giving reasonable to good performance. + * + * The implementation uses a few tricks that exploit properties of the + * two's complement: Floor division on negative dividents can be + * executed by using the one's complement of the divident. One's + * complement can be easily created using XOR and a mask. + * + * Finally, check for overflow conditions is minimal. There are only two + * calculation steps in the whole calendar that suffer from an internal + * overflow, and these conditions are checked: errno is set to EDOM and + * the results are clamped/saturated in this case. All other functions + * do not suffer from internal overflow and simply return the result + * truncated to 32 bits. + * + * This is a sacrifice made for execution speed. Since a 32-bit day + * counter covers +/- 5,879,610 years and the clamp limits the effective + * range to +/-2.9 million years, this should not pose a problem here. + * */ + #include <config.h> #include <sys/types.h> @@ -13,6 +61,33 @@ #include "ntp_fp.h" #include "ntp_unixtime.h" +/* For now, let's take the conservative approach: if the target property + * macros are not defined, check a few well-known compiler/architecture + * settings. Default is to assume that the representation of signed + * integers is unknown and shift-arithmetic-right is not available. + */ +#ifndef TARGET_HAS_2CPL +# if defined(__GNUC__) +# if defined(__i386__) || defined(__x86_64__) || defined(__arm__) +# define TARGET_HAS_2CPL 1 +# else +# define TARGET_HAS_2CPL 0 +# endif +# elif defined(_MSC_VER) +# if defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM) +# define TARGET_HAS_2CPL 1 +# else +# define TARGET_HAS_2CPL 0 +# endif +# else +# define TARGET_HAS_2CPL 0 +# endif +#endif + +#ifndef TARGET_HAS_SAR +# define TARGET_HAS_SAR 0 +#endif + /* *--------------------------------------------------------------------- * replacing the 'time()' function @@ -47,6 +122,117 @@ now(void) /* *--------------------------------------------------------------------- + * Get sign extension mask and unsigned 2cpl rep for a signed integer + *--------------------------------------------------------------------- + */ + +static inline uint32_t +int32_sflag( + const int32_t v) +{ +# if TARGET_HAS_2CPL && TARGET_HAS_SAR && SIZEOF_INT >= 4 + + /* Let's assume that shift is the fastest way to get the sign + * extension of of a signed integer. This might not always be + * true, though -- On 8bit CPUs or machines without barrel + * shifter this will kill the performance. So we make sure + * we do this only if 'int' has at least 4 bytes. + */ + return (uint32_t)(v >> 31); + +# else + + /* This should be a rather generic approach for getting a sign + * extension mask... + */ + return UINT32_C(0) - (uint32_t)(v < 0); + +# endif +} + +static inline uint32_t +int32_to_uint32_2cpl( + const int32_t v) +{ + uint32_t vu; + +# if TARGET_HAS_2CPL + + /* Just copy through the 32 bits from the signed value if we're + * on a two's complement target. + */ + vu = (uint32_t)v; + +# else + + /* Convert from signed int to unsigned int two's complement. Do + * not make any assumptions about the representation of signed + * integers, but make sure signed integer overflow cannot happen + * here. A compiler on a two's complement target *might* find + * out that this is just a complicated cast (as above), but your + * mileage might vary. + */ + if (v < 0) + vu = ~(uint32_t)(-(v + 1)); + else + vu = (uint32_t)v; + +# endif + + return vu; +} + +static inline int32_t +uint32_2cpl_to_int32( + const uint32_t vu) +{ + int32_t v; + +# if TARGET_HAS_2CPL + + /* Just copy through the 32 bits from the unsigned value if + * we're on a two's complement target. + */ + v = (int32_t)vu; + +# else + + /* Convert to signed integer, making sure signed integer + * overflow cannot happen. Again, the optimiser might or might + * not find out that this is just a copy of 32 bits on a target + * with two's complement representation for signed integers. + */ + if (vu > INT32_MAX) + v = -(int32_t)(~vu) - 1; + else + v = (int32_t)vu; + +# endif + + return v; +} + +/* Some of the calculations need to multiply the input by 4 before doing + * a division. This can cause overflow and strange results. Therefore we + * clamp / saturate the input operand. And since we do the calculations + * in unsigned int with an extra sign flag/mask, we only loose one bit + * of the input value range. + */ +static inline uint32_t +uint32_saturate( + uint32_t vu, + uint32_t mu) +{ + static const uint32_t limit = UINT32_MAX/4u; + if ((mu ^ vu) > limit) { + vu = mu ^ limit; + errno = EDOM; + } + return vu; +} + +/* + *--------------------------------------------------------------------- * Convert between 'time_t' and 'vint64' *--------------------------------------------------------------------- */ @@ -60,7 +246,7 @@ time_to_vint64( tt = *ptt; -#if SIZEOF_TIME_T <= 4 +# if SIZEOF_TIME_T <= 4 res.D_s.hi = 0; if (tt < 0) { @@ -70,11 +256,11 @@ time_to_vint64( res.D_s.lo = (uint32_t)tt; } -#elif defined(HAVE_INT64) +# elif defined(HAVE_INT64) res.q_s = tt; -#else +# else /* * shifting negative signed quantities is compiler-dependent, so * we better avoid it and do it all manually. And shifting more @@ -90,7 +276,7 @@ time_to_vint64( res.D_s.hi = (uint32_t)(tt >> 32); } -#endif +# endif return res; } @@ -103,19 +289,19 @@ vint64_to_time( { time_t res; -#if SIZEOF_TIME_T <= 4 +# if SIZEOF_TIME_T <= 4 res = (time_t)tv->D_s.lo; -#elif defined(HAVE_INT64) +# elif defined(HAVE_INT64) res = (time_t)tv->q_s; -#else +# else res = ((time_t)tv->d_s.hi << 32) | tv->D_s.lo; -#endif +# endif return res; } @@ -153,11 +339,11 @@ ntpcal_get_build_date( * problem. * */ -#ifdef MKREPRO_DATE +# ifdef MKREPRO_DATE static const char build[] = MKREPRO_TIME "/" MKREPRO_DATE; -#else +# else static const char build[] = __TIME__ "/" __DATE__; -#endif +# endif static const char mlist[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; char monstr[4]; @@ -167,16 +353,16 @@ ntpcal_get_build_date( * so using 'uint16_t' is contra-indicated! */ -#ifdef DEBUG +# ifdef DEBUG static int ignore = 0; -#endif +# endif ZERO(*jd); jd->year = 1970; jd->month = 1; jd->monthday = 1; -#ifdef DEBUG +# ifdef DEBUG /* check environment if build date should be ignored */ if (0 == ignore) { const char * envstr; @@ -185,7 +371,7 @@ ntpcal_get_build_date( } if (ignore > 1) return FALSE; -#endif +# endif if (6 == sscanf(build, "%hu:%hu:%hu/%3s %hu %hu", &hour, &minute, &second, monstr, &day, &year)) { @@ -254,37 +440,8 @@ static const uint16_t real_month_table[2][13] = { * (day number). This is the number of days elapsed since 0000-12-31 * in the proleptic Gregorian calendar. The begin of the Christian Era * (0001-01-01) is RD(1). - * - * - * Some notes on the implementation: - * - * Calendar algorithms thrive on the division operation, which is one of - * the slowest numerical operations in any CPU. What saves us here from - * abysmal performance is the fact that all divisions are divisions by - * constant numbers, and most compilers can do this by a multiplication - * operation. But this might not work when using the div/ldiv/lldiv - * function family, because many compilers are not able to do inline - * expansion of the code with following optimisation for the - * constant-divider case. - * - * Also div/ldiv/lldiv are defined in terms of int/long/longlong, which - * are inherently target dependent. Nothing that could not be cured with - * autoconf, but still a mess... - * - * Furthermore, we need floor division while C demands truncation to - * zero, so additional steps are required to make sure the algorithms - * work. - * - * For all this, all divisions by constant are coded manually, even when - * there is a joined div/mod operation: The optimiser should sort that - * out, if possible. - * - * Finally, the functions do not check for overflow conditions. This - * is a sacrifice made for execution speed; since a 32-bit day counter - * covers +/- 5,879,610 years, this should not pose a problem here. */ - /* * ================================================================== * @@ -363,22 +520,23 @@ ntpcal_periodic_extend( * Get absolute difference as unsigned quantity and * the complement flag. This is done by always * subtracting the smaller value from the bigger - * one. This implementation works only on a two's - * complement machine! + * one. */ if (value >= pivot) { - diff = (uint32_t)value - (uint32_t)pivot; + diff = int32_to_uint32_2cpl(value) + - int32_to_uint32_2cpl(pivot); } else { - diff = (uint32_t)pivot - (uint32_t)value; + diff = int32_to_uint32_2cpl(pivot) + - int32_to_uint32_2cpl(value); cpl ^= 1; } diff %= (uint32_t)cycle; if (diff) { if (cpl) - diff = cycle - diff; + diff = (uint32_t)cycle - diff; if (neg) diff = ~diff + 1; - pivot += diff; + pivot += uint32_2cpl_to_int32(diff); } } return pivot; @@ -405,7 +563,7 @@ ntpcal_ntp_to_time( { vint64 res; -#ifdef HAVE_INT64 +# if defined(HAVE_INT64) res.q_s = (pivot != NULL) ? *pivot @@ -415,7 +573,7 @@ ntpcal_ntp_to_time( ntp -= res.D_s.lo; /* cycle difference */ res.Q_s += (uint64_t)ntp; /* get expanded time */ -#else /* no 64bit scalars */ +# else /* no 64bit scalars */ time_t tmp; @@ -428,7 +586,7 @@ ntpcal_ntp_to_time( ntp -= res.D_s.lo; /* cycle difference */ M_ADD(res.D_s.hi, res.D_s.lo, 0, ntp); -#endif /* no 64bit scalars */ +# endif /* no 64bit scalars */ return res; } @@ -454,7 +612,7 @@ ntpcal_ntp_to_ntp( { vint64 res; -#ifdef HAVE_INT64 +# if defined(HAVE_INT64) res.q_s = (pivot) ? *pivot @@ -464,7 +622,7 @@ ntpcal_ntp_to_ntp( ntp -= res.D_s.lo; /* cycle difference */ res.Q_s += (uint64_t)ntp; /* get expanded time */ -#else /* no 64bit scalars */ +# else /* no 64bit scalars */ time_t tmp; @@ -477,7 +635,7 @@ ntpcal_ntp_to_ntp( ntp -= res.D_s.lo; /* cycle difference */ M_ADD(res.D_s.hi, res.D_s.lo, 0, ntp); -#endif /* no 64bit scalars */ +# endif /* no 64bit scalars */ return res; } @@ -505,78 +663,75 @@ ntpcal_daysplit( ) { ntpcal_split res; + uint32_t Q; + +# if defined(HAVE_INT64) + + /* Manual floor division by SECSPERDAY. This uses the one's + * complement trick, too, but without an extra flag value: The + * flag would be 64bit, and that's a bit of overkill on a 32bit + * target that has to use a register pair for a 64bit number. + */ + if (ts->q_s < 0) + Q = ~(uint32_t)(~ts->Q_s / SECSPERDAY); + else + Q = (uint32_t)(ts->Q_s / SECSPERDAY); -#ifdef HAVE_INT64 +# else - /* manual floor division by SECSPERDAY */ - res.hi = (int32_t)(ts->q_s / SECSPERDAY); - res.lo = (int32_t)(ts->q_s % SECSPERDAY); - if (res.lo < 0) { - res.hi -= 1; - res.lo += SECSPERDAY; - } + uint32_t ah, al, sflag, A; -#else + /* get operand into ah/al (either ts or ts' one's complement, + * for later floor division) + */ + sflag = int32_sflag(ts->d_s.hi); + ah = sflag ^ ts->D_s.hi; + al = sflag ^ ts->D_s.lo; + + /* Since 86400 == 128*675 we can drop the least 7 bits and + * divide by 675 instead of 86400. Then the maximum remainder + * after each devision step is 674, and we need 10 bits for + * that. So in the next step we can shift in 22 bits from the + * numerator. + * + * Therefore we load the accu with the top 13 bits (51..63) in + * the first shot. We don't have to remember the quotient -- it + * would be shifted out anyway. + */ + A = ah >> 19; + if (A >= 675) + A = (A % 675u); + + /* Now assemble the remainder with bits 29..50 from the + * numerator and divide. This creates the upper ten bits of the + * quotient. (Well, the top 22 bits of a 44bit result. But that + * will be truncated to 32 bits anyway.) + */ + A = (A << 19) | (ah & 0x0007FFFFu); + A = (A << 3) | (al >> 29); + Q = A / 675u; + A = A % 675u; - /* - * since we do not have 64bit ops, we have to this by hand. - * Luckily SECSPERDAY is 86400 is 675*128, so we do the division - * using chained 32/16 bit divisions and shifts. + /* Now assemble the remainder with bits 7..28 from the numerator + * and do a final division step. */ - vint64 op; - uint32_t q, r, a; - int isneg; + A = (A << 22) | ((al >> 7) & 0x003FFFFFu); + Q = (Q << 22) | (A / 675u); - memcpy(&op, ts, sizeof(op)); - /* fix sign */ - isneg = M_ISNEG(op.D_s.hi); - if (isneg) - M_NEG(op.D_s.hi, op.D_s.lo); - - /* save remainder of DIV 128, shift for divide */ - r = op.D_s.lo & 127; /* save remainder bits */ - op.D_s.lo = (op.D_s.lo >> 7) | (op.D_s.hi << 25); - op.D_s.hi = (op.D_s.hi >> 7); - - /* now do a mnual division, trying to remove as many ops as - * possible -- division is always slow! An since we do not have - * the advantage of a specific 64/32 bit or even a specific 32/16 - * bit division op, but must use the general 32/32bit division - * even if we *know* the divider fits into unsigned 16 bits, the - * exra code pathes should pay off. + /* The last 7 bits get simply dropped, as they have no affect on + * the quotient when dividing by 86400. */ - a = op.D_s.hi; - if (a > 675u) - a = a % 675u; - if (a) { - a = (a << 16) | op.W_s.lh; - q = a / 675u; - a = a % 675u; - - a = (a << 16) | op.W_s.ll; - q = (q << 16) | (a / 675u); - } else { - a = op.D_s.lo; - q = a / 675u; - } - a = a % 675u; - - /* assemble remainder */ - r |= a << 7; - - /* fix sign of result */ - if (isneg) { - if (r) { - r = SECSPERDAY - r; - q = ~q; - } else - q = ~q + 1; - } - res.hi = q; - res.lo = r; + /* apply sign correction and calculate the true floor + * remainder. + */ + Q ^= sflag; + +# endif + + res.hi = uint32_2cpl_to_int32(Q); + res.lo = ts->D_s.lo - Q * SECSPERDAY; -#endif return res; } @@ -593,25 +748,28 @@ priv_timesplit( int32_t ts ) { - int32_t days = 0; - - /* make sure we have a positive offset into a day */ - if (ts < 0 || ts >= SECSPERDAY) { - days = ts / SECSPERDAY; - ts = ts % SECSPERDAY; - if (ts < 0) { - days -= 1; - ts += SECSPERDAY; - } - } + /* Do 3 chained floor divisions by positive constants, using the + * one's complement trick and factoring out the intermediate XOR + * ops to reduce the number of operations. + */ + uint32_t us, um, uh, ud, sflag; - /* get secs, mins, hours */ - split[2] = (uint8_t)(ts % SECSPERMIN); - ts /= SECSPERMIN; - split[1] = (uint8_t)(ts % MINSPERHR); - split[0] = (uint8_t)(ts / MINSPERHR); + sflag = int32_sflag(ts); + us = int32_to_uint32_2cpl(ts); - return days; + um = (sflag ^ us) / SECSPERMIN; + uh = um / MINSPERHR; + ud = uh / HRSPERDAY; + + um ^= sflag; + uh ^= sflag; + ud ^= sflag; + + split[0] = (int32_t)(uh - ud * HRSPERDAY ); + split[1] = (int32_t)(um - uh * MINSPERHR ); + split[2] = (int32_t)(us - um * SECSPERMIN); + + return uint32_2cpl_to_int32(ud); } /* @@ -630,46 +788,45 @@ ntpcal_split_eradays( int *isleapyear ) { - ntpcal_split res; - int32_t n400, n100, n004, n001, yday; /* calendar year cycles */ - - /* - * Split off calendar cycles, using floor division in the first - * step. After that first step, simple division does it because - * all operands are positive; alas, we have to be aware of the - * possibe cycle overflows for 100 years and 1 year, caused by - * the additional leap day. + /* Use the fast cyclesplit algorithm here, to calculate the + * centuries and years in a century with one division each. This + * reduces the number of division operations to two, but is + * susceptible to internal range overflow. We make sure the + * input operands are in the safe range; this still gives us + * approx +/-2.9 million years. */ - n400 = days / GREGORIAN_CYCLE_DAYS; - yday = days % GREGORIAN_CYCLE_DAYS; - if (yday < 0) { - n400 -= 1; - yday += GREGORIAN_CYCLE_DAYS; - } - n100 = yday / GREGORIAN_NORMAL_CENTURY_DAYS; - yday = yday % GREGORIAN_NORMAL_CENTURY_DAYS; - n004 = yday / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS; - yday = yday % GREGORIAN_NORMAL_LEAP_CYCLE_DAYS; - n001 = yday / DAYSPERYEAR; - yday = yday % DAYSPERYEAR; - - /* - * check for leap cycle overflows and calculate the leap flag - * if needed + ntpcal_split res; + int32_t n100, n001; /* calendar year cycles */ + uint32_t uday, Q, sflag; + + /* split off centuries first */ + sflag = int32_sflag(days); + uday = uint32_saturate(int32_to_uint32_2cpl(days), sflag); + uday = (4u * uday) | 3u; + Q = sflag ^ ((sflag ^ uday) / GREGORIAN_CYCLE_DAYS); + uday = uday - Q * GREGORIAN_CYCLE_DAYS; + n100 = uint32_2cpl_to_int32(Q); + + /* Split off years in century -- days >= 0 here, and we're far + * away from integer overflow trouble now. */ + uday |= 3; + n001 = uday / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS; + uday = uday % GREGORIAN_NORMAL_LEAP_CYCLE_DAYS; + + /* Assemble the year and day in year */ + res.hi = n100 * 100 + n001; + res.lo = uday / 4u; + + /* Eventually set the leap year flag. Note: 0 <= n001 <= 99 and + * Q is still the two's complement representation of the + * centuries: The modulo 4 ops can be done with masking here. + * We also shift the year and the century by one, so the tests + * can be done against zero instead of 3. */ - if ((n001 | n100) > 3) { - /* hit last day of leap year */ - n001 -= 1; - yday += DAYSPERYEAR; - if (isleapyear) - *isleapyear = 1; - } else if (isleapyear) - *isleapyear = (n001 == 3) && ((n004 != 24) || (n100 == 3)); - - /* now merge the cycles to elapsed years, using horner scheme */ - res.hi = ((4*n400 + n100)*25 + n004)*4 + n001; - res.lo = yday; - + if (isleapyear) + *isleapyear = !((n001+1) & 3) + && ((n001 != 99) || !((Q+1) & 3)); + return res; } @@ -719,11 +876,9 @@ ntpcal_rd_to_date( ) { ntpcal_split split; - int leaps; - int retv; + int leapy; + u_int ymask; - leaps = 0; - retv = 0; /* Get day-of-week first. Since rd is signed, the remainder can * be in the range [-6..+6], but the assignment to an unsigned * variable maps the negative values to positive values >=7. @@ -731,26 +886,28 @@ ntpcal_rd_to_date( * causes the needed wrap-around into the desired value range of * zero to six, both inclusive. */ - jd->weekday = rd % 7; - if (jd->weekday >= 7) /* unsigned! */ - jd->weekday += 7; - - split = ntpcal_split_eradays(rd - 1, &leaps); - retv = leaps; - /* get year and day-of-year */ - jd->year = (uint16_t)split.hi + 1; - if (jd->year != split.hi + 1) { - jd->year = 0; - retv = -1; /* bletch. overflow trouble. */ - } + jd->weekday = rd % DAYSPERWEEK; + if (jd->weekday >= DAYSPERWEEK) /* weekday is unsigned! */ + jd->weekday += DAYSPERWEEK; + + split = ntpcal_split_eradays(rd - 1, &leapy); + /* Get year and day-of-year, with overflow check. If any of the + * upper 16 bits is set after shifting to unity-based years, we + * will have an overflow when converting to an unsigned 16bit + * year. Shifting to the right is OK here, since it does not + * matter if the shift is logic or arithmetic. + */ + split.hi += 1; + ymask = 0u - ((split.hi >> 16) == 0); + jd->year = (uint16_t)(split.hi & ymask); jd->yearday = (uint16_t)split.lo + 1; /* convert to month and mday */ - split = ntpcal_split_yeardays(split.lo, leaps); + split = ntpcal_split_yeardays(split.lo, leapy); jd->month = (uint8_t)split.hi + 1; jd->monthday = (uint8_t)split.lo + 1; - return retv ? retv : leaps; + return ymask ? leapy : -1; } /* @@ -765,25 +922,24 @@ ntpcal_rd_to_tm( ) { ntpcal_split split; - int leaps; + int leapy; - leaps = 0; /* get day-of-week first */ - utm->tm_wday = rd % 7; + utm->tm_wday = rd % DAYSPERWEEK; if (utm->tm_wday < 0) - utm->tm_wday += 7; + utm->tm_wday += DAYSPERWEEK; /* get year and day-of-year */ - split = ntpcal_split_eradays(rd - 1, &leaps); + split = ntpcal_split_eradays(rd - 1, &leapy); utm->tm_year = split.hi - 1899; utm->tm_yday = split.lo; /* 0-based */ /* convert to month and mday */ - split = ntpcal_split_yeardays(split.lo, leaps); + split = ntpcal_split_yeardays(split.lo, leapy); utm->tm_mon = split.hi; /* 0-based */ utm->tm_mday = split.lo + 1; /* 1-based */ - return leaps; + return leapy; } /* @@ -918,13 +1074,13 @@ ntpcal_dayjoin( { vint64 res; -#ifdef HAVE_INT64 +# if defined(HAVE_INT64) res.q_s = days; res.q_s *= SECSPERDAY; res.q_s += secs; -#else +# else uint32_t p1, p2; int isneg; @@ -963,47 +1119,57 @@ ntpcal_dayjoin( } M_ADD(res.D_s.hi, res.D_s.lo, p2, p1); -#endif +# endif return res; } /* *--------------------------------------------------------------------- - * Convert elapsed years in Era into elapsed days in Era. - * - * To accomodate for negative values of years, floor division would be - * required for all division operations. This can be eased by first - * splitting the years into full 400-year cycles and years in the - * cycle. Only this operation must be coded as a full floor division; as - * the years in the cycle is a non-negative number, all other divisions - * can be regular truncated divisions. + * get leap years since epoch in elapsed years *--------------------------------------------------------------------- */ int32_t -ntpcal_days_in_years( +ntpcal_leapyears_in_years( int32_t years ) { - int32_t cycle; /* full gregorian cycle */ - - /* split off full calendar cycles, using floor division */ - cycle = years / 400; - years = years % 400; - if (years < 0) { - cycle -= 1; - years += 400; - } + /* We use the in-out-in algorithm here, using the one's + * complement division trick for negative numbers. The chained + * division sequence by 4/25/4 gives the compiler the chance to + * get away with only one true division and doing shifts otherwise. + */ - /* - * Calculate days in cycle. years now is a non-negative number, - * holding the number of years in the 400-year cycle. + uint32_t sflag, sum, uyear; + + sflag = int32_sflag(years); + uyear = int32_to_uint32_2cpl(years); + uyear ^= sflag; + + sum = (uyear /= 4u); /* 4yr rule --> IN */ + sum -= (uyear /= 25u); /* 100yr rule --> OUT */ + sum += (uyear /= 4u); /* 400yr rule --> IN */ + + /* Thanks to the alternation of IN/OUT/IN we can do the sum + * directly and have a single one's complement operation + * here. (Only if the years are negative, of course.) Otherwise + * the one's complement would have to be done when + * adding/subtracting the terms. */ - return cycle * GREGORIAN_CYCLE_DAYS - + years * DAYSPERYEAR /* days inregular years */ - + years / 4 /* 4 year leap rule */ - - years / 100; /* 100 year leap rule */ - /* the 400-year rule does not apply due to full-cycle split-off */ + return uint32_2cpl_to_int32(sflag ^ sum); +} + +/* + *--------------------------------------------------------------------- + * Convert elapsed years in Era into elapsed days in Era. + *--------------------------------------------------------------------- + */ +int32_t +ntpcal_days_in_years( + int32_t years + ) +{ + return years * DAYSPERYEAR + ntpcal_leapyears_in_years(years); } /* @@ -1029,26 +1195,22 @@ ntpcal_days_in_months( { ntpcal_split res; - /* normalize month into range */ - res.hi = 0; - res.lo = m; - if (res.lo < 0 || res.lo >= 12) { - res.hi = res.lo / 12; - res.lo = res.lo % 12; - if (res.lo < 0) { - res.hi -= 1; - res.lo += 12; - } - } + /* Add ten months and correct if needed. (It likely is...) */ + res.lo = m + 10; + res.hi = (res.lo >= 12); + if (res.hi) + res.lo -= 12; - /* add 10 month for year starting with march */ - if (res.lo < 2) - res.lo += 10; - else { - res.hi += 1; - res.lo -= 2; + /* if still out of range, normalise by floor division ... */ + if (res.lo < 0 || res.lo >= 12) { + uint32_t mu, Q, sflag; + sflag = int32_sflag(res.lo); + mu = int32_to_uint32_2cpl(res.lo); + Q = sflag ^ ((sflag ^ mu) / 12u); + res.hi += uint32_2cpl_to_int32(Q); + res.lo = mu - Q * 12u; } - + /* get cummulated days in year with unshift */ res.lo = shift_month_table[res.lo] - 306; @@ -1451,37 +1613,42 @@ int32_t isocal_weeks_in_years( int32_t years ) -{ +{ /* * use: w = (y * 53431 + b[c]) / 1024 as interpolation */ - static const int32_t bctab[4] = { 449, 157, 889, 597 }; - int32_t cycle; /* full gregorian cycle */ - int32_t cents; /* full centuries */ - int32_t weeks; /* accumulated weeks */ - - /* split off full calendar cycles, using floor division */ - cycle = years / 400; - years = years % 400; - if (years < 0) { - cycle -= 1; - years += 400; - } - - /* split off full centuries */ - cents = years / 100; - years = years % 100; - - /* - * calculate elapsed weeks, taking into account that the - * first, third and fourth century have 5218 weeks but the - * second century falls short by one week. + static const uint16_t bctab[4] = { 157, 449, 597, 889 }; + + int32_t cs, cw; + uint32_t cc, ci, yu, sflag; + + sflag = int32_sflag(years); + yu = int32_to_uint32_2cpl(years); + + /* split off centuries, using floor division */ + cc = sflag ^ ((sflag ^ yu) / 100u); + yu -= cc * 100u; + + /* calculate century cycles shift and cycle index: + * Assuming a century is 5217 weeks, we have to add a cycle + * shift that is 3 for every 4 centuries, because 3 of the four + * centuries have 5218 weeks. So '(cc*3 + 1) / 4' is the actual + * correction, and the second century is the defective one. + * + * Needs floor division by 4, which is done with masking and + * shifting. + */ + ci = cc * 3u + 1; + cs = uint32_2cpl_to_int32(sflag ^ ((sflag ^ ci) / 4u)); + ci = ci % 4u; + + /* Get weeks in century. Can use plain division here as all ops + * are >= 0, and let the compiler sort out the possible + * optimisations. */ - weeks = (years * 53431 + bctab[cents]) / 1024; + cw = (yu * 53431u + bctab[ci]) / 1024u; - return cycle * GREGORIAN_CYCLE_WEEKS - + cents * 5218 - (cents > 1) - + weeks; + return uint32_2cpl_to_int32(cc) * 5217 + cs + cw; } /* @@ -1498,35 +1665,41 @@ isocal_split_eraweeks( /* * use: y = (w * 157 + b[c]) / 8192 as interpolation */ - static const int32_t bctab[4] = { 85, 131, 17, 62 }; + + static const uint16_t bctab[4] = { 85, 130, 17, 62 }; + ntpcal_split res; - int32_t cents; + int32_t cc, ci; + uint32_t sw, cy, Q, sflag; - /* - * split off 400-year cycles, using the fact that a 400-year - * cycle has 146097 days, which is exactly 20871 weeks. + /* Use two fast cycle-split divisions here. This is again + * susceptible to internal overflow, so we check the range. This + * still permits more than +/-20 million years, so this is + * likely a pure academical problem. + * + * We want to execute '(weeks * 4 + 2) /% 20871' under floor + * division rules in the first step. */ - res.hi = weeks / GREGORIAN_CYCLE_WEEKS; - res.lo = weeks % GREGORIAN_CYCLE_WEEKS; - if (res.lo < 0) { - res.hi -= 1; - res.lo += GREGORIAN_CYCLE_WEEKS; - } - res.hi *= 400; - - /* - * split off centuries, taking into account that the first, - * third and fourth century have 5218 weeks but that the - * second century falls short by one week. + sflag = int32_sflag(weeks); + sw = uint32_saturate(int32_to_uint32_2cpl(weeks), sflag); + sw = 4u * sw + 2; + Q = sflag ^ ((sflag ^ sw) / GREGORIAN_CYCLE_WEEKS); + sw -= Q * GREGORIAN_CYCLE_WEEKS; + ci = Q % 4u; + cc = uint32_2cpl_to_int32(Q); + + /* Split off years; sw >= 0 here! The scaled weeks in the years + * are scaled up by 157 afterwards. + */ + sw = (sw / 4u) * 157u + bctab[ci]; + cy = sw / 8192u; /* ws >> 13 , let the compiler sort it out */ + sw = sw % 8192u; /* ws & 8191, let the compiler sort it out */ + + /* assemble elapsed years and downscale the elapsed weeks in + * the year. */ - res.lo += (res.lo >= 10435); - cents = res.lo / 5218; - res.lo %= 5218; /* res.lo is weeks in century now */ - - /* convert elapsed weeks in century to elapsed years and weeks */ - res.lo = res.lo * 157 + bctab[cents]; - res.hi += cents * 100 + res.lo / 8192; - res.lo = (res.lo % 8192) / 157; + res.hi = 100*cc + cy; + res.lo = sw / 157u; return res; } @@ -1544,6 +1717,7 @@ isocal_ntp64_to_date( { ntpcal_split ds; int32_t ts[3]; + uint32_t uw, ud, sflag; /* * Split NTP time into days and seconds, shift days into CE @@ -1557,16 +1731,18 @@ isocal_ntp64_to_date( id->minute = (uint8_t)ts[1]; id->second = (uint8_t)ts[2]; - /* split date part */ - ds.lo = ds.hi + DAY_NTP_STARTS - 1; /* elapsed era days */ - ds.hi = ds.lo / 7; /* elapsed era weeks */ - ds.lo = ds.lo % 7; /* elapsed week days */ - if (ds.lo < 0) { /* floor division! */ - ds.hi -= 1; - ds.lo += 7; - } + /* split days into days and weeks, using floor division in unsigned */ + ds.hi += DAY_NTP_STARTS - 1; /* shift from NTP to RDN */ + sflag = int32_sflag(ds.hi); + ud = int32_to_uint32_2cpl(ds.hi); + uw = sflag ^ ((sflag ^ ud) / DAYSPERWEEK); + ud -= uw * DAYSPERWEEK; + ds.hi = uint32_2cpl_to_int32(uw); + ds.lo = ud; + id->weekday = (uint8_t)ds.lo + 1; /* weekday result */ + /* get year and week in year */ ds = isocal_split_eraweeks(ds.hi); /* elapsed years&week*/ id->year = (uint16_t)ds.hi + 1; /* shift to current */ id->week = (uint8_t )ds.lo + 1; diff --git a/contrib/ntp/libntp/ntp_intres.c b/contrib/ntp/libntp/ntp_intres.c index eea88a1..b0f5620 100644 --- a/contrib/ntp/libntp/ntp_intres.c +++ b/contrib/ntp/libntp/ntp_intres.c @@ -249,12 +249,12 @@ getaddrinfo_sometime( size_t servsize; time_t now; - NTP_REQUIRE(NULL != node); + REQUIRE(NULL != node); if (NULL != hints) { - NTP_REQUIRE(0 == hints->ai_addrlen); - NTP_REQUIRE(NULL == hints->ai_addr); - NTP_REQUIRE(NULL == hints->ai_canonname); - NTP_REQUIRE(NULL == hints->ai_next); + REQUIRE(0 == hints->ai_addrlen); + REQUIRE(NULL == hints->ai_addr); + REQUIRE(NULL == hints->ai_canonname); + REQUIRE(NULL == hints->ai_next); } idx = get_dnschild_ctx(); @@ -420,7 +420,7 @@ blocking_getaddrinfo( ai = ai_res; while (NULL != ai) { - NTP_INSIST(ai->ai_addrlen <= sizeof(sockaddr_u)); + INSIST(ai->ai_addrlen <= sizeof(sockaddr_u)); memcpy(cp, ai->ai_addr, ai->ai_addrlen); cp += sizeof(sockaddr_u); @@ -568,7 +568,7 @@ getaddrinfo_sometime_complete( ai[i].ai_canonname += (size_t)canon_start; } - NTP_ENSURE((char *)psau == canon_start); + ENSURE((char *)psau == canon_start); if (!gai_resp->ai_count) ai = NULL; @@ -634,8 +634,8 @@ getnameinfo_sometime( dnschild_ctx * child_ctx; time_t time_now; - NTP_REQUIRE(hostoctets); - NTP_REQUIRE(hostoctets + servoctets < 1024); + REQUIRE(hostoctets); + REQUIRE(hostoctets + servoctets < 1024); idx = get_dnschild_ctx(); child_ctx = dnschild_contexts[idx]; @@ -699,7 +699,7 @@ blocking_getnameinfo( * large allocations. We only need room for the host * and service names. */ - NTP_REQUIRE(octets < sizeof(host)); + REQUIRE(octets < sizeof(host)); service = host + gni_req->hostoctets; worker_ctx = get_worker_context(c, gni_req->dns_idx); @@ -775,8 +775,8 @@ blocking_getnameinfo( cp += gni_resp->servoctets; } - NTP_INSIST((size_t)(cp - (char *)resp) == resp_octets); - NTP_INSIST(resp_octets - sizeof(*resp) == gni_resp->octets); + INSIST((size_t)(cp - (char *)resp) == resp_octets); + INSIST(resp_octets - sizeof(*resp) == gni_resp->octets); rc = queue_blocking_response(c, resp, resp_octets, req); if (rc) diff --git a/contrib/ntp/libntp/ntp_lineedit.c b/contrib/ntp/libntp/ntp_lineedit.c index e3bc002..a2b2d29 100644 --- a/contrib/ntp/libntp/ntp_lineedit.c +++ b/contrib/ntp/libntp/ntp_lineedit.c @@ -36,7 +36,7 @@ * external references */ -extern char * progname; +extern char const * progname; /* * globals, private prototypes diff --git a/contrib/ntp/libntp/ntp_rfc2553.c b/contrib/ntp/libntp/ntp_rfc2553.c index f267999..a9ebb4b 100644 --- a/contrib/ntp/libntp/ntp_rfc2553.c +++ b/contrib/ntp/libntp/ntp_rfc2553.c @@ -221,7 +221,7 @@ copy_addrinfo_common( } ++ai_cpy; } - NTP_ENSURE(pcanon == ((char *)dst + octets)); + ENSURE(pcanon == ((char *)dst + octets)); return dst; } diff --git a/contrib/ntp/libntp/ntp_worker.c b/contrib/ntp/libntp/ntp_worker.c index bb1cb87..32970da 100644 --- a/contrib/ntp/libntp/ntp_worker.c +++ b/contrib/ntp/libntp/ntp_worker.c @@ -278,7 +278,7 @@ blocking_child_common( req = receive_blocking_req_internal(c); if (NULL == req) { say_bye = TRUE; - break; + continue; } DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == req->magic_sig); diff --git a/contrib/ntp/libntp/prettydate.c b/contrib/ntp/libntp/prettydate.c index 5da5ecc..25b085e 100644 --- a/contrib/ntp/libntp/prettydate.c +++ b/contrib/ntp/libntp/prettydate.c @@ -141,7 +141,7 @@ get_struct_tm( return NULL; /* That's truly pathological! */ /* 'tm' surely not NULL here! */ - NTP_INSIST(tm != NULL); + INSIST(tm != NULL); if (folds != 0) { tm->tm_year += folds * SOLAR_CYCLE_YEARS; if (tm->tm_year <= 0 || tm->tm_year >= 200) diff --git a/contrib/ntp/libntp/recvbuff.c b/contrib/ntp/libntp/recvbuff.c index 83a9ee1..73ebe88 100644 --- a/contrib/ntp/libntp/recvbuff.c +++ b/contrib/ntp/libntp/recvbuff.c @@ -216,7 +216,7 @@ get_free_recv_buffer_alloc(void) create_buffers(RECV_INC); buffer = get_free_recv_buffer(); } - NTP_ENSURE(buffer != NULL); + ENSURE(buffer != NULL); return (buffer); } #endif diff --git a/contrib/ntp/libntp/socket.c b/contrib/ntp/libntp/socket.c index de678c6..11fb0046 100644 --- a/contrib/ntp/libntp/socket.c +++ b/contrib/ntp/libntp/socket.c @@ -78,7 +78,7 @@ move_fd( static SOCKET socket_boundary = -1; SOCKET newfd; - NTP_REQUIRE((int)fd >= 0); + REQUIRE((int)fd >= 0); /* * check whether boundary has be set up @@ -115,7 +115,7 @@ move_fd( socket_boundary)); } while (socket_boundary > 0); #else - NTP_REQUIRE((int)fd >= 0); + ENSURE((int)fd >= 0); #endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */ return fd; } diff --git a/contrib/ntp/libntp/socktohost.c b/contrib/ntp/libntp/socktohost.c index c61e571..3d9ab960 100644 --- a/contrib/ntp/libntp/socktohost.c +++ b/contrib/ntp/libntp/socktohost.c @@ -79,7 +79,7 @@ socktohost( if (a_info) goto forward_fail; - NTP_INSIST(alist != NULL); + INSIST(alist != NULL); for (ai = alist; ai != NULL; ai = ai->ai_next) { /* diff --git a/contrib/ntp/libntp/statestr.c b/contrib/ntp/libntp/statestr.c index cd98eb3..313cd46 100644 --- a/contrib/ntp/libntp/statestr.c +++ b/contrib/ntp/libntp/statestr.c @@ -60,7 +60,7 @@ static const struct codestring select_codes[] = { { CTL_PST_SEL_REJECT, "sel_reject" }, { CTL_PST_SEL_SANE, "sel_falsetick" }, { CTL_PST_SEL_CORRECT, "sel_excess" }, - { CTL_PST_SEL_SELCAND, "sel_outlyer" }, + { CTL_PST_SEL_SELCAND, "sel_outlier" }, { CTL_PST_SEL_SYNCCAND, "sel_candidate" }, { CTL_PST_SEL_EXCESS, "sel_backup" }, { CTL_PST_SEL_SYSPEER, "sel_sys.peer" }, |