Skip to content

Commit 6e307db

Browse files
Automatic LoaderOptimization.SingleDomain (#4187)
* All non-default app domains use LoaderOptimization.SingleDomain Solves "Loading this assembly would produce a different grant set from other instances" for IIS .Net Framework applications. __DDVoidMethodType__ injected to mscorlib. __DDVoidMethodType__.__DDPatchAppDomainSetup__ use reflection-created delegate that calls OpenTelemetry.AutoInstrumentation.Loader.AppConfigUpdater.ModifyConfig to modify AppDomainSetup by setting LoaderOptimization.SingleDomain. That method called from AppDomain.CreateDomain and AppDomainManager.CreateDomainHelper. OpenTelemetry.AutoInstrumentation.Loader.AppConfigUpdater loader assembly loaded from __DDVoidMethodType__ static ctor. Added helpers: SignatureBuilder and MemberResolver. * Added installer parameter to skip GAC registration Added Asp.Net tests without registration assemblies in GAC. Removed LoaderOptimization=SingleDomain through registry change for ASP.Net tests. * Removed LoaderOptimization workaround from test dockerfiles * Code format applied * Updated test build to produce no-GAC docker images * Extended SignatureBuilder by providing semi-safe wrappers Moved it to be header-only. Added unit tests for SignatureBuilder. * Updated change log and documentation * Removed Troubleshooting link from IIS instrumentation docs * Fixed accident docker file changes * Added comment about callers of AppConfigUpdater.ModifyConfig * Update CHANGELOG.md typo based on review Co-authored-by: Chris Ventura <[email protected]> * Smaller cleanups * Minor names/comments changes based on @zacharycmontoya review * Fixed formatting * Make AppConfigUpdater internal --------- Co-authored-by: Chris Ventura <[email protected]>
1 parent 35976ea commit 6e307db

File tree

18 files changed

+2200
-576
lines changed

18 files changed

+2200
-576
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h
1111

1212
- Support for [`Npgsql`](https://www.nuget.org/packages/Npgsql/)
1313
metrics instrumentation for versions `6.0.0`+.
14+
- In install script, Install-OpenTelemetryCore accepts optional argument RegisterAssembliesInGAC,
15+
which is true by default. When set to false, assemblies would not be installed in GAC.
16+
- In install script, new function added: Register-AssembliesInGAC. It installs OpenTelemetry assemblies
17+
and dependencies in GAC.
1418

1519
### Changed
1620

1721
- `otel-dotnet-auto-install.sh` now optionally uses `wget` instead of `curl`,
1822
improving compatibility with `mcr.microsoft.com/dotnet/runtime` Alpine images.
23+
- Non-default application domains will be forced to load with LoaderOptimization.SingleDomain
1924

2025
#### Dependency updates
2126

build/Build.Steps.Windows.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ partial class Build
135135
.Executes(() =>
136136
{
137137
var aspNetProject = Solution.GetProjectByName(Projects.Tests.Applications.AspNet);
138-
BuildDockerImage(aspNetProject, "integrated", "classic");
138+
BuildDockerImage(aspNetProject, "integrated-nogac", "classic-nogac", "integrated", "classic");
139139

140140
var wcfProject = Solution.GetProjectByName(Projects.Tests.Applications.WcfIis);
141141
BuildDockerImage(wcfProject);

docs/iis-instrumentation.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,3 @@ application pool.
9999
1. Close all external windows and press 'Apply' in the main
100100
'Configuration Editor' view.
101101
1. Restart your application.
102-
103-
## Troubleshooting
104-
105-
See [`troubleshooting.md`](troubleshooting.md#iis---loading-this-assembly-would-produce-a-different-grant-set-from-other-instances).

docs/troubleshooting.md

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -232,23 +232,3 @@ Sample Diagnostic Output:
232232
For resolving runtime store assembly version conflicts, follow the same solution
233233
as outlined for [Assembly version conflicts](#assembly-version-conflicts) in
234234
this document.
235-
236-
### IIS - Loading this assembly would produce a different grant set from other instances
237-
238-
#### Symptoms
239-
240-
.NET Framework, IIS hosted application crashes and you get an event similar to
241-
the following:
242-
243-
```log
244-
Exception: System.IO.FileLoadException
245-
246-
Message: Loading this assembly would produce a different grant set from other instances.
247-
```
248-
249-
#### Solution
250-
251-
Create a new `DWORD` value called `LoaderOptimization` and give it the value `1`
252-
under the `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework`.
253-
It will allows to load different versions of the same application to different domains.
254-
It might increase CPU and memory usage.

script-templates/OpenTelemetry.DotNet.Auto.psm1.template

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,36 @@ function Is-Greater-Version($v1, $v2) {
295295
return $false;
296296
}
297297

298+
<#
299+
.SYNOPSIS
300+
Installs OpenTelemetry .NET Assemblies in GAC.
301+
.PARAMETER InstallDir
302+
Default: <auto> - the default path is Program Files dir.
303+
Install path of the OpenTelemetry .NET Automatic Instrumentation
304+
Possible values: <auto>, (Custom path)
305+
#>
306+
function Register-AssembliesInGAC() {
307+
$installDir = Get-Current-InstallDir
308+
309+
# Register .NET Framework dlls in GAC
310+
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") | Out-Null
311+
$publish = New-Object System.EnterpriseServices.Internal.Publish
312+
$dlls = Get-ChildItem -Path $installDir\netfx\ -Filter *.dll -File
313+
for ($i = 0; $i -lt $dlls.Count; $i++) {
314+
$percentageComplete = $i / $dlls.Count * 100
315+
Write-Progress -Activity "Registering .NET Framework dlls in GAC" `
316+
-Status "Module $($i+1) out of $($dlls.Count). Installing $($dlls[$i].Name):" `
317+
-PercentComplete $percentageComplete
318+
319+
if (Test-AssemblyNotForGAC $dlls[$i].Name) {
320+
continue
321+
}
322+
323+
$publish.GacInstall($dlls[$i].FullName)
324+
}
325+
Write-Progress -Activity "Registering .NET Framework dlls in GAC" -Status "Ready" -Completed
326+
}
327+
298328
<#
299329
.SYNOPSIS
300330
Installs OpenTelemetry .NET Automatic Instrumentation.
@@ -308,7 +338,9 @@ function Install-OpenTelemetryCore() {
308338
[Parameter(Mandatory = $false)]
309339
[string]$InstallDir = "<auto>",
310340
[Parameter(Mandatory = $false)]
311-
[string]$LocalPath
341+
[string]$LocalPath,
342+
[Parameter(Mandatory = $false)]
343+
[bool]$RegisterAssembliesInGAC = $true
312344
)
313345

314346
$version = "v{{VERSION}}"
@@ -332,23 +364,9 @@ function Install-OpenTelemetryCore() {
332364
# OpenTelemetry service locator
333365
[System.Environment]::SetEnvironmentVariable($ServiceLocatorVariable, $installDir, [System.EnvironmentVariableTarget]::Machine)
334366

335-
# Register .NET Framework dlls in GAC
336-
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") | Out-Null
337-
$publish = New-Object System.EnterpriseServices.Internal.Publish
338-
$dlls = Get-ChildItem -Path $installDir\netfx\ -Filter *.dll -File
339-
for ($i = 0; $i -lt $dlls.Count; $i++) {
340-
$percentageComplete = $i / $dlls.Count * 100
341-
Write-Progress -Activity "Registering .NET Framework dlls in GAC" `
342-
-Status "Module $($i+1) out of $($dlls.Count). Installing $($dlls[$i].Name):" `
343-
-PercentComplete $percentageComplete
344-
345-
if (Test-AssemblyNotForGAC $dlls[$i].Name) {
346-
continue
347-
}
348-
349-
$publish.GacInstall($dlls[$i].FullName)
367+
if ($RegisterAssembliesInGAC){
368+
Register-AssembliesInGAC $installDir
350369
}
351-
Write-Progress -Activity "Registering .NET Framework dlls in GAC" -Status "Ready" -Completed
352370
}
353371
catch {
354372
$message = $_
@@ -406,7 +424,9 @@ function Uninstall-OpenTelemetryCore() {
406424
function Update-OpenTelemetryCore() {
407425
param(
408426
[Parameter(Mandatory = $false)]
409-
[bool]$RegisterIIS = $false
427+
[bool]$RegisterIIS = $false,
428+
[Parameter(Mandatory = $false)]
429+
[bool]$RegisterAssembliesInGAC = $true
410430
)
411431

412432
$currentInstallVersion = Get-OpenTelemetryInstallVersion
@@ -436,7 +456,7 @@ function Update-OpenTelemetryCore() {
436456
Remove-Module OpenTelemetry.Dotnet.Auto
437457
Import-Module $modulePath
438458

439-
Install-OpenTelemetryCore -InstallDir $installDir
459+
Install-OpenTelemetryCore -InstallDir $installDir -RegisterAssembliesInGAC $$RegisterAssembliesInGAC
440460
if ($RegisterIIS) {
441461
Register-OpenTelemetryForIIS
442462
}
@@ -660,3 +680,4 @@ Export-ModuleMember -Function Get-OpenTelemetryInstallDirectory
660680
Export-ModuleMember -Function Get-OpenTelemetryInstallVersion
661681
Export-ModuleMember -Function Enable-OpenTelemetryForIISAppPool
662682
Export-ModuleMember -Function Disable-OpenTelemetryForIISAppPool
683+
Export-ModuleMember -Function Register-AssembliesInGAC
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#if NETFRAMEWORK
5+
namespace OpenTelemetry.AutoInstrumentation.Loader;
6+
7+
/// <summary>
8+
/// Handles update of config files for non-default AppDomain
9+
/// </summary>
10+
internal static class AppConfigUpdater
11+
{
12+
/// <summary>
13+
/// Modify assembly bindings in appDomainSetup.
14+
/// Will be called through reflection when new <see cref="System.AppDomain"/> created.
15+
/// Call done using bytecode modifications for <see cref="AppDomain.CreateDomain(string,System.Security.Policy.Evidence,System.AppDomainSetup)"/>
16+
/// and <see cref="AppDomainManager.CreateDomainHelper(string,System.Security.Policy.Evidence,System.AppDomainSetup)"/>.
17+
/// </summary>
18+
/// <param name="appDomainSetup">appDomainSetup to be updated</param>
19+
public static void ModifyConfig(AppDomainSetup appDomainSetup)
20+
{
21+
appDomainSetup.LoaderOptimization = LoaderOptimization.SingleDomain;
22+
}
23+
}
24+
#endif

src/OpenTelemetry.AutoInstrumentation.Native/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ add_library("OpenTelemetry.AutoInstrumentation.Native.static" STATIC
177177
il_rewriter_wrapper.cpp
178178
il_rewriter.cpp
179179
integration.cpp
180+
member_resolver.cpp
180181
metadata_builder.cpp
181182
miniutf.cpp
182183
string.cpp

src/OpenTelemetry.AutoInstrumentation.Native/OpenTelemetry.AutoInstrumentation.Native.vcxproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@
200200
<ClInclude Include="logger.h" />
201201
<ClInclude Include="logger_impl.h" />
202202
<ClInclude Include="macros.h" />
203+
<ClInclude Include="member_resolver.h" />
203204
<ClInclude Include="metadata_builder.h" />
204205
<ClInclude Include="method_rewriter.h" />
205206
<ClInclude Include="miniutf.hpp" />
@@ -211,6 +212,7 @@
211212
<ClInclude Include="rejit_handler.h" />
212213
<ClInclude Include="rejit_preprocessor.h" />
213214
<ClInclude Include="rejit_work_offloader.h" />
215+
<ClInclude Include="signature_builder.h" />
214216
<ClInclude Include="startup_hook.h" />
215217
<ClInclude Include="stats.h" />
216218
<ClInclude Include="string.h" />
@@ -230,6 +232,7 @@
230232
<ClCompile Include="il_rewriter.cpp" />
231233
<ClCompile Include="il_rewriter_wrapper.cpp" />
232234
<ClCompile Include="integration.cpp" />
235+
<ClCompile Include="member_resolver.cpp" />
233236
<ClCompile Include="metadata_builder.cpp" />
234237
<ClCompile Include="method_rewriter.cpp" />
235238
<ClCompile Include="miniutf.cpp" />

0 commit comments

Comments
 (0)