Subject: [PATCH] Fix segfault in profiler-cpu-log and profiler-memory-log
From: Zach Shaftel <[email-masked]>
To: [email-masked]
Date: Wed, 11 Jun 2025 16:03:12 -0400
List-Id: <debbugs-submit.debbugs.gnu.org>

Tags: patch

a simple NULL dereference fix. the profiler log would be null if
profiler-*-log is called without a profiler-*-start before it, or if a
previous profiler-*-log call had flushed the log and the profiler wasn't
restarted since then. then export_log would try to read the NULL log and
segfault.

to reproduce the bug:
emacs --batch -f profiler-cpu-log

this patch causes profiler-cpu-log and profiler-memory-log to just
return nil if the log is null.

In GNU Emacs 31.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version
 3.24.49, cairo version 1.18.4) of 2025-06-04 built on bigbox
Repository revision: 680fa61b5989b84c0e19ac568be012afd8345f0c
Repository branch: master
System Description: Arch Linux

Configured using:
 'configure --with-modules --without-xwidgets --with-native-compilation
 --with-tree-sitter --without-gsettings --without-gconf --without-gpm
 --with-pgtk --without-compress-install 'CFLAGS=-mtune=native
 -march=native -O2 -g -fuse-ld=mold''

From 2c1b3bc8b020acbef496dd991bd08bc0f5505528 Mon Sep 17 00:00:00 2001
From: Zach Shaftel <[email-masked]>
Date: Wed, 11 Jun 2025 15:37:31 -0400
Subject: [PATCH] Fix segfault in profiler-cpu-log and profiler-memory-log

* src/profiler.c (export_log): Check if a log has been allocated first,
and return nil if it hasn't.
(Fprofiler_cpu_log, Fprofiler_memory_log): Mention the possibly nil
result.
---
 src/profiler.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/src/profiler.c b/src/profiler.c
index 12d75012c79..816864e940e 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -534,7 +534,11 @@ DEFUN ("profiler-cpu-log", Fprofiler_cpu_log, Sprofiler_cpu_log,
 The log is a hash-table mapping backtraces to counters which represent
 the amount of time spent at those points.  Every backtrace is a vector
 of functions, where the last few elements may be nil.
-Before returning, a new log is allocated for future samples.  */)
+
+If the profiler has not run since the last invocation of
+`profiler-cpu-log' (or was never run at all), nil is returned.  If the
+profiler is currently running, a new log is allocated for future samples
+before returning.  */)
   (void)
 {
   /* Temporarily stop profiling to avoid it interfering with our data
@@ -556,6 +560,9 @@ DEFUN ("profiler-cpu-log", Fprofiler_cpu_log, Sprofiler_cpu_log,
 static Lisp_Object
 export_log (struct profiler_log *plog)
 {
+  if (plog->log == NULL)
+    /* We haven't collected any new data, so return nil.  */
+    return Qnil;
   log_t *log = plog->log;
   /* The returned hash table uses `equal' as key equivalence predicate
      which is more discriminating than the `function-equal' used by
@@ -639,7 +646,11 @@ DEFUN ("profiler-memory-log",
 The log is a hash-table mapping backtraces to counters which represent
 the amount of memory allocated at those points.  Every backtrace is a vector
 of functions, where the last few elements may be nil.
-Before returning, a new log is allocated for future samples.  */)
+
+If the profiler has not run since the last invocation of
+`profiler-memory-log' (or was never run at all), nil is returned.  If
+the profiler is currently running, a new log is allocated for future
+samples before returning.  */)
   (void)
 {
   bool prof_mem = profiler_memory_running;
-- 
2.49.0