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

dll not found, native transitive dependency #4343

Closed
coonsd opened this issue Mar 14, 2023 · 6 comments
Closed

dll not found, native transitive dependency #4343

coonsd opened this issue Mar 14, 2023 · 6 comments
Assignees
Labels
by-design needs-triage This item should be discussed in the next triage meeting.

Comments

@coonsd
Copy link

coonsd commented Mar 14, 2023

Description

Our unit test project is targeting net47, using xunit and xunit.runner.visualstudio. The test has a transitive dependency that is native (Yubico.NativeShims), but the dll isn't being copied to the test directory resulting in a failed test with the message:

System.DllNotFoundException : Unable to load DLL 'Yubico.NativeShims.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

However, if you look at the build directory (bin\Debug\net47) you'll see that Yubico.NativeShims.dll is present. I’m opening this issue in vstest as it appears the vstest project is responsible for creating and staging the temporary test directory.

Our team owns Yubico.NativeShims, and we are using the buildtransitive NuGet directive to specify a targets file that copies over the native dependency for native users (see the Yubico.NativeShims project for more information).

Steps to reproduce

I created this project to demonstrate the issue. First build the solution (config: debug, any CPU). Next, run the one unit test in the project, ComputeSharedSecretTests.ComputeSecret_Matches().

Expected behavior

The test passes.

Actual behavior

The test fails, and in the test results you'll see the following message:

System.DllNotFoundException : Unable to load DLL 'Yubico.NativeShims.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

Diagnostic logs

Microsoft (R) Test Execution Command Line Tool Version 17.4.1-release-20221129-02 (x64)
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...
Logging Vstest Diagnostics in file: C:\...\demo-net47-transitive-dependency\UnitTests\bin\Debug\net47\log.txt
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.4.5+1caef2f33e (64-bit Desktop .NET 4.0.30319.42000)
[xUnit.net 00:00:04.55]   Discovering: UnitTests
[xUnit.net 00:00:04.76]   Discovered:  UnitTests
[xUnit.net 00:00:04.76]   Starting:    UnitTests
[xUnit.net 00:00:05.16]     UnitTests.ComputeSharedSecretTests.ComputeSecret_Matches [FAIL]
[xUnit.net 00:00:05.16]       System.DllNotFoundException : Unable to load DLL 'Yubico.NativeShims.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
[xUnit.net 00:00:05.16]       Stack Trace:
[xUnit.net 00:00:05.16]            at Yubico.PlatformInterop.NativeMethods.BnBinaryToBigNum(Byte[] buffer, Int32 length, IntPtr ret)
[xUnit.net 00:00:05.16]            at Yubico.PlatformInterop.NativeMethods.BnBinaryToBigNum(Byte[] buffer)
[xUnit.net 00:00:05.16]            at Yubico.Core.Cryptography.EcdhPrimitivesOpenSsl.GenerateKeyPair(ECCurve curve)
[xUnit.net 00:00:05.16]         C:\...\demo-net47-transitive-dependency\UnitTests\ComputeSharedSecretTests.cs(31,0): at UnitTests.ComputeSharedSecretTests.ComputeSecret_Matches()
[xUnit.net 00:00:05.17]   Finished:    UnitTests
  Failed UnitTests.ComputeSharedSecretTests.ComputeSecret_Matches [234 ms]
  Error Message:
   System.DllNotFoundException : Unable to load DLL 'Yubico.NativeShims.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
  Stack Trace:
     at Yubico.PlatformInterop.NativeMethods.BnBinaryToBigNum(Byte[] buffer, Int32 length, IntPtr ret)
   at Yubico.PlatformInterop.NativeMethods.BnBinaryToBigNum(Byte[] buffer)
   at Yubico.Core.Cryptography.EcdhPrimitivesOpenSsl.GenerateKeyPair(ECCurve curve)
   at UnitTests.ComputeSharedSecretTests.ComputeSecret_Matches() in C:\...\demo-net47-transitive-dependency\UnitTests\ComputeSharedSecretTests.cs:line 31

Test Run Failed.
Total tests: 1
     Failed: 1
 Total time: 5.3646 Seconds

Environment

Windows 11, OS Build: 22621.1265
Test Execution Command Line Tool Version 17.4.1-release-20221129-02 (x64)

@microsoft-github-policy-service microsoft-github-policy-service bot added the needs-triage This item should be discussed in the next triage meeting. label Mar 14, 2023
@NiuBClass666
Copy link

NiuBClass666 commented Mar 17, 2023

I got the similar issue on a net48 c# project. The dll could be found 1 day ago and nothing changed. Then suddenly, it can't find the dll in bin/debug folder but using dir or diagnostic option can confirm that the needed dll is in that folder. In the VsBuild task, it also logs that that dll was copied to the right folder.

NUnit Adapter 4.3.1.0 is used in my case. Microsoft (R) Test Execution Command Line Tool Version 17.5.0.

