raddebugger
raddebugger copied to clipboard
Scoped variable at the end of for loop is inspectable, but shown as unrelated type
With the execution line marker at the closing brace of a for loop, I hovered over a variable declared inside the loop, and the debugger showed me a completely unrelated type InitValidIdentChar::__l2::<unnamed-type-result>. I'm on latest master ebac4ce, debug build. The locals widget doesn't list result, but watch and hovering over it show the foreign type. The target is built with optimizations disabled /Od.
The wrong type seems to persist for all iterations of the loop, restarts of the target, new launches of the debugger, and even a clean rebuild of the target (with .pdb deleted beforehand).
The other scoped variable desc doesn't react to hovering and doesn't show anything. Typing its name into watch window explicitly says "unknown identifier".
The InitValidIdentChar seems to be a type from the CRT. It is present in all .pdb files I searched, as well as in libvcruntime*.lib files.
I've confirmed that this is not actually a RADDBG bug, and is instead referring to a global introduced by somebody in the toolchain... I don't know who would decide to export a global variable called result, but I'll investigate a bit further...
Looks like I forgot to update the issue with my follow up messages from discord, sry about that. Keep in mind that everything below is a copy paste from around January 25th, I didn't have the opportunity yet to rerun and re-reproduce my findings on the latest debugger version! Attaching as is for now.
I found the
resultin asan here incompiler-rt/lib/interception/interception_win.cpp: https://github.com/llvm/llvm-project/blob/a01195ff5cc3d7fd084743b1f47007645bb385f4/compiler-rt/lib/interception/interception_win.cpp#L968
static void **InterestingDLLsAvailable() {
static const char *InterestingDLLs[] = {
"kernel32.dll",
"msvcr100d.dll", // VS2010
"msvcr110d.dll", // VS2012
"msvcr120d.dll", // VS2013
"vcruntime140d.dll", // VS2015
"ucrtbased.dll", // Universal CRT
"msvcr100.dll", // VS2010
"msvcr110.dll", // VS2012
"msvcr120.dll", // VS2013
"vcruntime140.dll", // VS2015
"ucrtbase.dll", // Universal CRT
# if (defined(__MINGW32__) && defined(__i386__))
"libc++.dll", // libc++
"libunwind.dll", // libunwind
# endif
// NTDLL should go last as it exports some functions that we should
// override in the CRT [presumably only used internally].
"ntdll.dll",
NULL
};
static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 };
if (!result[0]) {
for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) {
if (HMODULE h = GetModuleHandleA(InterestingDLLs[i]))
result[j++] = (void *)h;
}
}
return &result[0];
}
I can inspect the
InterestingDLLsin the watch too, it seems to work with static local_persist symbols inside functions
the type
__interception::dll_infoin my watch window doesn't match the one in the asan source I linked though, it'svoid *there, I think it's because the asan that comes with msvc 2022 is a bit different. if I expand one element of thedll_infotype, it shows me 3 members:
struct dll_info
{
void *data;
S8 guaranteed_hotpatchable;
char8 const *dll_name;
};
and
guaranteed_hotpatchableis a pretty searchable name, but it's nowhere in llvm-project source, and even all of github if its global search to be trusted