diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4e522812e23bc7..b54cff26d4cff0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -111,9 +111,9 @@ - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 @@ -121,69 +121,69 @@ 73f0850939d96131c28cf6ea6ee5aacb4da0083a - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 https://github.com/dotnet/runtime-assets @@ -334,9 +334,9 @@ https://github.com/dotnet/xharness a417169d3ba558fd6daa522f04e686574bbce520 - + https://github.com/dotnet/arcade - 61ae141d2bf3534619265c8f691fd55dc3e75147 + da98edc4c3ea539f109ea320672136ceb32591a7 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 8b755c5895c9db..00d310742cb1bb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,11 +1,11 @@ - 8.0.2 + 8.0.3 8 0 - 2 + 3 8.0.100 7.0.$([MSBuild]::Add($(PatchVersion),14)) 6.0.$([MSBuild]::Add($([System.Version]::Parse('$(PackageVersionNet7)').Build),11)) @@ -87,21 +87,21 @@ 8.0.100 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 - 2.5.1-beta.24059.4 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 - 8.0.0-beta.24059.4 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 + 2.5.1-beta.24113.2 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 + 8.0.0-beta.24113.2 6.0.0-preview.1.102 @@ -244,7 +244,6 @@ $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100Version) 1.1.87-gba258badda - 1.0.0-v3.14.0.5722 16.0.5-alpha.1.23566.1 16.0.5-alpha.1.23566.1 diff --git a/eng/common/post-build/publish-using-darc.ps1 b/eng/common/post-build/publish-using-darc.ps1 index 1e779fec4dd1ea..5a3a32ea8d75b4 100644 --- a/eng/common/post-build/publish-using-darc.ps1 +++ b/eng/common/post-build/publish-using-darc.ps1 @@ -12,7 +12,7 @@ param( try { . $PSScriptRoot\post-build-utils.ps1 - $darc = Get-Darc + $darc = Get-Darc $optionalParams = [System.Collections.ArrayList]::new() @@ -46,7 +46,7 @@ try { } Write-Host 'done.' -} +} catch { Write-Host $_ Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "There was an error while trying to publish build '$BuildId' to default channels." diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml index fa5446c093dd11..8ec0151def21a8 100644 --- a/eng/common/templates/job/publish-build-assets.yml +++ b/eng/common/templates/job/publish-build-assets.yml @@ -58,7 +58,7 @@ jobs: demands: Cmd # If it's not devdiv, it's dnceng ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: - name: $(DncEngInternalBuildPool) + name: NetCore1ESPool-Publishing-Internal demands: ImageOverride -equals windows.vs2019.amd64 steps: @@ -71,7 +71,7 @@ jobs: checkDownloadedFiles: true condition: ${{ parameters.condition }} continueOnError: ${{ parameters.continueOnError }} - + - task: NuGetAuthenticate@1 - task: PowerShell@2 @@ -86,7 +86,7 @@ jobs: /p:OfficialBuildId=$(Build.BuildNumber) condition: ${{ parameters.condition }} continueOnError: ${{ parameters.continueOnError }} - + - task: powershell@2 displayName: Create ReleaseConfigs Artifact inputs: @@ -95,7 +95,7 @@ jobs: Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(BARBuildId) Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value "$(DefaultChannels)" Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(IsStableBuild) - + - task: PublishBuildArtifacts@1 displayName: Publish ReleaseConfigs Artifact inputs: @@ -121,7 +121,7 @@ jobs: - task: PublishBuildArtifacts@1 displayName: Publish SymbolPublishingExclusionsFile Artifact - condition: eq(variables['SymbolExclusionFile'], 'true') + condition: eq(variables['SymbolExclusionFile'], 'true') inputs: PathtoPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt' PublishLocation: Container @@ -137,7 +137,7 @@ jobs: displayName: Publish Using Darc inputs: filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) + arguments: -BuildId $(BARBuildId) -PublishingInfraVersion 3 -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' -MaestroToken '$(MaestroApiAccessToken)' @@ -148,4 +148,4 @@ jobs: - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}: - template: /eng/common/templates/steps/publish-logs.yml parameters: - JobLabel: 'Publish_Artifacts_Logs' + JobLabel: 'Publish_Artifacts_Logs' diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index 3f74abf7ce0f8a..aba44a25a33878 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -39,7 +39,7 @@ parameters: displayName: Enable NuGet validation type: boolean default: true - + - name: publishInstallersAndChecksums displayName: Publish installers and checksums type: boolean @@ -131,8 +131,8 @@ stages: displayName: Validate inputs: filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1 - arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ - -ToolDestinationPath $(Agent.BuildDirectory)/Extract/ + arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ + -ToolDestinationPath $(Agent.BuildDirectory)/Extract/ - job: displayName: Signing Validation @@ -221,9 +221,9 @@ stages: displayName: Validate inputs: filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1 - arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/ - -ExtractPath $(Agent.BuildDirectory)/Extract/ - -GHRepoName $(Build.Repository.Name) + arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/ + -ExtractPath $(Agent.BuildDirectory)/Extract/ + -GHRepoName $(Build.Repository.Name) -GHCommit $(Build.SourceVersion) -SourcelinkCliVersion $(SourceLinkCLIVersion) continueOnError: true @@ -258,7 +258,7 @@ stages: demands: Cmd # If it's not devdiv, it's dnceng ${{ else }}: - name: $(DncEngInternalBuildPool) + name: NetCore1ESPool-Publishing-Internal demands: ImageOverride -equals windows.vs2019.amd64 steps: - template: setup-maestro-vars.yml @@ -272,7 +272,7 @@ stages: displayName: Publish Using Darc inputs: filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) + arguments: -BuildId $(BARBuildId) -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' -MaestroToken '$(MaestroApiAccessToken)' diff --git a/eng/common/templates/variables/pool-providers.yml b/eng/common/templates/variables/pool-providers.yml index 9cc5c550d3b36f..d236f9fdbb153b 100644 --- a/eng/common/templates/variables/pool-providers.yml +++ b/eng/common/templates/variables/pool-providers.yml @@ -1,15 +1,15 @@ -# Select a pool provider based off branch name. Anything with branch name containing 'release' must go into an -Svc pool, +# Select a pool provider based off branch name. Anything with branch name containing 'release' must go into an -Svc pool, # otherwise it should go into the "normal" pools. This separates out the queueing and billing of released branches. -# Motivation: +# Motivation: # Once a given branch of a repository's output has been officially "shipped" once, it is then considered to be COGS # (Cost of goods sold) and should be moved to a servicing pool provider. This allows both separation of queueing # (allowing release builds and main PR builds to not intefere with each other) and billing (required for COGS. -# Additionally, the pool provider name itself may be subject to change when the .NET Core Engineering Services -# team needs to move resources around and create new and potentially differently-named pools. Using this template +# Additionally, the pool provider name itself may be subject to change when the .NET Core Engineering Services +# team needs to move resources around and create new and potentially differently-named pools. Using this template # file from an Arcade-ified repo helps guard against both having to update one's release/* branches and renaming. -# How to use: +# How to use: # This yaml assumes your shipped product branches use the naming convention "release/..." (which many do). # If we find alternate naming conventions in broad usage it can be added to the condition below. # @@ -54,4 +54,4 @@ variables: False, 'NetCore1ESPool-Internal' ) - ] \ No newline at end of file + ] diff --git a/global.json b/global.json index 13f92203054630..c987cd4bc00e7d 100644 --- a/global.json +++ b/global.json @@ -8,9 +8,9 @@ "dotnet": "8.0.101" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24059.4", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24059.4", - "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.24059.4", + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24113.2", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24113.2", + "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.24113.2", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "8.0.0-rc.1.23406.6" diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs b/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs index 1edc4293785287..1a547dd45ebbb1 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs @@ -382,26 +382,26 @@ public void EmitRangeAttribute(string modifier, string prefix, string className, string initializationString = emitTimeSpanSupport ? """ - if (OperandType == typeof(global::System.TimeSpan)) - { - if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || - !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) - { - throw new global::System.InvalidOperationException(c_minMaxError); - } - Minimum = timeSpanMinimum; - Maximum = timeSpanMaximum; - } - else - { - Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - } + if (OperandType == typeof(global::System.TimeSpan)) + { + if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || + !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + { + throw new global::System.InvalidOperationException(MinMaxError); + } + Minimum = timeSpanMinimum; + Maximum = timeSpanMaximum; + } + else + { + Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + } """ : """ - Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); + Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); """; string convertValue = emitTimeSpanSupport ? @@ -470,7 +470,7 @@ public void EmitRangeAttribute(string modifier, string prefix, string className, public {{qualifiedClassName}}(global::System.Type type, string minimum, string maximum) : base() { OperandType = type; - NeedToConvertMinMax = true; + _needToConvertMinMax = true; Minimum = minimum; Maximum = maximum; } @@ -483,33 +483,40 @@ public void EmitRangeAttribute(string modifier, string prefix, string className, public bool ConvertValueInInvariantCulture { get; set; } public override string FormatErrorMessage(string name) => string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum); - private bool NeedToConvertMinMax { get; } - private bool Initialized { get; set; } - private const string c_minMaxError = "The minimum and maximum values must be set to valid values."; + private readonly bool _needToConvertMinMax; + private volatile bool _initialized; + private readonly object _lock = new(); + private const string MinMaxError = "The minimum and maximum values must be set to valid values."; public override bool IsValid(object? value) { - if (!Initialized) + if (!_initialized) { - if (Minimum is null || Maximum is null) - { - throw new global::System.InvalidOperationException(c_minMaxError); - } - if (NeedToConvertMinMax) + lock (_lock) { - System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; + if (!_initialized) + { + if (Minimum is null || Maximum is null) + { + throw new global::System.InvalidOperationException(MinMaxError); + } + if (_needToConvertMinMax) + { + System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; {{initializationString}} + } + int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); + if (cmp > 0) + { + throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); + } + else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) + { + throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); + } + _initialized = true; + } } - int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); - if (cmp > 0) - { - throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); - } - else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) - { - throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); - } - Initialized = true; } if (value is null or string { Length: 0 }) diff --git a/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj b/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj index de066111eb5797..e35606898e3914 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj +++ b/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj @@ -4,8 +4,8 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.1;netstandard2.0;$(NetFrameworkMinimum) true true - false - 1 + true + 2 Provides a strongly typed way of specifying and accessing settings using dependency injection. diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netcore.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netcore.g.cs index 38bacf966df052..b36fff7e49060b 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netcore.g.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netcore.g.cs @@ -84,7 +84,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base() public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base() { OperandType = type; - NeedToConvertMinMax = true; + _needToConvertMinMax = true; Minimum = minimum; Maximum = maximum; } @@ -97,34 +97,41 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str public bool ConvertValueInInvariantCulture { get; set; } public override string FormatErrorMessage(string name) => string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum); - private bool NeedToConvertMinMax { get; } - private bool Initialized { get; set; } - private const string c_minMaxError = "The minimum and maximum values must be set to valid values."; + private readonly bool _needToConvertMinMax; + private volatile bool _initialized; + private readonly object _lock = new(); + private const string MinMaxError = "The minimum and maximum values must be set to valid values."; public override bool IsValid(object? value) { - if (!Initialized) + if (!_initialized) { - if (Minimum is null || Maximum is null) + lock (_lock) { - throw new global::System.InvalidOperationException(c_minMaxError); + if (!_initialized) + { + if (Minimum is null || Maximum is null) + { + throw new global::System.InvalidOperationException(MinMaxError); + } + if (_needToConvertMinMax) + { + System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; + Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + } + int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); + if (cmp > 0) + { + throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); + } + else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) + { + throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); + } + _initialized = true; + } } - if (NeedToConvertMinMax) - { - System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; - Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - } - int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); - if (cmp > 0) - { - throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); - } - else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) - { - throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); - } - Initialized = true; } if (value is null or string { Length: 0 }) diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netfx.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netfx.g.cs index fe77e3e6bd924a..1fa2f9c2e25770 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netfx.g.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netfx.g.cs @@ -82,7 +82,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base() public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base() { OperandType = type; - NeedToConvertMinMax = true; + _needToConvertMinMax = true; Minimum = minimum; Maximum = maximum; } @@ -95,34 +95,41 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str public bool ConvertValueInInvariantCulture { get; set; } public override string FormatErrorMessage(string name) => string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum); - private bool NeedToConvertMinMax { get; } - private bool Initialized { get; set; } - private const string c_minMaxError = "The minimum and maximum values must be set to valid values."; + private readonly bool _needToConvertMinMax; + private volatile bool _initialized; + private readonly object _lock = new(); + private const string MinMaxError = "The minimum and maximum values must be set to valid values."; public override bool IsValid(object? value) { - if (!Initialized) + if (!_initialized) { - if (Minimum is null || Maximum is null) + lock (_lock) { - throw new global::System.InvalidOperationException(c_minMaxError); + if (!_initialized) + { + if (Minimum is null || Maximum is null) + { + throw new global::System.InvalidOperationException(MinMaxError); + } + if (_needToConvertMinMax) + { + System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; + Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + } + int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); + if (cmp > 0) + { + throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); + } + else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) + { + throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); + } + _initialized = true; + } } - if (NeedToConvertMinMax) - { - System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; - Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - } - int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); - if (cmp > 0) - { - throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); - } - else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) - { - throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); - } - Initialized = true; } if (value is null or string { Length: 0 }) diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang10.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang10.g.cs index 7cf1fe61e1a94b..789d299cf93c5a 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang10.g.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang10.g.cs @@ -410,7 +410,7 @@ public __SourceGen__2C497155_RangeAttribute(double minimum, double maximum) : ba public __SourceGen__2C497155_RangeAttribute(global::System.Type type, string minimum, string maximum) : base() { OperandType = type; - NeedToConvertMinMax = true; + _needToConvertMinMax = true; Minimum = minimum; Maximum = maximum; } @@ -423,47 +423,54 @@ public __SourceGen__2C497155_RangeAttribute(global::System.Type type, string min public bool ConvertValueInInvariantCulture { get; set; } public override string FormatErrorMessage(string name) => string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum); - private bool NeedToConvertMinMax { get; } - private bool Initialized { get; set; } - private const string c_minMaxError = "The minimum and maximum values must be set to valid values."; + private readonly bool _needToConvertMinMax; + private volatile bool _initialized; + private readonly object _lock = new(); + private const string MinMaxError = "The minimum and maximum values must be set to valid values."; public override bool IsValid(object? value) { - if (!Initialized) + if (!_initialized) { - if (Minimum is null || Maximum is null) + lock (_lock) { - throw new global::System.InvalidOperationException(c_minMaxError); - } - if (NeedToConvertMinMax) - { - System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; - if (OperandType == typeof(global::System.TimeSpan)) + if (!_initialized) { - if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || - !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + if (Minimum is null || Maximum is null) { - throw new global::System.InvalidOperationException(c_minMaxError); + throw new global::System.InvalidOperationException(MinMaxError); } - Minimum = timeSpanMinimum; - Maximum = timeSpanMaximum; - } - else - { - Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); + if (_needToConvertMinMax) + { + System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; + if (OperandType == typeof(global::System.TimeSpan)) + { + if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || + !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + { + throw new global::System.InvalidOperationException(MinMaxError); + } + Minimum = timeSpanMinimum; + Maximum = timeSpanMaximum; + } + else + { + Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + } + } + int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); + if (cmp > 0) + { + throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); + } + else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) + { + throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); + } + _initialized = true; } } - int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); - if (cmp > 0) - { - throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); - } - else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) - { - throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); - } - Initialized = true; } if (value is null or string { Length: 0 }) diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang11.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang11.g.cs index f7bba046033420..60d511f2e83561 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang11.g.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang11.g.cs @@ -410,7 +410,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base() public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base() { OperandType = type; - NeedToConvertMinMax = true; + _needToConvertMinMax = true; Minimum = minimum; Maximum = maximum; } @@ -423,47 +423,54 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str public bool ConvertValueInInvariantCulture { get; set; } public override string FormatErrorMessage(string name) => string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum); - private bool NeedToConvertMinMax { get; } - private bool Initialized { get; set; } - private const string c_minMaxError = "The minimum and maximum values must be set to valid values."; + private readonly bool _needToConvertMinMax; + private volatile bool _initialized; + private readonly object _lock = new(); + private const string MinMaxError = "The minimum and maximum values must be set to valid values."; public override bool IsValid(object? value) { - if (!Initialized) + if (!_initialized) { - if (Minimum is null || Maximum is null) + lock (_lock) { - throw new global::System.InvalidOperationException(c_minMaxError); - } - if (NeedToConvertMinMax) - { - System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; - if (OperandType == typeof(global::System.TimeSpan)) + if (!_initialized) { - if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || - !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + if (Minimum is null || Maximum is null) { - throw new global::System.InvalidOperationException(c_minMaxError); + throw new global::System.InvalidOperationException(MinMaxError); } - Minimum = timeSpanMinimum; - Maximum = timeSpanMaximum; - } - else - { - Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); + if (_needToConvertMinMax) + { + System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; + if (OperandType == typeof(global::System.TimeSpan)) + { + if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || + !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + { + throw new global::System.InvalidOperationException(MinMaxError); + } + Minimum = timeSpanMinimum; + Maximum = timeSpanMaximum; + } + else + { + Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + } + } + int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); + if (cmp > 0) + { + throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); + } + else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) + { + throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); + } + _initialized = true; } } - int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); - if (cmp > 0) - { - throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); - } - else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) - { - throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); - } - Initialized = true; } if (value is null or string { Length: 0 }) diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang10.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang10.g.cs index 4b28eb159d147b..9c20532b17631d 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang10.g.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang10.g.cs @@ -325,7 +325,7 @@ public __SourceGen__2C497155_RangeAttribute(double minimum, double maximum) : ba public __SourceGen__2C497155_RangeAttribute(global::System.Type type, string minimum, string maximum) : base() { OperandType = type; - NeedToConvertMinMax = true; + _needToConvertMinMax = true; Minimum = minimum; Maximum = maximum; } @@ -338,47 +338,54 @@ public __SourceGen__2C497155_RangeAttribute(global::System.Type type, string min public bool ConvertValueInInvariantCulture { get; set; } public override string FormatErrorMessage(string name) => string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum); - private bool NeedToConvertMinMax { get; } - private bool Initialized { get; set; } - private const string c_minMaxError = "The minimum and maximum values must be set to valid values."; + private readonly bool _needToConvertMinMax; + private volatile bool _initialized; + private readonly object _lock = new(); + private const string MinMaxError = "The minimum and maximum values must be set to valid values."; public override bool IsValid(object? value) { - if (!Initialized) + if (!_initialized) { - if (Minimum is null || Maximum is null) + lock (_lock) { - throw new global::System.InvalidOperationException(c_minMaxError); - } - if (NeedToConvertMinMax) - { - System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; - if (OperandType == typeof(global::System.TimeSpan)) + if (!_initialized) { - if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || - !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + if (Minimum is null || Maximum is null) { - throw new global::System.InvalidOperationException(c_minMaxError); + throw new global::System.InvalidOperationException(MinMaxError); } - Minimum = timeSpanMinimum; - Maximum = timeSpanMaximum; - } - else - { - Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); + if (_needToConvertMinMax) + { + System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; + if (OperandType == typeof(global::System.TimeSpan)) + { + if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || + !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + { + throw new global::System.InvalidOperationException(MinMaxError); + } + Minimum = timeSpanMinimum; + Maximum = timeSpanMaximum; + } + else + { + Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + } + } + int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); + if (cmp > 0) + { + throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); + } + else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) + { + throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); + } + _initialized = true; } } - int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); - if (cmp > 0) - { - throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); - } - else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) - { - throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); - } - Initialized = true; } if (value is null or string { Length: 0 }) diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang11.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang11.g.cs index 4c300abc6d05bc..c563c65e821903 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang11.g.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang11.g.cs @@ -325,7 +325,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base() public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base() { OperandType = type; - NeedToConvertMinMax = true; + _needToConvertMinMax = true; Minimum = minimum; Maximum = maximum; } @@ -338,47 +338,54 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str public bool ConvertValueInInvariantCulture { get; set; } public override string FormatErrorMessage(string name) => string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum); - private bool NeedToConvertMinMax { get; } - private bool Initialized { get; set; } - private const string c_minMaxError = "The minimum and maximum values must be set to valid values."; + private readonly bool _needToConvertMinMax; + private volatile bool _initialized; + private readonly object _lock = new(); + private const string MinMaxError = "The minimum and maximum values must be set to valid values."; public override bool IsValid(object? value) { - if (!Initialized) + if (!_initialized) { - if (Minimum is null || Maximum is null) + lock (_lock) { - throw new global::System.InvalidOperationException(c_minMaxError); - } - if (NeedToConvertMinMax) - { - System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; - if (OperandType == typeof(global::System.TimeSpan)) + if (!_initialized) { - if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || - !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + if (Minimum is null || Maximum is null) { - throw new global::System.InvalidOperationException(c_minMaxError); + throw new global::System.InvalidOperationException(MinMaxError); } - Minimum = timeSpanMinimum; - Maximum = timeSpanMaximum; - } - else - { - Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); + if (_needToConvertMinMax) + { + System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; + if (OperandType == typeof(global::System.TimeSpan)) + { + if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || + !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + { + throw new global::System.InvalidOperationException(MinMaxError); + } + Minimum = timeSpanMinimum; + Maximum = timeSpanMaximum; + } + else + { + Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + } + } + int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); + if (cmp > 0) + { + throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); + } + else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) + { + throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); + } + _initialized = true; } } - int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); - if (cmp > 0) - { - throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); - } - else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) - { - throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); - } - Initialized = true; } if (value is null or string { Length: 0 }) diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs index 4c701e4b9f498f..8487570d208b2b 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs @@ -7,6 +7,7 @@ using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Xunit; @@ -399,6 +400,23 @@ public void TestCustomGeneratedAttributes() Assert.Equal(results.Count(), generatorResult.Failures.Count()); } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public void TestGeneratedRangeAttributeThreadSafety() + { + OptionsWithTimeSpanRangeAttribute options = new OptionsWithTimeSpanRangeAttribute() { Name = "T1", Period = TimeSpan.FromHours(1) }; + TimeSpanRangeAttributeValidator validator = new TimeSpanRangeAttributeValidator(); + + var barrier = new Barrier(8); + Task.WaitAll( + (from i in Enumerable.Range(0, barrier.ParticipantCount) + select Task.Factory.StartNew(() => + { + barrier.SignalAndWait(); + ValidateOptionsResult result = validator.Validate("T1", options); + Assert.True(result.Succeeded); + }, TaskCreationOptions.LongRunning)).ToArray()); + } } public class FakeCount(int count) { public int Count { get { return count; } } } @@ -605,4 +623,17 @@ public partial class NewAttributesValidator : IValidateOptions + { + } } diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs index 93c101431004ca..81a68c3901647c 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs @@ -1,4 +1,4 @@ - + // #nullable enable #pragma warning disable CS1591 // Compensate for https://github.com/dotnet/roslyn/issues/54103 @@ -2195,7 +2195,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base() public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base() { OperandType = type; - NeedToConvertMinMax = true; + _needToConvertMinMax = true; Minimum = minimum; Maximum = maximum; } @@ -2208,47 +2208,54 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str public bool ConvertValueInInvariantCulture { get; set; } public override string FormatErrorMessage(string name) => string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum); - private bool NeedToConvertMinMax { get; } - private bool Initialized { get; set; } - private const string c_minMaxError = "The minimum and maximum values must be set to valid values."; + private readonly bool _needToConvertMinMax; + private volatile bool _initialized; + private readonly object _lock = new(); + private const string MinMaxError = "The minimum and maximum values must be set to valid values."; public override bool IsValid(object? value) { - if (!Initialized) + if (!_initialized) { - if (Minimum is null || Maximum is null) - { - throw new global::System.InvalidOperationException(c_minMaxError); - } - if (NeedToConvertMinMax) + lock (_lock) { - System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; - if (OperandType == typeof(global::System.TimeSpan)) + if (!_initialized) { - if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || - !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + if (Minimum is null || Maximum is null) { - throw new global::System.InvalidOperationException(c_minMaxError); + throw new global::System.InvalidOperationException(MinMaxError); } - Minimum = timeSpanMinimum; - Maximum = timeSpanMaximum; - } - else - { - Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); + if (_needToConvertMinMax) + { + System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; + if (OperandType == typeof(global::System.TimeSpan)) + { + if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || + !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + { + throw new global::System.InvalidOperationException(MinMaxError); + } + Minimum = timeSpanMinimum; + Maximum = timeSpanMaximum; + } + else + { + Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + } + } + int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); + if (cmp > 0) + { + throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); + } + else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) + { + throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); + } + _initialized = true; } } - int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); - if (cmp > 0) - { - throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); - } - else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) - { - throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); - } - Initialized = true; } if (value is null or string { Length: 0 }) diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs index 3c9f86fd84f8a2..7c388c228a7604 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs @@ -1,4 +1,4 @@ - + // #nullable enable #pragma warning disable CS1591 // Compensate for https://github.com/dotnet/roslyn/issues/54103 @@ -2087,7 +2087,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base() public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base() { OperandType = type; - NeedToConvertMinMax = true; + _needToConvertMinMax = true; Minimum = minimum; Maximum = maximum; } @@ -2100,47 +2100,54 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str public bool ConvertValueInInvariantCulture { get; set; } public override string FormatErrorMessage(string name) => string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum); - private bool NeedToConvertMinMax { get; } - private bool Initialized { get; set; } - private const string c_minMaxError = "The minimum and maximum values must be set to valid values."; + private readonly bool _needToConvertMinMax; + private volatile bool _initialized; + private readonly object _lock = new(); + private const string MinMaxError = "The minimum and maximum values must be set to valid values."; public override bool IsValid(object? value) { - if (!Initialized) + if (!_initialized) { - if (Minimum is null || Maximum is null) - { - throw new global::System.InvalidOperationException(c_minMaxError); - } - if (NeedToConvertMinMax) + lock (_lock) { - System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; - if (OperandType == typeof(global::System.TimeSpan)) + if (!_initialized) { - if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || - !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + if (Minimum is null || Maximum is null) { - throw new global::System.InvalidOperationException(c_minMaxError); + throw new global::System.InvalidOperationException(MinMaxError); } - Minimum = timeSpanMinimum; - Maximum = timeSpanMaximum; - } - else - { - Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); - Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); + if (_needToConvertMinMax) + { + System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; + if (OperandType == typeof(global::System.TimeSpan)) + { + if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) || + !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum)) + { + throw new global::System.InvalidOperationException(MinMaxError); + } + Minimum = timeSpanMinimum; + Maximum = timeSpanMaximum; + } + else + { + Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError); + } + } + int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); + if (cmp > 0) + { + throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); + } + else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) + { + throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); + } + _initialized = true; } } - int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); - if (cmp > 0) - { - throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); - } - else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) - { - throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); - } - Initialized = true; } if (value is null or string { Length: 0 }) diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertTests.cs index 4d4a46e33efcc4..f0b852c25b16a7 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertTests.cs @@ -591,6 +591,12 @@ public static void UseAfterDispose() } } + [Fact] + public static void EmptyPkcs7ThrowsException() + { + Assert.ThrowsAny(() => new X509Certificate2(TestData.EmptyPkcs7)); + } + [Fact] public static void ExportPublicKeyAsPkcs12() { diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/TestData.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/TestData.cs index cf14136eb6e058..0d7633f9992ef2 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/TestData.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/TestData.cs @@ -4273,5 +4273,7 @@ internal static DSAParameters GetDSA1024Params() "C0CC2B115B9D33BD6E528E35670E5A6A8D9CF52199F8D693315C60D9ADAD54EF7FDCED36" + "0C8C79E84D42AB5CB6355A70951B1ABF1F2B3FB8BEB7E3A8D6BA2293C0DB8C86B0BB060F" + "0D6DB9939E88B998662A27F092634BBF21F58EEAAA").HexToByteArray(); + + internal static readonly byte[] EmptyPkcs7 = "300B06092A864886F70D010702".HexToByteArray(); } } diff --git a/src/native/libs/System.Security.Cryptography.Native/apibridge.c b/src/native/libs/System.Security.Cryptography.Native/apibridge.c index 5c8d05d17c74d4..bf1eb9d9ecb96b 100644 --- a/src/native/libs/System.Security.Cryptography.Native/apibridge.c +++ b/src/native/libs/System.Security.Cryptography.Native/apibridge.c @@ -112,7 +112,7 @@ int32_t local_X509_get_version(const X509* x509) X509_PUBKEY* local_X509_get_X509_PUBKEY(const X509* x509) { - if (x509) + if (x509 && x509->cert_info) { return x509->cert_info->key; } @@ -123,13 +123,28 @@ X509_PUBKEY* local_X509_get_X509_PUBKEY(const X509* x509) int32_t local_X509_PUBKEY_get0_param( ASN1_OBJECT** palgOid, const uint8_t** pkeyBytes, int* pkeyBytesLen, X509_ALGOR** palg, X509_PUBKEY* pubkey) { + if (!pubkey) + { + return 0; + } + if (palgOid) { + if (!pubkey->algor) + { + return 0; + } + *palgOid = pubkey->algor->algorithm; } if (pkeyBytes) { + if (!pubkey->public_key) + { + return 0; + } + *pkeyBytes = pubkey->public_key->data; *pkeyBytesLen = pubkey->public_key->length; } diff --git a/src/native/libs/System.Security.Cryptography.Native/openssl.c b/src/native/libs/System.Security.Cryptography.Native/openssl.c index ba713b6fdcc212..73822045895425 100644 --- a/src/native/libs/System.Security.Cryptography.Native/openssl.c +++ b/src/native/libs/System.Security.Cryptography.Native/openssl.c @@ -669,6 +669,11 @@ BIO* CryptoNative_GetX509NameInfo(X509* x509, int32_t nameType, int32_t forIssue 0 == strncmp(localOid, szOidUpn, sizeof(szOidUpn))) { // OTHERNAME->ASN1_TYPE->union.field + if (!value->value) + { + return NULL; + } + str = value->value->value.asn1_string; } } diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_pkcs7.c b/src/native/libs/System.Security.Cryptography.Native/pal_pkcs7.c index efb0a738966f55..bc6c1215d632d2 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_pkcs7.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_pkcs7.c @@ -53,9 +53,19 @@ int32_t CryptoNative_GetPkcs7Certificates(PKCS7* p7, X509Stack** certs) switch (OBJ_obj2nid(p7->type)) { case NID_pkcs7_signed: + if (!p7->d.sign) + { + return 0; + } + *certs = p7->d.sign->cert; return 1; case NID_pkcs7_signedAndEnveloped: + if (!p7->d.signed_and_enveloped) + { + return 0; + } + *certs = p7->d.signed_and_enveloped->cert; return 1; } diff --git a/src/workloads/workloads.csproj b/src/workloads/workloads.csproj index 82c5c31badd71b..3db05c0a803404 100644 --- a/src/workloads/workloads.csproj +++ b/src/workloads/workloads.csproj @@ -30,7 +30,7 @@ - +