top: provide some protection against forking anomalies
This commit will eliminate a very nasty bug associated with top's forest view mode. It addresses a potential SIGSEGV/SIGABRT that was only encountered when another program (erroneously?) creates a lengthy forking loop. If the growing list of nested children is sufficiently fast such that proc_t start_time is duplicated between children then the sort upon which top relies might not produce the expected order. That, in turn, could cause the forest_adds function to initially miss some child. But that missed child would be caught by forest_create and eventually would cause our array boundary overrun. Such overrun occurs when some child of that originally *missed* child is found and a duplicate add attempted. In correcting this bug we'll also use this opportunity to prohibit a borrowed proc_t padding byte (char) from going negative. If the nesting level exceeded 127, the effect was an "unnesting" with the snprintf width then viewed as flag+width also yielding left justification. Henceforth, we'll limit nesting to 100 with subsequent children shown as " + ", not the usual " `- " prefix. References(s): https://bugzilla.redhat.com/show_bug.cgi?id=1153642 http://www.freelists.org/post/procps/Bug-in-the-forrest-view,6 Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
parent
b0767bd391
commit
ce70017eb1
15
top/top.c
15
top/top.c
@ -4895,22 +4895,24 @@ static void keys_xtra (int ch) {
|
|||||||
* ( plus, maintain alphabetical order with carefully chosen )
|
* ( plus, maintain alphabetical order with carefully chosen )
|
||||||
* ( function names: forest_a, forest_b, forest_c & forest_d )
|
* ( function names: forest_a, forest_b, forest_c & forest_d )
|
||||||
* ( each with exactly one letter more than its predecessor! ) */
|
* ( each with exactly one letter more than its predecessor! ) */
|
||||||
static proc_t **Seed_ppt; // temporary window ppt ptr
|
static proc_t **Seed_ppt; // temporary win ppt pointer
|
||||||
static proc_t **Tree_ppt; // resized by forest_create
|
static proc_t **Tree_ppt; // forest_create will resize
|
||||||
static int Tree_idx; // frame_make initializes
|
static int Tree_idx; // frame_make resets to zero
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This little recursive guy is the real forest view workhorse.
|
* This little recursive guy is the real forest view workhorse.
|
||||||
* He fills in the Tree_ppt array and also sets the child indent
|
* He fills in the Tree_ppt array and also sets the child indent
|
||||||
* level which is stored in an unused proc_t padding byte. */
|
* level which is stored in an unused proc_t padding byte. */
|
||||||
static void forest_adds (const int self, const int level) {
|
static void forest_adds (const int self, int level) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (level > 100) level = 101; // our arbitrary nests limit
|
||||||
Tree_ppt[Tree_idx] = Seed_ppt[self]; // add this as root or child
|
Tree_ppt[Tree_idx] = Seed_ppt[self]; // add this as root or child
|
||||||
Tree_ppt[Tree_idx++]->pad_3 = level; // borrow 1 byte, 127 levels
|
Tree_ppt[Tree_idx++]->pad_3 = level; // borrow 1 byte, 127 levels
|
||||||
for (i = self + 1; i < Frame_maxtask; i++) {
|
for (i = self + 1; i < Frame_maxtask; i++) {
|
||||||
if (Seed_ppt[self]->tid == Seed_ppt[i]->tgid
|
if ((Seed_ppt[self]->tid == Seed_ppt[i]->tgid
|
||||||
|| (Seed_ppt[self]->tid == Seed_ppt[i]->ppid && Seed_ppt[i]->tid == Seed_ppt[i]->tgid))
|
|| (Seed_ppt[self]->tid == Seed_ppt[i]->ppid && Seed_ppt[i]->tid == Seed_ppt[i]->tgid))
|
||||||
|
&& Tree_idx < Frame_maxtask) // shouldn't happen, but has
|
||||||
forest_adds(i, level + 1); // got one child any others?
|
forest_adds(i, level + 1); // got one child any others?
|
||||||
}
|
}
|
||||||
} // end: forest_adds
|
} // end: forest_adds
|
||||||
@ -4963,7 +4965,8 @@ static inline const char *forest_display (const WIN_t *q, const proc_t *p) {
|
|||||||
const char *which = (CHKw(q, Show_CMDLIN)) ? *p->cmdline : p->cmd;
|
const char *which = (CHKw(q, Show_CMDLIN)) ? *p->cmdline : p->cmd;
|
||||||
|
|
||||||
if (!CHKw(q, Show_FOREST) || 1 == p->pad_3) return which;
|
if (!CHKw(q, Show_FOREST) || 1 == p->pad_3) return which;
|
||||||
snprintf(buf, sizeof(buf), "%*s%s", 4 * (p->pad_3 - 1), " `- ", which);
|
if (p->pad_3 > 100) snprintf(buf, sizeof(buf), "%400s%s", " + ", which);
|
||||||
|
else snprintf(buf, sizeof(buf), "%*s%s", 4 * (p->pad_3 - 1), " `- ", which);
|
||||||
return buf;
|
return buf;
|
||||||
} // end: forest_display
|
} // end: forest_display
|
||||||
|
|
||||||
|
@ -780,7 +780,7 @@ typedef struct WIN_t {
|
|||||||
//atic void keys_window (int ch);
|
//atic void keys_window (int ch);
|
||||||
//atic void keys_xtra (int ch);
|
//atic void keys_xtra (int ch);
|
||||||
/*------ Forest View support -------------------------------------------*/
|
/*------ Forest View support -------------------------------------------*/
|
||||||
//atic void forest_adds (const int self, const int level);
|
//atic void forest_adds (const int self, int level);
|
||||||
//atic int forest_based (const proc_t **x, const proc_t **y);
|
//atic int forest_based (const proc_t **x, const proc_t **y);
|
||||||
//atic void forest_create (WIN_t *q);
|
//atic void forest_create (WIN_t *q);
|
||||||
//atic inline const char *forest_display (const WIN_t *q, const proc_t *p);
|
//atic inline const char *forest_display (const WIN_t *q, const proc_t *p);
|
||||||
|
Loading…
Reference in New Issue
Block a user