Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't find MSVC*80.DLL in SxS #3

Open
stavnskov opened this issue Nov 20, 2017 · 10 comments
Open

Can't find MSVC*80.DLL in SxS #3

stavnskov opened this issue Nov 20, 2017 · 10 comments

Comments

@stavnskov
Copy link

I have an assembly depending on MSVCRT 8.0 from Visual Studio 2005 ! This tool (v 1.5) cannot find it although it is located in C:\Windows\WinSxS\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.9185_none_d0905a48442809b8

@lucasg
Copy link
Owner

lucasg commented Nov 20, 2017

Yeah the SxS resolver is far from complete. I've sticked to what is somewhat documented, but it does not account for every load path possible.

If it's not too sensitive, can you ran the following commands on your binary ? It might help me troubleshoot the issue :

.\ClrPhTester.exe -manifest "C:\Windows\SysWow64\PresentationNative_v0300.dll"
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="PresentationNative_v0300" type="win32"></assemblyIdentity>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50727.1830" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
</assembly>
PS F:\Dev\Dependencies\Releases\Dependencies-v1.5> .\ClrPhTester.exe -sxsentries "C:\Windows\SysWow64\PresentationNative_v0300.dll"
  [+] msvcr80.dll : C:\WINDOWS\WinSxs\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.4027_none_d08a21a2442db2dc\msvcr80.dll
  [+] msvcp80.dll : C:\WINDOWS\WinSxs\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.4027_none_d08a21a2442db2dc\msvcp80.dll
  [+] msvcm80.dll : C:\WINDOWS\WinSxs\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.4027_none_d08a21a2442db2dc\msvcm80.dll

(ClrPhTester.exe is bundled with Dependencies, and it is able to correctly resolve some msvc*80.dll located in the sxs cache)

@learn-more
Copy link
Contributor

sxstrace might be of interest to you:
Run it like this:
sxstrace.exe Trace -logfile:r:\sxs\Trace.log
Then run an offending application
Stop the trace,
and convert the trace to txt:
sxstrace.exe Parse -logfile:r:\sxs\Trace.log -outfile:r:\sxs\Out.txt

@lucasg
Copy link
Owner

lucasg commented Dec 29, 2018

Thanks, but the issue lies in the fact that I have no test case to reproduce the bug ...

@schlamar
Copy link

schlamar commented Apr 10, 2019

You could just install Python 2.7 and cffi (via pip install cffi) and look at C:\Python27\Lib\site-packages\_cffi_backend.pyd and it will report MSVCR90.dll missing (other Python 2.7 extensions are affected, too).

@learn-more
Copy link
Contributor

You could just install Python 2.7 and cffi (via pip install cffi) and look at C:\Python27\Lib\site-packages\_cffi_backend.pyd and it will report MSVCR90.dll missing (other Python 2.7 extensions are affected, too).

This is not the same.
Python 2.7 ships with it's own Microsoft.VC90.CRT.manifest and msvcr90.dll file.
If you configure the binary cwd or add an additional search folder on c:\python27\ it correctly finds the local dll there.

@schlamar
Copy link

schlamar commented Apr 11, 2019

Python 2.7 ships with it's own Microsoft.VC90.CRT.manifest and msvcr90.dll file.

That's not true in my case. Python 2.7.15 installed the vcredist package (so msvcr90.dll ends in the winsxs folder). Maybe this depends on the ALLUSERS property.

grafik

Update There are two differenct CRT versions in the installer: https://github.com/python/cpython/blob/2.7/Tools/msi/msi.py#L858. The default "SharedCRT" vcredist package (bundled as msm module) is installed when the installer is run with a privileged user and ALLUSERS property is set.

@MarekKnapek
Copy link

Hi, your program will resolve wrong msvcr80.dll. Steps to reproduce:

  • I have Visual Studio 8 already installed (probably not needed).
  • I have VC8 redist already installed (probably multiple versions of it).
  • Now I will create new empty console application in Visual Studio 2015 that will link against VC8 CRT using application manifest (should also work with 2017 and 2019).
  • In Visual Studio press new project, C++, console application, empty.
  • Create new .cpp file and write simple program [1].
  • Create new .manifest file [2] and add it to project / manifest tool / input and output / additional manifest files.
  • Link against VC8 msvcrt.lib in project / linker / input / additional dependencies.
  • If you don't have Visual Studio 8, I can provide you with the .lib file.
  • Compile release 32bit .exe.
  • Inspect the .exe with Dependency Walker and with your Dependencies tool. Also run the program and observe what version of VC8 library actually gets loaded.

