Code Monkey home page Code Monkey logo

Comments (6)

natemcmaster avatar natemcmaster commented on July 30, 2024 1

even should be reported as a flaw in AssemblyLoadContext.LoadUnmanagedDllFromPath.

Yes, can you please open this on https://github.com/dotnet/coreclr, if it doesn't exist already?

In the meantime, I'm happy to take a workaround for this that normalizes slashes before calling LoadUnmanagedDllFromPath.

from dotnetcoreplugins.

natemcmaster avatar natemcmaster commented on July 30, 2024 1

@per-samuelsson thanks for sharing details on your investigation. I'd be happy to add a workaround to this library which normalizes the file path before calling LoadUnmanagedDllFromPath. Feel free to send a PR and I can get an update to nuget.org this week.

from dotnetcoreplugins.

per-samuelsson avatar per-samuelsson commented on July 30, 2024

even should be reported as a flaw in AssemblyLoadContext.LoadUnmanagedDllFromPath.

Yes, can you please open this on https://github.com/dotnet/coreclr, if it doesn't exist already?

https://github.com/dotnet/coreclr/issues/22094

from dotnetcoreplugins.

per-samuelsson avatar per-samuelsson commented on July 30, 2024

FYI: when investigating a possible workaround, I found this is more narrow than it first appeared to be.

For example, I debugged the unit test LoadsNativeDependenciesWhenDllImportUsesFilename() and that actually resolve sni.dll to full path C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder\\runtime.win-x64.runtime.native.system.data.sqlclient.sni\\4.4.0\\runtimes/win-x64/native/sni.dll on my machine (notice the forward slashes), and that succeed when passed on to AssemblyLoadeContext.LoadUnmanagedDllFromPath(path).

But then when I try with the library I reported about, it resolves to C:\\Users\\Per\\.nuget\\packages\\starcounter.queryprocessor\\2.0.10\\runtimes/win-x64/native/libswipl.dll, and that fails. However, if I normalize that path using Path.GetFullPath(path) before I pass it on to AssemblyLoadeContext.LoadUnmanagedDllFromPath(path), loading succeed.

I guess the takeaway right now is that a workaround doing Path.GetFullPath(path) just before calling AssemblyLoadeContext.LoadUnmanagedDllFromPath(path) would pass all cases I've got. The problem is it's not trivial to set up any decent regression test for it.

from dotnetcoreplugins.

per-samuelsson avatar per-samuelsson commented on July 30, 2024

The problem is it's not trivial to set up any decent regression test for it.

OK, now I crafted me a decent repro to illustrate, and where it's easy to tweak to apply the workaround:

  1. Clone https://github.com/per-samuelsson/ALCHostingTests
  2. Under Test2, there's two projects:
    • App: a console app invoking a native function in a package.
    • Loader: a console app loading "App" and calling the code that invokes the function (effectively forcing plugin library to resolve native asset).
  3. First cd Test2\App and dotnet run. You'll see standard host resolve properly.
  4. Now cd Test2\Loader and dotnet run. You'll see plugin library fail to resolve.

If you want to apply the workaround and see plugin library succeed, just change reference in Test2\Loader\Loader.csproj to point to sources of DotNetCorePlugins (just adjust location of relative project path).

Then I tweaked ManagedLoadContext.cs like below. Doing that, point [4] from above goes from red to green.

// All calls doing native loading now goes via `LoadUnmanagedDllFromResolvedPath` that
// does the normalization
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
    foreach (var prefix in PlatformInformation.NativeLibraryPrefixes)
    {
        if (_nativeLibraries.TryGetValue(prefix + unmanagedDllName, out var library))
        {
            if (SearchForLibrary(library, prefix, out var path))
            {
                return LoadUnmanagedDllFromResolvedPath(path);
            }
        }
        else
        {
            // coreclr allows code to use [DllImport("sni")] or [DllImport("sni.dll")]
            // This library treats the file name without the extension as the lookup name,
            // so this loop is necessary to check if the unmanaged name matches a library
            // when the file extension has been trimmed.
            foreach (var suffix in PlatformInformation.NativeLibraryExtensions)
            {
                if (!unmanagedDllName.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                // check to see if there is a library entry for the library without the file extension
                var trimmedName = unmanagedDllName.Substring(0, unmanagedDllName.Length - suffix.Length);

                if (_nativeLibraries.TryGetValue(prefix + trimmedName, out library))
                {
                    if (SearchForLibrary(library, prefix, out var path))
                    {
                        return LoadUnmanagedDllFromResolvedPath(path);
                    }
                }
                else
                {
                    // fallback to native assets which match the file name in the plugin base directory
                    var localFile = Path.Combine(_basePath, prefix + unmanagedDllName + suffix);
                    if (File.Exists(localFile))
                    {
                        return LoadUnmanagedDllFromResolvedPath(localFile);
                    }

                    var localFileWithoutSuffix = Path.Combine(_basePath, prefix + unmanagedDllName);
                    if (File.Exists(localFileWithoutSuffix))
                    {
                        return LoadUnmanagedDllFromResolvedPath(localFileWithoutSuffix);
                    }
                }
            }

        }
    }

    return base.LoadUnmanagedDll(unmanagedDllName);
}

private IntPtr LoadUnmanagedDllFromResolvedPath(string unmanagedDllPath)
{
    var normalized = Path.GetFullPath(unmanagedDllPath);
    return LoadUnmanagedDllFromPath(normalized);
}

from dotnetcoreplugins.

per-samuelsson avatar per-samuelsson commented on July 30, 2024

Feel free to send a PR and I can get an update to nuget.org this week.

#28

from dotnetcoreplugins.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.