Debug run-time DLL issue

Issue found

Debug run-time dlls for arm64 are not installed properly by Windows 10 SDK.

C:\Windows\System32 path can’t be used for arm64 debug dll loading, even if dlls manual copied from Windows 10 SDK package directories.

Steps to reproduce

My system

Edition Windows 10 Enterprise Experience Windows Feature Experience Pack 120.2212.3920.0

Install

Issue found

  • Visual Studio Community 2019 (Version 16.10.4)

  • Visual Studio Installer → Modify → Individual Components

    • C++ Universal Windows Platform support for v142 build tools (ARM64)

    • Windows 10 SDK (10.0.19041.0)

Re-tested and still reproduced with (at the time latest)

  • Visual Studio Community 2019 (Version 16.11.9)

  • Visual Studio Installer → Modify → Individual Components

    • C++ Universal Windows Platform support for v142 build tools (ARM64)

    • Windows 10 SDK (10.0.20348.0)

Sample project

hello_world.c

#include <stdio.h> int main (void) { printf("Hello World"); }

Alternatively a new Visual Studio C/C++ project can be created.

Steps

  1. Invoke vcvars for arm64

  2. Build sample project with debug dll run-time libraries: “/MDd”
    /MD, -MT, -LD (Use Run-Time Library)

  3. Try to run it, check it again in GUI to see error window.

/MDd Defines _DEBUG, _MT, and _DLL and causes the application to use the debug multithread-specific and DLL-specific version of the run-time library. It also causes the compiler to place the library name MSVCRTD.lib into the .obj file.


Commands in powershell

cmd /k '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsx86_arm64.bat" & powershell' cd <project_dir> cl /MDd .\hello_world.c .\hello_world.exe


In Visual Studio the same flag can be set by (/MD, -MT, -LD (Use Run-Time Library))

  1. Open the project's Property Pages dialog box. For details, see Set C++ compiler and build properties in Visual Studio.

  2. Select the Configuration Properties > C/C++ > Code Generation property page.

  3. Modify the Runtime Library property.

Expected behavior

  • Windows 10 SDK installs debug dlls into C:\Windows\System32 directory.

  • This directory is included in the PATH by default.

  • The hello_world sample application should be able to load the required and installed debug dlls, so it should print the hello world message, then exit successfully.

  • Just like as if it was built with non-debug dll loading requirements:

Actual behavior

  • The hello_world sample application fails to start as it can’t find the required debug dlls.

     

     

Sanity check

  • Are the debug dlls installed into System32? Yes

     

  • Is this directory included on the PATH? Yes

Investigation

Check dll header with dumpbin: ucrtbase*.dll

Release

Debug

Copy the debug dll into another directory:

Dumpbin the copy of the debug dll

Issues found here

  1. The debug dll installed into System32 directory is for x86, while the release version is for ARM64.

  2. In System32 directory the debug dll can’t be opened, but the same file is available on a different path!

Check debug dlls on other installed paths

ucrtbased.dll is packed by Windows 10 SDK to

Issues verified here

  1. x86/ucrtbased.dll is the same file (based on file sizes) as the installed at C:\Windows\System32.

  2. Copying the arm64/ucrtbased.dll to C:\Windows\System32 doesn’t fix the original problem as even dumpbin still can’t open that file on that path.

    1. Again, on another path dumbpin can reach it and the header is for ARM64 as expected.

Workaround

Add any missing debug dll’s Windows SDK package directory to the path.

Example:

1. ucrtbased.dll

Path:

Command in cmd:

Command in PS:

2. vcruntime140.dll

Path:

Command in cmd:

Command in PS:

Tools

You can find missing dll using an msys prompt:

To see dependencies of a given executable, you can use:

LDD

ldd (from cygwin/msys). It does not take into account arm64 arch, so it will only report first dll on your path. By using file, you can verify every dependency.

Dependencies

https://www.dependencywalker.com/ used to be a good solution to see DLL deps using a GUI. It is now outdated, and does not handle ARM64 arch.

A replacement, Dependencies, is now written to modernize it. It works with ARM64 arch: GitHub - lucasg/Dependencies