We faced segmentation fault on perf top -G at very high sampling rate due to a corrupted callchain. While the root cause was not revealed (I failed to figure it out), this patch tries to protect us from the segfault on such cases.
Unified · Split
| @@ -555,6 +555,8 @@ enum perf_event_type { · 554 unmodified lines | ||
| 555 | 555 | PERF_RECORD_MAX, /* non-ABI */ |
| 556 | 556 | }; |
| 557 | 557 | |
| 558 | +#define PERF_MAX_STACK_DEPTH 255 | |
| 559 | + | |
| 558 | 560 | enum perf_callchain_context { |
| 559 | 561 | PERF_CONTEXT_HV = (__u64)-32, |
| 560 | 562 | PERF_CONTEXT_KERNEL = (__u64)-128, |
| @@ -609,8 +611,6 @@ struct perf_guest_info_callbacks { · 48 unmodified lines | ||
| 609 | 611 | #include <linux/sysfs.h> |
| 610 | 612 | #include <asm/local.h> |
| 611 | 613 | |
| 612 | −#define PERF_MAX_STACK_DEPTH 255 | |
| 613 | − | |
| 614 | 614 | struct perf_callchain_entry { |
| 615 | 615 | __u64 nr; |
| 616 | 616 | __u64 ip[PERF_MAX_STACK_DEPTH]; |
| @@ -300,6 +300,11 @@ int machine__resolve_callchain(struct machine *self, · 299 unmodified lines | ||
| 300 | 300 | |
| 301 | 301 | callchain_cursor_reset(&callchain_cursor); |
| 302 | 302 | |
| 303 | + if (chain->nr > PERF_MAX_STACK_DEPTH) { | |
| 304 | + pr_warning("corrupted callchain. skipping...\n"); | |
| 305 | + return 0; | |
| 306 | + } | |
| 307 | + | |
| 303 | 308 | for (i = 0; i < chain->nr; i++) { |
| 304 | 309 | u64 ip; |
| 305 | 310 | struct addr_location al; |
| @@ -318,7 +323,14 @@ int machine__resolve_callchain(struct machine *self, · 12 unmodified lines | ||
| 318 | 323 | case PERF_CONTEXT_USER: |
| 319 | 324 | cpumode = PERF_RECORD_MISC_USER; break; |
| 320 | 325 | default: |
| 321 | − break; | |
| 326 | + pr_debug("invalid callchain context: " | |
| 327 | + "%"PRId64"\n", (s64) ip); | |
| 328 | + /* | |
| 329 | + * It seems the callchain is corrupted. | |
| 330 | + * Discard all. | |
| 331 | + */ | |
| 332 | + callchain_cursor_reset(&callchain_cursor); | |
| 333 | + return 0; | |
| 322 | 334 | } |
| 323 | 335 | continue; |
| 324 | 336 | } |