SDL: SDL_test: print no procname when SDL_TRACKMEM_SYMBOL_NAMES is false

From ea0ab2647a022c8695f1968962ec65cfc2862688 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Fri, 30 Aug 2024 23:29:09 +0200
Subject: [PATCH] SDL_test: print no procname when SDL_TRACKMEM_SYMBOL_NAMES is
 false

On ci, by default this variable is set to a false value.
By adding [sdl-ci-trackmem] to the commit message,
it will become true.
---
 .github/workflows/create-test-plan.py | 27 +++++++++++++++-------
 src/test/SDL_test_memory.c            | 32 ++++++++++++++++++++-------
 2 files changed, 43 insertions(+), 16 deletions(-)

diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py
index 82602d0460994..d7c286e15f9ec 100755
--- a/.github/workflows/create-test-plan.py
+++ b/.github/workflows/create-test-plan.py
@@ -293,7 +293,7 @@ def escape(s):
     return " ".join(escape(s))
 
 
-def spec_to_job(spec: JobSpec) -> JobDetails:
+def spec_to_job(spec: JobSpec, trackmem_symbol_names: bool) -> JobDetails:
     job = JobDetails(
         name=spec.name,
         os=spec.os.value,
@@ -308,6 +308,11 @@ def spec_to_job(spec: JobSpec) -> JobDetails:
             "ninja-build",
             "pkg-config",
         ])
+    pretest_cmd = []
+    if trackmem_symbol_names:
+        pretest_cmd.append("export SDL_TRACKMEM_SYMBOL_NAMES=1")
+    else:
+        pretest_cmd.append("export SDL_TRACKMEM_SYMBOL_NAMES=0")
     win32 = spec.platform in (SdlPlatform.Msys2, SdlPlatform.Msvc)
     fpic = None
     build_parallel = True
@@ -433,7 +438,9 @@ def spec_to_job(spec: JobSpec) -> JobDetails:
                 "libudev-dev",
                 "fcitx-libs-dev",
             ))
-            job.cmake_arguments.append("-DSDLTEST_TIMEOUT_MULTIPLIER=2")  # older libunwind is slow
+            if trackmem_symbol_names:
+                # older libunwind is slow
+                job.cmake_arguments.append("-DSDLTEST_TIMEOUT_MULTIPLIER=2")
             job.apt_packages.extend((
                 "libunwind-dev",  # For SDL_test memory tracking
             ))
@@ -541,12 +548,12 @@ def spec_to_job(spec: JobSpec) -> JobDetails:
             job.ldflags.extend((
                 "--source-map-base", "/",
             ))
-            job.pretest_cmd = "\n".join([
+            pretest_cmd.extend((
                 "# Start local HTTP server",
                 "cmake --build build --target serve-sdl-tests --verbose &",
                 "chrome --version",
                 "chromedriver --version",
-            ])
+            ))
             job.static_lib = StaticLibType.A
         case SdlPlatform.Ps2:
             build_parallel = False
@@ -703,7 +710,7 @@ def spec_to_job(spec: JobSpec) -> JobDetails:
     if job.ldflags:
         job.cmake_arguments.append(f"-DCMAKE_SHARED_LINKER_FLAGS=\"{my_shlex_join(job.ldflags)}\"")
         job.cmake_arguments.append(f"-DCMAKE_EXE_LINKER_FLAGS=\"{my_shlex_join(job.ldflags)}\"")
-
+    job.pretest_cmd = "\n".join(pretest_cmd)
     def tf(b):
         return "ON" if b else "OFF"
 
@@ -716,9 +723,9 @@ def tf(b):
     return job
 
 
-def spec_to_platform(spec: JobSpec, enable_artifacts: bool) -> dict[str, str|bool]:
+def spec_to_platform(spec: JobSpec, enable_artifacts: bool, trackmem_symbol_names: bool) -> dict[str, str|bool]:
     logger.info("spec=%r", spec)
-    job = spec_to_job(spec)
+    job = spec_to_job(spec, trackmem_symbol_names=trackmem_symbol_names)
     logger.info("job=%r", job)
     platform = job.to_workflow(enable_artifacts=enable_artifacts)
     logger.info("platform=%r", platform)
@@ -732,6 +739,7 @@ def main():
     parser.add_argument("--verbose", action="store_true")
     parser.add_argument("--commit-message-file")
     parser.add_argument("--no-artifact", dest="enable_artifacts", action="store_false")
+    parser.add_argument("--trackmem-symbol-names", dest="trackmem_symbol_names", action="store_true")
     args = parser.parse_args()
 
     logging.basicConfig(level=logging.INFO if args.verbose else logging.WARNING)
@@ -755,6 +763,9 @@ def main():
             if re.search(r"\[sdl-ci-artifacts?]", commit_message, flags=re.M):
                 args.enable_artifacts = True
 
