* [PATCH v4 01/18] rtla: Exit on memory allocation failures during initialization
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 02/18] rtla: Use strdup() to simplify code Wander Lairson Costa
` (16 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
Most memory allocations in rtla happen during early initialization
before any resources are acquired that would require cleanup. In these
cases, propagating allocation errors just adds complexity without any
benefit. There's nothing to clean up, and the program must exit anyway.
This patch introduces fatal allocation wrappers (calloc_fatal,
reallocarray_fatal, strdup_fatal) that call fatal() on allocation
failure. These wrappers simplify the code by eliminating unnecessary
error propagation paths.
The patch converts early allocations to use these wrappers in
actions_init() and related action functions, osnoise_context_alloc()
and osnoise_init_tool(), trace_instance_init() and trace event
functions, and parameter structure allocations in main functions.
This simplifies the code while maintaining the same behavior: immediate
exit on allocation failure during initialization. Allocations that
require cleanup, such as those in histogram allocation functions with
goto cleanup paths, are left unchanged and continue to return errors.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/actions.c | 50 ++++++++++++--------------
tools/tracing/rtla/src/actions.h | 8 ++---
tools/tracing/rtla/src/osnoise.c | 22 ++++--------
tools/tracing/rtla/src/osnoise_hist.c | 22 ++++--------
tools/tracing/rtla/src/osnoise_top.c | 22 ++++--------
tools/tracing/rtla/src/timerlat_hist.c | 22 ++++--------
tools/tracing/rtla/src/timerlat_top.c | 22 ++++--------
tools/tracing/rtla/src/trace.c | 30 ++++------------
tools/tracing/rtla/src/trace.h | 4 +--
tools/tracing/rtla/src/utils.c | 35 ++++++++++++++++++
tools/tracing/rtla/src/utils.h | 3 ++
11 files changed, 108 insertions(+), 132 deletions(-)
diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c
index a42615011962d..22b8283a183f3 100644
--- a/tools/tracing/rtla/src/actions.c
+++ b/tools/tracing/rtla/src/actions.c
@@ -15,7 +15,7 @@ void
actions_init(struct actions *self)
{
self->size = action_default_size;
- self->list = calloc(self->size, sizeof(struct action));
+ self->list = calloc_fatal(self->size, sizeof(struct action));
self->len = 0;
self->continue_flag = false;
@@ -50,8 +50,10 @@ static struct action *
actions_new(struct actions *self)
{
if (self->len >= self->size) {
- self->size *= 2;
- self->list = realloc(self->list, self->size * sizeof(struct action));
+ const size_t new_size = self->size * 2;
+
+ self->list = reallocarray_fatal(self->list, new_size, sizeof(struct action));
+ self->size = new_size;
}
return &self->list[self->len++];
@@ -60,25 +62,21 @@ actions_new(struct actions *self)
/*
* actions_add_trace_output - add an action to output trace
*/
-int
+void
actions_add_trace_output(struct actions *self, const char *trace_output)
{
struct action *action = actions_new(self);
self->present[ACTION_TRACE_OUTPUT] = true;
action->type = ACTION_TRACE_OUTPUT;
- action->trace_output = calloc(strlen(trace_output) + 1, sizeof(char));
- if (!action->trace_output)
- return -1;
+ action->trace_output = calloc_fatal(strlen(trace_output) + 1, sizeof(char));
strcpy(action->trace_output, trace_output);
-
- return 0;
}
/*
* actions_add_trace_output - add an action to send signal to a process
*/
-int
+void
actions_add_signal(struct actions *self, int signal, int pid)
{
struct action *action = actions_new(self);
@@ -87,40 +85,32 @@ actions_add_signal(struct actions *self, int signal, int pid)
action->type = ACTION_SIGNAL;
action->signal = signal;
action->pid = pid;
-
- return 0;
}
/*
* actions_add_shell - add an action to execute a shell command
*/
-int
+void
actions_add_shell(struct actions *self, const char *command)
{
struct action *action = actions_new(self);
self->present[ACTION_SHELL] = true;
action->type = ACTION_SHELL;
- action->command = calloc(strlen(command) + 1, sizeof(char));
- if (!action->command)
- return -1;
+ action->command = calloc_fatal(strlen(command) + 1, sizeof(char));
strcpy(action->command, command);
-
- return 0;
}
/*
* actions_add_continue - add an action to resume measurement
*/
-int
+void
actions_add_continue(struct actions *self)
{
struct action *action = actions_new(self);
self->present[ACTION_CONTINUE] = true;
action->type = ACTION_CONTINUE;
-
- return 0;
}
/*
@@ -176,7 +166,8 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
/* Only one argument allowed */
return -1;
}
- return actions_add_trace_output(self, trace_output);
+ actions_add_trace_output(self, trace_output);
+ break;
case ACTION_SIGNAL:
/* Takes two arguments, num (signal) and pid */
while (token != NULL) {
@@ -200,21 +191,26 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
/* Missing argument */
return -1;
- return actions_add_signal(self, signal, pid);
+ actions_add_signal(self, signal, pid);
+ break;
case ACTION_SHELL:
if (token == NULL)
return -1;
- if (strlen(token) > 8 && strncmp(token, "command=", 8) == 0)
- return actions_add_shell(self, token + 8);
- return -1;
+ if (strlen(token) > 8 && strncmp(token, "command=", 8))
+ return -1;
+ actions_add_shell(self, token + 8);
+ break;
case ACTION_CONTINUE:
/* Takes no argument */
if (token != NULL)
return -1;
- return actions_add_continue(self);
+ actions_add_continue(self);
+ break;
default:
return -1;
}
+
+ return 0;
}
/*
diff --git a/tools/tracing/rtla/src/actions.h b/tools/tracing/rtla/src/actions.h
index fb77069c972ba..034048682fefb 100644
--- a/tools/tracing/rtla/src/actions.h
+++ b/tools/tracing/rtla/src/actions.h
@@ -49,9 +49,9 @@ struct actions {
void actions_init(struct actions *self);
void actions_destroy(struct actions *self);
-int actions_add_trace_output(struct actions *self, const char *trace_output);
-int actions_add_signal(struct actions *self, int signal, int pid);
-int actions_add_shell(struct actions *self, const char *command);
-int actions_add_continue(struct actions *self);
+void actions_add_trace_output(struct actions *self, const char *trace_output);
+void actions_add_signal(struct actions *self, int signal, int pid);
+void actions_add_shell(struct actions *self, const char *command);
+void actions_add_continue(struct actions *self);
int actions_parse(struct actions *self, const char *trigger, const char *tracefn);
int actions_perform(struct actions *self);
diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c
index 945eb61efc465..ec074cd53dd84 100644
--- a/tools/tracing/rtla/src/osnoise.c
+++ b/tools/tracing/rtla/src/osnoise.c
@@ -938,9 +938,7 @@ struct osnoise_context *osnoise_context_alloc(void)
{
struct osnoise_context *context;
- context = calloc(1, sizeof(*context));
- if (!context)
- return NULL;
+ context = calloc_fatal(1, sizeof(*context));
context->orig_stop_us = OSNOISE_OPTION_INIT_VAL;
context->stop_us = OSNOISE_OPTION_INIT_VAL;
@@ -1017,24 +1015,16 @@ void osnoise_destroy_tool(struct osnoise_tool *top)
struct osnoise_tool *osnoise_init_tool(char *tool_name)
{
struct osnoise_tool *top;
- int retval;
-
- top = calloc(1, sizeof(*top));
- if (!top)
- return NULL;
+ top = calloc_fatal(1, sizeof(*top));
top->context = osnoise_context_alloc();
- if (!top->context)
- goto out_err;
- retval = trace_instance_init(&top->trace, tool_name);
- if (retval)
- goto out_err;
+ if (trace_instance_init(&top->trace, tool_name)) {
+ osnoise_destroy_tool(top);
+ return NULL;
+ }
return top;
-out_err:
- osnoise_destroy_tool(top);
- return NULL;
}
/*
diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c
index 9d70ea34807ff..efbd2e834cf0e 100644
--- a/tools/tracing/rtla/src/osnoise_hist.c
+++ b/tools/tracing/rtla/src/osnoise_hist.c
@@ -466,9 +466,7 @@ static struct common_params
int c;
char *trace_output = NULL;
- params = calloc(1, sizeof(*params));
- if (!params)
- exit(1);
+ params = calloc_fatal(1, sizeof(*params));
actions_init(¶ms->common.threshold_actions);
actions_init(¶ms->common.end_actions);
@@ -579,22 +577,16 @@ static struct common_params
params->common.hist.with_zeros = 1;
break;
case '4': /* trigger */
- if (params->common.events) {
- retval = trace_event_add_trigger(params->common.events, optarg);
- if (retval)
- fatal("Error adding trigger %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_trigger(params->common.events, optarg);
+ else
fatal("--trigger requires a previous -e");
- }
break;
case '5': /* filter */
- if (params->common.events) {
- retval = trace_event_add_filter(params->common.events, optarg);
- if (retval)
- fatal("Error adding filter %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_filter(params->common.events, optarg);
+ else
fatal("--filter requires a previous -e");
- }
break;
case '6':
params->common.warmup = get_llong_from_str(optarg);
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index d54d47947fb44..d2b4ac64e77b4 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -319,9 +319,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv)
int c;
char *trace_output = NULL;
- params = calloc(1, sizeof(*params));
- if (!params)
- exit(1);
+ params = calloc_fatal(1, sizeof(*params));
actions_init(¶ms->common.threshold_actions);
actions_init(¶ms->common.end_actions);
@@ -410,22 +408,16 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv)
params->threshold = get_llong_from_str(optarg);
break;
case '0': /* trigger */
- if (params->common.events) {
- retval = trace_event_add_trigger(params->common.events, optarg);
- if (retval)
- fatal("Error adding trigger %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_trigger(params->common.events, optarg);
+ else
fatal("--trigger requires a previous -e");
- }
break;
case '1': /* filter */
- if (params->common.events) {
- retval = trace_event_add_filter(params->common.events, optarg);
- if (retval)
- fatal("Error adding filter %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_filter(params->common.events, optarg);
+ else
fatal("--filter requires a previous -e");
- }
break;
case '2':
params->common.warmup = get_llong_from_str(optarg);
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 4e8c38a61197c..6ea397421f1c9 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -766,9 +766,7 @@ static struct common_params
int c;
char *trace_output = NULL;
- params = calloc(1, sizeof(*params));
- if (!params)
- exit(1);
+ params = calloc_fatal(1, sizeof(*params));
actions_init(¶ms->common.threshold_actions);
actions_init(¶ms->common.end_actions);
@@ -914,22 +912,16 @@ static struct common_params
params->common.hist.with_zeros = 1;
break;
case '6': /* trigger */
- if (params->common.events) {
- retval = trace_event_add_trigger(params->common.events, optarg);
- if (retval)
- fatal("Error adding trigger %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_trigger(params->common.events, optarg);
+ else
fatal("--trigger requires a previous -e");
- }
break;
case '7': /* filter */
- if (params->common.events) {
- retval = trace_event_add_filter(params->common.events, optarg);
- if (retval)
- fatal("Error adding filter %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_filter(params->common.events, optarg);
+ else
fatal("--filter requires a previous -e");
- }
break;
case '8':
params->dma_latency = get_llong_from_str(optarg);
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index 284b74773c2b5..dd727cb48b551 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -537,9 +537,7 @@ static struct common_params
int c;
char *trace_output = NULL;
- params = calloc(1, sizeof(*params));
- if (!params)
- exit(1);
+ params = calloc_fatal(1, sizeof(*params));
actions_init(¶ms->common.threshold_actions);
actions_init(¶ms->common.end_actions);
@@ -664,22 +662,16 @@ static struct common_params
params->common.user_data = true;
break;
case '0': /* trigger */
- if (params->common.events) {
- retval = trace_event_add_trigger(params->common.events, optarg);
- if (retval)
- fatal("Error adding trigger %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_trigger(params->common.events, optarg);
+ else
fatal("--trigger requires a previous -e");
- }
break;
case '1': /* filter */
- if (params->common.events) {
- retval = trace_event_add_filter(params->common.events, optarg);
- if (retval)
- fatal("Error adding filter %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_filter(params->common.events, optarg);
+ else
fatal("--filter requires a previous -e");
- }
break;
case '2': /* dma-latency */
params->dma_latency = get_llong_from_str(optarg);
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index b8be3e28680ee..211ca54b15b0e 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -191,9 +191,7 @@ void trace_instance_destroy(struct trace_instance *trace)
*/
int trace_instance_init(struct trace_instance *trace, char *tool_name)
{
- trace->seq = calloc(1, sizeof(*trace->seq));
- if (!trace->seq)
- goto out_err;
+ trace->seq = calloc_fatal(1, sizeof(*trace->seq));
trace_seq_init(trace->seq);
@@ -274,15 +272,9 @@ struct trace_events *trace_event_alloc(const char *event_string)
{
struct trace_events *tevent;
- tevent = calloc(1, sizeof(*tevent));
- if (!tevent)
- return NULL;
+ tevent = calloc_fatal(1, sizeof(*tevent));
- tevent->system = strdup(event_string);
- if (!tevent->system) {
- free(tevent);
- return NULL;
- }
+ tevent->system = strdup_fatal(event_string);
tevent->event = strstr(tevent->system, ":");
if (tevent->event) {
@@ -296,31 +288,23 @@ struct trace_events *trace_event_alloc(const char *event_string)
/*
* trace_event_add_filter - record an event filter
*/
-int trace_event_add_filter(struct trace_events *event, char *filter)
+void trace_event_add_filter(struct trace_events *event, char *filter)
{
if (event->filter)
free(event->filter);
- event->filter = strdup(filter);
- if (!event->filter)
- return 1;
-
- return 0;
+ event->filter = strdup_fatal(filter);
}
/*
* trace_event_add_trigger - record an event trigger action
*/
-int trace_event_add_trigger(struct trace_events *event, char *trigger)
+void trace_event_add_trigger(struct trace_events *event, char *trigger)
{
if (event->trigger)
free(event->trigger);
- event->trigger = strdup(trigger);
- if (!event->trigger)
- return 1;
-
- return 0;
+ event->trigger = strdup_fatal(trigger);
}
/*
diff --git a/tools/tracing/rtla/src/trace.h b/tools/tracing/rtla/src/trace.h
index 1e5aee4b828dd..95b911a2228b2 100644
--- a/tools/tracing/rtla/src/trace.h
+++ b/tools/tracing/rtla/src/trace.h
@@ -45,6 +45,6 @@ void trace_events_destroy(struct trace_instance *instance,
int trace_events_enable(struct trace_instance *instance,
struct trace_events *events);
-int trace_event_add_filter(struct trace_events *event, char *filter);
-int trace_event_add_trigger(struct trace_events *event, char *trigger);
+void trace_event_add_filter(struct trace_events *event, char *filter);
+void trace_event_add_trigger(struct trace_events *event, char *trigger);
int trace_set_buffer_size(struct trace_instance *trace, int size);
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index 18986a5aed3c1..75cdcc63d5a15 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -1032,3 +1032,38 @@ int strtoi(const char *s, int *res)
*res = (int) lres;
return 0;
}
+
+static inline void fatal_alloc(void)
+{
+ fatal("Error allocating memory\n");
+}
+
+void *calloc_fatal(size_t n, size_t size)
+{
+ void *p = calloc(n, size);
+
+ if (!p)
+ fatal_alloc();
+
+ return p;
+}
+
+void *reallocarray_fatal(void *p, size_t n, size_t size)
+{
+ p = reallocarray(p, n, size);
+
+ if (!p)
+ fatal_alloc();
+
+ return p;
+}
+
+char *strdup_fatal(const char *s)
+{
+ char *p = strdup(s);
+
+ if (!p)
+ fatal_alloc();
+
+ return p;
+}
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index f7c2a52a0ab54..e29c2eb5d569d 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -69,6 +69,9 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr);
int set_comm_cgroup(const char *comm_prefix, const char *cgroup);
int set_pid_cgroup(pid_t pid, const char *cgroup);
int set_cpu_dma_latency(int32_t latency);
+void *calloc_fatal(size_t n, size_t size);
+void *reallocarray_fatal(void *p, size_t n, size_t size);
+char *strdup_fatal(const char *s);
#ifdef HAVE_LIBCPUPOWER_SUPPORT
int save_cpu_idle_disable_state(unsigned int cpu);
int restore_cpu_idle_disable_state(unsigned int cpu);
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 02/18] rtla: Use strdup() to simplify code
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 01/18] rtla: Exit on memory allocation failures during initialization Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 03/18] rtla/actions: Simplify argument parsing Wander Lairson Costa
` (15 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
The actions_add_trace_output() and actions_add_shell() functions were
using calloc() followed by strcpy() to allocate and copy a string.
This can be simplified by using strdup(), which allocates memory and
copies the string in a single step.
Replace the calloc() and strcpy() calls with strdup(), making the
code more concise and readable.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/actions.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c
index 22b8283a183f3..0ac42ffd734a3 100644
--- a/tools/tracing/rtla/src/actions.c
+++ b/tools/tracing/rtla/src/actions.c
@@ -69,8 +69,7 @@ actions_add_trace_output(struct actions *self, const char *trace_output)
self->present[ACTION_TRACE_OUTPUT] = true;
action->type = ACTION_TRACE_OUTPUT;
- action->trace_output = calloc_fatal(strlen(trace_output) + 1, sizeof(char));
- strcpy(action->trace_output, trace_output);
+ action->trace_output = strdup_fatal(trace_output);
}
/*
@@ -97,8 +96,7 @@ actions_add_shell(struct actions *self, const char *command)
self->present[ACTION_SHELL] = true;
action->type = ACTION_SHELL;
- action->command = calloc_fatal(strlen(command) + 1, sizeof(char));
- strcpy(action->command, command);
+ action->command = strdup_fatal(command);
}
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 03/18] rtla/actions: Simplify argument parsing
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 01/18] rtla: Exit on memory allocation failures during initialization Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 02/18] rtla: Use strdup() to simplify code Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 04/18] rtla: Introduce common_threshold_handler() helper Wander Lairson Costa
` (14 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
The actions_parse() function uses open-coded logic to extract arguments
from a string. This includes manual length checks and strncmp() calls,
which can be verbose and error-prone.
To simplify and improve the robustness of argument parsing, introduce a
new extract_arg() helper macro. This macro extracts the value from a
"key=value" pair, making the code more concise and readable.
Also, introduce STRING_LENGTH() and strncmp_static() macros to
perform compile-time calculations of string lengths and safer string
comparisons.
Refactor actions_parse() to use these new helpers, resulting in
cleaner and more maintainable code.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/actions.c | 57 +++++++++++++++++++++++---------
tools/tracing/rtla/src/utils.h | 10 ++++++
2 files changed, 52 insertions(+), 15 deletions(-)
diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c
index 0ac42ffd734a3..b0d68b5de08db 100644
--- a/tools/tracing/rtla/src/actions.c
+++ b/tools/tracing/rtla/src/actions.c
@@ -111,6 +111,29 @@ actions_add_continue(struct actions *self)
action->type = ACTION_CONTINUE;
}
+static inline const char *__extract_arg(const char *token, const char *opt, size_t opt_len)
+{
+ const size_t tok_len = strlen(token);
+
+ if (tok_len <= opt_len)
+ return NULL;
+
+ if (strncmp(token, opt, opt_len))
+ return NULL;
+
+ return token + opt_len;
+}
+
+/*
+ * extract_arg - extract argument value from option token
+ * @token: option token (e.g., "file=trace.txt")
+ * @opt: option name to match (e.g., "file")
+ *
+ * Returns pointer to argument value after "=" if token matches "opt=",
+ * otherwise returns NULL.
+ */
+#define extract_arg(token, opt) __extract_arg(token, opt "=", STRING_LENGTH(opt "="))
+
/*
* actions_parse - add an action based on text specification
*/
@@ -120,6 +143,7 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
enum action_type type = ACTION_NONE;
const char *token;
char trigger_c[strlen(trigger) + 1];
+ const char *arg_value;
/* For ACTION_SIGNAL */
int signal = 0, pid = 0;
@@ -152,12 +176,10 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
if (token == NULL)
trace_output = tracefn;
else {
- if (strlen(token) > 5 && strncmp(token, "file=", 5) == 0) {
- trace_output = token + 5;
- } else {
+ trace_output = extract_arg(token, "file");
+ if (!trace_output)
/* Invalid argument */
return -1;
- }
token = strtok(NULL, ",");
if (token != NULL)
@@ -169,17 +191,21 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
case ACTION_SIGNAL:
/* Takes two arguments, num (signal) and pid */
while (token != NULL) {
- if (strlen(token) > 4 && strncmp(token, "num=", 4) == 0) {
- if (strtoi(token + 4, &signal))
- return -1;
- } else if (strlen(token) > 4 && strncmp(token, "pid=", 4) == 0) {
- if (strncmp(token + 4, "parent", 7) == 0)
- pid = -1;
- else if (strtoi(token + 4, &pid))
+ arg_value = extract_arg(token, "num");
+ if (arg_value) {
+ if (strtoi(arg_value, &signal))
return -1;
} else {
- /* Invalid argument */
- return -1;
+ arg_value = extract_arg(token, "pid");
+ if (arg_value) {
+ if (strncmp_static(arg_value, "parent") == 0)
+ pid = -1;
+ else if (strtoi(arg_value, &pid))
+ return -1;
+ } else {
+ /* Invalid argument */
+ return -1;
+ }
}
token = strtok(NULL, ",");
@@ -194,9 +220,10 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
case ACTION_SHELL:
if (token == NULL)
return -1;
- if (strlen(token) > 8 && strncmp(token, "command=", 8))
+ arg_value = extract_arg(token, "command");
+ if (!arg_value)
return -1;
- actions_add_shell(self, token + 8);
+ actions_add_shell(self, arg_value);
break;
case ACTION_CONTINUE:
/* Takes no argument */
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index e29c2eb5d569d..11458676f607d 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -14,6 +14,16 @@
#define MAX_NICE 20
#define MIN_NICE -19
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+#endif
+
+/* Calculate string length at compile time (excluding null terminator) */
+#define STRING_LENGTH(s) (ARRAY_SIZE(s) - sizeof(*(s)))
+
+/* Compare string with static string, length determined at compile time */
+#define strncmp_static(s1, s2) strncmp(s1, s2, ARRAY_SIZE(s2))
+
#define container_of(ptr, type, member)({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)) ; })
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 04/18] rtla: Introduce common_threshold_handler() helper
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (2 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 03/18] rtla/actions: Simplify argument parsing Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 05/18] rtla: Replace magic number with MAX_PATH Wander Lairson Costa
` (13 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
Several functions duplicate the logic for handling threshold actions.
When a threshold is reached, these functions stop the trace, perform
configured actions, and restart the trace if --on-threshold continue
is set.
Create common_threshold_handler() to centralize this shared logic and
avoid code duplication. The function executes the configured threshold
actions and restarts the necessary trace instances when appropriate.
Also add should_continue_tracing() helper to encapsulate the check
for whether tracing should continue after a threshold event, improving
code readability at call sites.
In timerlat_top_bpf_main_loop(), use common_params directly instead
of casting through timerlat_params when only common fields are needed.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/common.c | 61 ++++++++++++++++++--------
tools/tracing/rtla/src/common.h | 18 ++++++++
tools/tracing/rtla/src/timerlat_hist.c | 19 ++++----
tools/tracing/rtla/src/timerlat_top.c | 32 +++++++-------
4 files changed, 86 insertions(+), 44 deletions(-)
diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c
index ceff76a62a30b..cbc207fa58707 100644
--- a/tools/tracing/rtla/src/common.c
+++ b/tools/tracing/rtla/src/common.c
@@ -175,6 +175,38 @@ common_apply_config(struct osnoise_tool *tool, struct common_params *params)
}
+/**
+ * common_threshold_handler - handle latency threshold overflow
+ * @tool: pointer to the osnoise_tool instance containing trace contexts
+ *
+ * Executes the configured threshold actions (e.g., saving trace, printing,
+ * sending signals). If the continue flag is set (--on-threshold continue),
+ * restarts the auxiliary trace instances to continue monitoring.
+ *
+ * Return: 0 for success, -1 for error.
+ */
+int
+common_threshold_handler(const struct osnoise_tool *tool)
+{
+ actions_perform(&tool->params->threshold_actions);
+
+ if (!should_continue_tracing(tool->params))
+ /* continue flag not set, break */
+ return 0;
+
+ /* continue action reached, re-enable tracing */
+ if (tool->record && trace_instance_start(&tool->record->trace))
+ goto err;
+ if (tool->aa && trace_instance_start(&tool->aa->trace))
+ goto err;
+
+ return 0;
+
+err:
+ err_msg("Error restarting trace\n");
+ return -1;
+}
+
int run_tool(struct tool_ops *ops, int argc, char *argv[])
{
struct common_params *params;
@@ -352,17 +384,14 @@ int top_main_loop(struct osnoise_tool *tool)
/* stop tracing requested, do not perform actions */
return 0;
- actions_perform(¶ms->threshold_actions);
+ retval = common_threshold_handler(tool);
+ if (retval)
+ return retval;
+
- if (!params->threshold_actions.continue_flag)
- /* continue flag not set, break */
+ if (!should_continue_tracing(params))
return 0;
- /* continue action reached, re-enable tracing */
- if (record)
- trace_instance_start(&record->trace);
- if (tool->aa)
- trace_instance_start(&tool->aa->trace);
trace_instance_start(trace);
}
@@ -403,18 +432,14 @@ int hist_main_loop(struct osnoise_tool *tool)
/* stop tracing requested, do not perform actions */
break;
- actions_perform(¶ms->threshold_actions);
+ retval = common_threshold_handler(tool);
+ if (retval)
+ return retval;
- if (!params->threshold_actions.continue_flag)
- /* continue flag not set, break */
- break;
+ if (!should_continue_tracing(params))
+ return 0;
- /* continue action reached, re-enable tracing */
- if (tool->record)
- trace_instance_start(&tool->record->trace);
- if (tool->aa)
- trace_instance_start(&tool->aa->trace);
- trace_instance_start(&tool->trace);
+ trace_instance_start(trace);
}
/* is there still any user-threads ? */
diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h
index 7602c5593ef5d..c548decd3c40f 100644
--- a/tools/tracing/rtla/src/common.h
+++ b/tools/tracing/rtla/src/common.h
@@ -143,6 +143,24 @@ struct tool_ops {
void (*free)(struct osnoise_tool *tool);
};
+/**
+ * should_continue_tracing - check if tracing should continue after threshold
+ * @params: pointer to the common parameters structure
+ *
+ * Returns true if the continue action was configured (--on-threshold continue),
+ * indicating that tracing should be restarted after handling the threshold event.
+ *
+ * Return: 1 if tracing should continue, 0 otherwise.
+ */
+static inline int
+should_continue_tracing(const struct common_params *params)
+{
+ return params->threshold_actions.continue_flag;
+}
+
+int
+common_threshold_handler(const struct osnoise_tool *tool);
+
int osnoise_set_cpus(struct osnoise_context *context, char *cpus);
void osnoise_restore_cpus(struct osnoise_context *context);
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 6ea397421f1c9..6b8eaef8a3a09 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -17,6 +17,7 @@
#include "timerlat.h"
#include "timerlat_aa.h"
#include "timerlat_bpf.h"
+#include "common.h"
struct timerlat_hist_cpu {
int *irq;
@@ -1048,7 +1049,6 @@ static struct osnoise_tool
static int timerlat_hist_bpf_main_loop(struct osnoise_tool *tool)
{
- struct timerlat_params *params = to_timerlat_params(tool->params);
int retval;
while (!stop_tracing) {
@@ -1056,18 +1056,17 @@ static int timerlat_hist_bpf_main_loop(struct osnoise_tool *tool)
if (!stop_tracing) {
/* Threshold overflow, perform actions on threshold */
- actions_perform(¶ms->common.threshold_actions);
+ retval = common_threshold_handler(tool);
+ if (retval)
+ return retval;
- if (!params->common.threshold_actions.continue_flag)
- /* continue flag not set, break */
+ if (!should_continue_tracing(tool->params))
break;
- /* continue action reached, re-enable tracing */
- if (tool->record)
- trace_instance_start(&tool->record->trace);
- if (tool->aa)
- trace_instance_start(&tool->aa->trace);
- timerlat_bpf_restart_tracing();
+ if (timerlat_bpf_restart_tracing()) {
+ err_msg("Error restarting BPF trace\n");
+ return -1;
+ }
}
}
timerlat_bpf_detach();
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index dd727cb48b551..c6f6757c3fb6b 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -17,6 +17,7 @@
#include "timerlat.h"
#include "timerlat_aa.h"
#include "timerlat_bpf.h"
+#include "common.h"
struct timerlat_top_cpu {
unsigned long long irq_count;
@@ -801,10 +802,10 @@ static struct osnoise_tool
static int
timerlat_top_bpf_main_loop(struct osnoise_tool *tool)
{
- struct timerlat_params *params = to_timerlat_params(tool->params);
+ const struct common_params *params = tool->params;
int retval, wait_retval;
- if (params->common.aa_only) {
+ if (params->aa_only) {
/* Auto-analysis only, just wait for stop tracing */
timerlat_bpf_wait(-1);
return 0;
@@ -812,8 +813,8 @@ timerlat_top_bpf_main_loop(struct osnoise_tool *tool)
/* Pull and display data in a loop */
while (!stop_tracing) {
- wait_retval = timerlat_bpf_wait(params->common.quiet ? -1 :
- params->common.sleep_time);
+ wait_retval = timerlat_bpf_wait(params->quiet ? -1 :
+ params->sleep_time);
retval = timerlat_top_bpf_pull_data(tool);
if (retval) {
@@ -821,28 +822,27 @@ timerlat_top_bpf_main_loop(struct osnoise_tool *tool)
return retval;
}
- if (!params->common.quiet)
+ if (!params->quiet)
timerlat_print_stats(tool);
if (wait_retval != 0) {
/* Stopping requested by tracer */
- actions_perform(¶ms->common.threshold_actions);
+ retval = common_threshold_handler(tool);
+ if (retval)
+ return retval;
- if (!params->common.threshold_actions.continue_flag)
- /* continue flag not set, break */
+ if (!should_continue_tracing(tool->params))
break;
- /* continue action reached, re-enable tracing */
- if (tool->record)
- trace_instance_start(&tool->record->trace);
- if (tool->aa)
- trace_instance_start(&tool->aa->trace);
- timerlat_bpf_restart_tracing();
+ if (timerlat_bpf_restart_tracing()) {
+ err_msg("Error restarting BPF trace\n");
+ return -1;
+ }
}
/* is there still any user-threads ? */
- if (params->common.user_workload) {
- if (params->common.user.stopped_running) {
+ if (params->user_workload) {
+ if (params->user.stopped_running) {
debug_msg("timerlat user space threads stopped!\n");
break;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 05/18] rtla: Replace magic number with MAX_PATH
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (3 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 04/18] rtla: Introduce common_threshold_handler() helper Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 06/18] rtla: Simplify code by caching string lengths Wander Lairson Costa
` (12 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
The trace functions use a buffer to manipulate strings that will be
written to tracefs files. These buffers are defined with a magic number
of 1024, which is a common source of vulnerabilities.
Replace the magic number 1024 with the MAX_PATH macro to make the code
safer and more readable. While at it, replace other instances of the
magic number with ARRAY_SIZE() when the buffer is locally defined.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/osnoise.c | 2 +-
tools/tracing/rtla/src/timerlat_u.c | 4 ++--
tools/tracing/rtla/src/trace.c | 20 ++++++++++----------
3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c
index ec074cd53dd84..9d1fd9981fe91 100644
--- a/tools/tracing/rtla/src/osnoise.c
+++ b/tools/tracing/rtla/src/osnoise.c
@@ -62,7 +62,7 @@ int osnoise_set_cpus(struct osnoise_context *context, char *cpus)
if (!context->curr_cpus)
return -1;
- snprintf(buffer, 1024, "%s\n", cpus);
+ snprintf(buffer, ARRAY_SIZE(buffer), "%s\n", cpus);
debug_msg("setting cpus to %s from %s", cpus, context->orig_cpus);
diff --git a/tools/tracing/rtla/src/timerlat_u.c b/tools/tracing/rtla/src/timerlat_u.c
index ce68e39d25fde..efe2f72686486 100644
--- a/tools/tracing/rtla/src/timerlat_u.c
+++ b/tools/tracing/rtla/src/timerlat_u.c
@@ -32,7 +32,7 @@
static int timerlat_u_main(int cpu, struct timerlat_u_params *params)
{
struct sched_param sp = { .sched_priority = 95 };
- char buffer[1024];
+ char buffer[MAX_PATH];
int timerlat_fd;
cpu_set_t set;
int retval;
@@ -83,7 +83,7 @@ static int timerlat_u_main(int cpu, struct timerlat_u_params *params)
/* add should continue with a signal handler */
while (true) {
- retval = read(timerlat_fd, buffer, 1024);
+ retval = read(timerlat_fd, buffer, ARRAY_SIZE(buffer));
if (retval < 0)
break;
}
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index 211ca54b15b0e..e1af54f9531b8 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -313,7 +313,7 @@ void trace_event_add_trigger(struct trace_events *event, char *trigger)
static void trace_event_disable_filter(struct trace_instance *instance,
struct trace_events *tevent)
{
- char filter[1024];
+ char filter[MAX_PATH];
int retval;
if (!tevent->filter)
@@ -325,7 +325,7 @@ static void trace_event_disable_filter(struct trace_instance *instance,
debug_msg("Disabling %s:%s filter %s\n", tevent->system,
tevent->event ? : "*", tevent->filter);
- snprintf(filter, 1024, "!%s\n", tevent->filter);
+ snprintf(filter, ARRAY_SIZE(filter), "!%s\n", tevent->filter);
retval = tracefs_event_file_write(instance->inst, tevent->system,
tevent->event, "filter", filter);
@@ -344,7 +344,7 @@ static void trace_event_save_hist(struct trace_instance *instance,
{
int retval, index, out_fd;
mode_t mode = 0644;
- char path[1024];
+ char path[MAX_PATH];
char *hist;
if (!tevent)
@@ -359,7 +359,7 @@ static void trace_event_save_hist(struct trace_instance *instance,
if (retval)
return;
- snprintf(path, 1024, "%s_%s_hist.txt", tevent->system, tevent->event);
+ snprintf(path, ARRAY_SIZE(path), "%s_%s_hist.txt", tevent->system, tevent->event);
printf(" Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path);
@@ -391,7 +391,7 @@ static void trace_event_save_hist(struct trace_instance *instance,
static void trace_event_disable_trigger(struct trace_instance *instance,
struct trace_events *tevent)
{
- char trigger[1024];
+ char trigger[MAX_PATH];
int retval;
if (!tevent->trigger)
@@ -405,7 +405,7 @@ static void trace_event_disable_trigger(struct trace_instance *instance,
trace_event_save_hist(instance, tevent);
- snprintf(trigger, 1024, "!%s\n", tevent->trigger);
+ snprintf(trigger, ARRAY_SIZE(trigger), "!%s\n", tevent->trigger);
retval = tracefs_event_file_write(instance->inst, tevent->system,
tevent->event, "trigger", trigger);
@@ -444,7 +444,7 @@ void trace_events_disable(struct trace_instance *instance,
static int trace_event_enable_filter(struct trace_instance *instance,
struct trace_events *tevent)
{
- char filter[1024];
+ char filter[MAX_PATH];
int retval;
if (!tevent->filter)
@@ -456,7 +456,7 @@ static int trace_event_enable_filter(struct trace_instance *instance,
return 1;
}
- snprintf(filter, 1024, "%s\n", tevent->filter);
+ snprintf(filter, ARRAY_SIZE(filter), "%s\n", tevent->filter);
debug_msg("Enabling %s:%s filter %s\n", tevent->system,
tevent->event ? : "*", tevent->filter);
@@ -479,7 +479,7 @@ static int trace_event_enable_filter(struct trace_instance *instance,
static int trace_event_enable_trigger(struct trace_instance *instance,
struct trace_events *tevent)
{
- char trigger[1024];
+ char trigger[MAX_PATH];
int retval;
if (!tevent->trigger)
@@ -491,7 +491,7 @@ static int trace_event_enable_trigger(struct trace_instance *instance,
return 1;
}
- snprintf(trigger, 1024, "%s\n", tevent->trigger);
+ snprintf(trigger, ARRAY_SIZE(trigger), "%s\n", tevent->trigger);
debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
tevent->event ? : "*", tevent->trigger);
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 06/18] rtla: Simplify code by caching string lengths
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (4 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 05/18] rtla: Replace magic number with MAX_PATH Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 07/18] rtla: Add strscpy() and replace strncpy() calls Wander Lairson Costa
` (11 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
Simplify trace_event_save_hist() and set_comm_cgroup() by computing
string lengths once and storing them in local variables, rather than
calling strlen() multiple times on the same unchanged strings. This
makes the code clearer by eliminating redundant function calls and
improving readability.
In trace_event_save_hist(), the write loop previously called strlen()
on the hist buffer twice per iteration for both the size calculation
and loop condition. Store the length in hist_len before entering the
loop. In set_comm_cgroup(), strlen() was called on cgroup_path up to
three times in succession. Store the result in cg_path_len to use in
both the offset calculation and size parameter for subsequent append
operations.
This simplification makes the code easier to read and maintain without
changing program behavior.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/trace.c | 6 ++++--
tools/tracing/rtla/src/utils.c | 11 +++++++----
2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index e1af54f9531b8..2f529aaf8deef 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -346,6 +346,7 @@ static void trace_event_save_hist(struct trace_instance *instance,
mode_t mode = 0644;
char path[MAX_PATH];
char *hist;
+ size_t hist_len;
if (!tevent)
return;
@@ -376,9 +377,10 @@ static void trace_event_save_hist(struct trace_instance *instance,
}
index = 0;
+ hist_len = strlen(hist);
do {
- index += write(out_fd, &hist[index], strlen(hist) - index);
- } while (index < strlen(hist));
+ index += write(out_fd, &hist[index], hist_len - index);
+ } while (index < hist_len);
free(hist);
out_close:
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index 75cdcc63d5a15..b5a6007b108d2 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -811,6 +811,7 @@ static int open_cgroup_procs(const char *cgroup)
char cgroup_procs[MAX_PATH];
int retval;
int cg_fd;
+ size_t cg_path_len;
retval = find_mount("cgroup2", cgroup_path, sizeof(cgroup_path));
if (!retval) {
@@ -818,16 +819,18 @@ static int open_cgroup_procs(const char *cgroup)
return -1;
}
+ cg_path_len = strlen(cgroup_path);
+
if (!cgroup) {
- retval = get_self_cgroup(&cgroup_path[strlen(cgroup_path)],
- sizeof(cgroup_path) - strlen(cgroup_path));
+ retval = get_self_cgroup(&cgroup_path[cg_path_len],
+ sizeof(cgroup_path) - cg_path_len);
if (!retval) {
err_msg("Did not find self cgroup\n");
return -1;
}
} else {
- snprintf(&cgroup_path[strlen(cgroup_path)],
- sizeof(cgroup_path) - strlen(cgroup_path), "%s/", cgroup);
+ snprintf(&cgroup_path[cg_path_len],
+ sizeof(cgroup_path) - cg_path_len, "%s/", cgroup);
}
snprintf(cgroup_procs, MAX_PATH, "%s/cgroup.procs", cgroup_path);
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 07/18] rtla: Add strscpy() and replace strncpy() calls
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (5 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 06/18] rtla: Simplify code by caching string lengths Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 08/18] rtla/timerlat: Add bounds check for softirq vector Wander Lairson Costa
` (10 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
Introduce a userspace strscpy() implementation that matches the Linux
kernel's strscpy() semantics. The function is built on top of glibc's
strlcpy() and provides guaranteed NUL-termination along with proper
truncation detection through its return value.
The previous strncpy() calls had potential issues: strncpy() does not
guarantee NUL-termination when the source string length equals or
exceeds the destination buffer size. This required defensive patterns
like pre-zeroing buffers or manually setting the last byte to NUL.
The new strscpy() function always NUL-terminates the destination buffer
unless the size is zero, and returns -E2BIG on truncation, making error
handling cleaner and more consistent with kernel code.
Note that unlike the kernel's strscpy(), this implementation uses
strlcpy() internally, which reads the entire source string to determine
its length. The kernel avoids this to prevent potential DoS attacks from
extremely long untrusted strings. This is harmless for a userspace CLI
tool like rtla where input sources are bounded and trusted.
Replace all strncpy() calls in rtla with strscpy(), using sizeof() for
buffer sizes instead of magic constants to ensure the sizes stay in
sync with the actual buffer declarations. Also remove a now-redundant
memset() call that was previously needed to work around strncpy()
behavior.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/timerlat_aa.c | 6 ++---
tools/tracing/rtla/src/utils.c | 34 ++++++++++++++++++++++++++--
tools/tracing/rtla/src/utils.h | 1 +
3 files changed, 36 insertions(+), 5 deletions(-)
diff --git a/tools/tracing/rtla/src/timerlat_aa.c b/tools/tracing/rtla/src/timerlat_aa.c
index 31e66ea2b144c..30ef56d644f9c 100644
--- a/tools/tracing/rtla/src/timerlat_aa.c
+++ b/tools/tracing/rtla/src/timerlat_aa.c
@@ -455,9 +455,9 @@ static int timerlat_aa_thread_handler(struct trace_seq *s, struct tep_record *re
taa_data->thread_blocking_duration = duration;
if (comm)
- strncpy(taa_data->run_thread_comm, comm, MAX_COMM);
+ strscpy(taa_data->run_thread_comm, comm, sizeof(taa_data->run_thread_comm));
else
- sprintf(taa_data->run_thread_comm, "<...>");
+ strscpy(taa_data->run_thread_comm, "<...>", sizeof(taa_data->run_thread_comm));
} else {
taa_data->thread_thread_sum += duration;
@@ -519,7 +519,7 @@ static int timerlat_aa_sched_switch_handler(struct trace_seq *s, struct tep_reco
tep_get_field_val(s, event, "next_pid", record, &taa_data->current_pid, 1);
comm = tep_get_field_raw(s, event, "next_comm", record, &val, 1);
- strncpy(taa_data->current_comm, comm, MAX_COMM);
+ strscpy(taa_data->current_comm, comm, sizeof(taa_data->current_comm));
/*
* If this was a kworker, clean the last kworkers that ran.
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index b5a6007b108d2..e98288e55db15 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -722,8 +722,7 @@ static const int find_mount(const char *fs, char *mp, int sizeof_mp)
if (!found)
return 0;
- memset(mp, 0, sizeof_mp);
- strncpy(mp, mount_point, sizeof_mp - 1);
+ strscpy(mp, mount_point, sizeof_mp);
debug_msg("Fs %s found at %s\n", fs, mp);
return 1;
@@ -1036,6 +1035,37 @@ int strtoi(const char *s, int *res)
return 0;
}
+/**
+ * strscpy - Copy a C-string into a sized buffer
+ * @dst: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: Size of destination buffer
+ *
+ * Copy the source string @src, or as much of it as fits, into the destination
+ * @dst buffer. The destination @dst buffer is always NUL-terminated, unless
+ * it's zero-sized.
+ *
+ * This is a userspace implementation matching the kernel's strscpy() semantics,
+ * built on top of glibc's strlcpy().
+ *
+ * Returns the number of characters copied (not including the trailing NUL)
+ * or -E2BIG if @count is 0 or the copy was truncated.
+ */
+ssize_t strscpy(char *dst, const char *src, size_t count)
+{
+ size_t len;
+
+ if (count == 0)
+ return -E2BIG;
+
+ len = strlcpy(dst, src, count);
+
+ if (len >= count)
+ return -E2BIG;
+
+ return (ssize_t) len;
+}
+
static inline void fatal_alloc(void)
{
fatal("Error allocating memory\n");
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index 11458676f607d..3bca53ee48db6 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -97,6 +97,7 @@ static inline int have_libcpupower_support(void) { return 0; }
#endif /* HAVE_LIBCPUPOWER_SUPPORT */
int auto_house_keeping(cpu_set_t *monitored_cpus);
__attribute__((__warn_unused_result__)) int strtoi(const char *s, int *res);
+ssize_t strscpy(char *dst, const char *src, size_t count);
#define ns_to_usf(x) (((double)x/1000))
#define ns_to_per(total, part) ((part * 100) / (double)total)
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 08/18] rtla/timerlat: Add bounds check for softirq vector
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (6 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 07/18] rtla: Add strscpy() and replace strncpy() calls Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 09/18] rtla: Handle pthread_create() failure properly Wander Lairson Costa
` (9 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
Add bounds checking when accessing the softirq_name array using the
vector value from kernel trace data. The vector field from the
osnoise:softirq_noise event is used directly as an array index without
validation, which could cause an out-of-bounds read if the kernel
provides an unexpected vector value.
The softirq_name array contains 10 elements corresponding to the
standard Linux softirq vectors. While the kernel should only provide
valid vector values in the range 0-9, defensive programming requires
validating untrusted input before using it as an array index. If an
out-of-range vector is encountered, display the word UNKNOWN instead
of attempting to read beyond the array bounds.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/timerlat_aa.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/tracing/rtla/src/timerlat_aa.c b/tools/tracing/rtla/src/timerlat_aa.c
index 30ef56d644f9c..bc421637cc19b 100644
--- a/tools/tracing/rtla/src/timerlat_aa.c
+++ b/tools/tracing/rtla/src/timerlat_aa.c
@@ -417,8 +417,8 @@ static int timerlat_aa_softirq_handler(struct trace_seq *s, struct tep_record *r
taa_data->thread_softirq_sum += duration;
trace_seq_printf(taa_data->softirqs_seq, " %24s:%-3llu %.*s %9.2f us\n",
- softirq_name[vector], vector,
- 24, spaces,
+ vector < ARRAY_SIZE(softirq_name) ? softirq_name[vector] : "UNKNOWN",
+ vector, 24, spaces,
ns_to_usf(duration));
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 09/18] rtla: Handle pthread_create() failure properly
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (7 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 08/18] rtla/timerlat: Add bounds check for softirq vector Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 10/18] rtla: Add str_has_prefix() helper function Wander Lairson Costa
` (8 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Crystal Wood,
Ivan Pravdin, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
Add proper error handling when pthread_create() fails to create the
timerlat user-space dispatcher thread. Previously, the code only logged
an error message but continued execution, which could lead to undefined
behavior when the tool later expects the thread to be running.
When pthread_create() returns an error, the function now jumps to the
out_trace error path to properly clean up resources and exit. This
ensures consistent error handling and prevents the tool from running
in an invalid state without the required user-space thread.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/common.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c
index cbc207fa58707..73906065e7772 100644
--- a/tools/tracing/rtla/src/common.c
+++ b/tools/tracing/rtla/src/common.c
@@ -303,8 +303,10 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[])
params->user.cgroup_name = params->cgroup_name;
retval = pthread_create(&user_thread, NULL, timerlat_u_dispatcher, ¶ms->user);
- if (retval)
+ if (retval) {
err_msg("Error creating timerlat user-space threads\n");
+ goto out_trace;
+ }
}
retval = ops->enable(tool);
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 10/18] rtla: Add str_has_prefix() helper function
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (8 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 09/18] rtla: Handle pthread_create() failure properly Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 11/18] rtla: Use str_has_prefix() for prefix checks Wander Lairson Costa
` (7 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Crystal Wood,
Ivan Pravdin, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
Add a str_has_prefix() helper function that tests whether a string
starts with a given prefix. This function provides a cleaner interface
for prefix matching compared to using strncmp() with strlen() directly.
The function returns a boolean value indicating whether the string
starts with the specified prefix. This helper will be used in
subsequent changes to simplify prefix matching code throughout rtla.
Also add the missing string.h include which is needed for the strlen()
and strncmp() functions used by str_has_prefix() and the existing
strncmp_static() macro.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/utils.h | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index 3bca53ee48db6..165d6d0a0c6ab 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <stdint.h>
+#include <string.h>
#include <time.h>
#include <sched.h>
#include <stdbool.h>
@@ -24,6 +25,18 @@
/* Compare string with static string, length determined at compile time */
#define strncmp_static(s1, s2) strncmp(s1, s2, ARRAY_SIZE(s2))
+/**
+ * str_has_prefix - Test if a string has a given prefix
+ * @str: The string to test
+ * @prefix: The string to see if @str starts with
+ *
+ * Returns: true if @str starts with @prefix, false otherwise
+ */
+static inline bool str_has_prefix(const char *str, const char *prefix)
+{
+ return strncmp(str, prefix, strlen(prefix)) == 0;
+}
+
#define container_of(ptr, type, member)({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)) ; })
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 11/18] rtla: Use str_has_prefix() for prefix checks
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (9 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 10/18] rtla: Add str_has_prefix() helper function Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 12/18] rtla: Enforce exact match for time unit suffixes Wander Lairson Costa
` (6 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
The code currently uses strncmp() combined with strlen() to check if a
string starts with a specific prefix. This pattern is verbose and prone
to errors if the length does not match the prefix string.
Replace this pattern with the str_has_prefix() helper function in both
trace.c and utils.c. This improves code readability and safety by
handling the prefix length calculation automatically.
In addition, remove the unused retval variable from
trace_event_save_hist() in trace.c to clean up the function and
silence potential compiler warnings.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/trace.c | 5 ++---
tools/tracing/rtla/src/utils.c | 3 +--
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index 2f529aaf8deef..ed7db5f4115ce 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -342,7 +342,7 @@ static void trace_event_disable_filter(struct trace_instance *instance,
static void trace_event_save_hist(struct trace_instance *instance,
struct trace_events *tevent)
{
- int retval, index, out_fd;
+ int index, out_fd;
mode_t mode = 0644;
char path[MAX_PATH];
char *hist;
@@ -356,8 +356,7 @@ static void trace_event_save_hist(struct trace_instance *instance,
return;
/* is this a hist: trigger? */
- retval = strncmp(tevent->trigger, "hist:", strlen("hist:"));
- if (retval)
+ if (!str_has_prefix(tevent->trigger, "hist:"))
return;
snprintf(path, ARRAY_SIZE(path), "%s_%s_hist.txt", tevent->system, tevent->event);
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index e98288e55db15..486d96e8290fb 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -318,8 +318,7 @@ static int procfs_is_workload_pid(const char *comm_prefix, struct dirent *proc_e
return 0;
buffer[MAX_PATH-1] = '\0';
- retval = strncmp(comm_prefix, buffer, strlen(comm_prefix));
- if (retval)
+ if (!str_has_prefix(buffer, comm_prefix))
return 0;
/* comm already have \n */
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 12/18] rtla: Enforce exact match for time unit suffixes
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (10 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 11/18] rtla: Use str_has_prefix() for prefix checks Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-12 12:17 ` Tomas Glozar
2026-03-09 19:46 ` [PATCH v4 13/18] rtla: Use str_has_prefix() for option prefix check Wander Lairson Costa
` (5 subsequent siblings)
17 siblings, 1 reply; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Crystal Wood,
Ivan Pravdin, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
The parse_ns_duration() function currently uses prefix matching for
detecting time units. This approach is problematic as it silently
accepts malformed strings such as "100nsx" or "100us_invalid" by
ignoring the trailing characters, leading to potential configuration
errors.
Introduce a match_time_unit() helper that checks the suffix matches
exactly and is followed by either end-of-string or a ':' delimiter.
The ':' is needed because parse_ns_duration() is also called from
get_long_ns_after_colon() when parsing SCHED_DEADLINE priority
specifications in the format "d:runtime:period" (e.g., "d:10ms:100ms").
A plain strcmp() would reject valid deadline strings because the suffix
"ms" is followed by ":100ms", not end-of-string. Similarly,
strncmp_static() would fail because ARRAY_SIZE() includes the NUL
terminator, making it equivalent to strcmp() for this comparison.
The match_time_unit() helper solves both problems: it rejects malformed
input like "100msx" while correctly handling the colon-delimited
deadline format.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/utils.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index 486d96e8290fb..c3ed9089e7260 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -200,6 +200,21 @@ long parse_seconds_duration(char *val)
return t;
}
+/*
+ * match_time_unit - check if str starts with unit followed by end-of-string or ':'
+ *
+ * This allows the time unit parser to work both in standalone duration strings
+ * like "100ms" and in colon-delimited SCHED_DEADLINE specifications like
+ * "d:10ms:100ms", while still rejecting malformed input like "100msx".
+ */
+static bool match_time_unit(const char *str, const char *unit)
+{
+ size_t len = strlen(unit);
+
+ return strncmp(str, unit, len) == 0 &&
+ (str[len] == '\0' || str[len] == ':');
+}
+
/*
* parse_ns_duration - parse duration with ns/us/ms/s converting it to nanoseconds
*/
@@ -211,15 +226,15 @@ long parse_ns_duration(char *val)
t = strtol(val, &end, 10);
if (end) {
- if (!strncmp(end, "ns", 2)) {
+ if (match_time_unit(end, "ns")) {
return t;
- } else if (!strncmp(end, "us", 2)) {
+ } else if (match_time_unit(end, "us")) {
t *= 1000;
return t;
- } else if (!strncmp(end, "ms", 2)) {
+ } else if (match_time_unit(end, "ms")) {
t *= 1000 * 1000;
return t;
- } else if (!strncmp(end, "s", 1)) {
+ } else if (match_time_unit(end, "s")) {
t *= 1000 * 1000 * 1000;
return t;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [PATCH v4 12/18] rtla: Enforce exact match for time unit suffixes
2026-03-09 19:46 ` [PATCH v4 12/18] rtla: Enforce exact match for time unit suffixes Wander Lairson Costa
@ 2026-03-12 12:17 ` Tomas Glozar
0 siblings, 0 replies; 20+ messages in thread
From: Tomas Glozar @ 2026-03-12 12:17 UTC (permalink / raw)
To: Wander Lairson Costa
Cc: Steven Rostedt, Crystal Wood, Ivan Pravdin, Costa Shulyupin,
John Kacur, Tiezhu Yang, Daniel Bristot de Oliveira,
Daniel Wagner, open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
po 9. 3. 2026 v 20:58 odesílatel Wander Lairson Costa
<wander@redhat.com> napsal:
>
> The parse_ns_duration() function currently uses prefix matching for
> detecting time units. This approach is problematic as it silently
> accepts malformed strings such as "100nsx" or "100us_invalid" by
> ignoring the trailing characters, leading to potential configuration
> errors.
>
> Introduce a match_time_unit() helper that checks the suffix matches
> exactly and is followed by either end-of-string or a ':' delimiter.
> The ':' is needed because parse_ns_duration() is also called from
> get_long_ns_after_colon() when parsing SCHED_DEADLINE priority
> specifications in the format "d:runtime:period" (e.g., "d:10ms:100ms").
>
> A plain strcmp() would reject valid deadline strings because the suffix
> "ms" is followed by ":100ms", not end-of-string. Similarly,
> strncmp_static() would fail because ARRAY_SIZE() includes the NUL
> terminator, making it equivalent to strcmp() for this comparison.
>
This fixes both the command and the corresponding unit test, thanks!
> The match_time_unit() helper solves both problems: it rejects malformed
> input like "100msx" while correctly handling the colon-delimited
> deadline format.
>
It now fails to reject this kind of input:
$ rtla timerlat -P d:10ms:100ms:somethingsomething
// this is also parsed as valid
But that can be fixed in a future patchset, perhaps together with also migrating
parse_seconds_duration() from prefix matching to match_time_unit() as well.
That would prevent the same imprecise parsing issue for -d:
$ rtla timerlat -d 1somethingsomething
// this is also parsed as valid
Tomas
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v4 13/18] rtla: Use str_has_prefix() for option prefix check
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (11 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 12/18] rtla: Enforce exact match for time unit suffixes Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 14/18] rtla/timerlat: Simplify RTLA_NO_BPF environment variable check Wander Lairson Costa
` (4 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Crystal Wood,
Ivan Pravdin, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
The argument parsing code in timerlat_main() and osnoise_main() uses
strncmp() with a length of 1 to check if the first argument starts
with a dash, indicating an option flag was passed.
Replace this pattern with str_has_prefix() for consistency with the
rest of the codebase. While character comparison would be slightly
more efficient, using str_has_prefix() provides better readability
and maintains a uniform coding style throughout the rtla tool.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/osnoise.c | 2 +-
tools/tracing/rtla/src/timerlat.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c
index 9d1fd9981fe91..2db3db155c44a 100644
--- a/tools/tracing/rtla/src/osnoise.c
+++ b/tools/tracing/rtla/src/osnoise.c
@@ -1210,7 +1210,7 @@ int osnoise_main(int argc, char *argv[])
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) {
osnoise_usage(0);
- } else if (strncmp(argv[1], "-", 1) == 0) {
+ } else if (str_has_prefix(argv[1], "-")) {
/* the user skipped the tool, call the default one */
run_tool(&osnoise_top_ops, argc, argv);
exit(0);
diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
index 8f8811f7a13bd..84577daadd668 100644
--- a/tools/tracing/rtla/src/timerlat.c
+++ b/tools/tracing/rtla/src/timerlat.c
@@ -272,7 +272,7 @@ int timerlat_main(int argc, char *argv[])
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) {
timerlat_usage(0);
- } else if (strncmp(argv[1], "-", 1) == 0) {
+ } else if (str_has_prefix(argv[1], "-")) {
/* the user skipped the tool, call the default one */
run_tool(&timerlat_top_ops, argc, argv);
exit(0);
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 14/18] rtla/timerlat: Simplify RTLA_NO_BPF environment variable check
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (12 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 13/18] rtla: Use str_has_prefix() for option prefix check Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 15/18] rtla/trace: Fix write loop in trace_event_save_hist() Wander Lairson Costa
` (3 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
The code that checks the RTLA_NO_BPF environment variable calls
getenv() twice and uses strncmp() with a length of 2 to compare
against the single-character string "1". This is inefficient and
the comparison length is unnecessarily long.
Store the result of getenv() in a local variable to avoid the
redundant call, and replace strncmp() with strncmp_static() for
the exact match comparison. This follows the same pattern
established in recent commits that improved string comparison
consistency throughout the rtla codebase.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/timerlat.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
index 84577daadd668..91f15f86e78d4 100644
--- a/tools/tracing/rtla/src/timerlat.c
+++ b/tools/tracing/rtla/src/timerlat.c
@@ -28,12 +28,13 @@ int
timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params)
{
int retval;
+ const char *const rtla_no_bpf = getenv("RTLA_NO_BPF");
/*
* Try to enable BPF, unless disabled explicitly.
* If BPF enablement fails, fall back to tracefs mode.
*/
- if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) {
+ if (rtla_no_bpf && strncmp_static(rtla_no_bpf, "1") == 0) {
debug_msg("RTLA_NO_BPF set, disabling BPF\n");
params->mode = TRACING_MODE_TRACEFS;
} else if (!tep_find_event_by_name(tool->trace.tep, "osnoise", "timerlat_sample")) {
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 15/18] rtla/trace: Fix write loop in trace_event_save_hist()
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (13 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 14/18] rtla/timerlat: Simplify RTLA_NO_BPF environment variable check Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 16/18] rtla/trace: Fix I/O handling in save_trace_to_file() Wander Lairson Costa
` (2 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Crystal Wood,
Ivan Pravdin, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
The write loop in trace_event_save_hist() does not correctly handle
errors from the write() system call. If write() returns -1, this value
is added to the loop index, leading to an incorrect memory access on
the next iteration and potentially an infinite loop. The loop also
fails to handle EINTR.
Fix the write loop by introducing proper error handling. The return
value of write() is now stored in a ssize_t variable and checked for
errors. The loop retries the call if interrupted by a signal and breaks
on any other error after logging it with strerror().
Additionally, change the index variable type from int to size_t to
match the type used for buffer sizes and by strlen(), improving type
safety.
Fixes: 761916fd02c2 ("rtla/trace: Save event histogram output to a file")
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/trace.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index ed7db5f4115ce..fed3362527b08 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -342,11 +342,11 @@ static void trace_event_disable_filter(struct trace_instance *instance,
static void trace_event_save_hist(struct trace_instance *instance,
struct trace_events *tevent)
{
- int index, out_fd;
+ size_t index, hist_len;
mode_t mode = 0644;
char path[MAX_PATH];
char *hist;
- size_t hist_len;
+ int out_fd;
if (!tevent)
return;
@@ -378,7 +378,15 @@ static void trace_event_save_hist(struct trace_instance *instance,
index = 0;
hist_len = strlen(hist);
do {
- index += write(out_fd, &hist[index], hist_len - index);
+ const ssize_t written = write(out_fd, &hist[index], hist_len - index);
+
+ if (written < 0) {
+ if (errno == EINTR)
+ continue;
+ err_msg(" Error writing hist file: %s\n", strerror(errno));
+ break;
+ }
+ index += written;
} while (index < hist_len);
free(hist);
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 16/18] rtla/trace: Fix I/O handling in save_trace_to_file()
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (14 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 15/18] rtla/trace: Fix write loop in trace_event_save_hist() Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 17/18] rtla/utils: Fix resource leak in set_comm_sched_attr() Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 18/18] rtla/utils: Fix loop condition in PID validation Wander Lairson Costa
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Crystal Wood,
Ivan Pravdin, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
The read/write loop in save_trace_to_file() does not correctly handle
errors from the read() and write() system calls. If either call is
interrupted by a signal, it returns -1 with errno set to EINTR, but
the code treats this as a fatal error and aborts the save operation.
Additionally, write() may perform a partial write, returning fewer
bytes than requested, which the code does not handle.
Fix the I/O loop by introducing proper error handling. The return
value of read() is now stored in a ssize_t variable and checked for
errors, with EINTR causing a retry. For write(), an inner loop ensures
all bytes are written, handling both EINTR and partial writes. Error
messages now include strerror() output for better debugging.
This follows the same pattern established in the previous commit that
fixed trace_event_save_hist(), ensuring consistent and robust I/O
handling throughout the trace saving code.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/trace.c | 31 ++++++++++++++++++++++++-------
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index fed3362527b08..e407447773d04 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -73,6 +73,8 @@ int save_trace_to_file(struct tracefs_instance *inst, const char *filename)
char buffer[4096];
int out_fd, in_fd;
int retval = -1;
+ ssize_t n_read;
+ ssize_t n_written;
if (!inst || !filename)
return 0;
@@ -90,15 +92,30 @@ int save_trace_to_file(struct tracefs_instance *inst, const char *filename)
goto out_close_in;
}
- do {
- retval = read(in_fd, buffer, sizeof(buffer));
- if (retval <= 0)
+ for (;;) {
+ n_read = read(in_fd, buffer, sizeof(buffer));
+ if (n_read < 0) {
+ if (errno == EINTR)
+ continue;
+ err_msg("Error reading trace file: %s\n", strerror(errno));
goto out_close;
+ }
+ if (n_read == 0)
+ break;
- retval = write(out_fd, buffer, retval);
- if (retval < 0)
- goto out_close;
- } while (retval > 0);
+ n_written = 0;
+ while (n_written < n_read) {
+ const ssize_t w = write(out_fd, buffer + n_written, n_read - n_written);
+
+ if (w < 0) {
+ if (errno == EINTR)
+ continue;
+ err_msg("Error writing trace file: %s\n", strerror(errno));
+ goto out_close;
+ }
+ n_written += w;
+ }
+ }
retval = 0;
out_close:
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 17/18] rtla/utils: Fix resource leak in set_comm_sched_attr()
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (15 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 16/18] rtla/trace: Fix I/O handling in save_trace_to_file() Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
2026-03-09 19:46 ` [PATCH v4 18/18] rtla/utils: Fix loop condition in PID validation Wander Lairson Costa
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
The set_comm_sched_attr() function opens the /proc directory via
opendir() but fails to call closedir() on its successful exit path.
If the function iterates through all processes without error, it
returns 0 directly, leaking the DIR stream pointer.
Fix this by refactoring the function to use a single exit path. A
retval variable is introduced to track the success or failure status.
All exit points now jump to a unified out label that calls closedir()
before the function returns, ensuring the resource is always freed.
Fixes: dada03db9bb19 ("rtla: Remove procps-ng dependency")
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/utils.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index c3ed9089e7260..bcc5b5d383d8b 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -377,22 +377,23 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr)
if (strtoi(proc_entry->d_name, &pid)) {
err_msg("'%s' is not a valid pid", proc_entry->d_name);
- goto out_err;
+ retval = 1;
+ goto out;
}
/* procfs_is_workload_pid confirmed it is a pid */
retval = __set_sched_attr(pid, attr);
if (retval) {
err_msg("Error setting sched attributes for pid:%s\n", proc_entry->d_name);
- goto out_err;
+ goto out;
}
debug_msg("Set sched attributes for pid:%s\n", proc_entry->d_name);
}
- return 0;
-out_err:
+ retval = 0;
+out:
closedir(procfs);
- return 1;
+ return retval;
}
#define INVALID_VAL (~0L)
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 18/18] rtla/utils: Fix loop condition in PID validation
2026-03-09 19:46 [PATCH v4 00/18] rtla: Robustness and code quality improvements Wander Lairson Costa
` (16 preceding siblings ...)
2026-03-09 19:46 ` [PATCH v4 17/18] rtla/utils: Fix resource leak in set_comm_sched_attr() Wander Lairson Costa
@ 2026-03-09 19:46 ` Wander Lairson Costa
17 siblings, 0 replies; 20+ messages in thread
From: Wander Lairson Costa @ 2026-03-09 19:46 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Bristot de Oliveira, Daniel Wagner,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
The procfs_is_workload_pid() function iterates through a directory
entry name to validate if it represents a process ID. The loop
condition checks if the pointer t_name is non-NULL, but since
incrementing a pointer never makes it NULL, this condition is always
true within the loop's context. Although the inner isdigit() check
catches the NUL terminator and breaks out of the loop, the condition
is semantically misleading and not idiomatic for C string processing.
Correct the loop condition from checking the pointer (t_name) to
checking the character it points to (*t_name). This ensures the loop
terminates when the NUL terminator is reached, aligning with standard
C string iteration practices. While the original code functioned
correctly due to the existing character validation, this change
improves code clarity and maintainability.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/utils.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index bcc5b5d383d8b..16aa59c90bdb2 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -311,7 +311,7 @@ static int procfs_is_workload_pid(const char *comm_prefix, struct dirent *proc_e
return 0;
/* check if the string is a pid */
- for (t_name = proc_entry->d_name; t_name; t_name++) {
+ for (t_name = proc_entry->d_name; *t_name; t_name++) {
if (!isdigit(*t_name))
break;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread