Skip to content

Commit f0230db

Browse files
authored
Remove always searching executable directory for native libraries in single-file applications (#115236)
Avoid always searching the application directory for native libraries in single-file applications. The assembly directory, which is searched by default and when `DllImportSearchPath.AssemblyDirectory` is specified, is treated as the application directory. - Single-file - Stop adding the app directory and extraction directory to `NATIVE_DLL_SEARCH_DIRECTORIES` (paths which are always searched) - When looking for native libraries, treat assembly directory for bundled assemblies as the bundle directory - If the bundle has extracted assets, also look in the extraction path (if not found in the bundle directory) - NativeAOT - Update p/invoke default to search assembly directory - Don't set RPATH by default - Remove `IlcRPath` property
1 parent fc85a87 commit f0230db

File tree

20 files changed

+127
-84
lines changed

20 files changed

+127
-84
lines changed

docs/design/features/host-runtime-information.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ List of directory paths corresponding to shared store paths and additional probi
8080

8181
### Single-file
8282

83+
`BUNDLE_EXTRACTION_PATH`
84+
85+
**Added in .NET 10** Path to extraction directory, if the single-file bundle extracted any files. This is used by the runtime to search for native libraries associated with bundled managed assemblies.
86+
8387
`BUNDLE_PROBE`
8488

8589
Hex string representation of a function pointer. It is set when running a single-file application. The function is called by the runtime to look for assemblies bundled into the application. The expected signature is defined as `BundleProbeFn` in [`coreclrhost.h`](/src/coreclr/hosts/inc/coreclrhost.h)

src/coreclr/binder/assemblybindercommon.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,10 @@ namespace BINDER_SPACE
858858
ProbeExtensionResult probeExtensionResult = AssemblyProbeExtension::Probe(assemblyFileName, /* pathIsBundleRelative */ true);
859859
if (probeExtensionResult.IsValid())
860860
{
861-
SString assemblyFilePath(Bundle::AppIsBundle() ? Bundle::AppBundle->BasePath() : SString::Empty());
861+
SString assemblyFilePath;
862+
if (Bundle::AppIsBundle())
863+
assemblyFilePath.SetUTF8(Bundle::AppBundle->BasePath());
864+
862865
assemblyFilePath.Append(assemblyFileName);
863866

864867
hr = GetAssembly(assemblyFilePath,

src/coreclr/inc/bundle.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,13 @@ class Bundle
4343
Bundle(LPCSTR bundlePath, BundleProbeFn *probe);
4444
BundleFileLocation Probe(const SString& path, bool pathIsBundleRelative = false) const;
4545

46-
const SString &Path() const { LIMITED_METHOD_CONTRACT; return m_path; }
47-
const SString &BasePath() const { LIMITED_METHOD_CONTRACT; return m_basePath; }
46+
// Paths do not change and should remain valid for the lifetime of the Bundle
47+
const SString& Path() const { LIMITED_METHOD_CONTRACT; return m_path; }
48+
const UTF8* BasePath() const { LIMITED_METHOD_CONTRACT; return m_basePath.GetUTF8(); }
49+
50+
// Extraction path does not change and should remain valid for the lifetime of the Bundle
51+
bool HasExtractedFiles() const { LIMITED_METHOD_CONTRACT; return !m_extractionPath.IsEmpty(); }
52+
const WCHAR* ExtractionPath() const { LIMITED_METHOD_CONTRACT; return m_extractionPath.GetUnicode(); }
4853

4954
static Bundle* AppBundle; // The BundleInfo for the current app, initialized by coreclr_initialize.
5055
static bool AppIsBundle() { LIMITED_METHOD_CONTRACT; return AppBundle != nullptr; }
@@ -53,6 +58,7 @@ class Bundle
5358
private:
5459
SString m_path; // The path to single-file executable
5560
BundleProbeFn *m_probe;
61+
SString m_extractionPath; // The path to the extraction location, if bundle extracted any files
5662

5763
SString m_basePath; // The prefix to denote a path within the bundle
5864
COUNT_T m_basePathLength;

src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,6 @@ The .NET Foundation licenses this file to you under the MIT license.
6464
<TargetTriple Condition="'$(CrossCompileArch)' != '' and '$(_IsAlpineExitCode)' == '0'">$(CrossCompileArch)-alpine-linux-$(CrossCompileAbi)</TargetTriple>
6565
<TargetTriple Condition="'$(CrossCompileArch)' != '' and ($(CrossCompileRid.StartsWith('freebsd')))">$(CrossCompileArch)-unknown-freebsd12</TargetTriple>
6666

67-
<IlcRPath Condition="'$(IlcRPath)' == '' and '$(_IsApplePlatform)' != 'true'">$ORIGIN</IlcRPath>
68-
<IlcRPath Condition="'$(IlcRPath)' == '' and '$(_IsApplePlatform)' == 'true'">@executable_path</IlcRPath>
69-
7067
<SharedLibraryInstallName Condition="'$(SharedLibraryInstallName)' == '' and '$(_IsApplePlatform)' == 'true' and '$(NativeLib)' == 'Shared'">@rpath/$(TargetName)$(NativeBinaryExt)</SharedLibraryInstallName>
7168

7269
<EventPipeName>libeventpipe-disabled</EventPipeName>
@@ -234,8 +231,6 @@ The .NET Foundation licenses this file to you under the MIT license.
234231
<LinkerArg Include="--target=$(TargetTriple)" Condition="'$(TargetTriple)' != ''" />
235232
<LinkerArg Include="-g" Condition="$(NativeDebugSymbols) == 'true'" />
236233
<LinkerArg Include="-Wl,--strip-debug" Condition="$(NativeDebugSymbols) != 'true' and '$(_IsApplePlatform)' != 'true'" />
237-
<LinkerArg Include="-Wl,-rpath,'$(IlcRPath)'" Condition="'$(StaticExecutable)' != 'true' and !$([MSBuild]::IsOSPlatform('Windows'))" />
238-
<LinkerArg Include="-Wl,-rpath,&quot;$(IlcRPath)&quot;" Condition="'$(StaticExecutable)' != 'true' and $([MSBuild]::IsOSPlatform('Windows'))" />
239234
<LinkerArg Include="-Wl,-install_name,&quot;$(SharedLibraryInstallName)&quot;" Condition="'$(_IsApplePlatform)' == 'true' and '$(NativeLib)' == 'Shared'" />
240235
<LinkerArg Include="-Wl,--build-id=sha1" Condition="'$(_IsApplePlatform)' != 'true'" />
241236
<LinkerArg Include="-Wl,--as-needed" Condition="'$(_IsApplePlatform)' != 'true'" />

src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/InteropHelpers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ internal static unsafe void FixupModuleCell(ModuleFixupCell* pCell)
292292
{
293293
string moduleName = GetModuleName(pCell);
294294

295-
uint dllImportSearchPath = 0;
295+
uint dllImportSearchPath = (uint)DllImportSearchPath.AssemblyDirectory;
296296
bool hasDllImportSearchPath = (pCell->DllImportSearchPathAndCookie & InteropDataConstants.HasDllImportSearchPath) != 0;
297297
if (hasDllImportSearchPath)
298298
{

src/coreclr/vm/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON
5353
assembly.cpp
5454
assemblybinder.cpp
5555
binder.cpp
56-
bundle.cpp
5756
castcache.cpp
5857
callcounting.cpp
5958
cdacplatformmetadata.cpp
@@ -298,6 +297,7 @@ set(VM_SOURCES_WKS
298297
assemblyprobeextension.cpp
299298
assemblyspec.cpp
300299
baseassemblyspec.cpp
300+
bundle.cpp
301301
${RUNTIME_DIR}/CachedInterfaceDispatch.cpp
302302
CachedInterfaceDispatch_Coreclr.cpp
303303
cachelinealloc.cpp

src/coreclr/vm/bundle.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "common.h"
1111
#include "bundle.h"
12+
#include "hostinformation.h"
1213
#include <utilcode.h>
1314
#include <corhost.h>
1415
#include <sstring.h>
@@ -47,6 +48,10 @@ Bundle::Bundle(LPCSTR bundlePath, BundleProbeFn *probe)
4748
size_t baseLen = pos - bundlePath + 1; // Include DIRECTORY_SEPARATOR_CHAR_A in m_basePath
4849
m_basePath.SetUTF8(bundlePath, (COUNT_T)baseLen);
4950
m_basePathLength = (COUNT_T)baseLen;
51+
52+
SString extractionPathMaybe;
53+
if (HostInformation::GetProperty(HOST_PROPERTY_BUNDLE_EXTRACTION_PATH, extractionPathMaybe))
54+
m_extractionPath.Set(extractionPathMaybe.GetUnicode());
5055
}
5156

5257
BundleFileLocation Bundle::Probe(const SString& path, bool pathIsBundleRelative) const

src/coreclr/vm/nativelibrary.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,12 +472,20 @@ namespace
472472
NATIVE_LIBRARY_HANDLE LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
473473
{
474474
STANDARD_VM_CONTRACT;
475+
_ASSERTE(libName != NULL);
475476

476-
if (pAssembly->GetPEAssembly()->GetPath().IsEmpty())
477+
SString path{ pAssembly->GetPEAssembly()->GetPath() };
478+
479+
// Bundled assembly - path will be empty, path to load should point to the single-file bundle
480+
bool isBundledAssembly = pAssembly->GetPEAssembly()->HasPEImage() && pAssembly->GetPEAssembly()->GetPEImage()->IsInBundle();
481+
_ASSERTE(!isBundledAssembly || Bundle::AppBundle != NULL);
482+
if (isBundledAssembly)
483+
path.Set(pAssembly->GetPEAssembly()->GetPEImage()->GetPathToLoad());
484+
485+
if (path.IsEmpty())
477486
return NULL;
478487

479488
NATIVE_LIBRARY_HANDLE hmod = NULL;
480-
SString path{ pAssembly->GetPEAssembly()->GetPath() };
481489
_ASSERTE(!Path::IsRelative(path));
482490

483491
SString::Iterator lastPathSeparatorIter = path.End();
@@ -490,6 +498,15 @@ namespace
490498
hmod = LocalLoadLibraryHelper(path, flags, pErrorTracker);
491499
}
492500

501+
// Bundle with additional files extracted - also treat the extraction path as the assembly directory for native library load
502+
if (hmod == NULL && isBundledAssembly && Bundle::AppBundle->HasExtractedFiles())
503+
{
504+
path.Set(Bundle::AppBundle->ExtractionPath());
505+
path.Append(DIRECTORY_SEPARATOR_CHAR_W);
506+
path.Append(libName);
507+
hmod = LocalLoadLibraryHelper(path, flags, pErrorTracker);
508+
}
509+
493510
return hmod;
494511
}
495512

src/coreclr/vm/peimage.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -758,8 +758,6 @@ PTR_PEImage PEImage::CreateFromHMODULE(HMODULE hMod)
758758
}
759759
#endif // !TARGET_UNIX
760760

761-
#endif //DACCESS_COMPILE
762-
763761
HANDLE PEImage::GetFileHandle()
764762
{
765763
CONTRACTL
@@ -776,11 +774,7 @@ HANDLE PEImage::GetFileHandle()
776774

777775
if (m_hFile == INVALID_HANDLE_VALUE)
778776
{
779-
#if !defined(DACCESS_COMPILE)
780777
EEFileLoadException::Throw(GetPathToLoad(), hr);
781-
#else // defined(DACCESS_COMPILE)
782-
ThrowHR(hr);
783-
#endif // !defined(DACCESS_COMPILE)
784778
}
785779

786780
return m_hFile;
@@ -819,6 +813,7 @@ HRESULT PEImage::TryOpenFile(bool takeLock)
819813
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
820814
}
821815

816+
#endif // !DACCESS_COMPILE
822817

823818
BOOL PEImage::IsPtrInImage(PTR_CVOID data)
824819
{

src/coreclr/vm/peimage.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,10 @@ class PEImage final
145145
INT64 GetSize() const;
146146
BOOL IsCompressed(INT64* uncompressedSize = NULL) const;
147147

148+
#ifndef DACCESS_COMPILE
148149
HANDLE GetFileHandle();
149150
HRESULT TryOpenFile(bool takeLock = false);
151+
#endif
150152

151153
void GetMVID(GUID *pMvid);
152154
IMDInternalImport* GetMDImport();

0 commit comments

Comments
 (0)