+            if re.search(r"\[sdl-ci-(full-)?trackmem(-symbol-names)?]", commit_message, flags=re.M):
+                args.trackmem_symbol_names = True
+
     if not filters:
         filters.append("*")
 
@@ -762,7 +773,7 @@ def main():
 
     all_level_platforms = {}
 
-    all_platforms = {k: spec_to_platform(spec, enable_artifacts=args.enable_artifacts) for k, spec in JOB_SPECS.items()}
+    all_platforms = {k: spec_to_platform(spec, enable_artifacts=args.enable_artifacts, trackmem_symbol_names=args.trackmem_symbol_names) for k, spec in JOB_SPECS.items()}
 
     for level_i, level_keys in enumerate(all_level_keys, 1):
         level_key = f"level{level_i}"
diff --git a/src/test/SDL_test_memory.c b/src/test/SDL_test_memory.c
index ec40cb53d55b1..aa69faca0d12e 100644
--- a/src/test/SDL_test_memory.c
+++ b/src/test/SDL_test_memory.c
@@ -24,7 +24,8 @@
 #define UNW_LOCAL_ONLY
 #include <libunwind.h>
 #ifndef unw_get_proc_name_by_ip
-#define SDLTEST_EARLY_PROCNAME
+#define SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
+static SDL_bool s_unwind_symbol_names = SDL_TRUE;
 #endif
 #endif
 
@@ -60,7 +61,7 @@ typedef struct SDL_tracked_allocation
     size_t size;
     Uint64 stack[MAXIMUM_TRACKED_STACK_DEPTH];
     struct SDL_tracked_allocation *next;
-#ifdef SDLTEST_EARLY_PROCNAME
+#ifdef SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
     char stack_names[MAXIMUM_TRACKED_STACK_DEPTH][256];
 #endif
 } SDL_tracked_allocation;
@@ -150,7 +151,7 @@ static void SDL_TrackAllocation(void *mem, size_t size)
         stack_index = 0;
         while (unw_step(&cursor) > 0) {
             unw_word_t pc;
-#ifdef SDLTEST_EARLY_PROCNAME
+#ifdef SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
             unw_word_t offset;
             char sym[236];
 #endif
@@ -158,8 +159,8 @@ static void SDL_TrackAllocation(void *mem, size_t size)
             unw_get_reg(&cursor, UNW_REG_IP, &pc);
             entry->stack[stack_index] = pc;
 
-#ifdef SDLTEST_EARLY_PROCNAME
-            if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
+#ifdef SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
+            if (s_unwind_symbol_names && unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
                 SDL_snprintf(entry->stack_names[stack_index], sizeof(entry->stack_names[stack_index]), "%s+0x%llx", sym, (unsigned long long)offset);
             }
 #endif
@@ -295,7 +296,20 @@ void SDLTest_TrackAllocations(void)
     if (s_previous_allocations != 0) {
         SDL_Log("SDLTest_TrackAllocations(): There are %d previous allocations, disabling free() validation", s_previous_allocations);
     }
-#ifdef SDL_PLATFORM_WIN32
+#ifdef SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
+    do {
+        /* Don't use SDL_GetHint: SDL_malloc is off limits. */
+        const char *env_trackmem = SDL_getenv("SDL_TRACKMEM_SYMBOL_NAMES");
+        if (env_trackmem) {
+            if (SDL_strcasecmp(env_trackmem, "1") == 0 || SDL_strcasecmp(env_trackmem, "yes") == 0 || SDL_strcasecmp(env_trackmem, "true") == 0) {
+                s_unwind_symbol_names = SDL_TRUE;
+            } else if (SDL_strcasecmp(env_trackmem, "0") == 0 || SDL_strcasecmp(env_trackmem, "no") == 0 || SDL_strcasecmp(env_trackmem, "false") == 0) {
+                s_unwind_symbol_names = SDL_FALSE;
+            }
+        }
+    } while (0);
+
+#elif defined(SDL_PLATFORM_WIN32)
     do {
         dyn_dbghelp.module = SDL_LoadObject("dbghelp.dll");
         if (!dyn_dbghelp.module) {
@@ -383,8 +397,10 @@ void SDLTest_LogAllocations(void)
                 }
 #ifdef HAVE_LIBUNWIND_H
                 {
-#ifdef SDLTEST_EARLY_PROCNAME
-                    (void)SDL_snprintf(stack_entry_description, sizeof(stack_entry_description), "%s", entry->stack_names[stack_index]);
+#ifdef SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
+                    if (s_unwind_symbol_names) {
+                        (void)SDL_snprintf(stack_entry_description, sizeof(stack_entry_description), "%s", entry->stack_names[stack_index]);
+                    }
 #else
                     char name[256] = "???";
                     unw_word_t offset = 0;