diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 82602d046..d7c286e15 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -293,7 +293,7 @@ def my_shlex_join(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 spec_to_job(spec: JobSpec) -> JobDetails: 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 ec40cb53d..aa69faca0 100644 --- a/src/test/SDL_test_memory.c +++ b/src/test/SDL_test_memory.c @@ -24,7 +24,8 @@ #define UNW_LOCAL_ONLY #include #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;