tracing: Silence GCC 9 array bounds warning 80/221280/1
authorMiguel Ojeda <miguel.ojeda.sandonis@gmail.com>
Thu, 23 May 2019 12:45:35 +0000 (14:45 +0200)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Tue, 31 Dec 2019 00:42:29 +0000 (09:42 +0900)
commit 0c97bf863efce63d6ab7971dad811601e6171d2f upstream.

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/20190523124535.GA12931@gmail.com
Signed-off-by: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
[ Removed unnecessary parenthesis around "iter" ]
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[sw0312.kim: cherry-pick from stable linux-4.14.y commit 50bbae7dad92 for gcc 9 build]
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Change-Id: I9f9b22003b8d13267b0f0b1d2b00f66bdd9af5f6

kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_kdb.c

index e9cbb96cd99e4c1dbafa5d46045aeb9d8f32c4cd..a3e1828f24e906f5200e54bda710ced91b1dc1c9 100644 (file)
@@ -8239,12 +8239,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;
index 851cd1605085774f21e85eaafeb09047fe87dce7..53a917d83c2d308bcf689be80f8e8051c2f45880 100644 (file)
@@ -1820,4 +1820,22 @@ static inline int tracing_alloc_snapshot_instance(struct trace_array *tr)
 
 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 */
index d953c163a0794f5cd4578ae6957f0645ff1eaa0d..9f2b85b4d9e4c2642a90d23913a94ce3ad685ff3 100644 (file)
@@ -41,12 +41,8 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
 
        kdb_printf("Dumping ftrace buffer:\n");
 
-       /* 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) {