False positive memory leak with execinfo backtrace?

Hey!

When I call backtrace_symbols() or backtrace_symbols_fd() valgrind rapports 6,452 bytes definitely lost in 11 blocks. This is inside a SDL3 application using SDL_MAIN_USE_CALLBACKS.

Have any of you noticed the same problem? Is this a false positive rapport related to how SDL3 handles stack unwinding internally?

Idk exactly why but using SDL_free() instead of free() to clear string array returned by backtrace_symbols() fixes this problem. backtrace_symbols_fd() use free() internally so that’s probably why it leaks.

I thought SDL_free() is just an alias to free() but turns out I need to dig deeper into SDL3 source.

SDL_free and other memory functions operate within the SDL memory manager:

A memory block obtained or allocated using SDL memory functions must be freed using them. Otherwise you will either get a segmentation fault or memory leaks.

1 Like

A memory block obtained or allocated using SDL memory functions must be freed using them. Otherwise you will either get a segmentation fault or memory leaks.

But how is the strings pointer returned by backtrace_symbols() bound to SDL memory?

My solution is to have an alternative build that doesn’t use sdl. I have plenty of data structures, parsing code and algorithms that I can test the majority of my code without SDL being involved. I have coverage testing (with and without sdl), alternative builds, asan, etc. This solution might not work in games but it sure does work for my use case

I got curious so I tried the code below. It prints malloc 4 times. I’m surprised it didn’t crash. I thought I would have to use static memory or mmap

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void print_trace() {
	void *array;
	char **strings;
	int size, i;

	size = backtrace(array, 10);
	strings = backtrace_symbols(array, size);
	free(strings);
}

void dummy_function() {
	print_trace();
}

int main() {
	dummy_function();
}

void *malloc(size_t size) { write(2, "Custom malloc\n", 14); return 0; }

Should not the buffer array specify the array size as well? I tried something like this in my code:

// ...
#include <execinfo.h>
#include <malloc.h>

#define BACKTRACE_LIMIT 50

static void
print_trace(void)
{
  char **strings;
  void *buffer[BACKTRACE_LIMIT];
  size_t nptrs = backtrace(buffer, BACKTRACE_LIMIT);

  strings = backtrace_symbols(buffer, nptrs);
  if (strings == NULL) {
    _elog(false, __FILE__, __LINE__, ERROR_MEMORY_ALLOCATION);
    return;
  }
  free(strings);
}

or call to backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO), which just accepts file handler and handles buffer memory internally.

I didn’t actually write or look at the the backtrace code :rofl: I just wanted to see if the file or glibc malloc was used. I hope that code explains your question on how SDL is overloading malloc. At least that’s how I would assume it does if it does overload malloc