raddebugger icon indicating copy to clipboard operation
raddebugger copied to clipboard

Scoped variable at the end of for loop is inspectable, but shown as unrelated type

Open IntendedConsequence opened this issue 1 year ago • 2 comments

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.

image

IntendedConsequence avatar Jan 23 '24 19:01 IntendedConsequence

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...

ryanfleury avatar Mar 29 '24 18:03 ryanfleury

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 result in asan here in compiler-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 InterestingDLLs in the watch too, it seems to work with static local_persist symbols inside functions

the type __interception::dll_info in my watch window doesn't match the one in the asan source I linked though, it's void * there, I think it's because the asan that comes with msvc 2022 is a bit different. if I expand one element of the dll_info type, it shows me 3 members:

struct dll_info
{
   void *data;
   S8 guaranteed_hotpatchable;
   char8 const *dll_name;
};

and guaranteed_hotpatchable is a pretty searchable name, but it's nowhere in llvm-project source, and even all of github if its global search to be trusted image

IntendedConsequence avatar Mar 30 '24 09:03 IntendedConsequence