Re: top vs. array sorted_state's out of bounds indexing (and related issues)
Date: Mon, 19 Jun 2023 16:05:11 UTC
On Sun, Jun 18, 2023 at 09:23:06PM -0700, Mark Millard wrote:
> 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;
> }
https://reviews.freebsd.org/D40607