Now what happens.

  • On my machine I have multiple versions of VC8 CRT and multiple manifests in my sxs [3].
  • I also have multiple policy files [4]. Which I don't know any documentation about. But their content seems self-explanatory.
  • In my application manifest (don't confuse it by assembly manifest) I deliberately chosen the lowest possible version of VC8 CRT I could (8.0.41204.256) and the application still worked fine.
  • Dependencies displays C:\Windows\WinSxs\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.1833_none_d08b763a442c70c2\msvcr80.dll as static dependency to my .exe, which is incorrect. It is the alphabetically fist manifest that Dependencies finds by using regular expression. This is wrong.
  • Dependency Walker displays c:\windows\winsxs\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.6229_none_d089f796442de10e\MSVCR80.DLL, which is correct. It is the latest version I have on my system. I believe it uses CreateActCtx, ActivateActCtx and SearchPath functions to find it.
  • When I actually run the application, it will load the same .dll as Dependency Walker reports. You can test it by stopping it in debugger and inspecting all loaded dlls in some tool such as Process Explorer or Process Hacker.

Best regards,
Marek Knápek

[1]

extern "C" int puts(char const*);
int main()
{
	puts("test msvcr80.dll\n");
}

[2]

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
		<security>
			<requestedPrivileges>
				<requestedExecutionLevel level='asInvoker' uiAccess='false' />
			</requestedPrivileges>
		</security>
	</trustInfo>
	<dependency>
		<dependentAssembly>
			<assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.41204.256" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
		</dependentAssembly>
	</dependency>
</assembly>

[3]

x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.1833_none_d08b763a442c70c2.manifest
x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.4027_none_d08a21a2442db2dc.manifest
x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.4053_none_d08d7da0442a985d.manifest
x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.42_none_db5f52fb98cb24ad.manifest
x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.4940_none_d08cc06a442b34fc.manifest
x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.6195_none_d09154e044272b9a.manifest
x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.6229_none_d089f796442de10e.manifest
x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.762_none_10b2f55f9bffb8f8.manifest

[4]

x86_policy.8.0.microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.1833_none_516c26fb0f4a960b.manifest
x86_policy.8.0.microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.4027_none_516ad2630f4bd825.manifest
x86_policy.8.0.microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.4053_none_516e2e610f48bda6.manifest
x86_policy.8.0.microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.42_none_5c4003bc63e949f6.manifest
x86_policy.8.0.microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.4940_none_516d712b0f495a45.manifest
x86_policy.8.0.microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.6195_none_517205a10f4550e3.manifest
x86_policy.8.0.microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.6229_none_516aa8570f4c0657.manifest
x86_policy.8.0.microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.762_none_9193a620671dde41.manifest

ConsoleApplication14.zip

@lucasg
Copy link
Owner

lucasg commented Aug 22, 2019

@MarekKnapek : thank you for this unit test, this is really helpful.

From what I gather, I need to match the "version" more precisely :

  • If the "Build" and "Patch" version are set (like "8.0.41204.256" in your example), I need to match the exact version in WinSxS, or return an error if not found.
  • If the "Build" and "Patch" version are not set (like <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />) I need to return the "default" version on the system, which is the one with the highest Build and Patch number

But it is not sufficient in your case since vc8.crt manifest has an unknown bindingRedirect xml directive in its manifest :

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

    <assemblyIdentity type="win32-policy" name="policy.8.0.Microsoft.VC80.CRT" version="8.0.50727.9659" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
    <dependency>
        <dependentAssembly>
            <assemblyIdentity type="win32" name="Microsoft.VC80.CRT" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
            <bindingRedirect oldVersion="8.0.41204.256-8.0.50608.0" newVersion="8.0.50727.9659"/>
             <bindingRedirect oldVersion="8.0.50727.42-8.0.50727.9659" newVersion="8.0.50727.9659"/>
        </dependentAssembly>
    </dependency>

</assembly>

(Oh man SxS is such an headache ...)

NB : you're right about Dependency Walker rely on undocumented APIs and the ActivationContext to return the correct path.

@lucasg
Copy link
Owner

lucasg commented Aug 22, 2019

commit 9a4598a partially fix this issue

@MarekKnapek
Copy link

MarekKnapek commented Aug 22, 2019

Hi @lucasg, yes SxS is crazy.

I believe you need to match only first two most significant version numbers (such as 8.0.x.x for my example of 8.0.41204.256) and for the rest two use the largest numbers available. But it didn't work for me with Microsoft.VC80.CRT. But it worked fine with Microsoft.Windows.Common-Controls with version 6.0.0.0 locating 6.0.7601.24483. I don't know why and I'm sad (or desperate) about it. Beware, for the common controls case, the assembly version is 6.0.7601.24483, but the DLL has version 6.10.7601.24483.

But in case you match all four version digits exactly, it should take precedence (maybe?).

I don't understand your comment about unknown bindingRedirect. Could you explain it more?

I also don't understand your comment about CreateActCtx function being undocumented. All three functions I mentioned (CreateActCtx, ActivateActCtx and SearchPath) are indeed documented.

There is another issue with "default" manifests, such as GDIPlus.dll. It is not located in system32 but is referenced by "default" manifest. Your application can not find it, Dependency Walker can. But this is story for another issue I will create later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants