[PATCH stalld 48/52] stalld: guard nextline() returns in sched_debug parsing
Wander Lairson Costa <[email protected]> Mon, 8 Jun 2026 15:31:58 -0300
| Newsgroups | org.kernel.vger.linux-rt-users |
|---|---|
| Message-ID | <[email protected]> |
nextline() returns NULL when the input lacks a trailing newline, which happens if sched_debug output is truncated. Both detect_task_format() and parse_task_lines() pass the result directly to string helpers that dereference it, causing a NULL pointer fault. Add NULL checks after every nextline() call. In detect_task_format() the daemon cannot function without a valid format, so it calls die(). In parse_task_lines() a truncated buffer simply means no more tasks to parse, so the function returns the count collected so far. Also remove the unreachable exit() after die() in the TASK_MARKER check. Signed-off-by: Wander Lairson Costa <[email protected]> --- src/sched_debug.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/sched_debug.c b/src/sched_debug.c index f481bb2..7d79255 100644 --- a/src/sched_debug.c +++ b/src/sched_debug.c @@ -233,13 +233,13 @@ static int detect_task_format(void) /* find the delimiter for task information */ ptr = strstr(buffer, TASK_MARKER); - if (ptr == NULL) { + if (ptr == NULL) die("unable to find 'runnable tasks' in buffer, invalid input\n"); - exit(-1); - } /* move to the column header line */ ptr = nextline(ptr); + if (!ptr) + die("invalid file format: %s\n", config_sched_debug_path); i = 0; /* @@ -386,13 +386,20 @@ static int parse_task_lines(char *buffer, struct task_info *task_info, int nr_en line = ptr; /* skip "runnable tasks:" */ - line = nextline(line); + line = nextline(line); + if (!line) + return 0; /* skip header lines */ line = nextline(line); + if (!line) + return 0; /* skip divider line */ line = nextline(line); + if (!line) + return 0; + /* at this point, line should point to the start of a task line */ /* now loop over the task info @@ -415,6 +422,8 @@ static int parse_task_lines(char *buffer, struct task_info *task_info, int nr_en (*ptr == 'R')) { /* Go to the end of the line and ignore this task. */ line = nextline(line); + if (!line) + return 0; continue; } @@ -429,6 +438,8 @@ static int parse_task_lines(char *buffer, struct task_info *task_info, int nr_en if (config_task_format == NEW_TASK_FORMAT) { if (*ptr == '>' || (*ptr != 'R' && *ptr != 'X')) { line = nextline(line); + if (!line) + return 0; continue; } } @@ -436,7 +447,7 @@ static int parse_task_lines(char *buffer, struct task_info *task_info, int nr_en /* * At this point we have a task line to record */ - + /* get the task field */ ptr = skip2word(line, config_task_format_offsets.task); @@ -485,6 +496,8 @@ static int parse_task_lines(char *buffer, struct task_info *task_info, int nr_en /* move our line pointer to the next availble line */ line = nextline(line); + if (!line) + return 0; } return tasks; } -- 2.54.0