#!/bin/bash # Test that perf report handles truncated perf.data gracefully (no crash, no segfault — clean error exit). # SPDX-License-Identifier: GPL-2.0 # # Exercises the bounds checking and minimum-size validation added # by the perf-data-validation hardening series. err=0 cleanup() { [ -n "${perfdata}" ] && rm -f "${perfdata}" "${perfdata}.old" rm -f "${truncated}" "${stderrfile}" trap - EXIT TERM INT } trap 'cleanup; exit 1' TERM INT trap cleanup EXIT perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2 truncated=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2 stderrfile=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2 # Record a simple workload if ! perf record -o "${perfdata}" -- perf test -w noploop 2>/dev/null; then echo "Skip: perf record failed" cleanup exit 2 fi file_size=$(wc -c < "${perfdata}") if [ "${file_size}" -lt 512 ]; then echo "Skip: perf.data too small (${file_size} bytes)" cleanup exit 2 fi # Test truncation at various offsets that exercise different # parsing stages: # 8 — file header magic only, no attrs or data # 64 — partial file header (attr section incomplete) # 256 — into the first events (partial event headers) # 75% — mid-stream truncation (partial event data) for cut_at in 8 64 256 $((file_size * 3 / 4)); do if [ "${cut_at}" -ge "${file_size}" ]; then continue fi dd if="${perfdata}" of="${truncated}" bs="${cut_at}" count=1 2>/dev/null # perf report should exit with an error, not crash. # Capture stderr to detect sanitizer violations. perf report -i "${truncated}" --stdio > /dev/null 2> "${stderrfile}" exit_code=$? # A truncated file should never parse successfully if [ ${exit_code} -eq 0 ]; then echo "FAIL: perf report exited 0 (success) on ${cut_at}-byte truncated file — expected an error" err=1 continue fi # Detect sanitizer violations — ASAN/MSAN/TSAN/UBSAN exit # with code 1 by default, which would otherwise look like a # clean error exit. Check stderr for their markers. if grep -qE "^(==[0-9]+==ERROR:|SUMMARY: [A-Za-z]*Sanitizer)" "${stderrfile}" 2>/dev/null; then sanitizer=$(grep -oE "(Address|Memory|Thread|UndefinedBehavior)Sanitizer" "${stderrfile}" | head -1) echo "FAIL: perf report triggered ${sanitizer:-sanitizer} on ${cut_at}-byte truncated file" err=1 continue fi # Detect crash signals portably — signal numbers differ # across architectures (e.g. SIGBUS is 7 on x86/ARM but # 10 on MIPS/SPARC). Use kill -l to map the number to a # name on the running system. if [ ${exit_code} -gt 128 ] && [ ${exit_code} -lt 200 ]; then sig_name=$(kill -l $((exit_code - 128)) 2>/dev/null) case ${sig_name} in KILL|ILL|ABRT|BUS|FPE|SEGV|TRAP|SYS) echo "FAIL: perf report crashed (SIG${sig_name}) on ${cut_at}-byte truncated file" err=1 ;; esac fi done cleanup exit ${err}