https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=298891

            Bug ID: 298891
           Summary: ps(1), top(1), systat(1): Fix floating-point underflow
                    / SIGFPE in weighted CPU calculation
           Product: Base System
           Version: 14.4-RELEASE
          Hardware: arm
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: bin
          Assignee: [email protected]
          Reporter: [email protected]

Created attachment 275162
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=275162&action=edit
underflow patch for bin/ps/print.c usr.bin/top/machine.c usr.bin/systat/pigs.c

A critical floating-point underflow bug exists in the weighted CPU percentage
calculation across three core utilities in the base system: bin/ps/print.c,
usr.bin/top/machine.c, and usr.bin/systat/pigs.c.

Problem:
When a process accumulates a very large `ki_swtime` (swap/residence time), the
exponent expression `(ki_swtime * log(ccpu))` or `(ki_swtime * logcpu)` yields
a large negative value.

Due to hardware floating-point boundaries, passing this extreme negative value
directly to exp() causes a floating-point underflow. On specific architectures
(such as ARMv6/ARM), this triggers an unmasked floating-point exception
(SIGFPE), causin
g intermittent core dumps in top(1), ps(1), and potentially systat(1).

Proposed Fixes:

To mitigate this, the exponent value must be clamped to a safe hardware
threshold (-700.0) before evaluating exp(), preventing underflow and subsequent
division issues.

1. In bin/ps/print.c:
Modify the return statement to clamp the intermediate double value:

double d = k->ki_p->ki_swtime * log(fxtofl(ccpu));
if (d < -700.0)
        d = -700.0;
return (100.0 * fxtofl(k->ki_p->ki_pctcpu) / (1.0 - exp(d)));

2. In usr.bin/top/machine.c:
Convert the `weighted_cpu` macro into a static inline function (using const
struct kinfo_proc * for type safety) and clamp the exponent:

static inline double
weighted_cpu(double pct, const struct kinfo_proc *pp)
{
        if (pp->ki_swtime == 0)
                return (0.0);

        double d = pp->ki_swtime * logcpu;
        if (d < -700.0)
                d = -700.0;

        return (pct / (1.0 - exp(d)));
}

3. In usr.bin/systat/pigs.c:
Clamp the `ftime * lccpu` value inside the process evaluation loop:

double d = ftime * lccpu;
if (d < -700.0)
        d = -700.0;

*pctp = ((double) kpp[i].ki_pctcpu / fscale) / (1.0 - exp(d));

All three patches have been successfully compiled and verified on FreeBSD
14-RELEASE on armv6 target (Raspberry Pi zero 1). The fixes eliminate the
crashes under high ki_swtime conditions.

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to