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

From: Konstantin Belousov <kostikbel_at_gmail.com>
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