From nobody Fri Oct 2 08:24:49 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3837D418A34; Mon, 3 Aug 2026 14:41:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785768102; cv=none; b=aO457lrdJCuWJy0u5Gov51yLjgFHqaIX9fxpAPvlZRsqJNPJwgS0AH9J4n8aiOEdjkVwLi5i3NjCroOMPL9fxb4bxKOm4EQPrGuqtNvh43Wkx7nb5k3kekUH6vsFfWVWkqsgaBiYcS24Hx6v2MVyivqJC1PPx7q9v0o2JnNUmfw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785768102; c=relaxed/simple; bh=F+Y3g7G6Rq+Vi+eJAQylJFEwTrHyxo29y112ARY/oPc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iXW5ifFDLSgqgxthx1yW0QEEIMKCXJ5vBc/DHfcMdq+vr6dHf/l15PPM7tANXucGRfWT4tuRUQoX3sECPfJfhkxKtfn9gIXrnXZtCHVZwvtAfG6Hml825rCBaJZrkhGLyasFx1aCytQmXjNFiGvz08rBIQyoF3qLbs5WnqcQIhI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=W9qG1z/n; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="W9qG1z/n" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 42FAB1F00A3D; Mon, 3 Aug 2026 14:41:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785768100; bh=GXnT7/9Nv0I33oRbVH6au8RlGNu5JPUzzjP023EpBP8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=W9qG1z/n43SzjoOhJ1o7DjGMGdbSz3XJax48PP5gApnO0PL+l1hqvV9KSFM/qY4b2 3D14K0k7ZGFImlMbvjZSxlUDtpfzNwIX34VE3tvehPmnucEOk8MrM4sQKDLUtfZKpP u+17a+OmpYR34biwCMCVfzVhWVWpXumZ9iAu5r/hY7PR+uxnA4ZXhzBvdUHMNn3dmp VxXqgEMm15MAN5P7jVKUrR/NIdNLo6m8sZ+S/QzKT1cGeGIUzCSgywuTwc1zNkBOZ+ wyRDIAbdbhyz+SCNMkAVABc5rnS6Ewy7xCa7e7PSyZRz+7r6i05BBhUNBthYxFYd9Q 1WmYweWesOOsQ== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo , sashiko-bot Subject: [PATCH 1/2] perf c2c: Fix error masking, OOM, and unchecked caller errors in hpp_list__parse() Date: Mon, 3 Aug 2026 11:41:18 -0300 Message-ID: <20260803144119.185637-2-acme@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260803144119.185637-1-acme@kernel.org> References: <20260803144119.185637-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo hpp_list__parse() has three bugs: 1. The PARSE_LIST macro resets ret =3D 0 at the start of each invocation, so an error from output parsing is silently overwritten when the sort parsing block runs. The function returns success with partially initialized state. 2. When the caller passes a non-NULL output_ or sort_ string, but strdup() returns NULL due to OOM, NULL is passed to PARSE_LIST which treats it as empty input (the "if (!_list) break" branch). No error is returned. 3. When the called _fn function fails and returns something other than -ESRCH or -EINVAL (-ENOMEM, for instance) it was not bailing out of the strtok loop. Fix them by checking strdup() return values before proceeding and adding a cleanup label so that ret from each PARSE_LIST call is checked before the next runs, preserving the first error. The early exits now skip perf_hpp__setup_output_field(), which means c2c_hists__reinit() can return a non-zero value in cases that previously always succeeded silently. Both callers discarded its return: resort_cl_cb() continued into hists__collapse_resort() on a broken list, and perf_c2c__report() proceeded with uninitialised hists. Fix the full chain: check and propagate the error in resort_cl_cb() -- hists__iterate_cb= () already stops iteration and returns the callback error -- and check both c2c_hists__reinit() and hists__iterate_cb() in perf_c2c__report(). Also turn PARSE_LIST into a function, using a switch to catch other errors, converting the called functions to return an appropriate errno instead of -1 on failure. Fixes: 2d388bd0c9d3 ("perf c2c report: Add stdio output support") Reported-by: sashiko-bot Cc: Jiri Olsa Assisted-by: Claude:claude-sonnet-4.6 Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-c2c.c | 80 +++++++++++++++++++++++++++------------- tools/perf/util/sort.c | 38 +++++++++++-------- 2 files changed, 77 insertions(+), 41 deletions(-) diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index c9584dbedf77afe8..b0f2ba8318304914 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -12,6 +12,8 @@ */ #include #include +#include +#include =20 #include #include @@ -2063,26 +2065,34 @@ static int c2c_hists__init_sort(struct perf_hpp_lis= t *hpp_list, char *name, stru return 0; } =20 -#define PARSE_LIST(_list, _fn) \ - do { \ - char *tmp, *tok; \ - ret =3D 0; \ - \ - if (!_list) \ - break; \ - \ - for (tok =3D strtok_r((char *)_list, ", ", &tmp); \ - tok; tok =3D strtok_r(NULL, ", ", &tmp)) { \ - ret =3D _fn(hpp_list, tok, env); \ - if (ret =3D=3D -EINVAL) { \ - pr_err("Invalid --fields key: `%s'", tok); \ - break; \ - } else if (ret =3D=3D -ESRCH) { \ - pr_err("Unknown --fields key: `%s'", tok); \ - break; \ - } \ - } \ - } while (0) +static int __hpp_list__parse(struct perf_hpp_list *hpp_list, char *_list, = struct perf_env *env, + int (*_fn)(struct perf_hpp_list *hpp_list, char *name, struct perf= _env *env)) +{ + char *tmp, *tok; + int ret =3D 0; + + if (!_list) + return 0; + + for (tok =3D strtok_r(_list, ", ", &tmp); tok; tok =3D strtok_r(NULL, ", = ", &tmp)) { + ret =3D _fn(hpp_list, tok, env); + switch (ret) { + case 0: + continue; + case -EINVAL: + pr_err("Invalid --fields key: `%s'", tok); + goto out; + case -ESRCH: + pr_err("Unknown --fields key: `%s'", tok); + goto out; + default: + pr_err("%m for --fields key: `%s'", tok); + goto out; + } + } +out: + return ret; +} =20 static int hpp_list__parse(struct perf_hpp_list *hpp_list, const char *output_, @@ -2093,8 +2103,18 @@ static int hpp_list__parse(struct perf_hpp_list *hpp= _list, char *sort =3D sort_ ? strdup(sort_) : NULL; int ret; =20 - PARSE_LIST(output, c2c_hists__init_output); - PARSE_LIST(sort, c2c_hists__init_sort); + /* strdup() returns NULL on OOM, don't silently treat as empty */ + if ((output_ && !output) || (sort_ && !sort)) { + ret =3D -ENOMEM; + goto out; + } + + ret =3D __hpp_list__parse(hpp_list, output, env, c2c_hists__init_output); + if (ret) + goto out; + ret =3D __hpp_list__parse(hpp_list, sort, env, c2c_hists__init_sort); + if (ret) + goto out; =20 /* copy sort keys to output fields */ perf_hpp__setup_output_field(hpp_list); @@ -2111,6 +2131,7 @@ static int hpp_list__parse(struct perf_hpp_list *hpp_= list, perf_hpp__append_sort_keys(&hists->list); #endif =20 +out: free(output); free(sort); return ret; @@ -2281,6 +2302,7 @@ static int resort_cl_cb(struct hist_entry *he, void *= arg) struct c2c_hist_entry *c2c_he; struct c2c_hists *c2c_hists; bool display =3D he__display(he, &c2c.shared_clines_stats); + int ret; =20 c2c_he =3D container_of(he, struct c2c_hist_entry, he); c2c_hists =3D c2c_he->hists; @@ -2291,7 +2313,9 @@ static int resort_cl_cb(struct hist_entry *he, void *= arg) c2c_he->cacheline_idx =3D idx++; calc_width(c2c_he); =20 - c2c_hists__reinit(c2c_hists, c2c.cl_output, c2c.cl_resort, env); + ret =3D c2c_hists__reinit(c2c_hists, c2c.cl_output, c2c.cl_resort, env); + if (ret) + return ret; =20 hists__collapse_resort(&c2c_hists->hists, NULL); hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb); @@ -3356,13 +3380,19 @@ static int perf_c2c__report(int argc, const char **= argv) else if (c2c.display =3D=3D DISPLAY_SNP_PEER) sort_str =3D "tot_peer"; =20 - c2c_hists__reinit(&c2c.hists, output_str, sort_str, perf_session__env(ses= sion)); + err =3D c2c_hists__reinit(&c2c.hists, output_str, sort_str, perf_session_= _env(session)); + if (err) { + pr_err("Failed to reinitialize hists\n"); + goto out_mem2node; + } =20 ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting..."); =20 hists__collapse_resort(&c2c.hists.hists, NULL); hists__output_resort_cb(&c2c.hists.hists, &prog, resort_shared_cl_cb); - hists__iterate_cb(&c2c.hists.hists, resort_cl_cb, perf_session__env(sessi= on)); + err =3D hists__iterate_cb(&c2c.hists.hists, resort_cl_cb, perf_session__e= nv(session)); + if (err) + goto out_mem2node; =20 ui_progress__finish(); =20 diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index dcf9189786f8aeba..2f59e37089ef06a2 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -3105,7 +3105,7 @@ static int __sort_dimension__add_hpp_sort(struct sort= _dimension *sd, struct hpp_sort_entry *hse =3D __sort_dimension__alloc_hpp(sd, level); =20 if (hse =3D=3D NULL) - return -1; + return -ENOMEM; =20 perf_hpp_list__register_sort_field(list, &hse->hpp); return 0; @@ -3118,7 +3118,7 @@ static int __sort_dimension__add_hpp_output(struct so= rt_dimension *sd, struct hpp_sort_entry *hse =3D __sort_dimension__alloc_hpp(sd, level); =20 if (hse =3D=3D NULL) - return -1; + return -ENOMEM; =20 perf_hpp_list__column_register(list, &hse->hpp); return 0; @@ -3742,14 +3742,18 @@ static int __sort_dimension__add(struct sort_dimens= ion *sd, struct perf_hpp_list *list, int level) { + int ret; + if (sd->taken) return 0; =20 - if (__sort_dimension__add_hpp_sort(sd, list, level) < 0) - return -1; + ret =3D __sort_dimension__add_hpp_sort(sd, list, level); + if (ret < 0) + return ret; =20 - if (__sort_dimension__update(sd, list) < 0) - return -1; + ret =3D __sort_dimension__update(sd, list); + if (ret < 0) + return ret; =20 sd->taken =3D 1; =20 @@ -3767,7 +3771,7 @@ static int __hpp_dimension__add(struct hpp_dimension = *hd, =20 fmt =3D __hpp_dimension__alloc_hpp(hd, level); if (!fmt) - return -1; + return -ENOMEM; =20 hd->taken =3D 1; hd->was_taken =3D 1; @@ -3779,14 +3783,18 @@ static int __sort_dimension__add_output(struct perf= _hpp_list *list, struct sort_dimension *sd, int level) { + int ret; + if (sd->taken) return 0; =20 - if (__sort_dimension__add_hpp_output(sd, list, level) < 0) - return -1; + ret =3D __sort_dimension__add_hpp_output(sd, list, level); + if (ret < 0) + return ret; =20 - if (__sort_dimension__update(sd, list) < 0) - return -1; + ret =3D __sort_dimension__update(sd, list); + if (ret < 0) + return ret; =20 sd->taken =3D 1; return 0; @@ -3803,7 +3811,7 @@ static int __hpp_dimension__add_output(struct perf_hp= p_list *list, =20 fmt =3D __hpp_dimension__alloc_hpp(hd, level); if (!fmt) - return -1; + return -ENOMEM; =20 hd->taken =3D 1; perf_hpp_list__column_register(list, fmt); @@ -3869,8 +3877,7 @@ int sort_dimension__add(struct perf_hpp_list *list, c= onst char *tok, strlen(tok))) return -EINVAL; =20 - __sort_dimension__add(sd, list, level); - return 0; + return __sort_dimension__add(sd, list, level); } =20 for (i =3D 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { @@ -3882,8 +3889,7 @@ int sort_dimension__add(struct perf_hpp_list *list, c= onst char *tok, if (sort__mode !=3D SORT_MODE__MEMORY) return -EINVAL; =20 - __sort_dimension__add(sd, list, level); - return 0; + return __sort_dimension__add(sd, list, level); } =20 for (i =3D 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { --=20 2.55.0 From nobody Fri Oct 2 08:24:49 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E67441B8F7; Mon, 3 Aug 2026 14:41:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785768107; cv=none; b=ZRtG78RqhCIBsRhOw/o+h92gV8K0nz1By751aQMa/9DbwfGV9fRLAwWzv1Ci17bGwg9ZrVrW9SsNn49KaJxVVoHosgSOrPysGApj+BaKW4ptNbmYEAmQNWO3MEFw39Kj0Orxjt7tVZqqg5Ntgh/TLtTUDx9nLSjMdxi+2Wlre00= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785768107; c=relaxed/simple; bh=Y6vuqrhQbmGQWSuYzfuKKxnnBww4ZZCFVRBhyT7j5gY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EqO8jeVAdSES0mhhN3rHMK2755rNfsKLGH1Y8PAW2JQDGnvo9nIl+9iw4HdlfiWoPmWr1uN8z7KAC0wHrNXp/9cGtp5sSlxN/cXQWrK6YBTtvL0hUp61hchT2iZrxYpX8IFjTk0aqHm5ilRN78SSnQI8VkCBQYOhFWNRmVBrm7Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FojtA5b3; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FojtA5b3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7841E1F000E9; Mon, 3 Aug 2026 14:41:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785768106; bh=OfVWbXj1OyVDsuO437AUap4y4lwETZYY/FcpnfRqg5o=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=FojtA5b32xb3C3PGrtyaKZbLlzYFzaHdrynMM+8frhZUfM4vqIdD8PIJBlKXyRMVO 9MnmB2jjY5FMeGZSTN8JC0d6bu5WakBGpzyHCxS2uKX52N3SVDNVs4w3je+pW7uk7X xpT2vCZbaxW5H1lPoaLhiaWoZedlLB4IHK2nJdM9m4VTE/xHgPmT/uoogpukIQPLci boQgkVLf5+BrY6JIENbbhSYOUfKcdR3jYO/hNXsPDKpvU8ENgerEQgLlQWPNY3mjZT DjBJT/pUY5co5VwAgl22G67niojZLAjIlcScZmUQyI4NEx67HUMRbgvpfnP3y8PM80 fnLlWjzEjpE8g== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo , sashiko-bot Subject: [PATCH 2/2] perf c2c: Clean up registered formats on c2c_hists__init() failure Date: Mon, 3 Aug 2026 11:41:19 -0300 Message-ID: <20260803144119.185637-3-acme@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260803144119.185637-1-acme@kernel.org> References: <20260803144119.185637-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo When c2c_hists__init() calls hpp_list__parse() and it fails partway through, format structures registered via perf_hpp_list__column_register() and perf_hpp_list__register_sort_field() are left on the hpp_list. The c2c_he__alloc_hists() caller handles this with perf_hpp__reset_output_field(), but perf_c2c_report() does not, leaking the partially registered entries. Fix by adding cleanup inside c2c_hists__init() itself, so all callers are protected. Fixes: 78b275437873 ("perf c2c report: Add sample processing") Reported-by: sashiko-bot Cc: Jiri Olsa Assisted-by: Claude:claude-opus-4.6 Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-c2c.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index b0f2ba8318304914..e66e9ca8618dc927 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2142,6 +2142,8 @@ static int c2c_hists__init(struct c2c_hists *hists, int nr_header_lines, struct perf_env *env) { + int ret; + __hists__init(&hists->hists, &hists->list); =20 /* @@ -2154,7 +2156,13 @@ static int c2c_hists__init(struct c2c_hists *hists, /* Overload number of header lines.*/ hists->list.nr_header_lines =3D nr_header_lines; =20 - return hpp_list__parse(&hists->list, /*output=3D*/NULL, sort, env); + ret =3D hpp_list__parse(&hists->list, /*output=3D*/NULL, sort, env); + + /* Unregister any formats added before the failure point */ + if (ret) + perf_hpp__reset_output_field(&hists->list); + + return ret; } =20 static int c2c_hists__reinit(struct c2c_hists *c2c_hists, --=20 2.55.0