Linux Perf Users
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Tanushree Shah" <tshah@linux.ibm.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [RFC PATCH v3 1/5] perf/trace-dat: Add trace.dat export infrastructure
Date: Mon, 03 Aug 2026 15:14:23 +0000	[thread overview]
Message-ID: <20260803151423.D69211F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260803145958.299956-2-tshah@linux.ibm.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] The `TIME_EXTEND` upper bits are calculated using an incorrect bitwise right shift of 5 instead of 27, resulting in corrupted extended timestamps.
- [High] The ftrace ring buffer event length encoding for large events incorrectly writes the unaligned payload length, omitting necessary alignment padding.
- [High] Using 32-bit `long` variables and `ftell()`/`fseek()` for file offsets truncates trace files larger than 2GB on 32-bit systems.
- [High] Trace data export file headers and ftrace metadata are written in host endianness instead of the target trace's endianness, breaking cross-platform analysis.
- [Medium] Lack of validation for `trace_dat_page_size` can result in a fatal integer division by zero exception when calculating page padding.
--

--- Patch [1]: [RFC PATCH v3 1/5] perf/trace-dat: Add trace.dat export infrastructure ---
commit 34a2391aa9ca8393dfbdda4a477f39710a409324
Author: Tanushree Shah <tshah@linux.ibm.com>

perf/trace-dat: Add trace.dat export infrastructure

This commit adds new utility files to implement infrastructure for
exporting perf.data tracepoints to the trace.dat format. It provides
functions for managing per-cpu event buffers and constructing ftrace
ring buffer pages.

> diff --git a/tools/perf/util/trace-dat.c b/tools/perf/util/trace-dat.c
> new file mode 100644
> index 0000000000000..55a7bd982c6f8
> --- /dev/null
> +++ b/tools/perf/util/trace-dat.c
[ ... ]
> +static int trace_dat__write_page(FILE *fp, unsigned long long base_ts,
> +			char **records, int *rec_sizes, int nr_recs)
> +{
> +	unsigned long long commit = 0;
> +	int offset = TRACE_DAT_RECORD_HEADER_SIZE;
> +	int i;
> +	char *page;
> +
> +	page = calloc(1, trace_dat_page_size);
> +	if (!page)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < nr_recs; i++) {
> +		memcpy(page + offset, records[i], rec_sizes[i]);
> +		offset += rec_sizes[i];
> +		commit += rec_sizes[i];
> +	}
> +
> +	memcpy(page, &base_ts, sizeof(base_ts));
> +	memcpy(page + sizeof(base_ts), &commit, sizeof(commit));

[Severity: High]
Does this write the ftrace page header using native host endianness?

If a trace was recorded on a different architecture, copying the integers
directly to the output stream might mix host-endian metadata with
target-endian payloads.

Should this metadata be byte-swapped to match the target architecture
to ensure cross-platform trace analysis works correctly?

