Skip to content

Conversation

SamWindell
Copy link

This fixes 2 issues I was having when using libbacktrace inside a Window DLL.

  • Instead of GetModuleHandle (NULL), pass in the filename so we get the correct base address regardless of if we're running in a EXE or DLL. Before this patch, all debug symbol lookups within a 'main' DLL were offset by the base address of the parent process - giving nonsense.
  • Only register for DLL added notifications if we are an EXE. We can't support this from inside a DLL without having a way to unregister the notification prior to our running DLL being unloaded. Before this fix we would get crashes related to calling registered functions that are no longer loaded.

SamWindell and others added 2 commits January 31, 2025 21:25
When libbacktrace is used directly in a DLL (for example backtrace_create_state is being called DllMain), we can't use GetModuleHandle(NULL) since that returns the module handle of the calling process (executable) and so all our lookups are incorrect. 

Instead, we can use the same function, but pass in the filepath that we already have. This fixes the DLL issue and still works for EXEs.
This fixes and issue when libbacktrace is used inside a DLL - where
libbacktrace is initialised in DllMain, for example.

If the module is a DLL itself, we shouldn't register for DLL
notifications - that is the job of the executing processing, not of one
of it's modules. Prior to this patch, there can be crashes when using
libbacktrace directly from DLL due to notifications being sent to
invalid addresses.

GetModuleHandle(NULL) returns the handle of the process - so we can use
that alongside our already existing module handle to determine if we are
running as a DLL or EXE.
@ianlancetaylor
Copy link
Owner

CC @HazardyKnusperkeks

@HazardyKnusperkeks
Copy link

This fixes 2 issues I was having when using libbacktrace inside a Window DLL.

* Instead of GetModuleHandle (NULL), pass in the filename so we get the correct base address regardless of if we're running in a EXE or DLL. Before this patch, all debug symbol lookups within a 'main' DLL were offset by the base address of the parent process - giving nonsense.

Although I directly linked libbacktrace while making these changes, my main usage is through a DLL and I get the correct names and line numbers for functions from the exe and the DLL. Do you have an example I can look at?

* Only register for DLL added notifications if we are an EXE. We can't support this from inside a DLL without having a way to unregister the notification prior to our running DLL being unloaded. Before this fix we would get crashes related to calling registered functions that are no longer loaded.

It's correct, that there could be crashes, but as stated the usage from a DLL is my main usage. I think we should look for a compromise.

And I don't use libbacktrace directly, but std::stack_trace from libstdc++.

@SamWindell
Copy link
Author

My use case is in an audio plugin, which is just a shared library binary. The host application is nothing to do with me and just calls into my functions. The host does have a standard API for calling me with init()/deinit() though, where I can set up some error reporting for my own code - this is where I initialise libbacktrace.

Is that the same use case you have @HazardyKnusperkeks? Just want to check if it's the same because you say you've always had correct file and line numbers.

@HazardyKnusperkeks
Copy link

No, I write the application and the libraries. Logging is a library, which then uses std::stacktrace on some occasions, and that is implemented using libbacktrace. In my use case the library is a dll, but directly linked (and thus will never be unloaded before the application ends). You will be loaded using LoadLibrary, right? I will set up a test to see what happens.

@SamWindell
Copy link
Author

Yes that's right, my audio plugin will be loaded with LoadLibrary. I am also using DWARF info rather than PDB, I'm not sure if that's relevant. My windows DLL is compiled with clang with the -gdwarf flag to embed the DWARF info.

@HazardyKnusperkeks
Copy link

Okay after some hours of testing, thinking, etc. I know what your main difference is. You set the filename in backtrace_create_state, neither my tests nor libstdc++ does that.

So yes the first commit is correct (with my little remark).

I'm fine with the second commit, since I never run in this scenario, because state->filename is null for me.
The "right thing" would be to clean up, which is (by intention) not in the libbacktrace API. I mean you still leak the memory.

Co-authored-by: Björn Schäpers <github@hazardy.de>
@SamWindell
Copy link
Author

Ok thank you very much for taking a look into this. You are right, I am passing in the filename since for now I am only interested in my own symbols, not the hosts.

So it seems like this change fixes my use-case but doesn't really touch any other use-case - they work the same.

Happy to have this merged whenever then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants