0

All these APIs (DbgHelp, DbgEng, DIA SDK) can be used to recover function name/source file location from function pointers, so are usable to decrypt stack traces.

However, every DbgHelp function has the following remark:

All DbgHelp functions, such as this one, are single threaded. Therefore, calls from more than one thread to this function will likely result in unexpected behavior or memory corruption. To avoid this, you must synchronize all concurrent calls from more than one thread to this function.

As for DbgEng, there aren't such claims, however it seems that it is based on DbgHelp, so cannot be thread-safe: even if DbgEng guards every call to DbgHelp, there may be calls to DbgHelp not from DbgEng, but directly from the user's code.

I'm afraid if DIA SDK is also implemented using DbgHelp.

So is there any robust symbols API that can be used in a library designed for a multithreaded application?

Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79
  • DIA SDK use another dll (*msdia80.dll*) and not depend from dbghelp or dbgeng. however i not think that it interfaceses design for call in pararell from multiple threads. anyway - take for instance *IDiaEnumSymbols* - exist at all sense call this from multiple threads (on the same object which implement this interface)? of course no. and this for most interfaces. state inside object which implement interface. depend from how use but im most case - must not be problems – RbMm Feb 07 '22 at 15:39
  • all this interfaceses is "read only" by design. it not modify pdb, pe, target process memory, etc. it only collect info. and for most interfaceses no sense use the same object from several threads. for Enum type interfaceses exist Clone method – RbMm Feb 07 '22 at 15:46
  • Parallel usage could make sense: example could be post-analysis in a profiler or utility like umdh that could split work and use more CPU cores. But for now I don't mind if the calls are serialized, I want parallel usage only to be correct. Say if I create my own `std::stacktrace` I cannot control if users try to print it simultaneously from multiple threads. Or if they use `std::stacktrace` in one thread and some of these APIs in another. – Alex Guteniev Feb 07 '22 at 15:53
  • i mean that use any *IDiaEnum..* on the **same object** never have sense, but possible *Clone* object and pass cloned enum. for your task you primary need calls like *IDiaSession::findSymbolByVAEx*. once create *IDiaSession* for exe/dll ( this in any way require your own synchronization) and then use this `IDiaSession` from multiple threads for get closest symbol for address. i not look DIA implementation of this (i already many years use my own) but can assume that it thread safe (how minimum my own is safe) – RbMm Feb 07 '22 at 16:02
  • Personally, I find it questionable to even want a "classical" stack trace on Windows. A call to `MiniDumpWriteDump` can easily provide far better diagnostics, including the call stack. The latter also doesn't require that you ship debug symbols. Irrespective of the library you use, availability of the program database is required at the client. I'm not entirely convinced that users of a library are fine with the idea of inflating their deployment ten-fold. – IInspectable Feb 07 '22 at 17:56
  • @IInspectable, my preference is about the same. But some still want `std::stacktrace`, otherwise it wouldn't have been standardized. I believe it is useful because: (1) sometimes it is only about local unit tests, not deployment. (2) it is viable without .pdb, can rely on exports, or, in worst case, print module name and offset relative to that. – Alex Guteniev Feb 07 '22 at 18:05
  • 2
    I will question the viability of implementing `std::stacktrace` in a useful fashion without access to .pdb's. Given that Microsoft's linker treats all symbols as private by default, you won't find a whole lot of exported symbols. So now you're back at the same problem you set out to solve: decyphering a stack trace. And that's not even the worst case. The worst case is code that isn't backed by a module at all. That's not entirely [rare](https://learn.microsoft.com/en-us/windows/win32/api/atlthunk/), either. – IInspectable Feb 07 '22 at 18:44
  • @IInspectable, currently with x64 Windows 10 and the latest updates installed, I observe that ATL thunks doesn't generate code in memory. They instead contain some amount of thunks in `atlthunk.dll`, and if I call `AtlThunk_AllocateData` too many times, multiple copies of `atlthunk.dll` are loaded. So the call stack entry is at least `atlthunk+0x1028` and at most `atlthunk.dll!AtlThunk_0x03+0x18` – Alex Guteniev Feb 08 '22 at 19:25

1 Answers1

0

DIA SDK is assumed to be a thread safe solution.

There's an issue in Boost.Stacktrace repo that asks for switching to DIA SDK. Unsafety of DbgHelp and DbgEng is mentioned there.

Also there's an option to roll own implementation; a possible starting point is here: https://github.com/microsoft/microsoft-pdb

Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79