diff options
author | Jiri Olsa <jolsa@redhat.com> | 2011-03-07 15:13:40 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-03-10 08:54:13 -0500 |
commit | b9a46bba88001504235459c8410f17e6a7e38008 (patch) | |
tree | 35687cc87135475ce5be257c878cee6eeaf40f37 /tools | |
parent | 2a8247a2600c3e087a568fc68a6ec4eedac27ef1 (diff) |
perf top: Fix events overflow in top command
The snprintf function returns number of printed characters even if it
cross the size parameter. So passing enough events via '-e' parameter
will cause segmentation fault.
It's reproduced by following command:
perf top -e `perf list | grep Tracepoint | awk -F'[' '\
{gsub(/[[:space:]]+/,"",$1);array[FNR]=$1}END{outputs=array[1];\
for (i=2;i<=FNR;i++){ outputs=outputs "," array[i];};print outputs}'`
Attached patch is adding SNPRINTF macro that provides the overflow check
and returns actuall number of printed characters.
Reported-by: Han Pingtian <phan@redhat.com>
Cc: Han Pingtian <phan@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <1299528821-17521-2-git-send-email-jolsa@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/top.c | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index 70a9c13f4ad5..4f869da4e9c7 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c | |||
@@ -61,6 +61,12 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) | |||
61 | rb_insert_color(&se->rb_node, tree); | 61 | rb_insert_color(&se->rb_node, tree); |
62 | } | 62 | } |
63 | 63 | ||
64 | #define SNPRINTF(buf, size, fmt, args...) \ | ||
65 | ({ \ | ||
66 | size_t r = snprintf(buf, size, fmt, ## args); \ | ||
67 | r > size ? size : r; \ | ||
68 | }) | ||
69 | |||
64 | size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | 70 | size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) |
65 | { | 71 | { |
66 | struct perf_evsel *counter; | 72 | struct perf_evsel *counter; |
@@ -70,7 +76,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
70 | size_t ret = 0; | 76 | size_t ret = 0; |
71 | 77 | ||
72 | if (!perf_guest) { | 78 | if (!perf_guest) { |
73 | ret = snprintf(bf, size, | 79 | ret = SNPRINTF(bf, size, |
74 | " PerfTop:%8.0f irqs/sec kernel:%4.1f%%" | 80 | " PerfTop:%8.0f irqs/sec kernel:%4.1f%%" |
75 | " exact: %4.1f%% [", samples_per_sec, | 81 | " exact: %4.1f%% [", samples_per_sec, |
76 | 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / | 82 | 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / |
@@ -81,7 +87,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
81 | float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs; | 87 | float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs; |
82 | float guest_us_samples_per_sec = top->guest_us_samples / top->delay_secs; | 88 | float guest_us_samples_per_sec = top->guest_us_samples / top->delay_secs; |
83 | 89 | ||
84 | ret = snprintf(bf, size, | 90 | ret = SNPRINTF(bf, size, |
85 | " PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%" | 91 | " PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%" |
86 | " guest kernel:%4.1f%% guest us:%4.1f%%" | 92 | " guest kernel:%4.1f%% guest us:%4.1f%%" |
87 | " exact: %4.1f%% [", samples_per_sec, | 93 | " exact: %4.1f%% [", samples_per_sec, |
@@ -101,38 +107,38 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
101 | if (top->evlist->nr_entries == 1 || !top->display_weighted) { | 107 | if (top->evlist->nr_entries == 1 || !top->display_weighted) { |
102 | struct perf_evsel *first; | 108 | struct perf_evsel *first; |
103 | first = list_entry(top->evlist->entries.next, struct perf_evsel, node); | 109 | first = list_entry(top->evlist->entries.next, struct perf_evsel, node); |
104 | ret += snprintf(bf + ret, size - ret, "%" PRIu64 "%s ", | 110 | ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", |
105 | (uint64_t)first->attr.sample_period, | 111 | (uint64_t)first->attr.sample_period, |
106 | top->freq ? "Hz" : ""); | 112 | top->freq ? "Hz" : ""); |
107 | } | 113 | } |
108 | 114 | ||
109 | if (!top->display_weighted) { | 115 | if (!top->display_weighted) { |
110 | ret += snprintf(bf + ret, size - ret, "%s", | 116 | ret += SNPRINTF(bf + ret, size - ret, "%s", |
111 | event_name(top->sym_evsel)); | 117 | event_name(top->sym_evsel)); |
112 | } else list_for_each_entry(counter, &top->evlist->entries, node) { | 118 | } else list_for_each_entry(counter, &top->evlist->entries, node) { |
113 | ret += snprintf(bf + ret, size - ret, "%s%s", | 119 | ret += SNPRINTF(bf + ret, size - ret, "%s%s", |
114 | counter->idx ? "/" : "", event_name(counter)); | 120 | counter->idx ? "/" : "", event_name(counter)); |
115 | } | 121 | } |
116 | 122 | ||
117 | ret += snprintf(bf + ret, size - ret, "], "); | 123 | ret += SNPRINTF(bf + ret, size - ret, "], "); |
118 | 124 | ||
119 | if (top->target_pid != -1) | 125 | if (top->target_pid != -1) |
120 | ret += snprintf(bf + ret, size - ret, " (target_pid: %d", | 126 | ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %d", |
121 | top->target_pid); | 127 | top->target_pid); |
122 | else if (top->target_tid != -1) | 128 | else if (top->target_tid != -1) |
123 | ret += snprintf(bf + ret, size - ret, " (target_tid: %d", | 129 | ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d", |
124 | top->target_tid); | 130 | top->target_tid); |
125 | else | 131 | else |
126 | ret += snprintf(bf + ret, size - ret, " (all"); | 132 | ret += SNPRINTF(bf + ret, size - ret, " (all"); |
127 | 133 | ||
128 | if (top->cpu_list) | 134 | if (top->cpu_list) |
129 | ret += snprintf(bf + ret, size - ret, ", CPU%s: %s)", | 135 | ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", |
130 | top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); | 136 | top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); |
131 | else { | 137 | else { |
132 | if (top->target_tid != -1) | 138 | if (top->target_tid != -1) |
133 | ret += snprintf(bf + ret, size - ret, ")"); | 139 | ret += SNPRINTF(bf + ret, size - ret, ")"); |
134 | else | 140 | else |
135 | ret += snprintf(bf + ret, size - ret, ", %d CPU%s)", | 141 | ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", |
136 | top->evlist->cpus->nr, | 142 | top->evlist->cpus->nr, |
137 | top->evlist->cpus->nr > 1 ? "s" : ""); | 143 | top->evlist->cpus->nr > 1 ? "s" : ""); |
138 | } | 144 | } |