My solution: For my case, It turns out that it was caused by the latest update of Windows Server 2022 (20230314) image running on Azure agent which no longer has Microsoft Visual C++ 2010 Redistributable package pre-installed. So preinstalling that fixed my issue.

@ryansusername00
Copy link

ryansusername00 commented Mar 21, 2023

Same issue happened to my team last week. CI failed during testing with no related changes, and consistently failed from then on out.

@johanrex
Copy link

@coonsd I'm having the same issue. Is there a workaround?

@coonsd
Copy link
Author

coonsd commented Apr 3, 2023

@coonsd I'm having the same issue. Is there a workaround?

@johanrex Not that I know of, unfortunately. Hoping to get some feedback from the vstest team.

@nohwnd
Copy link
Member

nohwnd commented Jul 11, 2024

This is because the code specifies

[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]

[DllImport("Yubico.NativeShims.dll", CharSet = CharSet.Ansi, EntryPoint = "Native_CMAC_EVP_MAC_CTX_new", ExactSpelling = true)]

Safe directories are system32 and the app directory, but the app itself is testhost.exe which resides in Visual Studio folder and the native dll is not next to it.

This is architectural problem and can be solved only by building the test project itself as an exe, which is out of scope for vstest, but we do that in our new testing platform https://aka.ms/testingplatform (which so far does not support xunit), and xunit does that in xunit3. Our new testing platform allows running under VS (under preview flad) while xunit does not have that support yet.

image

The project modified to run with MSTest SDK:

// file ComputeSharedSecretTests.cs
// Copyright 2022 Yubico AB
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Security.Cryptography;
using Yubico.Core.Cryptography;

namespace UnitTests
{
    [TestClass]
    public class ComputeSharedSecretTests
    {
        [TestMethod]
        public void ComputeSecret_Matches()
        {
            IEcdhPrimitives ecdhObject = EcdhPrimitives.Create();

            ECCurve ecCurve = ECCurve.NamedCurves.nistP256;

            ECParameters keyPairA = ecdhObject.GenerateKeyPair(ecCurve);
            ECParameters keyPairB = ecdhObject.GenerateKeyPair(ecCurve);

            byte[] secretA = ecdhObject.ComputeSharedSecret(keyPairB, keyPairA.D);
            byte[] secretB = ecdhObject.ComputeSharedSecret(keyPairA, keyPairB.D);

            bool isValid = MemoryExtensions.SequenceEqual(secretA.AsSpan(), secretB.AsSpan());

            Assert.IsTrue(isValid);
        }
    }
}
<!-- file UnitTests.csproj -->
<Project Sdk="MSTest.Sdk/3.3.1">

  <PropertyGroup>
    <TargetFramework>net47</TargetFramework>
    <LangVersion>Latest</LangVersion>
    <Nullable>enable</Nullable>
    <Prefer32Bit>true</Prefer32Bit>

  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
    <PackageReference Include="Yubico.YubiKey" Version="1.11.0" />
  </ItemGroup>


  <ItemGroup>
    <Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
  </ItemGroup>

</Project>

Notice the Prefer32Bit (@MarcoRossignoli) I had to force the exe to be 32 bit because the targets that the nuget uses don't recognize our build as 64-bit and copies the x86 dll failing with "Image loaded in incorrect format" error.

The yubicon.nativeshims.targets from 1.10.0 package:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <!--
        .NET Framework versions don't seem to include the native runtime files that
        are needed for this package. This makes sure they are included in downlevel projects.
        Since .NET Framework is Windows only, we only need to worry about that platform.
    -->

    <!-- x86 -->
    <ItemGroup Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'X86' OR '$(Platform)' == 'x86'">
        <Content Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-x86\native\Yubico.NativeShims.dll">
            <Link>Yubico.NativeShims.dll</Link>
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
            <Visible>false</Visible>
        </Content>
    </ItemGroup>

    <!-- x64 -->
    <ItemGroup Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'X64' OR '$(Platform)' == 'x64'">
        <Content Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-x64\native\Yubico.NativeShims.dll">
            <Link>Yubico.NativeShims.dll</Link>
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
            <Visible>false</Visible>
        </Content>
    </ItemGroup>

    <!-- Arm64 -->
    <ItemGroup Condition="'$(Platform)' == 'arm64'">
        <Content Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-arm64\native\Yubico.NativeShims.dll">
            <Link>Yubico.NativeShims.dll</Link>
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
            <Visible>false</Visible>
        </Content>
    </ItemGroup>
</Project>

It work correctly in normal build. So I am not sure if this is problem with our target (e.g. the platform is anycpu), or if it is problem with their target (not considering anyCPU that is usual value for platform to have, just guessing here)

@nohwnd nohwnd closed this as completed Jul 11, 2024
@bplatypus
Copy link

The 'OSArchitecture' combined with an 'OR' in the 'yubicon.nativeshims.targets' seems wrong to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
by-design needs-triage This item should be discussed in the next triage meeting.
Projects
None yet
Development

No branches or pull requests

6 participants