Port-sparc archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Overflow during subtraction



Hi everyone,

I've got an intermittent overflow problem occurring in ntpd's code. It's calculating the difference between two 64 bit longs. The problem area seems to be in (or possibly the calling function) refclock_process_f() in ntp_refclock.c.

The calculations result in a value of exactly 2**31 (2147483648) for an offset which causes ntpd to panic and bomb out (thinking something has gone wrong with the system clock).

The actual panic stop message says:
panic_stop +214748365 s; set clock manually within 1000 s.

But this value is approximately one tenth of 2**31 (possibly a printf truncation error?). The computed offset in another log file is:

56227 24243.574 127.127.22.0    975a  2147483648.000000000  0.000000000
0.000353156  2147483647.999994993

There you can see the 2**31 value which came from refclock_process_f().

Everything is now instrumented in refclock_process_f but the original code is below in case anyone has a suggestion about what's going on.


int
refclock_process_f(
        struct refclockproc *pp,        /* refclock structure pointer */
        double fudge
        )
{
        l_fp offset, ltemp;

        /*
         * Compute the timecode timestamp from the days, hours, minutes,
         * seconds and milliseconds/microseconds of the timecode. Use
         * clocktime() for the aggregate seconds and the msec/usec for
         * the fraction, when present. Note that this code relies on the
         * filesystem time for the years and does not use the years of
         * the timecode.
         */
        if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,
                pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui))
                return (0);

        offset.l_uf = 0;
        DTOLFP(pp->nsec / 1e9, &ltemp);
        L_ADD(&offset, &ltemp);
        refclock_process_offset(pp, offset, pp->lastrec, fudge);
        return (1);
}


void
refclock_process_offset(
        struct refclockproc *pp,        /* refclock structure pointer */
        l_fp lasttim,                   /* last timecode timestamp */
        l_fp lastrec,                   /* last receive timestamp */
        double fudge
        )
{
        l_fp lftemp;
        double doffset;

        pp->lastrec = lastrec;
        lftemp = lasttim;
        L_SUB(&lftemp, &lastrec);
        LFPTOD(&lftemp, doffset);
        SAMPLE(doffset + fudge);
}



The long is stored as 32 bits of integer and 32 bits of fractional defined as:

typedef struct {
        union {
                u_int32 Xl_ui;
                int32 Xl_i;
        } Ul_i;
        u_int32 l_uf;
} l_fp;
#define l_ui    Ul_i.Xl_ui              /* unsigned integral part */
#define l_i     Ul_i.Xl_i               /* signed integral part */

The macros used in the functions are below:


#define DTOLFP(d, v)    M_DTOLFP((d), (v)->l_ui, (v)->l_uf)
#define LFPTOD(v, d)    M_LFPTOD((v)->l_ui, (v)->l_uf, (d))

#define L_ADD(r, a)     M_ADD((r)->l_ui, (r)->l_uf, (a)->l_ui, (a)->l_uf)

#define L_SUB(r, a)     M_SUB((r)->l_ui, (r)->l_uf, (a)->l_ui, (a)->l_uf)


#define M_ADD(r_i, r_f, a_i, a_f)       /* r += a */ \
        do { \
                u_int32 add_t = (r_f); \
                (r_f) += (a_f); \
                (r_i) += (a_i) + ((u_int32)(r_f) < add_t); \
        } while (FALSE)


#define M_SUB(r_i, r_f, a_i, a_f)       /* r -= a */ \
        do { \
                u_int32 sub_t = (r_f); \
                (r_f) -= (a_f); \
                (r_i) -= (a_i) + ((u_int32)(r_f) > sub_t); \
        } while (FALSE)




The conversion functions for 32-bit architecture (this is #if/#else selected by:
#if defined(HAVE_U_INT64) && \
    !(defined(__SVR4) && defined(__sun) && \
      defined(sparc) && defined(__GNUC__))

Result in these definitions

#define M_DTOLFP(d, r_ui, r_uf)                 /* double to l_fp */ \
        do { \
                double d_tmp; \
                if ((d_tmp = (d)) < 0) { \
                        (r_ui) = (u_int32)(-d_tmp); \
(r_uf) = (u_int32)(-(d_tmp + (double)(r_ui)) * FRAC); \
                        M_NEG((r_ui), (r_uf)); \
                } else { \
                        (r_ui) = (u_int32)d_tmp; \
(r_uf) = (u_int32)((d_tmp - (double)(r_ui)) * FRAC); \
                } \
        } while (0)

#define M_LFPTOD(r_ui, r_uf, d)                 /* l_fp to double */ \
        do { \
                u_int32 l_thi, l_tlo; \
                l_thi = (r_ui); l_tlo = (r_uf); \
                if (M_ISNEG(l_thi)) { \
                        M_NEG(l_thi, l_tlo); \
                        (d) = -((double)l_thi + (double)l_tlo / FRAC); \
                } else { \
                        (d) = (double)l_thi + (double)l_tlo / FRAC; \
                } \

        } while (0)



#define M_NEG(v_i, v_f)         /* v = -v */ \
        do { \
                (v_f) = ~(v_f) + 1u; \
                (v_i) = ~(v_i) + ((v_f) == 0); \
        } while (FALSE)

#define M_ISNEG(v_i)                    /* v < 0 */ \
        (((v_i) & 0x80000000) != 0)


Home | Main Index | Thread Index | Old Index