> +
> +	if (!fwrite(page, 1, trace_dat_page_size, fp)) {
> +		free(page);
> +		return -EIO;
> +	}
> +	free(page);
> +
> +	return 0;
> +}
[ ... ]
> +static int trace_dat__write_cpu_dat(FILE *fp, int cpu, unsigned long long *file_offset_out)
> +{
[ ... ]
> +		/* Emit TIME_EXTEND when delta does not fit in 27 bits */
> +		if (time_delta > TRACE_DAT_RECORD_TIME_MASK) {
> +			unsigned int extend_hdr;
> +			unsigned int delta_upper;
> +
> +			extend_size = TRACE_DAT_RECORD_TIME_EXTEND_SIZE;
> +			extend = calloc(1, extend_size);
> +			if (!extend)
> +				return -ENOMEM;
> +
> +			extend_hdr =
> +				((time_delta & TRACE_DAT_RECORD_TIME_MASK) <<
> +				 TRACE_DAT_RECORD_TIME_SHIFT) |
> +				TRACE_DAT_RECORD_TYPE_TIME_EXTEND;
> +			delta_upper = time_delta >> TRACE_DAT_RECORD_TIME_SHIFT;

[Severity: High]
Does this shift the upper bits of the time delta by the correct amount?

The code uses TRACE_DAT_RECORD_TIME_SHIFT, which is 5.
This calculates the upper bits as time_delta >> 5 rather than >> 27.
Would this copy the middle 22 bits instead of the upper bits, causing
timestamp corruption for any events that follow a time extend?

> +
> +			memcpy(extend, &extend_hdr, TRACE_DAT_WORD_SIZE);
> +			memcpy(extend + TRACE_DAT_WORD_SIZE, &delta_upper,
> +				TRACE_DAT_WORD_SIZE);
> +
> +			time_delta = 0;
> +		}
[ ... ]
> +		hdr_word = (time_delta << TRACE_DAT_RECORD_TIME_SHIFT) | type_len;
> +
> +		data_rec = calloc(1, data_rec_size);
> +		if (!data_rec) {
> +			free(extend);
> +			ret = -ENOMEM;
> +			goto out_free;
> +		}
> +
> +		memcpy(data_rec, &hdr_word, TRACE_DAT_WORD_SIZE);
> +
> +		/* Large events: write actual byte length after header */
> +		if (type_len == 0)
> +			memcpy(data_rec + TRACE_DAT_WORD_SIZE, &data_len, TRACE_DAT_WORD_SIZE);

[Severity: High]
For large events, is this writing the raw, unaligned data_len into the
payload length field?

The internal offset data_rec_size advances by the padded size, but the
unaligned data_len is written here. If data_len is not a multiple of 4,
a parser reading this file might compute an incorrect total length and
fail to skip the alignment padding.

Could this cause the reader to misread the next event boundary?

> +
> +		memcpy(data_rec + payload_offset, event->raw, data_len);
> +
[ ... ]
> +int trace_dat__write_flyrecord_section(void)
> +{
[ ... ]
> +	section_size_pos = ftell(trace_dat_fp);
> +	if (!fwrite(&section_size, sizeof(unsigned long long), 1, trace_dat_fp)) {
> +		ret = -EIO;
> +		goto cleanup;
> +	}
> +
> +	/* Align to page boundary */
> +	after_header   = ftell(trace_dat_fp);
> +	padding_needed = (trace_dat_page_size -
> +			 (after_header % trace_dat_page_size)) % trace_dat_page_size;

[Severity: Medium]
Is trace_dat_page_size guaranteed to be non-zero here?

If the caller fails to initialize this global variable or parses a
configuration that sets it to zero, this modulo operation will trigger a
fatal integer division by zero exception.

> +
> +	if (padding_needed > 0) {
> +		pad = calloc(1, padding_needed);
> +		if (!pad) {
> +			ret = -ENOMEM;
> +			goto cleanup;
> +		}
> +
> +		if (!fwrite(pad, 1, padding_needed, trace_dat_fp)) {
> +			free(pad);
> +			ret = -EIO;
> +			goto cleanup;
> +		}
> +		free(pad);
> +	}
> +
> +	/* write per-cpu trace data */
[ ... ]
> diff --git a/tools/perf/util/trace-dat.h b/tools/perf/util/trace-dat.h
> new file mode 100644
> index 0000000000000..9aec37b708d41
> --- /dev/null
> +++ b/tools/perf/util/trace-dat.h
> @@ -0,0 +1,83 @@
[ ... ]
> +extern FILE *trace_dat_fp;
> +extern int trace_dat_page_size;
> +extern int trace_dat_nr_cpus;
> +extern long trace_dat_options_offset;
> +extern long trace_dat_header_info_offset;
> +extern long trace_dat_events_format_offset;
> +extern long trace_dat_ftrace_format_offset;
> +extern long trace_dat_kallsyms_offset;
> +extern long trace_dat_cmdline_offset;
> +extern long trace_dat_next_options_offset;

[Severity: High]
Are these offsets safe for trace files larger than 2GB on 32-bit systems?

Using long for offsets and relying on ftell() limits the maximum supported
file size to 2GB on 32-bit architectures. Since perf.data files can easily
exceed this size, could this result in integer overflow and corrupted offsets?

Should this use standard 64-bit interfaces like u64 and ftello()/fseeko()
instead?

> +
> +/* collect and manage per-cpu tracepoint event buffers */
> +#define TRACE_DAT_RECORD_TYPE_TIME_EXTEND 30
> +#define TRACE_DAT_RECORD_TIME_EXTEND_SIZE 8
> +#define TRACE_DAT_RECORD_TYPE_LEN_MAX 28
[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803145958.299956-1-tshah@linux.ibm.com?part=1

  reply	other threads:[~2026-08-03 15:14 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-03 14:59 [RFC PATCH v3 0/5] Add perf.data tracepoint events to trace.dat conversion Tanushree Shah
2026-08-03 14:59 ` [RFC PATCH v3 1/5] perf/trace-dat: Add trace.dat export infrastructure Tanushree Shah
2026-08-03 15:14   ` sashiko-bot [this message]
2026-08-03 14:59 ` [RFC PATCH v3 2/5] perf/trace-event: Write trace.dat metadata sections during parsing Tanushree Shah
2026-08-03 15:14   ` sashiko-bot
2026-08-03 14:59 ` [RFC PATCH v3 3/5] perf data-convert: Add perf.data to trace.dat conversion backend Tanushree Shah
2026-08-03 15:11   ` sashiko-bot
2026-08-03 14:59 ` [RFC PATCH v3 4/5] perf data: Add --to-trace-dat option for converting perf.data tracepoint events into trace.dat format Tanushree Shah
2026-08-03 15:13   ` sashiko-bot
2026-08-03 14:59 ` [RFC PATCH v3 5/5] perf test: Add test validating trace.dat generated by 'perf data convert --to-trace-dat' Tanushree Shah
2026-08-03 15:19   ` sashiko-bot
2026-08-06  0:15     ` Ian Rogers
2026-08-06  9:20       ` Tanushree Shah
2026-08-06  0:18 ` [RFC PATCH v3 0/5] Add perf.data tracepoint events to trace.dat conversion Ian Rogers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260803151423.D69211F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=tshah@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox