Incremental add for late-loaded DLLs via GetModuleHandleExW — avoids full snapshot reinit. Concurrency: writers serialize through getCacheMutex(); readers in findModule() load g_modules[] without locking. The memmove below shifts existing entries in place, so a concurrent reader's binary search may briefly observe torn base/end/pdataLast values from an in-flight shift. Possible outcomes: 1. Mis-c
| 198 | // LoadLibrary. Net effect at the diagnostic level is rare truncated frames, |
| 199 | // no crashes, which matches the trade-off in the upstream Gaijin source. |
| 200 | static bool tryAddModuleForPC(ULONG64 pc) noexcept { |
| 201 | if (isNegCached(pc)) return false; |
| 202 | HMODULE hMod = nullptr; |
| 203 | if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, |
| 204 | (LPCWSTR)(uintptr_t)pc, &hMod) || !hMod) { |
| 205 | addNegCache(pc); |
| 206 | return false; |
| 207 | } |
| 208 | CachedModule newMod{}; |
| 209 | if (!parseModuleHeader(pc, (const BYTE*)hMod, newMod)) return false; |
| 210 | |
| 211 | std::lock_guard<std::mutex> lock(getCacheMutex()); |
| 212 | int count = g_moduleCount.load(std::memory_order_relaxed); |
| 213 | if (count >= MAX_CACHED_MODULES) return false; |
| 214 | // sorted insert |
| 215 | int lo = 0, hi = count - 1, insertPos = count; |
| 216 | while (lo <= hi) { |
| 217 | int mid = (lo + hi) >> 1; |
| 218 | if (newMod.base < g_modules[mid].base) { insertPos = mid; hi = mid - 1; } |
| 219 | else if (newMod.base > g_modules[mid].base) { lo = mid + 1; } |
| 220 | else { return true; } // already added by other thread |
| 221 | } |
| 222 | memmove(&g_modules[insertPos + 1], &g_modules[insertPos], |
| 223 | (count - insertPos) * sizeof(CachedModule)); |
| 224 | g_modules[insertPos] = newMod; |
| 225 | g_moduleCount.store(count + 1, std::memory_order_release); |
| 226 | return true; |
| 227 | } |
| 228 | |
| 229 | static __declspec(noinline) PRUNTIME_FUNCTION tryAddAndLookup(ULONG64 pc, const CachedModule *&lastMod, |
| 230 | ULONG64 &imageBase, int &pdataHint) noexcept { |
no test coverage detected