Re: top vs. array sorted_state's out of bounds indexing (and related issues)
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 02 Jul 2023 22:45:10 UTC
Clifton Royston <cliftonr_at_volcano.org> wrote on Date: Sun, 02 Jul 2023 21:44:10 UTC : > On 7/2/2023 9:52 AM, Clifton Royston wrote: > > On 6/19/2023 6:05 AM, Konstantin Belousov wrote: > >> On Sun, Jun 18, 2023 at 09:23:06PM -0700, Mark Millard wrote: > >>> usr.bin/top/machine.c (from main) has: > [...] > >>> > >>> 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] > > [...] > >>> /* > >>> * 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. */ > >>> > > [...] > >>> } else if (TD_ON_LOCK(td)) { > >>> kp->ki_stat = SLOCK; > > [...] > >> https://reviews.freebsd.org/D40607 > > > > I rarely comment here and hesitate to now, but out of curiosity I > > looked at the original report and at the chain of commits. > > > > It appears to me that in making the code more readable the final > > result may have accidentally inverted the sort order from the intended > > values (mostly.) A casual test wouldn't show this, as unless the sort > > order in top were changed, normally it would only come into play for > > two processes with equal CPU % and ticks which seems unlikely. > [...] > > And, following up to myself, I now realized that both the committed > patch *and* my reply completely missed addressing the original issue > Mark reported: > > No value for the index SLOCK is included in the array initializer, Not true now. See below. > so > SLOCK is still not translated to a meaningful index, and AFAICT it is > not included in the dimensions! SLOCK has a element in the array now. See below. > I expect it would still result in the > same out-of-bounds indexing problem Mark reported for that case. Nope. See below. > A further corrected comment and array initializer: > > /* > * proc_compare - comparison function for "qsort" > * Compares the resource consumption of two processes using five > * distinct keys. The keys (in descending order of importance) are: > * percent cpu, cpu ticks, state, resident set size, total virtual > * memory usage. The process states are ordered as follows (from most > * to least important): run, zombie, idle (being created), interrupt > * wait, blocked on lock, stop, sleep. > * The array declaration below maps a process state index into a > * number that reflects this ordering. > */ > > static const int sorted_state[] = { > [SRUN] = 7, /* Currently runnable. */ > [SZOMB] = 6, /* Awaiting collection by parent. */ > [SIDL] = 5, /* Process being created by fork. */ > [SWAIT] = 4, /* Waiting for interrupt. */ > [SLOCK] = 3, /* Blocked on a lock. */ > [SSTOP] = 2, /* Process debugging or suspension. */ > [SSLEEP] = 1, /* Sleeping on an address. */ > } [I ignore here specific choices/views of what sort order should result.] Looking at modern /usr/main-src/usr.bin/top/machine.c in main's source I see: static const int sorted_state[] = { [SIDL] = 3, /* being created */ [SRUN] = 1, /* running/runnable */ [SSLEEP] = 6, /* sleeping */ [SSTOP] = 5, /* stopped/suspended */ [SZOMB] = 2, /* zombie */ [SWAIT] = 4, /* intr */ [SLOCK] = 7, /* blocked on lock */ }; In other words, after substitutions for the macros: static const int sorted_state[] = { [1] = 3, /* being created */ [2] = 1, /* running/runnable */ [3] = 6, /* sleeping */ [4] = 5, /* stopped/suspended */ [5] = 2, /* zombie */ [6] = 4, /* intr */ [7] = 7, /* blocked on lock */ }; That notation means (being explicit about the size and the implicit [0] case): static const int sorted_state[8] = { [0] = 0, /* implicit case */ [1] = 3, /* being created */ [2] = 1, /* running/runnable */ [3] = 6, /* sleeping */ [4] = 5, /* stopped/suspended */ [5] = 2, /* zombie */ [6] = 4, /* intr */ [7] = 7, /* blocked on lock */ }; It spans all the indexes for use of: #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. */ So there is no out of bounds access for any of those named values. === Mark Millard marklmi at yahoo.com