Skip to content

Commit

Permalink
tracing: Silence GCC 9 array bounds warning
Browse files Browse the repository at this point in the history
Starting with GCC 9, -Warray-bounds detects cases when memset is called
starting on a member of a struct but the size to be cleared ends up
writing over further members.

Such a call happens in the trace code to clear, at once, all members
after and including `seq` on struct trace_iterator:

    In function 'memset',
        inlined from 'ftrace_dump' at kernel/trace/trace.c:8914:3:
    ./include/linux/string.h:344:9: warning: '__builtin_memset' offset
    [8505, 8560] from the object at 'iter' is out of the bounds of
    referenced subobject 'seq' with type 'struct trace_seq' at offset
    4368 [-Warray-bounds]
      344 |  return __builtin_memset(p, c, size);
          |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

In order to avoid GCC complaining about it, we compute the address
ourselves by adding the offsetof distance instead of referring
directly to the member.

Since there are two places doing this clear (trace.c and trace_kdb.c),
take the chance to move the workaround into a single place in
the internal header.

Link: http://lkml.kernel.org/r/[email protected]

Signed-off-by: Miguel Ojeda <[email protected]>
[ Removed unnecessary parenthesis around "iter" ]
Signed-off-by: Steven Rostedt (VMware) <[email protected]>
  • Loading branch information
ojeda authored and rostedt committed May 26, 2019
1 parent 4eebe38 commit 0c97bf8
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 10 deletions.
6 changes: 1 addition & 5 deletions kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -8910,12 +8910,8 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)

cnt++;

/* reset all but tr, trace, and overruns */
memset(&iter.seq, 0,
sizeof(struct trace_iterator) -
offsetof(struct trace_iterator, seq));
trace_iterator_reset(&iter);
iter.iter_flags |= TRACE_FILE_LAT_FMT;
iter.pos = -1;

if (trace_find_next_entry_inc(&iter) != NULL) {
int ret;
Expand Down
18 changes: 18 additions & 0 deletions kernel/trace/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -1966,4 +1966,22 @@ static inline void tracer_hardirqs_off(unsigned long a0, unsigned long a1) { }

extern struct trace_iterator *tracepoint_print_iter;

/*
* Reset the state of the trace_iterator so that it can read consumed data.
* Normally, the trace_iterator is used for reading the data when it is not
* consumed, and must retain state.
*/
static __always_inline void trace_iterator_reset(struct trace_iterator *iter)
{
const size_t offset = offsetof(struct trace_iterator, seq);

/*
* Keep gcc from complaining about overwriting more than just one
* member in the structure.
*/
memset((char *)iter + offset, 0, sizeof(struct trace_iterator) - offset);

iter->pos = -1;
}

#endif /* _LINUX_KERNEL_TRACE_H */
6 changes: 1 addition & 5 deletions kernel/trace/trace_kdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,8 @@ static void ftrace_dump_buf(int skip_entries, long cpu_file)
if (skip_entries)
kdb_printf("(skipping %d entries)\n", skip_entries);

/* reset all but tr, trace, and overruns */
memset(&iter.seq, 0,
sizeof(struct trace_iterator) -
offsetof(struct trace_iterator, seq));
trace_iterator_reset(&iter);
iter.iter_flags |= TRACE_FILE_LAT_FMT;
iter.pos = -1;

if (cpu_file == RING_BUFFER_ALL_CPUS) {
for_each_tracing_cpu(cpu) {
Expand Down

0 comments on commit 0c97bf8

Please sign in to comment.