From 0ae0226cd12a0c77ad0c299896fa8792ea7f9cbe Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Sun, 9 Mar 2025 23:00:59 -0400 Subject: [PATCH] libdtrace: Fix an off-by-one in CPU ID handling The illumos-specific _SC_CPUID_MAX is the largest CPU ID in the system. This was mapped to _SC_NPROCESSORS_CONF, which is the total number of CPUs recognized by the kernel. If CPU IDs are contiguous, as is the case on amd64 and arm64, this value is one greater than the maximum ID. As a result, when consuming per-CPU dtrace buffers, libdtrace tries to fetch from a non-existent CPU. This is mostly harmless in practice, but still wrong. As we don't have a sysconf value for the maximum CPU ID, add a wrapper which fetches it using the kern.smp.maxid sysctl. MFC after: 2 weeks Sponsored by: Innovate UK Differential Revision: https://reviews.freebsd.org/D49243 (cherry picked from commit 9a30c8d347bf9aaa89277b6e5a275f737be8edce) --- .../lib/libdtrace/common/dt_aggregate.c | 6 ++++-- .../opensolaris/lib/libdtrace/common/dt_consume.c | 8 ++++---- .../opensolaris/lib/libdtrace/common/dt_impl.h | 1 + .../opensolaris/lib/libdtrace/common/dt_subr.c | 14 ++++++++++++++ .../opensolaris/lib/libdtrace/common/dtrace.h | 5 ----- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c index 643e7fae8ac..1c3131e74cb 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c @@ -1092,8 +1092,10 @@ dt_aggregate_go(dtrace_hdl_t *dtp) assert(agp->dtat_ncpu == 0); assert(agp->dtat_cpus == NULL); - agp->dtat_maxcpu = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; - agp->dtat_ncpu = dt_sysconf(dtp, _SC_NPROCESSORS_MAX); + agp->dtat_maxcpu = dt_cpu_maxid(dtp) + 1; + if (agp->dtat_maxcpu <= 0) + return (-1); + agp->dtat_ncpu = dt_sysconf(dtp, _SC_NPROCESSORS_CONF); agp->dtat_cpus = malloc(agp->dtat_ncpu * sizeof (processorid_t)); if (agp->dtat_cpus == NULL) diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c index 6a32235f7e3..a760642c33b 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c @@ -3949,8 +3949,8 @@ dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, return (rval); } - if (max_ncpus == 0) - max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; + if (max_ncpus == 0 && (max_ncpus = dt_cpu_maxid(dtp) + 1) <= 0) + return (-1); for (i = 0; i < max_ncpus; i++) { dtrace_bufdesc_t *nbuf; @@ -4040,8 +4040,8 @@ dtrace_consume(dtrace_hdl_t *dtp, FILE *fp, if (!dtp->dt_active) return (dt_set_errno(dtp, EINVAL)); - if (max_ncpus == 0) - max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; + if (max_ncpus == 0 && (max_ncpus = dt_cpu_maxid(dtp) + 1) <= 0) + return (-1); if (pf == NULL) pf = (dtrace_consume_probe_f *)dt_nullprobe; diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h index 1be984f2800..b73ecc3e57f 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h @@ -620,6 +620,7 @@ extern int dt_version_defined(dt_version_t); */ extern char *dt_cpp_add_arg(dtrace_hdl_t *, const char *); extern char *dt_cpp_pop_arg(dtrace_hdl_t *); +extern int dt_cpu_maxid(dtrace_hdl_t *); #ifdef illumos extern int dt_set_errno(dtrace_hdl_t *, int); diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c index 5976333e1b1..5dc8e1648fd 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c @@ -463,6 +463,20 @@ dt_cpp_pop_arg(dtrace_hdl_t *dtp) return (arg); } +int +dt_cpu_maxid(dtrace_hdl_t *dtp) +{ + size_t len; + u_int count; + int error; + + len = sizeof(count); + error = sysctlbyname("kern.smp.maxid", &count, &len, NULL, 0); + if (error != 0) + return (dt_set_errno(dtp, errno)); + return (count); +} + /*PRINTFLIKE1*/ void dt_dprintf(const char *format, ...) diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h index 1f4c5a2efd6..c9496c2df5b 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h @@ -620,11 +620,6 @@ extern int _dtrace_debug; } #endif -#ifndef illumos -#define _SC_CPUID_MAX _SC_NPROCESSORS_CONF -#define _SC_NPROCESSORS_MAX _SC_NPROCESSORS_CONF -#endif - /* * Values for the dt_oformat property. */