top vs. array sorted_state's out of bounds indexing (and related issues)

From: Mark Millard <marklmi_at_yahoo.com>
Date: Mon, 19 Jun 2023 04:23:06 UTC
usr.bin/top/machine.c (from main) has:

/*
. . . The process states are ordered as follows (from least
 *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
 *      array declaration below maps a process state index into a number
 *      that reflects this ordering.
 */

static int sorted_state[] = {
        0,      /* not used             */
        3,      /* sleep                */
        1,      /* ABANDONED (WAIT)     */
        6,      /* run                  */
        5,      /* start                */
        2,      /* zombie               */
        4       /* stop                 */
};

Note the elements are 0..6, so 7 elements.

It is accessed via code like:

sorted_state[(unsigned char)(b)->ki_stat]

But ->ki_stat has the values listed in
sys/sys/proc.h :

/*
 * These were process status values (p_stat), now they are only used in
 * legacy conversion code.
 */
#define SIDL    1               /* Process being created by fork. */
#define SRUN    2               /* Currently runnable. */
#define SSLEEP  3               /* Sleeping on an address. */
#define SSTOP   4               /* Process debugging or suspension. */
#define SZOMB   5               /* Awaiting collection by parent. */
#define SWAIT   6               /* Waiting for interrupt. */
#define SLOCK   7               /* Blocked on a lock. */

This leads to element indexes (including the
"unused" 0) of 0..7 so spanning 8 elements.

Thus there is a out of bounds error involved when
->ki_stat == SLOCK .

(I later show the ki_stat assignments.)

There is also the issue that:

SIDL   is misidentified as: sleep
SRUN   is misidentified as: ABANDONED (WAIT)
SSLEEP is misidentified as: run
SZOMB  is misidentified as: start
SWAIT  is misidentified as: zombie
SLOCK  is out of bounds (as indicated above).

So the sort order in top is not as documented.


For reference, from sys/kern/kern_proc.c :

        if (p->p_state == PRS_NORMAL) { /* approximate. */
                if (TD_ON_RUNQ(td) ||
                    TD_CAN_RUN(td) ||
                    TD_IS_RUNNING(td)) {
                        kp->ki_stat = SRUN;
                } else if (P_SHOULDSTOP(p)) {
                        kp->ki_stat = SSTOP;
                } else if (TD_IS_SLEEPING(td)) {
                        kp->ki_stat = SSLEEP;
                } else if (TD_ON_LOCK(td)) {
                        kp->ki_stat = SLOCK;
                } else {
                        kp->ki_stat = SWAIT;
                }
        } else if (p->p_state == PRS_ZOMBIE) {
                kp->ki_stat = SZOMB;
        } else {
                kp->ki_stat = SIDL;
        }

===
Mark Millard
marklmi at yahoo.com