From nobody Mon Feb 9 23:44:42 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 85FB5C77B6C for ; Fri, 7 Apr 2023 23:04:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229535AbjDGXEl (ORCPT ); Fri, 7 Apr 2023 19:04:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57242 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229455AbjDGXEj (ORCPT ); Fri, 7 Apr 2023 19:04:39 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 38190E059 for ; Fri, 7 Apr 2023 16:04:38 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id z4-20020a25bb04000000b00b392ae70300so43700803ybg.21 for ; Fri, 07 Apr 2023 16:04:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; t=1680908678; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=59paec+IWSQBz2L9CjqeP22mRhkSxyuTil9toZzz+2E=; b=jlZb9danWvv+ixJf3PU7oMdPaoWTKji9N1XTbeOIi2Q4zCMVso1x0EQEF0GmrJFyqw /eBDqunf5xCemE7/Ccz8arnTjRSY6aqbJBDdXMN4PpMDNgMzY+dlKb7HClsohYGHS6y9 O8h5Q+X52uCBkRUwtyv0V80QU+dKa9YX+3Ot6UIS5oqzHZwJaYIsX76zjlRhRlr/QqzN WIivivWJL0jCQVgm9BV+51EMoC0akd0CxnxSdP86HYvW/brazjK+M1zDraRKi0G2RKpq PWcOiNPXSywqsFJVZHpFdyKJBTo4kEV0ykNE10v7Z13dDJxEqjFu7KBJt7nwTSxO2GWs lUsw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680908678; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=59paec+IWSQBz2L9CjqeP22mRhkSxyuTil9toZzz+2E=; b=nlN9+eckEOBEIbiC+J1CMbGYOAYKEJN20EZNa4qLGx20lGk3ghjQqbMBby/YixBdbM Qs/ythoe9goFMs+q0L359l/VAoxIRDRsrzm+l4MFeyfbBPqctn/kOsaUKmwXQN2sFhKh Njykgn++wU5/2BOGmVEP7Rbmmx+P5qnUN2fbzk1TXrxtXnbEbtfbQBXsdR/dT/mwixUy Hs7p5eUSrJjPOD+RW7BTEsl49WWQUyomKdAkdRXy1fOsSn22TLsUcOuzAR/rb16ZryeF GM+lBvnv26u+64HzEEwuln6jiu2WlOOY8FfmtM8BEydzWYb4uxrCiEwxFfx4cDQkoGdN Y35Q== X-Gm-Message-State: AAQBX9dYKqv9Innxyx35/kh3NLxCnr/fMHve/YKbwRFSBXswqg7KKrdQ rTleGYU9TuKE9GnX4god0gdFzEorp57f X-Google-Smtp-Source: AKy350bKg/Da1VLiNEVJ2OJM6u7YBHcM9+S2I35CQPhyi/mADelAipjwwpcBKwDi+gl/5RcsJ4RaXJ0uPV/4 X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:b240:9cdf:7861:b23e]) (user=irogers job=sendgmr) by 2002:a25:cbd6:0:b0:b6e:361a:c86 with SMTP id b205-20020a25cbd6000000b00b6e361a0c86mr314698ybg.3.1680908677793; Fri, 07 Apr 2023 16:04:37 -0700 (PDT) Date: Fri, 7 Apr 2023 16:04:01 -0700 In-Reply-To: <20230407230405.2931830-1-irogers@google.com> Message-Id: <20230407230405.2931830-2-irogers@google.com> Mime-Version: 1.0 References: <20230407230405.2931830-1-irogers@google.com> X-Mailer: git-send-email 2.40.0.577.gac1e443424-goog Subject: [PATCH v7 1/5] libperf: Add reference count checking macros. From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Thomas Gleixner , Darren Hart , Davidlohr Bueso , James Clark , John Garry , Riccardo Mancini , Yury Norov , Andy Shevchenko , Andrew Morton , Adrian Hunter , Leo Yan , Andi Kleen , Thomas Richter , Kan Liang , Madhavan Srinivasan , Shunsuke Nakamura , Song Liu , Masami Hiramatsu , Steven Rostedt , Miaoqian Lin , Stephen Brennan , Kajol Jain , Alexey Bayduraev , German Gomez , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Dumazet , Dmitry Vyukov , Hao Luo Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The macros serve as a way to debug use of a reference counted struct. The macros add a memory allocated pointer that is interposed between the reference counted original struct at a get and freed by a put. The pointer replaces the original struct, so use of the struct name via APIs remains unchanged. Signed-off-by: Ian Rogers --- tools/lib/perf/include/internal/rc_check.h | 94 ++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tools/lib/perf/include/internal/rc_check.h diff --git a/tools/lib/perf/include/internal/rc_check.h b/tools/lib/perf/in= clude/internal/rc_check.h new file mode 100644 index 000000000000..c0626d8beb59 --- /dev/null +++ b/tools/lib/perf/include/internal/rc_check.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __LIBPERF_INTERNAL_RC_CHECK_H +#define __LIBPERF_INTERNAL_RC_CHECK_H + +#include +#include + +/* + * Shared reference count checking macros. + * + * Reference count checking is an approach to sanitizing the use of refere= nce + * counted structs. It leverages address and leak sanitizers to make sure = gets + * are paired with a put. Reference count checking adds a malloc-ed layer = of + * indirection on a get, and frees it on a put. A missed put will be repor= ted as + * a memory leak. A double put will be reported as a double free. Accessing + * after a put will cause a use-after-free and/or a segfault. + */ + +#ifndef REFCNT_CHECKING +/* Replaces "struct foo" so that the pointer may be interposed. */ +#define DECLARE_RC_STRUCT(struct_name) \ + struct struct_name + +/* Declare a reference counted struct variable. */ +#define RC_STRUCT(struct_name) struct struct_name + +/* + * Interpose the indirection. Result will hold the indirection and object = is the + * reference counted struct. + */ +#define ADD_RC_CHK(result, object) (result =3D object, object) + +/* Strip the indirection layer. */ +#define RC_CHK_ACCESS(object) object + +/* Frees the object and the indirection layer. */ +#define RC_CHK_FREE(object) free(object) + +/* A get operation adding the indirection layer. */ +#define RC_CHK_GET(result, object) ADD_RC_CHK(result, object) + +/* A put operation removing the indirection layer. */ +#define RC_CHK_PUT(object) {} + +#else + +/* Replaces "struct foo" so that the pointer may be interposed. */ +#define DECLARE_RC_STRUCT(struct_name) \ + struct original_##struct_name; \ + struct struct_name { \ + struct original_##struct_name *orig; \ + }; \ + struct original_##struct_name + +/* Declare a reference counted struct variable. */ +#define RC_STRUCT(struct_name) struct original_##struct_name + +/* + * Interpose the indirection. Result will hold the indirection and object = is the + * reference counted struct. + */ +#define ADD_RC_CHK(result, object) \ + ( \ + object ? (result =3D malloc(sizeof(*result)), \ + result ? (result->orig =3D object, result) \ + : (result =3D NULL, NULL)) \ + : (result =3D NULL, NULL) \ + ) + +/* Strip the indirection layer. */ +#define RC_CHK_ACCESS(object) object->orig + +/* Frees the object and the indirection layer. */ +#define RC_CHK_FREE(object) \ + do { \ + zfree(&object->orig); \ + free(object); \ + } while(0) + +/* A get operation adding the indirection layer. */ +#define RC_CHK_GET(result, object) ADD_RC_CHK(result, (object ? object->or= ig : NULL)) + +/* A put operation removing the indirection layer. */ +#define RC_CHK_PUT(object) \ + do { \ + if (object) { \ + object->orig =3D NULL; \ + free(object); \ + } \ + } while(0) + +#endif + +#endif /* __LIBPERF_INTERNAL_RC_CHECK_H */ --=20 2.40.0.577.gac1e443424-goog From nobody Mon Feb 9 23:44:42 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3B0CC76196 for ; Fri, 7 Apr 2023 23:04:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229556AbjDGXEz (ORCPT ); Fri, 7 Apr 2023 19:04:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57726 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229502AbjDGXEw (ORCPT ); Fri, 7 Apr 2023 19:04:52 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9263EE075 for ; Fri, 7 Apr 2023 16:04:47 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-54ee0b7dbdbso1190047b3.0 for ; Fri, 07 Apr 2023 16:04:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; t=1680908686; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=RC3j3MvNSqhqdahKk5GatyUi9kpNiFRU0Tiq11OGY9U=; b=Y1Nid9cu5o8F0X5Lt9SXjJRrDmEBlQjT5SO/SCKWFG08EyI3kd6QIPs8bmj8k2nRpl n3p9KSo3TD4yJHIaBiQZI1Dyx4lnFDnl3TCH6m/4bCo7Iw3qMaZCbIC+bctdoTe4+Isg D3P9+mxTRyhJHdce3ollbCapl3cc5APJFxnnyaXoh9GF+zGPoTX/HtE7At3MfuIi5V0U VeoZlsYLZvVQuS3XttvuPjyF5kJ6uP+zrwlutwK8vVbPAjXNgqSV8UikPzqGCzIHk3hs 3RWJmzu2Nm9ZBf0FQa7jWvk31gkvo2wS46v7SBo2/K87frh4TAUZwIXjZwdMBWKA90ip leaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680908686; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=RC3j3MvNSqhqdahKk5GatyUi9kpNiFRU0Tiq11OGY9U=; b=MR9qT0Kis4LbJ42TvDxYyw9HHioduaEiM4NnIYG57WNDmhWepsq0PTtCZX9v/Xy6OI OgDbByS7PKwFJ9vjF/+ffm9Nz0tmTiV4hyf7bpC8qdqJXBFbsttrZ1cnJhIJJUYa5Qtj xenOiv7i+u7SRuxjd01IfZHlzVFkkhhtju3O00xndG9KWCGOniDsDjnzwjGjWki702hF LdJi/C5XmkQHCs4WE9DHQ/CQAR5nM5kzTI6RDiReoxFJpvD4jlOFT/qURyz9ATsU7mRO +7CoFoGpd6PoA51J16ykYfX5yCep/xdUu8G1QlZOza7SdHrJtSCQztqadK7oXJkvfrxV RMiw== X-Gm-Message-State: AAQBX9dFhsSRIke62v5UnugQbbFC8rLUni4q/4cFw0MTK6TkTRfeU3zE KQfwh92AkFxg9n7sAnm81NGRFJwTV0Xk X-Google-Smtp-Source: AKy350aCF00VS1Uj2dO3alss4KgHHM1xpvEYJZpEu4+XLdkm7rX/Q7JW60ovWVL1Q+ARAuLpnfU5WxkvsZr7 X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:b240:9cdf:7861:b23e]) (user=irogers job=sendgmr) by 2002:a25:cc47:0:b0:b77:97d9:f096 with SMTP id l68-20020a25cc47000000b00b7797d9f096mr2739532ybf.10.1680908686591; Fri, 07 Apr 2023 16:04:46 -0700 (PDT) Date: Fri, 7 Apr 2023 16:04:02 -0700 In-Reply-To: <20230407230405.2931830-1-irogers@google.com> Message-Id: <20230407230405.2931830-3-irogers@google.com> Mime-Version: 1.0 References: <20230407230405.2931830-1-irogers@google.com> X-Mailer: git-send-email 2.40.0.577.gac1e443424-goog Subject: [PATCH v7 2/5] perf cpumap: Add reference count checking From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Thomas Gleixner , Darren Hart , Davidlohr Bueso , James Clark , John Garry , Riccardo Mancini , Yury Norov , Andy Shevchenko , Andrew Morton , Adrian Hunter , Leo Yan , Andi Kleen , Thomas Richter , Kan Liang , Madhavan Srinivasan , Shunsuke Nakamura , Song Liu , Masami Hiramatsu , Steven Rostedt , Miaoqian Lin , Stephen Brennan , Kajol Jain , Alexey Bayduraev , German Gomez , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Dumazet , Dmitry Vyukov , Hao Luo Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enabled when REFCNT_CHECKING is defined. The change adds a memory allocated pointer that is interposed between the reference counted cpu map at a get and freed by a put. The pointer replaces the original perf_cpu_map struct, so use of the perf_cpu_map via APIs remains unchanged. Any use of the cpu map without the API requires two versions, handled via the RC_CHK_ACCESS macro. This change is intended to catch: - use after put: using a cpumap after you have put it will cause a segv. - unbalanced puts: two puts for a get will result in a double free that can be captured and reported by tools like address sanitizer, including with the associated stack traces of allocation and frees. - missing puts: if a put is missing then the get turns into a memory leak that can be reported by leak sanitizer, including the stack trace at the point the get occurs. Signed-off-by: Ian Rogers --- tools/lib/perf/Makefile | 2 +- tools/lib/perf/cpumap.c | 94 +++++++++++++----------- tools/lib/perf/include/internal/cpumap.h | 4 +- tools/perf/tests/cpumap.c | 4 +- tools/perf/util/cpumap.c | 40 +++++----- tools/perf/util/pmu.c | 8 +- 6 files changed, 81 insertions(+), 71 deletions(-) diff --git a/tools/lib/perf/Makefile b/tools/lib/perf/Makefile index d8cad124e4c5..3a9b2140aa04 100644 --- a/tools/lib/perf/Makefile +++ b/tools/lib/perf/Makefile @@ -188,7 +188,7 @@ install_lib: libs cp -fpR $(LIBPERF_ALL) $(DESTDIR)$(libdir_SQ) =20 HDRS :=3D bpf_perf.h core.h cpumap.h threadmap.h evlist.h evsel.h event.h = mmap.h -INTERNAL_HDRS :=3D cpumap.h evlist.h evsel.h lib.h mmap.h threadmap.h xyar= ray.h +INTERNAL_HDRS :=3D cpumap.h evlist.h evsel.h lib.h mmap.h rc_check.h threa= dmap.h xyarray.h =20 INSTALL_HDRS_PFX :=3D $(DESTDIR)$(prefix)/include/perf INSTALL_HDRS :=3D $(addprefix $(INSTALL_HDRS_PFX)/, $(HDRS)) diff --git a/tools/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c index 6cd0be7c1bb4..56eed1ac80d9 100644 --- a/tools/lib/perf/cpumap.c +++ b/tools/lib/perf/cpumap.c @@ -10,16 +10,16 @@ #include #include =20 -static struct perf_cpu_map *perf_cpu_map__alloc(int nr_cpus) +struct perf_cpu_map *perf_cpu_map__alloc(int nr_cpus) { - struct perf_cpu_map *cpus =3D malloc(sizeof(*cpus) + sizeof(struct perf_c= pu) * nr_cpus); - - if (cpus !=3D NULL) { + struct perf_cpu_map *result; + RC_STRUCT(perf_cpu_map) *cpus =3D + malloc(sizeof(*cpus) + sizeof(struct perf_cpu) * nr_cpus); + if (ADD_RC_CHK(result, cpus)) { cpus->nr =3D nr_cpus; refcount_set(&cpus->refcnt, 1); - } - return cpus; + return result; } =20 struct perf_cpu_map *perf_cpu_map__dummy_new(void) @@ -27,7 +27,7 @@ struct perf_cpu_map *perf_cpu_map__dummy_new(void) struct perf_cpu_map *cpus =3D perf_cpu_map__alloc(1); =20 if (cpus) - cpus->map[0].cpu =3D -1; + RC_CHK_ACCESS(cpus)->map[0].cpu =3D -1; =20 return cpus; } @@ -35,23 +35,30 @@ struct perf_cpu_map *perf_cpu_map__dummy_new(void) static void cpu_map__delete(struct perf_cpu_map *map) { if (map) { - WARN_ONCE(refcount_read(&map->refcnt) !=3D 0, + WARN_ONCE(refcount_read(&RC_CHK_ACCESS(map)->refcnt) !=3D 0, "cpu_map refcnt unbalanced\n"); - free(map); + RC_CHK_FREE(map); } } =20 struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map) { - if (map) - refcount_inc(&map->refcnt); - return map; + struct perf_cpu_map *result; + + if (RC_CHK_GET(result, map)) + refcount_inc(&RC_CHK_ACCESS(map)->refcnt); + + return result; } =20 void perf_cpu_map__put(struct perf_cpu_map *map) { - if (map && refcount_dec_and_test(&map->refcnt)) - cpu_map__delete(map); + if (map) { + if (refcount_dec_and_test(&RC_CHK_ACCESS(map)->refcnt)) + cpu_map__delete(map); + else + RC_CHK_PUT(map); + } } =20 static struct perf_cpu_map *cpu_map__default_new(void) @@ -68,7 +75,7 @@ static struct perf_cpu_map *cpu_map__default_new(void) int i; =20 for (i =3D 0; i < nr_cpus; ++i) - cpus->map[i].cpu =3D i; + RC_CHK_ACCESS(cpus)->map[i].cpu =3D i; } =20 return cpus; @@ -94,15 +101,16 @@ static struct perf_cpu_map *cpu_map__trim_new(int nr_c= pus, const struct perf_cpu int i, j; =20 if (cpus !=3D NULL) { - memcpy(cpus->map, tmp_cpus, payload_size); - qsort(cpus->map, nr_cpus, sizeof(struct perf_cpu), cmp_cpu); + memcpy(RC_CHK_ACCESS(cpus)->map, tmp_cpus, payload_size); + qsort(RC_CHK_ACCESS(cpus)->map, nr_cpus, sizeof(struct perf_cpu), cmp_cp= u); /* Remove dups */ j =3D 0; for (i =3D 0; i < nr_cpus; i++) { - if (i =3D=3D 0 || cpus->map[i].cpu !=3D cpus->map[i - 1].cpu) - cpus->map[j++].cpu =3D cpus->map[i].cpu; + if (i =3D=3D 0 || + RC_CHK_ACCESS(cpus)->map[i].cpu !=3D RC_CHK_ACCESS(cpus)->map[i - 1= ].cpu) + RC_CHK_ACCESS(cpus)->map[j++].cpu =3D RC_CHK_ACCESS(cpus)->map[i].cpu; } - cpus->nr =3D j; + RC_CHK_ACCESS(cpus)->nr =3D j; assert(j <=3D nr_cpus); } return cpus; @@ -263,20 +271,20 @@ struct perf_cpu perf_cpu_map__cpu(const struct perf_c= pu_map *cpus, int idx) .cpu =3D -1 }; =20 - if (cpus && idx < cpus->nr) - return cpus->map[idx]; + if (cpus && idx < RC_CHK_ACCESS(cpus)->nr) + return RC_CHK_ACCESS(cpus)->map[idx]; =20 return result; } =20 int perf_cpu_map__nr(const struct perf_cpu_map *cpus) { - return cpus ? cpus->nr : 1; + return cpus ? RC_CHK_ACCESS(cpus)->nr : 1; } =20 bool perf_cpu_map__empty(const struct perf_cpu_map *map) { - return map ? map->map[0].cpu =3D=3D -1 : true; + return map ? RC_CHK_ACCESS(map)->map[0].cpu =3D=3D -1 : true; } =20 int perf_cpu_map__idx(const struct perf_cpu_map *cpus, struct perf_cpu cpu) @@ -287,10 +295,10 @@ int perf_cpu_map__idx(const struct perf_cpu_map *cpus= , struct perf_cpu cpu) return -1; =20 low =3D 0; - high =3D cpus->nr; + high =3D RC_CHK_ACCESS(cpus)->nr; while (low < high) { int idx =3D (low + high) / 2; - struct perf_cpu cpu_at_idx =3D cpus->map[idx]; + struct perf_cpu cpu_at_idx =3D RC_CHK_ACCESS(cpus)->map[idx]; =20 if (cpu_at_idx.cpu =3D=3D cpu.cpu) return idx; @@ -316,7 +324,9 @@ struct perf_cpu perf_cpu_map__max(const struct perf_cpu= _map *map) }; =20 // cpu_map__trim_new() qsort()s it, cpu_map__default_new() sorts it as we= ll. - return map->nr > 0 ? map->map[map->nr - 1] : result; + return RC_CHK_ACCESS(map)->nr > 0 + ? RC_CHK_ACCESS(map)->map[RC_CHK_ACCESS(map)->nr - 1] + : result; } =20 /** Is 'b' a subset of 'a'. */ @@ -324,15 +334,15 @@ bool perf_cpu_map__is_subset(const struct perf_cpu_ma= p *a, const struct perf_cpu { if (a =3D=3D b || !b) return true; - if (!a || b->nr > a->nr) + if (!a || RC_CHK_ACCESS(b)->nr > RC_CHK_ACCESS(a)->nr) return false; =20 - for (int i =3D 0, j =3D 0; i < a->nr; i++) { - if (a->map[i].cpu > b->map[j].cpu) + for (int i =3D 0, j =3D 0; i < RC_CHK_ACCESS(a)->nr; i++) { + if (RC_CHK_ACCESS(a)->map[i].cpu > RC_CHK_ACCESS(b)->map[j].cpu) return false; - if (a->map[i].cpu =3D=3D b->map[j].cpu) { + if (RC_CHK_ACCESS(a)->map[i].cpu =3D=3D RC_CHK_ACCESS(b)->map[j].cpu) { j++; - if (j =3D=3D b->nr) + if (j =3D=3D RC_CHK_ACCESS(b)->nr) return true; } } @@ -362,27 +372,27 @@ struct perf_cpu_map *perf_cpu_map__merge(struct perf_= cpu_map *orig, return perf_cpu_map__get(other); } =20 - tmp_len =3D orig->nr + other->nr; + tmp_len =3D RC_CHK_ACCESS(orig)->nr + RC_CHK_ACCESS(other)->nr; tmp_cpus =3D malloc(tmp_len * sizeof(struct perf_cpu)); if (!tmp_cpus) return NULL; =20 /* Standard merge algorithm from wikipedia */ i =3D j =3D k =3D 0; - while (i < orig->nr && j < other->nr) { - if (orig->map[i].cpu <=3D other->map[j].cpu) { - if (orig->map[i].cpu =3D=3D other->map[j].cpu) + while (i < RC_CHK_ACCESS(orig)->nr && j < RC_CHK_ACCESS(other)->nr) { + if (RC_CHK_ACCESS(orig)->map[i].cpu <=3D RC_CHK_ACCESS(other)->map[j].cp= u) { + if (RC_CHK_ACCESS(orig)->map[i].cpu =3D=3D RC_CHK_ACCESS(other)->map[j]= .cpu) j++; - tmp_cpus[k++] =3D orig->map[i++]; + tmp_cpus[k++] =3D RC_CHK_ACCESS(orig)->map[i++]; } else - tmp_cpus[k++] =3D other->map[j++]; + tmp_cpus[k++] =3D RC_CHK_ACCESS(other)->map[j++]; } =20 - while (i < orig->nr) - tmp_cpus[k++] =3D orig->map[i++]; + while (i < RC_CHK_ACCESS(orig)->nr) + tmp_cpus[k++] =3D RC_CHK_ACCESS(orig)->map[i++]; =20 - while (j < other->nr) - tmp_cpus[k++] =3D other->map[j++]; + while (j < RC_CHK_ACCESS(other)->nr) + tmp_cpus[k++] =3D RC_CHK_ACCESS(other)->map[j++]; assert(k <=3D tmp_len); =20 merged =3D cpu_map__trim_new(k, tmp_cpus); diff --git a/tools/lib/perf/include/internal/cpumap.h b/tools/lib/perf/incl= ude/internal/cpumap.h index 35dd29642296..6c01bee4d048 100644 --- a/tools/lib/perf/include/internal/cpumap.h +++ b/tools/lib/perf/include/internal/cpumap.h @@ -4,6 +4,7 @@ =20 #include #include +#include =20 /** * A sized, reference counted, sorted array of integers representing CPU @@ -12,7 +13,7 @@ * gaps if CPU numbers were used. For events associated with a pid, rather= than * a CPU, a single dummy map with an entry of -1 is used. */ -struct perf_cpu_map { +DECLARE_RC_STRUCT(perf_cpu_map) { refcount_t refcnt; /** Length of the map array. */ int nr; @@ -24,6 +25,7 @@ struct perf_cpu_map { #define MAX_NR_CPUS 2048 #endif =20 +struct perf_cpu_map *perf_cpu_map__alloc(int nr_cpus); int perf_cpu_map__idx(const struct perf_cpu_map *cpus, struct perf_cpu cpu= ); bool perf_cpu_map__is_subset(const struct perf_cpu_map *a, const struct pe= rf_cpu_map *b); =20 diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index 3150fc1fed6f..d6f77b676d11 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -68,7 +68,7 @@ static int process_event_cpus(struct perf_tool *tool __ma= ybe_unused, TEST_ASSERT_VAL("wrong nr", perf_cpu_map__nr(map) =3D=3D 2); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__cpu(map, 0).cpu =3D=3D 1); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__cpu(map, 1).cpu =3D=3D 256); - TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) =3D=3D 1); + TEST_ASSERT_VAL("wrong refcnt", refcount_read(&RC_CHK_ACCESS(map)->refcnt= ) =3D=3D 1); perf_cpu_map__put(map); return 0; } @@ -94,7 +94,7 @@ static int process_event_range_cpus(struct perf_tool *too= l __maybe_unused, TEST_ASSERT_VAL("wrong nr", perf_cpu_map__nr(map) =3D=3D 256); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__cpu(map, 0).cpu =3D=3D 1); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__max(map).cpu =3D=3D 256); - TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) =3D=3D 1); + TEST_ASSERT_VAL("wrong refcnt", refcount_read(&RC_CHK_ACCESS(map)->refcnt= ) =3D=3D 1); perf_cpu_map__put(map); return 0; } diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 5e564974fba4..22453893105f 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -77,9 +77,9 @@ static struct perf_cpu_map *cpu_map__from_entries(const s= truct perf_record_cpu_m * otherwise it would become 65535. */ if (data->cpus_data.cpu[i] =3D=3D (u16) -1) - map->map[i].cpu =3D -1; + RC_CHK_ACCESS(map)->map[i].cpu =3D -1; else - map->map[i].cpu =3D (int) data->cpus_data.cpu[i]; + RC_CHK_ACCESS(map)->map[i].cpu =3D (int) data->cpus_data.cpu[i]; } } =20 @@ -107,7 +107,7 @@ static struct perf_cpu_map *cpu_map__from_mask(const st= ruct perf_record_cpu_map_ =20 perf_record_cpu_map_data__read_one_mask(data, i, local_copy); for_each_set_bit(cpu, local_copy, 64) - map->map[j++].cpu =3D cpu + cpus_per_i; + RC_CHK_ACCESS(map)->map[j++].cpu =3D cpu + cpus_per_i; } return map; =20 @@ -124,11 +124,11 @@ static struct perf_cpu_map *cpu_map__from_range(const= struct perf_record_cpu_map return NULL; =20 if (data->range_cpu_data.any_cpu) - map->map[i++].cpu =3D -1; + RC_CHK_ACCESS(map)->map[i++].cpu =3D -1; =20 for (int cpu =3D data->range_cpu_data.start_cpu; cpu <=3D data->range_cpu= _data.end_cpu; i++, cpu++) - map->map[i].cpu =3D cpu; + RC_CHK_ACCESS(map)->map[i].cpu =3D cpu; =20 return map; } @@ -160,16 +160,13 @@ size_t cpu_map__fprintf(struct perf_cpu_map *map, FIL= E *fp) =20 struct perf_cpu_map *perf_cpu_map__empty_new(int nr) { - struct perf_cpu_map *cpus =3D malloc(sizeof(*cpus) + sizeof(int) * nr); + struct perf_cpu_map *cpus =3D perf_cpu_map__alloc(nr); =20 if (cpus !=3D NULL) { int i; =20 - cpus->nr =3D nr; for (i =3D 0; i < nr; i++) - cpus->map[i].cpu =3D -1; - - refcount_set(&cpus->refcnt, 1); + RC_CHK_ACCESS(cpus)->map[i].cpu =3D -1; } =20 return cpus; @@ -239,7 +236,7 @@ struct cpu_aggr_map *cpu_aggr_map__new(const struct per= f_cpu_map *cpus, { int idx; struct perf_cpu cpu; - struct cpu_aggr_map *c =3D cpu_aggr_map__empty_new(cpus->nr); + struct cpu_aggr_map *c =3D cpu_aggr_map__empty_new(perf_cpu_map__nr(cpus)= ); =20 if (!c) return NULL; @@ -263,7 +260,7 @@ struct cpu_aggr_map *cpu_aggr_map__new(const struct per= f_cpu_map *cpus, } } /* Trim. */ - if (c->nr !=3D cpus->nr) { + if (c->nr !=3D perf_cpu_map__nr(cpus)) { struct cpu_aggr_map *trimmed_c =3D realloc(c, sizeof(struct cpu_aggr_map) + sizeof(struct aggr_cpu_id) * c->nr); @@ -582,31 +579,32 @@ size_t cpu_map__snprint(struct perf_cpu_map *map, cha= r *buf, size_t size) =20 #define COMMA first ? "" : "," =20 - for (i =3D 0; i < map->nr + 1; i++) { + for (i =3D 0; i < perf_cpu_map__nr(map) + 1; i++) { struct perf_cpu cpu =3D { .cpu =3D INT_MAX }; - bool last =3D i =3D=3D map->nr; + bool last =3D i =3D=3D perf_cpu_map__nr(map); =20 if (!last) - cpu =3D map->map[i]; + cpu =3D perf_cpu_map__cpu(map, i); =20 if (start =3D=3D -1) { start =3D i; if (last) { ret +=3D snprintf(buf + ret, size - ret, "%s%d", COMMA, - map->map[i].cpu); + perf_cpu_map__cpu(map, i).cpu); } - } else if (((i - start) !=3D (cpu.cpu - map->map[start].cpu)) || last) { + } else if (((i - start) !=3D (cpu.cpu - perf_cpu_map__cpu(map, start).cp= u)) || last) { int end =3D i - 1; =20 if (start =3D=3D end) { ret +=3D snprintf(buf + ret, size - ret, "%s%d", COMMA, - map->map[start].cpu); + perf_cpu_map__cpu(map, start).cpu); } else { ret +=3D snprintf(buf + ret, size - ret, "%s%d-%d", COMMA, - map->map[start].cpu, map->map[end].cpu); + perf_cpu_map__cpu(map, start).cpu, + perf_cpu_map__cpu(map, end).cpu); } first =3D false; start =3D i; @@ -633,7 +631,7 @@ size_t cpu_map__snprint_mask(struct perf_cpu_map *map, = char *buf, size_t size) int i, cpu; char *ptr =3D buf; unsigned char *bitmap; - struct perf_cpu last_cpu =3D perf_cpu_map__cpu(map, map->nr - 1); + struct perf_cpu last_cpu =3D perf_cpu_map__cpu(map, perf_cpu_map__nr(map)= - 1); =20 if (buf =3D=3D NULL) return 0; @@ -644,7 +642,7 @@ size_t cpu_map__snprint_mask(struct perf_cpu_map *map, = char *buf, size_t size) return 0; } =20 - for (i =3D 0; i < map->nr; i++) { + for (i =3D 0; i < perf_cpu_map__nr(map); i++) { cpu =3D perf_cpu_map__cpu(map, i).cpu; bitmap[cpu / 8] |=3D 1 << (cpu % 8); } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 91cccfb3c515..a9109605425c 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -2016,13 +2016,13 @@ int perf_pmu__cpus_match(struct perf_pmu *pmu, stru= ct perf_cpu_map *cpus, =20 perf_cpu_map__for_each_cpu(cpu, i, cpus) { if (!perf_cpu_map__has(pmu_cpus, cpu)) - unmatched_cpus->map[unmatched_nr++] =3D cpu; + RC_CHK_ACCESS(unmatched_cpus)->map[unmatched_nr++] =3D cpu; else - matched_cpus->map[matched_nr++] =3D cpu; + RC_CHK_ACCESS(matched_cpus)->map[matched_nr++] =3D cpu; } =20 - unmatched_cpus->nr =3D unmatched_nr; - matched_cpus->nr =3D matched_nr; + RC_CHK_ACCESS(unmatched_cpus)->nr =3D unmatched_nr; + RC_CHK_ACCESS(matched_cpus)->nr =3D matched_nr; *mcpus_ptr =3D matched_cpus; *ucpus_ptr =3D unmatched_cpus; return 0; --=20 2.40.0.577.gac1e443424-goog From nobody Mon Feb 9 23:44:42 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 70791C76196 for ; Fri, 7 Apr 2023 23:05:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229579AbjDGXFS (ORCPT ); Fri, 7 Apr 2023 19:05:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58330 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229532AbjDGXFP (ORCPT ); Fri, 7 Apr 2023 19:05:15 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BB4EDE058 for ; Fri, 7 Apr 2023 16:04:58 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id 184-20020a2515c1000000b009419f64f6afso172917ybv.2 for ; Fri, 07 Apr 2023 16:04:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; t=1680908698; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=LHqrX260PO2JkpWJuoXDRgjLDyiCkFPZ68iFLvLZDs8=; b=QzSpvDgl+t+i9S/CkRfiiAMgvlnZ6ypV7F5TOBau3PvNW/UX7uixEfLMg/DSYliGwV CGyfN7/kMC4v3mDaKSvJ7sOQgQyzAd2pxYRMzam4z2+syqawxUEfBman1czTTILxtpWR dxMjn49ZA6aQXea5KkesIIIQ4/+3yKW/dVnCXIuulnQWZSTADQxWXHZ7q3nYEenMKRjh MHDgNVjg5O0I1i2pGk3VAD5pOM/bKzUW1BKIgVxMQEeFBjmBQvZyhA/3rnKsqkk5em1T APDEpuH/Rs6DE6w64Q2z7WpaTIUHow06Z/rjYk2vK2e2iG+hmjnaWmaRj5IEJThhHEJg gEkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680908698; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=LHqrX260PO2JkpWJuoXDRgjLDyiCkFPZ68iFLvLZDs8=; b=zMY7ETgDLhsOE+r4K3N0Mtwj10Hzu0ZY9cJsVUOkCCrahm/77NoE2lZA8TYban0H5M chydJOjnHPT5sQOKejmVut1UpYWBRAgCTZNg76uDDFDInggOP8qfbZMU0GzZ/aV0K111 HxSC91s+i/IUEpcJdSXXsDj7m0jUxmIke3BU8Xgt+8bQSInbOhMwkUnRxGQxi7d67GFd 29J/GP7ek7G1szj/Tc6ui2zHpOdRDm3vVTtd/+GJxRVqSAel/aRTj+VlVlcuGgZL1bj0 snl1osHkKwD8W7hPc/ulbJ3C2rsoWJ9AmONUA5t9dVdxOt/jVr3YFzjWZbvf0hxivg3T zkHw== X-Gm-Message-State: AAQBX9d+W7biu4Qbl1AYOK2La091cfJM3cxng1edLyhm2q7zFqE70kxr 1LmnS1nnGBFfWMOG9JdlmaDnVxpcUpyF X-Google-Smtp-Source: AKy350bsaq7YNWCyHx3ZoTz6f+AuEqUr7ENZRW4bxFc5TVdE01kfhXQLY38FXD+bu3CPLsgjbSdSpF0VmgBP X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:b240:9cdf:7861:b23e]) (user=irogers job=sendgmr) by 2002:a81:e401:0:b0:54c:19a6:480 with SMTP id r1-20020a81e401000000b0054c19a60480mr1775683ywl.4.1680908697786; Fri, 07 Apr 2023 16:04:57 -0700 (PDT) Date: Fri, 7 Apr 2023 16:04:03 -0700 In-Reply-To: <20230407230405.2931830-1-irogers@google.com> Message-Id: <20230407230405.2931830-4-irogers@google.com> Mime-Version: 1.0 References: <20230407230405.2931830-1-irogers@google.com> X-Mailer: git-send-email 2.40.0.577.gac1e443424-goog Subject: [PATCH v7 3/5] perf namespaces: Add reference count checking From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Thomas Gleixner , Darren Hart , Davidlohr Bueso , James Clark , John Garry , Riccardo Mancini , Yury Norov , Andy Shevchenko , Andrew Morton , Adrian Hunter , Leo Yan , Andi Kleen , Thomas Richter , Kan Liang , Madhavan Srinivasan , Shunsuke Nakamura , Song Liu , Masami Hiramatsu , Steven Rostedt , Miaoqian Lin , Stephen Brennan , Kajol Jain , Alexey Bayduraev , German Gomez , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Dumazet , Dmitry Vyukov , Hao Luo Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add reference count checking controlled by REFCNT_CHECKING ifdef. The reference count checking interposes an allocated pointer between the reference counted struct on a get and frees the pointer on a put. Accesses after a put cause faults and use after free, missed puts are caughts as leaks and double puts are double frees. This checking helped resolve a memory leak and use after free: https://lore.kernel.org/linux-perf-users/CAP-5=3DfWZH20L4kv-BwVtGLwR=3DEm3A= OOT+Q4QGivvQuYn5AsPRg@mail.gmail.com/ Signed-off-by: Ian Rogers --- tools/perf/builtin-inject.c | 2 +- tools/perf/util/annotate.c | 2 +- tools/perf/util/dso.c | 2 +- tools/perf/util/dsos.c | 2 +- tools/perf/util/namespaces.c | 132 ++++++++++++++++++++--------------- tools/perf/util/namespaces.h | 3 +- tools/perf/util/symbol.c | 2 +- 7 files changed, 83 insertions(+), 62 deletions(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index fd2b38458a5d..fe6ddcf7fb1e 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -632,7 +632,7 @@ static int dso__read_build_id(struct dso *dso) else if (dso->nsinfo) { char *new_name; =20 - new_name =3D filename_with_chroot(dso->nsinfo->pid, + new_name =3D filename_with_chroot(RC_CHK_ACCESS(dso->nsinfo)->pid, dso->long_name); if (new_name && filename__read_build_id(new_name, &dso->bid) > 0) dso->has_build_id =3D true; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 55f2e3a7577e..a29b94078dae 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1691,7 +1691,7 @@ static int dso__disassemble_filename(struct dso *dso,= char *filename, size_t fil =20 mutex_lock(&dso->lock); if (access(filename, R_OK) && errno =3D=3D ENOENT && dso->nsinfo) { - char *new_name =3D filename_with_chroot(dso->nsinfo->pid, + char *new_name =3D filename_with_chroot(RC_CHK_ACCESS(dso->nsinfo)->pid, filename); if (new_name) { strlcpy(filename, new_name, filename_size); diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index e36b418df2c6..6c4129598f5d 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -515,7 +515,7 @@ static int __open_dso(struct dso *dso, struct machine *= machine) if (errno !=3D ENOENT || dso->nsinfo =3D=3D NULL) goto out; =20 - new_name =3D filename_with_chroot(dso->nsinfo->pid, name); + new_name =3D filename_with_chroot(RC_CHK_ACCESS(dso->nsinfo)->pid, name); if (!new_name) goto out; =20 diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c index 2bd23e4cf19e..53b989072ec5 100644 --- a/tools/perf/util/dsos.c +++ b/tools/perf/util/dsos.c @@ -91,7 +91,7 @@ bool __dsos__read_build_ids(struct list_head *head, bool = with_hits) have_build_id =3D true; pos->has_build_id =3D true; } else if (errno =3D=3D ENOENT && pos->nsinfo) { - char *new_name =3D filename_with_chroot(pos->nsinfo->pid, + char *new_name =3D filename_with_chroot(RC_CHK_ACCESS(pos->nsinfo)->pid, pos->long_name); =20 if (new_name && filename__read_build_id(new_name, diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c index dd536220cdb9..8a3b7bd27b19 100644 --- a/tools/perf/util/namespaces.c +++ b/tools/perf/util/namespaces.c @@ -60,7 +60,7 @@ void namespaces__free(struct namespaces *namespaces) free(namespaces); } =20 -static int nsinfo__get_nspid(struct nsinfo *nsi, const char *path) +static int nsinfo__get_nspid(pid_t *tgid, pid_t *nstgid, bool *in_pidns, c= onst char *path) { FILE *f =3D NULL; char *statln =3D NULL; @@ -74,19 +74,18 @@ static int nsinfo__get_nspid(struct nsinfo *nsi, const = char *path) while (getline(&statln, &linesz, f) !=3D -1) { /* Use tgid if CONFIG_PID_NS is not defined. */ if (strstr(statln, "Tgid:") !=3D NULL) { - nsi->tgid =3D (pid_t)strtol(strrchr(statln, '\t'), - NULL, 10); - nsi->nstgid =3D nsinfo__tgid(nsi); + *tgid =3D (pid_t)strtol(strrchr(statln, '\t'), NULL, 10); + *nstgid =3D *tgid; } =20 if (strstr(statln, "NStgid:") !=3D NULL) { nspid =3D strrchr(statln, '\t'); - nsi->nstgid =3D (pid_t)strtol(nspid, NULL, 10); + *nstgid =3D (pid_t)strtol(nspid, NULL, 10); /* * If innermost tgid is not the first, process is in a different * PID namespace. */ - nsi->in_pidns =3D (statln + sizeof("NStgid:") - 1) !=3D nspid; + *in_pidns =3D (statln + sizeof("NStgid:") - 1) !=3D nspid; break; } } @@ -121,8 +120,8 @@ int nsinfo__init(struct nsinfo *nsi) * want to switch as part of looking up dso/map data. */ if (old_stat.st_ino !=3D new_stat.st_ino) { - nsi->need_setns =3D true; - nsi->mntns_path =3D newns; + RC_CHK_ACCESS(nsi)->need_setns =3D true; + RC_CHK_ACCESS(nsi)->mntns_path =3D newns; newns =3D NULL; } =20 @@ -132,13 +131,26 @@ int nsinfo__init(struct nsinfo *nsi) if (snprintf(spath, PATH_MAX, "/proc/%d/status", nsinfo__pid(nsi)) >=3D P= ATH_MAX) goto out; =20 - rv =3D nsinfo__get_nspid(nsi, spath); + rv =3D nsinfo__get_nspid(&RC_CHK_ACCESS(nsi)->tgid, &RC_CHK_ACCESS(nsi)->= nstgid, + &RC_CHK_ACCESS(nsi)->in_pidns, spath); =20 out: free(newns); return rv; } =20 +static struct nsinfo *nsinfo__alloc(void) +{ + struct nsinfo *res; + RC_STRUCT(nsinfo) *nsi; + + nsi =3D calloc(1, sizeof(*nsi)); + if (ADD_RC_CHK(res, nsi)) + refcount_set(&nsi->refcnt, 1); + + return res; +} + struct nsinfo *nsinfo__new(pid_t pid) { struct nsinfo *nsi; @@ -146,22 +158,21 @@ struct nsinfo *nsinfo__new(pid_t pid) if (pid =3D=3D 0) return NULL; =20 - nsi =3D calloc(1, sizeof(*nsi)); - if (nsi !=3D NULL) { - nsi->pid =3D pid; - nsi->tgid =3D pid; - nsi->nstgid =3D pid; - nsi->need_setns =3D false; - nsi->in_pidns =3D false; - /* Init may fail if the process exits while we're trying to look - * at its proc information. In that case, save the pid but - * don't try to enter the namespace. - */ - if (nsinfo__init(nsi) =3D=3D -1) - nsi->need_setns =3D false; + nsi =3D nsinfo__alloc(); + if (!nsi) + return NULL; =20 - refcount_set(&nsi->refcnt, 1); - } + RC_CHK_ACCESS(nsi)->pid =3D pid; + RC_CHK_ACCESS(nsi)->tgid =3D pid; + RC_CHK_ACCESS(nsi)->nstgid =3D pid; + RC_CHK_ACCESS(nsi)->need_setns =3D false; + RC_CHK_ACCESS(nsi)->in_pidns =3D false; + /* Init may fail if the process exits while we're trying to look at its + * proc information. In that case, save the pid but don't try to enter + * the namespace. + */ + if (nsinfo__init(nsi) =3D=3D -1) + RC_CHK_ACCESS(nsi)->need_setns =3D false; =20 return nsi; } @@ -173,21 +184,21 @@ struct nsinfo *nsinfo__copy(const struct nsinfo *nsi) if (nsi =3D=3D NULL) return NULL; =20 - nnsi =3D calloc(1, sizeof(*nnsi)); - if (nnsi !=3D NULL) { - nnsi->pid =3D nsinfo__pid(nsi); - nnsi->tgid =3D nsinfo__tgid(nsi); - nnsi->nstgid =3D nsinfo__nstgid(nsi); - nnsi->need_setns =3D nsinfo__need_setns(nsi); - nnsi->in_pidns =3D nsinfo__in_pidns(nsi); - if (nsi->mntns_path) { - nnsi->mntns_path =3D strdup(nsi->mntns_path); - if (!nnsi->mntns_path) { - free(nnsi); - return NULL; - } + nnsi =3D nsinfo__alloc(); + if (!nnsi) + return NULL; + + RC_CHK_ACCESS(nnsi)->pid =3D nsinfo__pid(nsi); + RC_CHK_ACCESS(nnsi)->tgid =3D nsinfo__tgid(nsi); + RC_CHK_ACCESS(nnsi)->nstgid =3D nsinfo__nstgid(nsi); + RC_CHK_ACCESS(nnsi)->need_setns =3D nsinfo__need_setns(nsi); + RC_CHK_ACCESS(nnsi)->in_pidns =3D nsinfo__in_pidns(nsi); + if (RC_CHK_ACCESS(nsi)->mntns_path) { + RC_CHK_ACCESS(nnsi)->mntns_path =3D strdup(RC_CHK_ACCESS(nsi)->mntns_pat= h); + if (!RC_CHK_ACCESS(nnsi)->mntns_path) { + nsinfo__put(nnsi); + return NULL; } - refcount_set(&nnsi->refcnt, 1); } =20 return nnsi; @@ -195,51 +206,60 @@ struct nsinfo *nsinfo__copy(const struct nsinfo *nsi) =20 static void nsinfo__delete(struct nsinfo *nsi) { - zfree(&nsi->mntns_path); - free(nsi); + if (nsi) { + WARN_ONCE(refcount_read(&RC_CHK_ACCESS(nsi)->refcnt) !=3D 0, + "nsinfo refcnt unbalanced\n"); + zfree(&RC_CHK_ACCESS(nsi)->mntns_path); + RC_CHK_FREE(nsi); + } } =20 struct nsinfo *nsinfo__get(struct nsinfo *nsi) { - if (nsi) - refcount_inc(&nsi->refcnt); - return nsi; + struct nsinfo *result; + + if (RC_CHK_GET(result, nsi)) + refcount_inc(&RC_CHK_ACCESS(nsi)->refcnt); + + return result; } =20 void nsinfo__put(struct nsinfo *nsi) { - if (nsi && refcount_dec_and_test(&nsi->refcnt)) + if (nsi && refcount_dec_and_test(&RC_CHK_ACCESS(nsi)->refcnt)) nsinfo__delete(nsi); + else + RC_CHK_PUT(nsi); } =20 bool nsinfo__need_setns(const struct nsinfo *nsi) { - return nsi->need_setns; + return RC_CHK_ACCESS(nsi)->need_setns; } =20 void nsinfo__clear_need_setns(struct nsinfo *nsi) { - nsi->need_setns =3D false; + RC_CHK_ACCESS(nsi)->need_setns =3D false; } =20 pid_t nsinfo__tgid(const struct nsinfo *nsi) { - return nsi->tgid; + return RC_CHK_ACCESS(nsi)->tgid; } =20 pid_t nsinfo__nstgid(const struct nsinfo *nsi) { - return nsi->nstgid; + return RC_CHK_ACCESS(nsi)->nstgid; } =20 pid_t nsinfo__pid(const struct nsinfo *nsi) { - return nsi->pid; + return RC_CHK_ACCESS(nsi)->pid; } =20 pid_t nsinfo__in_pidns(const struct nsinfo *nsi) { - return nsi->in_pidns; + return RC_CHK_ACCESS(nsi)->in_pidns; } =20 void nsinfo__mountns_enter(struct nsinfo *nsi, @@ -256,7 +276,7 @@ void nsinfo__mountns_enter(struct nsinfo *nsi, nc->oldns =3D -1; nc->newns =3D -1; =20 - if (!nsi || !nsi->need_setns) + if (!nsi || !RC_CHK_ACCESS(nsi)->need_setns) return; =20 if (snprintf(curpath, PATH_MAX, "/proc/self/ns/mnt") >=3D PATH_MAX) @@ -270,7 +290,7 @@ void nsinfo__mountns_enter(struct nsinfo *nsi, if (oldns < 0) goto errout; =20 - newns =3D open(nsi->mntns_path, O_RDONLY); + newns =3D open(RC_CHK_ACCESS(nsi)->mntns_path, O_RDONLY); if (newns < 0) goto errout; =20 @@ -339,9 +359,9 @@ int nsinfo__stat(const char *filename, struct stat *st,= struct nsinfo *nsi) =20 bool nsinfo__is_in_root_namespace(void) { - struct nsinfo nsi; + pid_t tgid =3D 0, nstgid =3D 0; + bool in_pidns =3D false; =20 - memset(&nsi, 0x0, sizeof(nsi)); - nsinfo__get_nspid(&nsi, "/proc/self/status"); - return !nsi.in_pidns; + nsinfo__get_nspid(&tgid, &nstgid, &in_pidns, "/proc/self/status"); + return !in_pidns; } diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h index 567829262c42..8c0731c6cbb7 100644 --- a/tools/perf/util/namespaces.h +++ b/tools/perf/util/namespaces.h @@ -13,6 +13,7 @@ #include #include #include +#include =20 #ifndef HAVE_SETNS_SUPPORT int setns(int fd, int nstype); @@ -29,7 +30,7 @@ struct namespaces { struct namespaces *namespaces__new(struct perf_record_namespaces *event); void namespaces__free(struct namespaces *namespaces); =20 -struct nsinfo { +DECLARE_RC_STRUCT(nsinfo) { pid_t pid; pid_t tgid; pid_t nstgid; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 91ebf93e0c20..639343d5577c 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1963,7 +1963,7 @@ int dso__load(struct dso *dso, struct map *map) =20 is_reg =3D is_regular_file(name); if (!is_reg && errno =3D=3D ENOENT && dso->nsinfo) { - char *new_name =3D filename_with_chroot(dso->nsinfo->pid, + char *new_name =3D filename_with_chroot(RC_CHK_ACCESS(dso->nsinfo)->pid, name); if (new_name) { is_reg =3D is_regular_file(new_name); --=20 2.40.0.577.gac1e443424-goog From nobody Mon Feb 9 23:44:42 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7D9D4C77B6C for ; Fri, 7 Apr 2023 23:05:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229580AbjDGXF2 (ORCPT ); Fri, 7 Apr 2023 19:05:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58554 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229561AbjDGXFZ (ORCPT ); Fri, 7 Apr 2023 19:05:25 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4394FE059 for ; Fri, 7 Apr 2023 16:05:07 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id f66-20020a255145000000b00b714602d43fso43848673ybb.10 for ; Fri, 07 Apr 2023 16:05:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; t=1680908706; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=/9OxK9O+214Ftf+emLqWQX0BdscBsNuKoaQhFz4awdI=; b=LIOvfvs+TGmGTVeJEWXBv464qGMyynjYkPyh9q1i4FcTu+BbqB14qBQYVxZo/idxYT MwwOZ9Q9cfrvg35DFin1M4Mku/iF6o1hY8v24+8D/pLnNgGz+Phk9dMxdPp4EBF/3R3m Q2kbsBxhikq0RgsMSemv9AuKVs/zXZw1Zeii/vtYjsKWL65jHp0yo5rtb8q2WqtYooNZ wlRpmTDg6cZnaFMm+ysN8/e56b1ItP1O0lsFJimB2dQy3UyCTb2lTR/4MKzO/cxyvxPu Se1YG/EPWFvI+7XogijDDmBo+azmNIZ8ugvLk3qvwppfe9iKewMAnF+CTJvqknXKRAUA gCfQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680908706; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=/9OxK9O+214Ftf+emLqWQX0BdscBsNuKoaQhFz4awdI=; b=jFd+b6meKUaOg1s08TWQ2xeJzXy1e+DhHe6VuQ3BEVc6NVSXyToMi6Hj/f9oE9kkcL DW9he3vGvTbomLwgExiAF5Be6IX8bZqUBufEn2kFJQfFsQPyr+de78B0ND4qrTnxDfyB X1w4bV/ETD1H6pj6Wm6jSISfTZj5O285arfNeWbEM6G2u67UtioGsw0/d5WqcDEhoP23 XV8VzCytaPWyAk1nMgtGbkG5Z1nu3FFCYfVJe90DreO99QXdynCAGwGLc57/Xu2Zf2Q7 HXKTl1niMMLxcWeTjHFgmxiQeB1fyAe5K8fnqjCh69bUQj+P+XOJrPSNhHnax6IwVhS/ 12qQ== X-Gm-Message-State: AAQBX9c95pJXh4CQfC8GWcGqe/Zj19tsKbKxMtESIyZIZGPWx7BZ/gm1 z40AeJfSnPtSyvc9rCNqXY3aarizqD+u X-Google-Smtp-Source: AKy350bqU/u3LkAM2Zl5P0gS5bWJTxR36K5/ojhBUTzBLhsfw+rRpaGZFuULjQPUqBp12wO0Dl7A0Tnbef8+ X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:b240:9cdf:7861:b23e]) (user=irogers job=sendgmr) by 2002:a81:eb12:0:b0:545:1d7f:acbf with SMTP id n18-20020a81eb12000000b005451d7facbfmr84341ywm.10.1680908706095; Fri, 07 Apr 2023 16:05:06 -0700 (PDT) Date: Fri, 7 Apr 2023 16:04:04 -0700 In-Reply-To: <20230407230405.2931830-1-irogers@google.com> Message-Id: <20230407230405.2931830-5-irogers@google.com> Mime-Version: 1.0 References: <20230407230405.2931830-1-irogers@google.com> X-Mailer: git-send-email 2.40.0.577.gac1e443424-goog Subject: [PATCH v7 4/5] perf maps: Add reference count checking. From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Thomas Gleixner , Darren Hart , Davidlohr Bueso , James Clark , John Garry , Riccardo Mancini , Yury Norov , Andy Shevchenko , Andrew Morton , Adrian Hunter , Leo Yan , Andi Kleen , Thomas Richter , Kan Liang , Madhavan Srinivasan , Shunsuke Nakamura , Song Liu , Masami Hiramatsu , Steven Rostedt , Miaoqian Lin , Stephen Brennan , Kajol Jain , Alexey Bayduraev , German Gomez , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Dumazet , Dmitry Vyukov , Hao Luo Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add reference count checking to make sure of good use of get and put. Add and use accessors to reduce RC_CHK clutter. The only significant issue was in tests/thread-maps-share.c where reference counts were released in the reverse order to acquisition, leading to a use after put. This was fixed by reversing the put order. Signed-off-by: Ian Rogers --- tools/perf/tests/thread-maps-share.c | 29 ++++++------- tools/perf/util/machine.c | 2 +- tools/perf/util/maps.c | 53 +++++++++++++----------- tools/perf/util/maps.h | 17 ++++---- tools/perf/util/symbol.c | 13 +++--- tools/perf/util/unwind-libdw.c | 2 +- tools/perf/util/unwind-libunwind-local.c | 2 +- tools/perf/util/unwind-libunwind.c | 2 +- 8 files changed, 64 insertions(+), 56 deletions(-) diff --git a/tools/perf/tests/thread-maps-share.c b/tools/perf/tests/thread= -maps-share.c index 84edd82c519e..dfe51b21bd7d 100644 --- a/tools/perf/tests/thread-maps-share.c +++ b/tools/perf/tests/thread-maps-share.c @@ -43,12 +43,12 @@ static int test__thread_maps_share(struct test_suite *t= est __maybe_unused, int s leader && t1 && t2 && t3 && other); =20 maps =3D leader->maps; - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 4); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&RC_CHK_ACCESS(maps)->ref= cnt), 4); =20 /* test the maps pointer is shared */ - TEST_ASSERT_VAL("maps don't match", maps =3D=3D t1->maps); - TEST_ASSERT_VAL("maps don't match", maps =3D=3D t2->maps); - TEST_ASSERT_VAL("maps don't match", maps =3D=3D t3->maps); + TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(maps) =3D=3D RC_CHK_ACC= ESS(t1->maps)); + TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(maps) =3D=3D RC_CHK_ACC= ESS(t2->maps)); + TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(maps) =3D=3D RC_CHK_ACC= ESS(t3->maps)); =20 /* * Verify the other leader was created by previous call. @@ -71,25 +71,26 @@ static int test__thread_maps_share(struct test_suite *t= est __maybe_unused, int s machine__remove_thread(machine, other_leader); =20 other_maps =3D other->maps; - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_maps->refcnt), 2); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&RC_CHK_ACCESS(other_maps= )->refcnt), 2); =20 - TEST_ASSERT_VAL("maps don't match", other_maps =3D=3D other_leader->maps); + TEST_ASSERT_VAL("maps don't match", + RC_CHK_ACCESS(other_maps) =3D=3D RC_CHK_ACCESS(other_leader->maps)); =20 /* release thread group */ - thread__put(leader); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 3); - - thread__put(t1); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 2); + thread__put(t3); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&RC_CHK_ACCESS(maps)->ref= cnt), 3); =20 thread__put(t2); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 1); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&RC_CHK_ACCESS(maps)->ref= cnt), 2); =20 - thread__put(t3); + thread__put(t1); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&RC_CHK_ACCESS(maps)->ref= cnt), 1); + + thread__put(leader); =20 /* release other group */ thread__put(other_leader); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_maps->refcnt), 1); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&RC_CHK_ACCESS(other_maps= )->refcnt), 1); =20 thread__put(other); =20 diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 25738775834e..2d9ce6966238 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -435,7 +435,7 @@ static struct thread *findnew_guest_code(struct machine= *machine, return NULL; =20 /* Assume maps are set up if there are any */ - if (thread->maps->nr_maps) + if (RC_CHK_ACCESS(thread->maps)->nr_maps) return thread; =20 host_thread =3D machine__find_thread(host_machine, -1, pid); diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 5afed53ea0b4..567952587247 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -12,13 +12,13 @@ =20 static void maps__init(struct maps *maps, struct machine *machine) { - maps->entries =3D RB_ROOT; + RC_CHK_ACCESS(maps)->entries =3D RB_ROOT; init_rwsem(maps__lock(maps)); - maps->machine =3D machine; - maps->last_search_by_name =3D NULL; - maps->nr_maps =3D 0; - maps->maps_by_name =3D NULL; - refcount_set(&maps->refcnt, 1); + RC_CHK_ACCESS(maps)->machine =3D machine; + RC_CHK_ACCESS(maps)->last_search_by_name =3D NULL; + RC_CHK_ACCESS(maps)->nr_maps =3D 0; + RC_CHK_ACCESS(maps)->maps_by_name =3D NULL; + refcount_set(&RC_CHK_ACCESS(maps)->refcnt, 1); } =20 static void __maps__free_maps_by_name(struct maps *maps) @@ -29,8 +29,8 @@ static void __maps__free_maps_by_name(struct maps *maps) for (unsigned int i =3D 0; i < maps__nr_maps(maps); i++) map__put(maps__maps_by_name(maps)[i]); =20 - zfree(&maps->maps_by_name); - maps->nr_maps_allocated =3D 0; + zfree(&RC_CHK_ACCESS(maps)->maps_by_name); + RC_CHK_ACCESS(maps)->nr_maps_allocated =3D 0; } =20 static int __maps__insert(struct maps *maps, struct map *map) @@ -71,7 +71,7 @@ int maps__insert(struct maps *maps, struct map *map) if (err) goto out; =20 - ++maps->nr_maps; + ++RC_CHK_ACCESS(maps)->nr_maps; =20 if (dso && dso->kernel) { struct kmap *kmap =3D map__kmap(map); @@ -88,7 +88,7 @@ int maps__insert(struct maps *maps, struct map *map) * inserted map and resort. */ if (maps__maps_by_name(maps)) { - if (maps__nr_maps(maps) > maps->nr_maps_allocated) { + if (maps__nr_maps(maps) > RC_CHK_ACCESS(maps)->nr_maps_allocated) { int nr_allocate =3D maps__nr_maps(maps) * 2; struct map **maps_by_name =3D realloc(maps__maps_by_name(maps), nr_allocate * sizeof(map)); @@ -99,8 +99,8 @@ int maps__insert(struct maps *maps, struct map *map) goto out; } =20 - maps->maps_by_name =3D maps_by_name; - maps->nr_maps_allocated =3D nr_allocate; + RC_CHK_ACCESS(maps)->maps_by_name =3D maps_by_name; + RC_CHK_ACCESS(maps)->nr_maps_allocated =3D nr_allocate; } maps__maps_by_name(maps)[maps__nr_maps(maps) - 1] =3D map__get(map); __maps__sort_by_name(maps); @@ -122,15 +122,15 @@ void maps__remove(struct maps *maps, struct map *map) struct map_rb_node *rb_node; =20 down_write(maps__lock(maps)); - if (maps->last_search_by_name =3D=3D map) - maps->last_search_by_name =3D NULL; + if (RC_CHK_ACCESS(maps)->last_search_by_name =3D=3D map) + RC_CHK_ACCESS(maps)->last_search_by_name =3D NULL; =20 rb_node =3D maps__find_node(maps, map); assert(rb_node->map =3D=3D map); __maps__remove(maps, rb_node); if (maps__maps_by_name(maps)) __maps__free_maps_by_name(maps); - --maps->nr_maps; + --RC_CHK_ACCESS(maps)->nr_maps; up_write(maps__lock(maps)); } =20 @@ -162,33 +162,38 @@ bool maps__empty(struct maps *maps) =20 struct maps *maps__new(struct machine *machine) { - struct maps *maps =3D zalloc(sizeof(*maps)); + struct maps *res; + RC_STRUCT(maps) *maps =3D zalloc(sizeof(*maps)); =20 - if (maps !=3D NULL) - maps__init(maps, machine); + if (ADD_RC_CHK(res, maps)) + maps__init(res, machine); =20 - return maps; + return res; } =20 void maps__delete(struct maps *maps) { maps__exit(maps); unwind__finish_access(maps); - free(maps); + RC_CHK_FREE(maps); } =20 struct maps *maps__get(struct maps *maps) { - if (maps) - refcount_inc(&maps->refcnt); + struct maps *result; =20 - return maps; + if (RC_CHK_GET(result, maps)) + refcount_inc(&RC_CHK_ACCESS(maps)->refcnt); + + return result; } =20 void maps__put(struct maps *maps) { - if (maps && refcount_dec_and_test(&maps->refcnt)) + if (maps && refcount_dec_and_test(&RC_CHK_ACCESS(maps)->refcnt)) maps__delete(maps); + else + RC_CHK_PUT(maps); } =20 struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map *= *mapp) diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h index bde3390c7096..0af4b7e42fca 100644 --- a/tools/perf/util/maps.h +++ b/tools/perf/util/maps.h @@ -8,6 +8,7 @@ #include #include #include "rwsem.h" +#include =20 struct ref_reloc_sym; struct machine; @@ -32,7 +33,7 @@ struct map *maps__find(struct maps *maps, u64 addr); for (map =3D maps__first(maps), next =3D map_rb_node__next(map); map; \ map =3D next, next =3D map_rb_node__next(map)) =20 -struct maps { +DECLARE_RC_STRUCT(maps) { struct rb_root entries; struct rw_semaphore lock; struct machine *machine; @@ -65,38 +66,38 @@ void maps__put(struct maps *maps); =20 static inline struct rb_root *maps__entries(struct maps *maps) { - return &maps->entries; + return &RC_CHK_ACCESS(maps)->entries; } =20 static inline struct machine *maps__machine(struct maps *maps) { - return maps->machine; + return RC_CHK_ACCESS(maps)->machine; } =20 static inline struct rw_semaphore *maps__lock(struct maps *maps) { - return &maps->lock; + return &RC_CHK_ACCESS(maps)->lock; } =20 static inline struct map **maps__maps_by_name(struct maps *maps) { - return maps->maps_by_name; + return RC_CHK_ACCESS(maps)->maps_by_name; } =20 static inline unsigned int maps__nr_maps(const struct maps *maps) { - return maps->nr_maps; + return RC_CHK_ACCESS(maps)->nr_maps; } =20 #ifdef HAVE_LIBUNWIND_SUPPORT static inline void *maps__addr_space(struct maps *maps) { - return maps->addr_space; + return RC_CHK_ACCESS(maps)->addr_space; } =20 static inline const struct unwind_libunwind_ops *maps__unwind_libunwind_op= s(const struct maps *maps) { - return maps->unwind_libunwind_ops; + return RC_CHK_ACCESS(maps)->unwind_libunwind_ops; } #endif =20 diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 639343d5577c..6993b51b9416 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2097,8 +2097,8 @@ static int map__groups__sort_by_name_from_rbtree(stru= ct maps *maps) up_read(maps__lock(maps)); down_write(maps__lock(maps)); =20 - maps->maps_by_name =3D maps_by_name; - maps->nr_maps_allocated =3D maps__nr_maps(maps); + RC_CHK_ACCESS(maps)->maps_by_name =3D maps_by_name; + RC_CHK_ACCESS(maps)->nr_maps_allocated =3D maps__nr_maps(maps); =20 maps__for_each_entry(maps, rb_node) maps_by_name[i++] =3D map__get(rb_node->map); @@ -2133,11 +2133,12 @@ struct map *maps__find_by_name(struct maps *maps, c= onst char *name) =20 down_read(maps__lock(maps)); =20 - if (maps->last_search_by_name) { - const struct dso *dso =3D map__dso(maps->last_search_by_name); + + if (RC_CHK_ACCESS(maps)->last_search_by_name) { + const struct dso *dso =3D map__dso(RC_CHK_ACCESS(maps)->last_search_by_n= ame); =20 if (strcmp(dso->short_name, name) =3D=3D 0) { - map =3D maps->last_search_by_name; + map =3D RC_CHK_ACCESS(maps)->last_search_by_name; goto out_unlock; } } @@ -2157,7 +2158,7 @@ struct map *maps__find_by_name(struct maps *maps, con= st char *name) map =3D rb_node->map; dso =3D map__dso(map); if (strcmp(dso->short_name, name) =3D=3D 0) { - maps->last_search_by_name =3D map; + RC_CHK_ACCESS(maps)->last_search_by_name =3D map; goto out_unlock; } } diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 9565f9906e5d..bdccfc511b7e 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -230,7 +230,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct unwind_info *ui, ui_buf =3D { .sample =3D data, .thread =3D thread, - .machine =3D thread->maps->machine, + .machine =3D RC_CHK_ACCESS(thread->maps)->machine, .cb =3D cb, .arg =3D arg, .max_stack =3D max_stack, diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unw= ind-libunwind-local.c index f9a52af48de4..83dd79dcd597 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -677,7 +677,7 @@ static int _unwind__prepare_access(struct maps *maps) { void *addr_space =3D unw_create_addr_space(&accessors, 0); =20 - maps->addr_space =3D addr_space; + RC_CHK_ACCESS(maps)->addr_space =3D addr_space; if (!addr_space) { pr_err("unwind: Can't create unwind address space.\n"); return -ENOMEM; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-li= bunwind.c index 4378daaafcd3..b54968e6a4e4 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -14,7 +14,7 @@ struct unwind_libunwind_ops __weak *arm64_unwind_libunwin= d_ops; =20 static void unwind__register_ops(struct maps *maps, struct unwind_libunwin= d_ops *ops) { - maps->unwind_libunwind_ops =3D ops; + RC_CHK_ACCESS(maps)->unwind_libunwind_ops =3D ops; } =20 int unwind__prepare_access(struct maps *maps, struct map *map, bool *initi= alized) --=20 2.40.0.577.gac1e443424-goog From nobody Mon Feb 9 23:44:42 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 95AF4C76196 for ; Fri, 7 Apr 2023 23:05:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229592AbjDGXFq (ORCPT ); Fri, 7 Apr 2023 19:05:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59072 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229561AbjDGXFm (ORCPT ); Fri, 7 Apr 2023 19:05:42 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C1319E066 for ; Fri, 7 Apr 2023 16:05:15 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id n14-20020a25400e000000b00b6d6655dc35so40800yba.6 for ; Fri, 07 Apr 2023 16:05:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; t=1680908715; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=r8pJnP6RbyFujTICIoNTWoAACWFJ4BwJMUkbZhyU8UE=; b=Nb5rMTaS+Pe7Rosg7zJz5o1TWYbPx6xunaRvt047V3Rn2iHJRY5S258MRC+tcyUH5U ItK2DI8BApAysl5FiZSDpFY8IRCjEjBKSoTHKzK8bIFOnE/uhT7OohA5nNQ+7fjTdCHc NhMvzY+LavItUYd0H9gLA4NIcn7gkO/DgSZ/yfDizvvzRZcQNDcvevu1OFpR1/lUhKf2 ulwv7laL/jg9xOSdnQVQJAUIRKs3YXq5SLuSyb/r21HoeR9p33lr/CXeQi57IFXdPj4X blHbkxIFrEI06Dc+BBx9I0EqzQLAIwSVYeBS1XJvRXwXW8cdFsPQJ/LhXdW+ODoCJlLc 74HQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680908715; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=r8pJnP6RbyFujTICIoNTWoAACWFJ4BwJMUkbZhyU8UE=; b=KpPaaEmRTEmqD2y9EPt3cPlrCdM/AzQhcTvQCWsk/d2IUgbK91fApd5ONUCbAFtPC+ qiYaQFF1SthdNSyACwvmqqZNQt26dS3rzunqurlGNkURL18HOcBQxkFbNFa8iCr0mFJ0 frlCHdiSpA/7AZAWsot7gxHrOHIWASBtyhDMmPWhNGanXG3wZOndUW3CGfCgnu3PfhBY YsvUE/RVBslemDVsF0fkKHXILcHGK2mItVnRw+lmOb0bEBPFo9j+k/7Q7mdBRfrtvGJN qgsusj+W41i19ZFZSsrFIO2QWaNwYZVKsr9vIptzXAIx98GTuBTpE0S3oEKcAqVHjzIo rtlQ== X-Gm-Message-State: AAQBX9f7SAYcebeEmgPNcmqtOTXOvD2+f04ervef0btP4J56FKivS7kP 8bt+GK0GdVdlavn8LEbicr+dgEBi5Hm2 X-Google-Smtp-Source: AKy350ZYLLhoD03IZPy6IkALBLFhMGg7QdH+v8iXuL5le624IhSzV13BJ45sBRLRHN0zvuAYAixtoLnsvcA6 X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:b240:9cdf:7861:b23e]) (user=irogers job=sendgmr) by 2002:a81:ef0c:0:b0:549:2cc8:6e3e with SMTP id o12-20020a81ef0c000000b005492cc86e3emr1882170ywm.9.1680908714879; Fri, 07 Apr 2023 16:05:14 -0700 (PDT) Date: Fri, 7 Apr 2023 16:04:05 -0700 In-Reply-To: <20230407230405.2931830-1-irogers@google.com> Message-Id: <20230407230405.2931830-6-irogers@google.com> Mime-Version: 1.0 References: <20230407230405.2931830-1-irogers@google.com> X-Mailer: git-send-email 2.40.0.577.gac1e443424-goog Subject: [PATCH v7 5/5] perf map: Add reference count checking From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Thomas Gleixner , Darren Hart , Davidlohr Bueso , James Clark , John Garry , Riccardo Mancini , Yury Norov , Andy Shevchenko , Andrew Morton , Adrian Hunter , Leo Yan , Andi Kleen , Thomas Richter , Kan Liang , Madhavan Srinivasan , Shunsuke Nakamura , Song Liu , Masami Hiramatsu , Steven Rostedt , Miaoqian Lin , Stephen Brennan , Kajol Jain , Alexey Bayduraev , German Gomez , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Dumazet , Dmitry Vyukov , Hao Luo Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" There's no strict get/put policy with map that leads to leaks or use after free. Reference count checking identifies correct pairing of gets and puts. Signed-off-by: Ian Rogers --- tools/perf/builtin-top.c | 4 +- tools/perf/tests/hists_link.c | 2 +- tools/perf/tests/maps.c | 20 ++++----- tools/perf/tests/vmlinux-kallsyms.c | 4 +- tools/perf/util/machine.c | 25 ++++++----- tools/perf/util/map.c | 69 ++++++++++++++++------------- tools/perf/util/map.h | 32 +++++++------ tools/perf/util/maps.c | 11 ++--- tools/perf/util/symbol-elf.c | 26 ++++++----- tools/perf/util/symbol.c | 40 +++++++++-------- 10 files changed, 126 insertions(+), 107 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 3162bad0d17d..11141a492837 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -191,7 +191,7 @@ static void ui__warn_map_erange(struct map *map, struct= symbol *sym, u64 ip) if (use_browser <=3D 0) sleep(5); =20 - map->erange_warned =3D true; + RC_CHK_ACCESS(map)->erange_warned =3D true; } =20 static void perf_top__record_precise_ip(struct perf_top *top, @@ -225,7 +225,7 @@ static void perf_top__record_precise_ip(struct perf_top= *top, */ mutex_unlock(&he->hists->lock); =20 - if (err =3D=3D -ERANGE && !he->ms.map->erange_warned) + if (err =3D=3D -ERANGE && !RC_CHK_ACCESS(he->ms.map)->erange_warned) ui__warn_map_erange(he->ms.map, sym, ip); else if (err =3D=3D -ENOMEM) { pr_err("Not enough memory for annotating '%s' symbol!\n", diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 64ce8097889c..141e2972e34f 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -145,7 +145,7 @@ static int find_sample(struct sample *samples, size_t n= r_samples, { while (nr_samples--) { if (samples->thread =3D=3D t && - samples->map =3D=3D m && + RC_CHK_ACCESS(samples->map) =3D=3D RC_CHK_ACCESS(m) && samples->sym =3D=3D s) return 1; samples++; diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c index 1c7293476aca..b8dab6278bca 100644 --- a/tools/perf/tests/maps.c +++ b/tools/perf/tests/maps.c @@ -30,7 +30,7 @@ static int check_maps(struct map_def *merged, unsigned in= t size, struct maps *ma if (map__start(map) !=3D merged[i].start || map__end(map) !=3D merged[i].end || strcmp(map__dso(map)->name, merged[i].name) || - refcount_read(&map->refcnt) !=3D 1) { + refcount_read(&RC_CHK_ACCESS(map)->refcnt) !=3D 1) { failed =3D true; } i++; @@ -50,7 +50,7 @@ static int check_maps(struct map_def *merged, unsigned in= t size, struct maps *ma map__start(map), map__end(map), map__dso(map)->name, - refcount_read(&map->refcnt)); + refcount_read(&RC_CHK_ACCESS(map)->refcnt)); } } return failed ? TEST_FAIL : TEST_OK; @@ -95,8 +95,8 @@ static int test__maps__merge_in(struct test_suite *t __ma= ybe_unused, int subtest map =3D dso__new_map(bpf_progs[i].name); TEST_ASSERT_VAL("failed to create map", map); =20 - map->start =3D bpf_progs[i].start; - map->end =3D bpf_progs[i].end; + RC_CHK_ACCESS(map)->start =3D bpf_progs[i].start; + RC_CHK_ACCESS(map)->end =3D bpf_progs[i].end; TEST_ASSERT_VAL("failed to insert map", maps__insert(maps, map) =3D=3D 0= ); map__put(map); } @@ -111,16 +111,16 @@ static int test__maps__merge_in(struct test_suite *t = __maybe_unused, int subtest TEST_ASSERT_VAL("failed to create map", map_kcore3); =20 /* kcore1 map overlaps over all bpf maps */ - map_kcore1->start =3D 100; - map_kcore1->end =3D 1000; + RC_CHK_ACCESS(map_kcore1)->start =3D 100; + RC_CHK_ACCESS(map_kcore1)->end =3D 1000; =20 /* kcore2 map hides behind bpf_prog_2 */ - map_kcore2->start =3D 550; - map_kcore2->end =3D 570; + RC_CHK_ACCESS(map_kcore2)->start =3D 550; + RC_CHK_ACCESS(map_kcore2)->end =3D 570; =20 /* kcore3 map hides behind bpf_prog_3, kcore1 and adds new map */ - map_kcore3->start =3D 880; - map_kcore3->end =3D 1100; + RC_CHK_ACCESS(map_kcore3)->start =3D 880; + RC_CHK_ACCESS(map_kcore3)->end =3D 1100; =20 ret =3D maps__merge_in(maps, map_kcore1); TEST_ASSERT_VAL("failed to merge map", !ret); diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux= -kallsyms.c index af511233c764..a087b24463ff 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -304,7 +304,7 @@ static int test__vmlinux_matches_kallsyms(struct test_s= uite *test __maybe_unused dso->short_name : dso->name)); if (pair) { - pair->priv =3D 1; + RC_CHK_ACCESS(pair)->priv =3D 1; } else { if (!header_printed) { pr_info("WARN: Maps only in vmlinux:\n"); @@ -340,7 +340,7 @@ static int test__vmlinux_matches_kallsyms(struct test_s= uite *test __maybe_unused pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64, map__start(pair), map__end(pair), map__pgoff(pair)); pr_info(" %s\n", dso->name); - pair->priv =3D 1; + RC_CHK_ACCESS(pair)->priv =3D 1; } } =20 diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 2d9ce6966238..9a472ee52129 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -910,8 +910,8 @@ static int machine__process_ksymbol_register(struct mac= hine *machine, dso__set_loaded(dso); } =20 - map->start =3D event->ksymbol.addr; - map->end =3D map__start(map) + event->ksymbol.len; + RC_CHK_ACCESS(map)->start =3D event->ksymbol.addr; + RC_CHK_ACCESS(map)->end =3D map__start(map) + event->ksymbol.len; err =3D maps__insert(machine__kernel_maps(machine), map); if (err) { err =3D -ENOMEM; @@ -953,7 +953,7 @@ static int machine__process_ksymbol_unregister(struct m= achine *machine, if (!map) return 0; =20 - if (map !=3D machine->vmlinux_map) + if (RC_CHK_ACCESS(map) !=3D RC_CHK_ACCESS(machine->vmlinux_map)) maps__remove(machine__kernel_maps(machine), map); else { struct dso *dso =3D map__dso(map); @@ -1218,8 +1218,8 @@ int machine__create_extra_kernel_map(struct machine *= machine, if (!map) return -ENOMEM; =20 - map->end =3D xm->end; - map->pgoff =3D xm->pgoff; + RC_CHK_ACCESS(map)->end =3D xm->end; + RC_CHK_ACCESS(map)->pgoff =3D xm->pgoff; =20 kmap =3D map__kmap(map); =20 @@ -1291,7 +1291,7 @@ int machine__map_x86_64_entry_trampolines(struct mach= ine *machine, =20 dest_map =3D maps__find(kmaps, map__pgoff(map)); if (dest_map !=3D map) - map->pgoff =3D map__map_ip(dest_map, map__pgoff(map)); + RC_CHK_ACCESS(map)->pgoff =3D map__map_ip(dest_map, map__pgoff(map)); found =3D true; } if (found || machine->trampolines_mapped) @@ -1342,7 +1342,8 @@ __machine__create_kernel_maps(struct machine *machine= , struct dso *kernel) if (machine->vmlinux_map =3D=3D NULL) return -ENOMEM; =20 - machine->vmlinux_map->map_ip =3D machine->vmlinux_map->unmap_ip =3D ident= ity__map_ip; + RC_CHK_ACCESS(machine->vmlinux_map)->map_ip =3D identity__map_ip; + RC_CHK_ACCESS(machine->vmlinux_map)->unmap_ip =3D identity__map_ip; return maps__insert(machine__kernel_maps(machine), machine->vmlinux_map); } =20 @@ -1623,7 +1624,7 @@ static int machine__create_module(void *arg, const ch= ar *name, u64 start, map =3D machine__addnew_module_map(machine, start, name); if (map =3D=3D NULL) return -1; - map->end =3D start + size; + RC_CHK_ACCESS(map)->end =3D start + size; =20 dso__kernel_module_get_build_id(map__dso(map), machine->root_dir); map__put(map); @@ -1659,14 +1660,14 @@ static int machine__create_modules(struct machine *= machine) static void machine__set_kernel_mmap(struct machine *machine, u64 start, u64 end) { - machine->vmlinux_map->start =3D start; - machine->vmlinux_map->end =3D end; + RC_CHK_ACCESS(machine->vmlinux_map)->start =3D start; + RC_CHK_ACCESS(machine->vmlinux_map)->end =3D end; /* * Be a bit paranoid here, some perf.data file came with * a zero sized synthesized MMAP event for the kernel. */ if (start =3D=3D 0 && end =3D=3D 0) - machine->vmlinux_map->end =3D ~0ULL; + RC_CHK_ACCESS(machine->vmlinux_map)->end =3D ~0ULL; } =20 static int machine__update_kernel_mmap(struct machine *machine, @@ -1810,7 +1811,7 @@ static int machine__process_kernel_mmap_event(struct = machine *machine, if (map =3D=3D NULL) goto out_problem; =20 - map->end =3D map__start(map) + xm->end - xm->start; + RC_CHK_ACCESS(map)->end =3D map__start(map) + xm->end - xm->start; =20 if (build_id__is_defined(bid)) dso__set_build_id(map__dso(map), bid); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index d81b6ca18ee9..d13c787faea9 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -104,15 +104,15 @@ static inline bool replace_android_lib(const char *fi= lename, char *newfilename) =20 void map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso = *dso) { - map->start =3D start; - map->end =3D end; - map->pgoff =3D pgoff; - map->reloc =3D 0; - map->dso =3D dso__get(dso); - map->map_ip =3D map__dso_map_ip; - map->unmap_ip =3D map__dso_unmap_ip; - map->erange_warned =3D false; - refcount_set(&map->refcnt, 1); + RC_CHK_ACCESS(map)->start =3D start; + RC_CHK_ACCESS(map)->end =3D end; + RC_CHK_ACCESS(map)->pgoff =3D pgoff; + RC_CHK_ACCESS(map)->reloc =3D 0; + RC_CHK_ACCESS(map)->dso =3D dso__get(dso); + RC_CHK_ACCESS(map)->map_ip =3D map__dso_map_ip; + RC_CHK_ACCESS(map)->unmap_ip =3D map__dso_unmap_ip; + RC_CHK_ACCESS(map)->erange_warned =3D false; + refcount_set(&RC_CHK_ACCESS(map)->refcnt, 1); } =20 struct map *map__new(struct machine *machine, u64 start, u64 len, @@ -120,11 +120,13 @@ struct map *map__new(struct machine *machine, u64 sta= rt, u64 len, u32 prot, u32 flags, struct build_id *bid, char *filename, struct thread *thread) { - struct map *map =3D malloc(sizeof(*map)); + struct map *res; + RC_STRUCT(map) *map; struct nsinfo *nsi =3D NULL; struct nsinfo *nnsi; =20 - if (map !=3D NULL) { + map =3D malloc(sizeof(*map)); + if (ADD_RC_CHK(res, map)) { char newfilename[PATH_MAX]; struct dso *dso, *header_bid_dso; int anon, no_dso, vdso, android; @@ -167,7 +169,7 @@ struct map *map__new(struct machine *machine, u64 start= , u64 len, if (dso =3D=3D NULL) goto out_delete; =20 - map__init(map, start, start + len, pgoff, dso); + map__init(res, start, start + len, pgoff, dso); =20 if (anon || no_dso) { map->map_ip =3D map->unmap_ip =3D identity__map_ip; @@ -204,10 +206,10 @@ struct map *map__new(struct machine *machine, u64 sta= rt, u64 len, } dso__put(dso); } - return map; + return res; out_delete: nsinfo__put(nsi); - free(map); + RC_CHK_FREE(res); return NULL; } =20 @@ -218,16 +220,18 @@ struct map *map__new(struct machine *machine, u64 sta= rt, u64 len, */ struct map *map__new2(u64 start, struct dso *dso) { - struct map *map =3D calloc(1, (sizeof(*map) + - (dso->kernel ? sizeof(struct kmap) : 0))); - if (map !=3D NULL) { + struct map *res; + RC_STRUCT(map) *map; + + map =3D calloc(1, sizeof(*map) + (dso->kernel ? sizeof(struct kmap) : 0)); + if (ADD_RC_CHK(res, map)) { /* * ->end will be filled after we load all the symbols */ - map__init(map, start, 0, 0, dso); + map__init(res, start, 0, 0, dso); } =20 - return map; + return res; } =20 bool __map__is_kernel(const struct map *map) @@ -292,20 +296,22 @@ bool map__has_symbols(const struct map *map) =20 static void map__exit(struct map *map) { - BUG_ON(refcount_read(&map->refcnt) !=3D 0); - dso__zput(map->dso); + BUG_ON(refcount_read(&RC_CHK_ACCESS(map)->refcnt) !=3D 0); + dso__zput(RC_CHK_ACCESS(map)->dso); } =20 void map__delete(struct map *map) { map__exit(map); - free(map); + RC_CHK_FREE(map); } =20 void map__put(struct map *map) { - if (map && refcount_dec_and_test(&map->refcnt)) + if (map && refcount_dec_and_test(&RC_CHK_ACCESS(map)->refcnt)) map__delete(map); + else + RC_CHK_PUT(map); } =20 void map__fixup_start(struct map *map) @@ -317,7 +323,7 @@ void map__fixup_start(struct map *map) if (nd !=3D NULL) { struct symbol *sym =3D rb_entry(nd, struct symbol, rb_node); =20 - map->start =3D sym->start; + RC_CHK_ACCESS(map)->start =3D sym->start; } } =20 @@ -329,7 +335,7 @@ void map__fixup_end(struct map *map) =20 if (nd !=3D NULL) { struct symbol *sym =3D rb_entry(nd, struct symbol, rb_node); - map->end =3D sym->end; + RC_CHK_ACCESS(map)->end =3D sym->end; } } =20 @@ -400,20 +406,21 @@ struct symbol *map__find_symbol_by_name(struct map *m= ap, const char *name) =20 struct map *map__clone(struct map *from) { - size_t size =3D sizeof(struct map); - struct map *map; + struct map *res; + RC_STRUCT(map) *map; + size_t size =3D sizeof(RC_STRUCT(map)); struct dso *dso =3D map__dso(from); =20 if (dso && dso->kernel) size +=3D sizeof(struct kmap); =20 - map =3D memdup(from, size); - if (map !=3D NULL) { + map =3D memdup(RC_CHK_ACCESS(from), size); + if (ADD_RC_CHK(res, map)) { refcount_set(&map->refcnt, 1); map->dso =3D dso__get(dso); } =20 - return map; + return res; } =20 size_t map__fprintf(struct map *map, FILE *fp) @@ -567,7 +574,7 @@ struct kmap *__map__kmap(struct map *map) =20 if (!dso || !dso->kernel) return NULL; - return (struct kmap *)(map + 1); + return (struct kmap *)(&RC_CHK_ACCESS(map)[1]); } =20 struct kmap *map__kmap(struct map *map) diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 102485699aa8..55d047e818e7 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -10,12 +10,13 @@ #include #include #include +#include =20 struct dso; struct maps; struct machine; =20 -struct map { +DECLARE_RC_STRUCT(map) { u64 start; u64 end; bool erange_warned:1; @@ -49,52 +50,52 @@ u64 identity__map_ip(const struct map *map __maybe_unus= ed, u64 ip); =20 static inline struct dso *map__dso(const struct map *map) { - return map->dso; + return RC_CHK_ACCESS(map)->dso; } =20 static inline u64 map__map_ip(const struct map *map, u64 ip) { - return map->map_ip(map, ip); + return RC_CHK_ACCESS(map)->map_ip(map, ip); } =20 static inline u64 map__unmap_ip(const struct map *map, u64 ip) { - return map->unmap_ip(map, ip); + return RC_CHK_ACCESS(map)->unmap_ip(map, ip); } =20 static inline u64 map__start(const struct map *map) { - return map->start; + return RC_CHK_ACCESS(map)->start; } =20 static inline u64 map__end(const struct map *map) { - return map->end; + return RC_CHK_ACCESS(map)->end; } =20 static inline u64 map__pgoff(const struct map *map) { - return map->pgoff; + return RC_CHK_ACCESS(map)->pgoff; } =20 static inline u64 map__reloc(const struct map *map) { - return map->reloc; + return RC_CHK_ACCESS(map)->reloc; } =20 static inline u32 map__flags(const struct map *map) { - return map->flags; + return RC_CHK_ACCESS(map)->flags; } =20 static inline u32 map__prot(const struct map *map) { - return map->prot; + return RC_CHK_ACCESS(map)->prot; } =20 static inline bool map__priv(const struct map *map) { - return map->priv; + return RC_CHK_ACCESS(map)->priv; } =20 static inline size_t map__size(const struct map *map) @@ -153,9 +154,12 @@ struct map *map__clone(struct map *map); =20 static inline struct map *map__get(struct map *map) { - if (map) - refcount_inc(&map->refcnt); - return map; + struct map *result; + + if (RC_CHK_GET(result, map)) + refcount_inc(&RC_CHK_ACCESS(map)->refcnt); + + return result; } =20 void map__put(struct map *map); diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 567952587247..a33ae321c65a 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -126,7 +126,7 @@ void maps__remove(struct maps *maps, struct map *map) RC_CHK_ACCESS(maps)->last_search_by_name =3D NULL; =20 rb_node =3D maps__find_node(maps, map); - assert(rb_node->map =3D=3D map); + assert(rb_node->RC_CHK_ACCESS(map) =3D=3D RC_CHK_ACCESS(map)); __maps__remove(maps, rb_node); if (maps__maps_by_name(maps)) __maps__free_maps_by_name(maps); @@ -339,7 +339,7 @@ int maps__fixup_overlappings(struct maps *maps, struct = map *map, FILE *fp) goto put_map; } =20 - before->end =3D map__start(map); + RC_CHK_ACCESS(before)->end =3D map__start(map); err =3D __maps__insert(maps, before); if (err) { map__put(before); @@ -359,8 +359,9 @@ int maps__fixup_overlappings(struct maps *maps, struct = map *map, FILE *fp) goto put_map; } =20 - after->start =3D map__end(map); - after->pgoff +=3D map__end(map) - map__start(pos->map); + RC_CHK_ACCESS(after)->start =3D map__end(map); + RC_CHK_ACCESS(after)->pgoff +=3D + map__end(map) - map__start(pos->map); assert(map__map_ip(pos->map, map__end(map)) =3D=3D map__map_ip(after, map__end(map))); err =3D __maps__insert(maps, after); @@ -420,7 +421,7 @@ struct map_rb_node *maps__find_node(struct maps *maps, = struct map *map) struct map_rb_node *rb_node; =20 maps__for_each_entry(maps, rb_node) { - if (rb_node->map =3D=3D map) + if (rb_node->RC_CHK_ACCESS(map) =3D=3D RC_CHK_ACCESS(map)) return rb_node; } return NULL; diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index c55981116f68..302599073b5d 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1354,11 +1354,11 @@ static int dso__process_kernel_symbol(struct dso *d= so, struct map *map, */ if (*remap_kernel && dso->kernel && !kmodule) { *remap_kernel =3D false; - map->start =3D shdr->sh_addr + ref_reloc(kmap); - map->end =3D map__start(map) + shdr->sh_size; - map->pgoff =3D shdr->sh_offset; - map->map_ip =3D map__dso_map_ip; - map->unmap_ip =3D map__dso_unmap_ip; + RC_CHK_ACCESS(map)->start =3D shdr->sh_addr + ref_reloc(kmap); + RC_CHK_ACCESS(map)->end =3D map__start(map) + shdr->sh_size; + RC_CHK_ACCESS(map)->pgoff =3D shdr->sh_offset; + RC_CHK_ACCESS(map)->map_ip =3D map__dso_map_ip; + RC_CHK_ACCESS(map)->unmap_ip =3D map__dso_unmap_ip; /* Ensure maps are correctly ordered */ if (kmaps) { int err; @@ -1379,7 +1379,7 @@ static int dso__process_kernel_symbol(struct dso *dso= , struct map *map, */ if (*remap_kernel && kmodule) { *remap_kernel =3D false; - map->pgoff =3D shdr->sh_offset; + RC_CHK_ACCESS(map)->pgoff =3D shdr->sh_offset; } =20 *curr_mapp =3D map; @@ -1414,11 +1414,13 @@ static int dso__process_kernel_symbol(struct dso *d= so, struct map *map, map__kmap(curr_map)->kmaps =3D kmaps; =20 if (adjust_kernel_syms) { - curr_map->start =3D shdr->sh_addr + ref_reloc(kmap); - curr_map->end =3D map__start(curr_map) + shdr->sh_size; - curr_map->pgoff =3D shdr->sh_offset; + RC_CHK_ACCESS(curr_map)->start =3D shdr->sh_addr + ref_reloc(kmap); + RC_CHK_ACCESS(curr_map)->end =3D map__start(curr_map) + + shdr->sh_size; + RC_CHK_ACCESS(curr_map)->pgoff =3D shdr->sh_offset; } else { - curr_map->map_ip =3D curr_map->unmap_ip =3D identity__map_ip; + RC_CHK_ACCESS(curr_map)->map_ip =3D identity__map_ip; + RC_CHK_ACCESS(curr_map)->unmap_ip =3D identity__map_ip; } curr_dso->symtab_type =3D dso->symtab_type; if (maps__insert(kmaps, curr_map)) @@ -1525,7 +1527,7 @@ dso__load_sym_internal(struct dso *dso, struct map *m= ap, struct symsrc *syms_ss, if (strcmp(elf_name, kmap->ref_reloc_sym->name)) continue; kmap->ref_reloc_sym->unrelocated_addr =3D sym.st_value; - map->reloc =3D kmap->ref_reloc_sym->addr - + RC_CHK_ACCESS(map)->reloc =3D kmap->ref_reloc_sym->addr - kmap->ref_reloc_sym->unrelocated_addr; break; } @@ -1536,7 +1538,7 @@ dso__load_sym_internal(struct dso *dso, struct map *m= ap, struct symsrc *syms_ss, * attempted to prelink vdso to its virtual address. */ if (dso__is_vdso(dso)) - map->reloc =3D map__start(map) - dso->text_offset; + RC_CHK_ACCESS(map)->reloc =3D map__start(map) - dso->text_offset; =20 dso->adjust_symbols =3D runtime_ss->adjust_symbols || ref_reloc(kmap); /* diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 6993b51b9416..42458582621b 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -279,7 +279,7 @@ void maps__fixup_end(struct maps *maps) =20 maps__for_each_entry(maps, curr) { if (prev !=3D NULL && !map__end(prev->map)) - prev->map->end =3D map__start(curr->map); + RC_CHK_ACCESS(prev->map)->end =3D map__start(curr->map); =20 prev =3D curr; } @@ -289,7 +289,7 @@ void maps__fixup_end(struct maps *maps) * last map final address. */ if (curr && !map__end(curr->map)) - curr->map->end =3D ~0ULL; + RC_CHK_ACCESS(curr->map)->end =3D ~0ULL; =20 up_write(maps__lock(maps)); } @@ -865,7 +865,7 @@ static int maps__split_kallsyms(struct maps *kmaps, str= uct dso *dso, u64 delta, *module++ =3D '\0'; curr_map_dso =3D map__dso(curr_map); if (strcmp(curr_map_dso->short_name, module)) { - if (curr_map !=3D initial_map && + if (RC_CHK_ACCESS(curr_map) !=3D RC_CHK_ACCESS(initial_map) && dso->kernel =3D=3D DSO_SPACE__KERNEL_GUEST && machine__is_default_guest(machine)) { /* @@ -944,7 +944,8 @@ static int maps__split_kallsyms(struct maps *kmaps, str= uct dso *dso, u64 delta, return -1; } =20 - curr_map->map_ip =3D curr_map->unmap_ip =3D identity__map_ip; + RC_CHK_ACCESS(curr_map)->map_ip =3D identity__map_ip; + RC_CHK_ACCESS(curr_map)->unmap_ip =3D identity__map_ip; if (maps__insert(kmaps, curr_map)) { dso__put(ndso); return -1; @@ -1250,8 +1251,8 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff,= void *data) return -ENOMEM; } =20 - list_node->map->end =3D map__start(list_node->map) + len; - list_node->map->pgoff =3D pgoff; + list_node->RC_CHK_ACCESS(map)->end =3D map__start(list_node->map) + len; + list_node->RC_CHK_ACCESS(map)->pgoff =3D pgoff; =20 list_add(&list_node->node, &md->maps); =20 @@ -1286,7 +1287,7 @@ int maps__merge_in(struct maps *kmaps, struct map *ne= w_map) * |new......| -> |new..| * |old....| -> |old....| */ - new_map->end =3D map__start(old_map); + RC_CHK_ACCESS(new_map)->end =3D map__start(old_map); } else { /* * |new.............| -> |new..| |new..| @@ -1306,10 +1307,12 @@ int maps__merge_in(struct maps *kmaps, struct map *= new_map) goto out; } =20 - m->map->end =3D map__start(old_map); + + RC_CHK_ACCESS(m->map)->end =3D map__start(old_map); list_add_tail(&m->node, &merged); - new_map->pgoff +=3D map__end(old_map) - map__start(new_map); - new_map->start =3D map__end(old_map); + RC_CHK_ACCESS(new_map)->pgoff +=3D + map__end(old_map) - map__start(new_map); + RC_CHK_ACCESS(new_map)->start =3D map__end(old_map); } } else { /* @@ -1329,8 +1332,9 @@ int maps__merge_in(struct maps *kmaps, struct map *ne= w_map) * |new......| -> |new...| * |old....| -> |old....| */ - new_map->pgoff +=3D map__end(old_map) - map__start(new_map); - new_map->start =3D map__end(old_map); + RC_CHK_ACCESS(new_map)->pgoff +=3D + map__end(old_map) - map__start(new_map); + RC_CHK_ACCESS(new_map)->start =3D map__end(old_map); } } } @@ -1456,12 +1460,12 @@ static int dso__load_kcore(struct dso *dso, struct = map *map, =20 list_del_init(&new_node->node); =20 - if (new_map =3D=3D replacement_map) { - map->start =3D map__start(new_map); - map->end =3D map__end(new_map); - map->pgoff =3D map__pgoff(new_map); - map->map_ip =3D new_map->map_ip; - map->unmap_ip =3D new_map->unmap_ip; + if (RC_CHK_ACCESS(new_map) =3D=3D RC_CHK_ACCESS(replacement_map)) { + RC_CHK_ACCESS(map)->start =3D map__start(new_map); + RC_CHK_ACCESS(map)->end =3D map__end(new_map); + RC_CHK_ACCESS(map)->pgoff =3D map__pgoff(new_map); + RC_CHK_ACCESS(map)->map_ip =3D RC_CHK_ACCESS(new_map)->map_ip; + RC_CHK_ACCESS(map)->unmap_ip =3D RC_CHK_ACCESS(new_map)->unmap_ip; /* Ensure maps are correctly ordered */ map__get(map); maps__remove(kmaps, map); --=20 2.40.0.577.gac1e443424-goog