diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index a5134ea83618a9..9f0e420032d725 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "11.0.0-prerelease.26168.1", + "version": "11.0.0-prerelease.26230.4", "commands": [ "xharness" ] diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d0774450c348c0..2e459f11930c01 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,9 @@ + - + https://github.com/dotnet/icu - cda39b50d316241f6c9dea44ed241a83aaccdfac + 67d0db7e61ed6ba212622a174bed04ef47aa2118 https://github.com/dotnet/msquic @@ -79,10 +80,10 @@ - - https://github.com/dotnet/source-build-reference-packages - a9cadb09ddcc99b1e535efb0648047634f0c4f40 - + + https://github.com/dotnet/source-build-assets + 8e19a1b4f607fcbecc4edbd322d77a60d4e25c3c + @@ -92,139 +93,139 @@ - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 https://github.com/dotnet/llvm-project @@ -320,21 +321,21 @@ https://github.com/dotnet/runtime b030c4dfdfa1bf287f10f96006619a06bc2000ae - + https://github.com/dotnet/xharness - 607b3de9cf2dbfec6734e686e68d2813b40b2b51 + 92962e5c46ac08a66ded4c5696209cc60f1a232f - + https://github.com/dotnet/xharness - 607b3de9cf2dbfec6734e686e68d2813b40b2b51 + 92962e5c46ac08a66ded4c5696209cc60f1a232f - + https://github.com/dotnet/xharness - 607b3de9cf2dbfec6734e686e68d2813b40b2b51 + 92962e5c46ac08a66ded4c5696209cc60f1a232f - + https://github.com/dotnet/arcade - 29a2184303379b9840b70e7cdb2faa0f39833b89 + 6c1a2a69259c3f66af6176c9c70021b3d9989504 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -356,9 +357,9 @@ https://github.com/dotnet/hotreload-utils 2a70fdb0e55455dc067a6f24582b5d9ed75ed373 - + https://github.com/dotnet/runtime-assets - 70d5fa7d7d041da17e6f3827f55d7d9ceaffdb12 + 45c55b97e4006bac84d19a382ace44ef3dcb8d94 https://github.com/dotnet/roslyn @@ -372,11 +373,11 @@ https://github.com/dotnet/roslyn dc344ef24932dcd53cdd24c15364a5996bc6a675 - + https://github.com/dotnet/roslyn-analyzers 5ef1abb57ce3df89eae65ecadeb1ddbab323ae05 - + https://github.com/dotnet/roslyn-analyzers 5ef1abb57ce3df89eae65ecadeb1ddbab323ae05 diff --git a/eng/Versions.props b/eng/Versions.props index 2d630617adf6d2..aa06b49159d30d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -35,8 +35,8 @@ - 3.11.0-beta1.26057.1 - 9.0.0-preview.26057.1 + 3.11.0-beta1.26075.3 + 9.0.0-preview.26075.3 9.0.109 - 9.0.0-beta.26123.3 - 9.0.0-beta.26123.3 - 9.0.0-beta.26123.3 - 9.0.0-beta.26123.3 - 2.9.0-beta.26123.3 - 9.0.0-beta.26123.3 - 2.9.0-beta.26123.3 - 9.0.0-beta.26123.3 - 9.0.0-beta.26123.3 - 9.0.0-beta.26123.3 - 9.0.0-beta.26123.3 - 9.0.0-beta.26123.3 - 9.0.0-beta.26123.3 - 9.0.0-beta.26123.3 - 9.0.0-beta.26123.3 - 9.0.0-beta.26123.3 + 9.0.0-beta.26261.1 + 9.0.0-beta.26261.1 + 9.0.0-beta.26261.1 + 9.0.0-beta.26261.1 + 2.9.0-beta.26261.1 + 9.0.0-beta.26261.1 + 2.9.0-beta.26261.1 + 9.0.0-beta.26261.1 + 9.0.0-beta.26261.1 + 9.0.0-beta.26261.1 + 9.0.0-beta.26261.1 + 9.0.0-beta.26261.1 + 9.0.0-beta.26261.1 + 9.0.0-beta.26261.1 + 9.0.0-beta.26261.1 + 9.0.0-beta.26261.1 1.4.0 @@ -146,20 +146,20 @@ 8.0.0 4.5.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 - 9.0.0-beta.25625.4 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 + 9.0.0-beta.26071.2 1.0.0-prerelease.24462.2 1.0.0-prerelease.24462.2 @@ -190,9 +190,9 @@ 1.4.0 17.4.0-preview-20220707-01 - 11.0.0-prerelease.26168.1 - 11.0.0-prerelease.26168.1 - 11.0.0-prerelease.26168.1 + 11.0.0-prerelease.26230.4 + 11.0.0-prerelease.26230.4 + 11.0.0-prerelease.26230.4 9.0.0-alpha.0.26152.4 3.12.0 @@ -226,8 +226,7 @@ 9.0.0-rtm.24511.16 - 9.0.0-rtm.25627.1 - 9.0.0-rtm.24466.4 + 9.0.0-rtm.26261.1 2.4.18 diff --git a/eng/pipelines/common/evaluate-default-paths.yml b/eng/pipelines/common/evaluate-default-paths.yml index 28991920c330d5..b950e3a923b60b 100644 --- a/eng/pipelines/common/evaluate-default-paths.yml +++ b/eng/pipelines/common/evaluate-default-paths.yml @@ -258,22 +258,6 @@ jobs: - ${{ parameters._const_paths._always_exclude }} - ${{ parameters._const_paths._perf_pipeline_specific_only }} - - subset: wasmdebuggertests - combined: true - include: - - ${{ parameters._const_paths._wasm_chrome }} - - src/libraries/System.Runtime.InteropServices/* - - src/libraries/System.Runtime.InteropServices.JavaScript/* - - src/mono/mono/* - - src/mono/browser/debugger/* - - src/mono/browser/runtime/* - - ${{ parameters._const_paths._wasm_src_native }} - - ${{ parameters._const_paths._wasm_pipelines }} - exclude: - - src/mono/nuget/* - - ${{ parameters._const_paths._always_exclude }} - - ${{ parameters._const_paths._perf_pipeline_specific_only }} - # wasm/runtimetests need to be run - subset: wasm_runtimetests combined: true diff --git a/eng/pipelines/common/templates/wasm-debugger-tests.yml b/eng/pipelines/common/templates/wasm-debugger-tests.yml deleted file mode 100644 index a61321809bc552..00000000000000 --- a/eng/pipelines/common/templates/wasm-debugger-tests.yml +++ /dev/null @@ -1,62 +0,0 @@ -parameters: - alwaysRun: false - isExtraPlatformsBuild: false - isWasmOnlyBuild: false - browser: 'chrome' - shouldContinueOnError: false - runOnlyOnWasmOnlyPipelines: false - extraBuildArgs: '' - nameSuffix: '' - platforms: [] - -jobs: - -# Wasm debugger tests - windows -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: ${{ parameters.platforms }} - shouldContinueOnError: ${{ parameters.shouldContinueOnError }} - variables: - # map dependencies variables to local variables - - name: alwaysRunVar - value: ${{ parameters.alwaysRun }} - - name: shouldRunOnDefaultPipelines - value: $[ - or( - eq(variables['wasmDarcDependenciesChanged'], true), - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true), - eq(stageDependencies.EvaluatePaths.evaluate_paths_outputs['DarcDependenciesChanged.Microsoft_DotNet_HotReload_Utils_Generator_BuildTool'], true), - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'], true)) - ] - jobParameters: - testGroup: innerloop - isExtraPlatforms: ${{ parameters.isExtraPlatformsBuild }} - ${{ if eq(parameters.nameSuffix, '') }}: - nameSuffix: Mono_DebuggerTests_${{ parameters.browser }} - ${{ else }}: - nameSuffix: ${{ parameters.nameSuffix }} - buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:TestWasmDebuggerTests=true /p:TestAssemblies=false /p:BrowserHost=$(_hostedOs) /p:DebuggerHost=${{ parameters.browser }} ${{ parameters.extraBuildArgs }} - timeoutInMinutes: 180 - # if !alwaysRun, then: - # if this is runtime-wasm (isWasmOnlyBuild): - # - then run only if it would not have run on default pipelines (based - # on path changes) - # - else run based on path changes - condition: >- - or( - eq(variables['alwaysRunVar'], true), - and( - eq(variables['isDefaultPipeline'], variables['shouldRunOnDefaultPipelines']), - eq(${{ parameters.isWasmOnlyBuild }}, ${{ parameters.runOnlyOnWasmOnlyPipelines }}))) - postBuildSteps: - - template: /eng/pipelines/libraries/helix.yml - parameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_${{ parameters.browser }}_$(_BuildConfig) - extraHelixArguments: /p:BrowserHost=$(_hostedOs) /p:_DebuggerHosts=${{ parameters.browser }} - scenarios: - - wasmdebuggertests diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml index 259982aff35451..32899b04862407 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml @@ -55,17 +55,6 @@ jobs: runAOT: true alwaysRun: true - # Wasm Debugger tests - firefox - - template: /eng/pipelines/common/templates/wasm-debugger-tests.yml - parameters: - platforms: - - browser_wasm_firefox - browser: firefox - extraBuildArgs: /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS) - ## ff tests are unstable currently - shouldContinueOnError: true - alwaysRun: true - # Disabled for now #- template: /eng/pipelines/coreclr/perf-wasm-jobs.yml #parameters: @@ -240,42 +229,6 @@ jobs: isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }} isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }} -- ${{ if and(ne(parameters.isRollingBuild, true), or(ne(parameters.excludeNonLibTests, true), eq(parameters.debuggerTestsOnly, true))) }}: - # Debugger tests - - template: /eng/pipelines/common/templates/wasm-debugger-tests.yml - parameters: - platforms: - - browser_wasm - - browser_wasm_win - extraBuildArgs: /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS) - isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }} - isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }} - - - template: /eng/pipelines/common/templates/wasm-debugger-tests.yml - parameters: - platforms: - - browser_wasm_firefox - browser: firefox - extraBuildArgs: /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS) - isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }} - isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }} - alwaysRun: ${{ parameters.isWasmOnlyBuild }} - # ff tests are unstable currently - shouldContinueOnError: true - - # Active Issue https://github.com/dotnet/runtime/issues/98771 - # - template: /eng/pipelines/common/templates/wasm-debugger-tests.yml - # parameters: - # platforms: - # - Browser_wasm - # - Browser_wasm_win - # extraBuildArgs: /p:WasmEnableThreads=true /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS) - # nameSuffix: DebuggerTests_MultiThreaded - # alwaysRun: ${{ parameters.isWasmOnlyBuild }} - # isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }} - # isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }} - # runOnlyOnWasmOnlyPipelines: true - # Disable for now #- template: /eng/pipelines/coreclr/perf-wasm-jobs.yml #parameters: diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index 4f5a71dcd39c10..f94bd937525cd6 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -907,15 +907,6 @@ extends: alwaysRun: ${{ variables.isRollingBuild }} extraBuildArgs: /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS) - # Wasm Debugger tests - - template: /eng/pipelines/common/templates/wasm-debugger-tests.yml - parameters: - platforms: - - browser_wasm - - browser_wasm_win - alwaysRun: ${{ variables.isRollingBuild }} - extraBuildArgs: /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS) - # Wasm runtime tests - template: /eng/pipelines/common/templates/wasm-runtime-tests.yml parameters: diff --git a/eng/testing/tests.browser.targets b/eng/testing/tests.browser.targets index a3406b78f43686..44c7bc6805fa80 100644 --- a/eng/testing/tests.browser.targets +++ b/eng/testing/tests.browser.targets @@ -245,9 +245,8 @@ + Text="Only supported scenarios are WasmTestOnV8, WasmTestOnChrome, WasmTestOnFirefox and BuildWasmApps at the moment. It was $(Scenario)." /> diff --git a/global.json b/global.json index 782fb2436191bd..df7a579aeb2df1 100644 --- a/global.json +++ b/global.json @@ -1,16 +1,16 @@ { "sdk": { - "version": "9.0.113", + "version": "9.0.116", "allowPrerelease": true, "rollForward": "major" }, "tools": { - "dotnet": "9.0.113" + "dotnet": "9.0.116" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.26123.3", - "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.26123.3", - "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.26123.3", + "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.26261.1", + "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.26261.1", + "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.26261.1", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "9.0.0-rtm.24511.16" diff --git a/src/coreclr/jit/loopcloning.cpp b/src/coreclr/jit/loopcloning.cpp index 0a74288cb0b7e8..edf370e0fe2a42 100644 --- a/src/coreclr/jit/loopcloning.cpp +++ b/src/coreclr/jit/loopcloning.cpp @@ -1331,17 +1331,17 @@ bool Compiler::optDeriveLoopCloningConditions(FlowGraphNaturalLoop* loop, LoopCl // GT_LE loop test: (start <= end) ==> (end < arrLen) // // Decreasing loops - // GT_GT loop test: (end > start) ==> (end <= arrLen) - // GT_GE loop test: (end >= start) ==> (end < arrLen) + // Always check if iter var is less than array length. genTreeOps opLimitCondition; switch (iterInfo->TestOper()) { case GT_LT: - case GT_GT: + opLimitCondition = GT_LE; break; case GT_LE: case GT_GE: + case GT_GT: opLimitCondition = GT_LT; break; default: diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslCrlCache.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslCrlCache.cs index 52b6b967c0640d..ff047a1e755863 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslCrlCache.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslCrlCache.cs @@ -2,11 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Formats.Asn1; using System.IO; using System.Runtime.InteropServices; using System.Security.Cryptography.Asn1; using System.Security.Cryptography.X509Certificates.Asn1; +using System.Threading; using Microsoft.Win32.SafeHandles; namespace System.Security.Cryptography.X509Certificates @@ -23,6 +25,8 @@ internal static class OpenSslCrlCache X509Persistence.CryptographyFeatureName, X509Persistence.OcspSubFeatureName); + private static readonly MruCrlCache s_crlCache = new(); + private const ulong X509_R_CERT_ALREADY_IN_HASH_TABLE = 0x0B07D065; public static void AddCrlForCertificate( @@ -73,6 +77,95 @@ public static void AddCrlForCertificate( } private static bool AddCachedCrl(string crlFileName, SafeX509StoreHandle store, DateTime verificationTime) + { + // OpenSSL is going to convert our input time to universal, so we should be in Local or + // Unspecified (local-assumed). + Debug.Assert( + verificationTime.Kind != DateTimeKind.Utc, + "UTC verificationTime should have been normalized to Local"); + + if (s_crlCache.TryGetValueAndUpRef(crlFileName, out CachedCrlEntry? cacheEntry)) + { + try + { + Debug.Assert(cacheEntry is not null); + + if (verificationTime < cacheEntry.Expiration) + { + if (OpenSslX509ChainEventSource.Log.IsEnabled()) + { + OpenSslX509ChainEventSource.Log.CrlCacheInMemoryHit(cacheEntry.Expiration); + } + + AttachCrl(store, cacheEntry.CrlHandle); + return true; + } + + if (OpenSslX509ChainEventSource.Log.IsEnabled()) + { + OpenSslX509ChainEventSource.Log.CrlCacheInMemoryExpired(verificationTime, cacheEntry.Expiration); + } + } + finally + { + cacheEntry.CrlHandle.DangerousRelease(); + } + } + else if (OpenSslX509ChainEventSource.Log.IsEnabled()) + { + OpenSslX509ChainEventSource.Log.CrlCacheInMemoryMiss(); + } + + // Check the disk cache. + // For uncached this is the first load, for collected it's a reload, + // for expired it's checking to see if another process has updated the disk cache. + CachedCrlEntry? diskCacheEntry = CheckDiskCache(crlFileName, verificationTime); + + if (diskCacheEntry is null) + { + return false; + } + + UpdateCacheAndAttachCrl(crlFileName, store, diskCacheEntry); + return true; + } + + private static void UpdateCacheAndAttachCrl(string crlFileName, SafeX509StoreHandle store, CachedCrlEntry newEntry) + { + Debug.Assert(!newEntry.CrlHandle.IsInvalid); + CachedCrlEntry toAttach = s_crlCache.AddOrUpdateAndUpRef(crlFileName, newEntry); + + try + { + AttachCrl(store, toAttach.CrlHandle); + } + finally + { + toAttach.CrlHandle.DangerousRelease(); + } + } + + private static void AttachCrl(SafeX509StoreHandle store, SafeX509CrlHandle crl) + { + Debug.Assert(!crl.IsInvalid); + + // X509_STORE_add_crl will increase the refcount on the CRL object, + // so we don't need to worry about our copy getting cleaned up as a weak reference. + if (!Interop.Crypto.X509StoreAddCrl(store, crl)) + { + // Ignore error "cert already in store", throw on anything else. In any case the error queue will be cleared. + if (X509_R_CERT_ALREADY_IN_HASH_TABLE == Interop.Crypto.ErrPeekLastError()) + { + Interop.Crypto.ErrClearError(); + } + else + { + throw Interop.Crypto.CreateOpenSslCryptographicException(); + } + } + } + + private static CachedCrlEntry? CheckDiskCache(string crlFileName, DateTime verificationTime) { string crlFile = GetCachedCrlPath(crlFileName); @@ -83,7 +176,7 @@ private static bool AddCachedCrl(string crlFileName, SafeX509StoreHandle store, try { - return AddCachedCrlCore(crlFile, store, verificationTime); + return CheckDiskCacheCore(crlFile, verificationTime); } finally { @@ -94,7 +187,7 @@ private static bool AddCachedCrl(string crlFileName, SafeX509StoreHandle store, } } - private static bool AddCachedCrlCore(string crlFile, SafeX509StoreHandle store, DateTime verificationTime) + private static CachedCrlEntry? CheckDiskCacheCore(string crlFile, DateTime verificationTime) { using (SafeBioHandle bio = Interop.Crypto.BioNewFile(crlFile, "rb")) { @@ -106,12 +199,11 @@ private static bool AddCachedCrlCore(string crlFile, SafeX509StoreHandle store, } Interop.Crypto.ErrClearError(); - return false; + return null; } - // X509_STORE_add_crl will increase the refcount on the CRL object, so we should still - // dispose our copy. - using (SafeX509CrlHandle crl = Interop.Crypto.PemReadBioX509Crl(bio)) + SafeX509CrlHandle crl = Interop.Crypto.PemReadBioX509Crl(bio); + { if (crl.IsInvalid) { @@ -120,8 +212,9 @@ private static bool AddCachedCrlCore(string crlFile, SafeX509StoreHandle store, OpenSslX509ChainEventSource.Log.CrlCacheDecodeError(); } + crl.Dispose(); Interop.Crypto.ErrClearError(); - return false; + return null; } // If crl.LastUpdate is in the past, downloading a new version isn't really going @@ -144,14 +237,15 @@ private static bool AddCachedCrlCore(string crlFile, SafeX509StoreHandle store, try { - nextUpdate = File.GetLastWriteTime(crlFile).AddDays(3); + nextUpdate = ExpirationTimeFromCacheFileTime(File.GetLastWriteTime(crlFile)); } catch { // We couldn't determine when the CRL was last written to, // so consider it expired. Debug.Fail("Failed to get the last write time of the CRL file"); - return false; + crl.Dispose(); + return null; } } else @@ -159,12 +253,6 @@ private static bool AddCachedCrlCore(string crlFile, SafeX509StoreHandle store, nextUpdate = OpenSslX509CertificateReader.ExtractValidityDateTime(nextUpdatePtr); } - // OpenSSL is going to convert our input time to universal, so we should be in Local or - // Unspecified (local-assumed). - Debug.Assert( - verificationTime.Kind != DateTimeKind.Utc, - "UTC verificationTime should have been normalized to Local"); - // In the event that we're to-the-second accurate on the match, OpenSSL will consider this // to be already expired. if (nextUpdate <= verificationTime) @@ -174,20 +262,8 @@ private static bool AddCachedCrlCore(string crlFile, SafeX509StoreHandle store, OpenSslX509ChainEventSource.Log.CrlCacheExpired(nextUpdate, verificationTime); } - return false; - } - - if (!Interop.Crypto.X509StoreAddCrl(store, crl)) - { - // Ignore error "cert already in store", throw on anything else. In any case the error queue will be cleared. - if (X509_R_CERT_ALREADY_IN_HASH_TABLE == Interop.Crypto.ErrPeekLastError()) - { - Interop.Crypto.ErrClearError(); - } - else - { - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } + crl.Dispose(); + return null; } if (OpenSslX509ChainEventSource.Log.IsEnabled()) @@ -195,7 +271,7 @@ private static bool AddCachedCrlCore(string crlFile, SafeX509StoreHandle store, OpenSslX509ChainEventSource.Log.CrlCacheAcceptedFile(nextUpdate); } - return true; + return new CachedCrlEntry(crl, nextUpdate); } } } @@ -206,57 +282,81 @@ private static void DownloadAndAddCrl( SafeX509StoreHandle store, TimeSpan downloadTimeout) { - // X509_STORE_add_crl will increase the refcount on the CRL object, so we should still - // dispose our copy. - using (SafeX509CrlHandle? crl = OpenSslCertificateAssetDownloader.DownloadCrl(url, downloadTimeout)) + CachedCrlEntry? newEntry = DownloadAndCacheCrl(url, crlFileName, downloadTimeout); + + if (newEntry is not null) + { + UpdateCacheAndAttachCrl(crlFileName, store, newEntry); + } + } + + private static CachedCrlEntry? DownloadAndCacheCrl( + string url, + string crlFileName, + TimeSpan downloadTimeout) + { + SafeX509CrlHandle? crl = OpenSslCertificateAssetDownloader.DownloadCrl(url, downloadTimeout); + + // null is a valid return (e.g. no remainingDownloadTime) + if (crl == null || crl.IsInvalid) { - // null is a valid return (e.g. no remainingDownloadTime) - if (crl != null && !crl.IsInvalid) - { - if (!Interop.Crypto.X509StoreAddCrl(store, crl)) - { - // Ignore error "cert already in store", throw on anything else. In any case the error queue will be cleared. - if (X509_R_CERT_ALREADY_IN_HASH_TABLE == Interop.Crypto.ErrPeekLastError()) - { - Interop.Crypto.ErrClearError(); - } - else - { - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } - } + crl?.Dispose(); + return null; + } - // Saving the CRL to the disk is just a performance optimization for later requests to not - // need to use the network again, so failure to save shouldn't throw an exception or mark - // the chain as invalid. - try - { - string crlFile = GetCachedCrlPath(crlFileName, mkDir: true); + IntPtr nextUpdatePtr = Interop.Crypto.GetX509CrlNextUpdate(crl); + DateTime expiryTime; - using (SafeBioHandle bio = Interop.Crypto.BioNewFile(crlFile, "wb")) - { - if (bio.IsInvalid || Interop.Crypto.PemWriteBioX509Crl(bio, crl) == 0) - { - // No bio, or write failed + // If there is no crl.NextUpdate, this indicates that the CA is not providing + // any more updates to the CRL, or they made a mistake not providing a NextUpdate. + // We'll cache it for a few days to cover the case it was a mistake. + if (nextUpdatePtr == IntPtr.Zero) + { + expiryTime = ExpirationTimeFromCacheFileTime(DateTime.Now); + } + else + { + expiryTime = OpenSslX509CertificateReader.ExtractValidityDateTime(nextUpdatePtr); + } - if (OpenSslX509ChainEventSource.Log.IsEnabled()) - { - OpenSslX509ChainEventSource.Log.CrlCacheWriteFailed(crlFile); - } + // Saving the CRL to the disk is just a performance optimization for later requests to not + // need to use the network again, so failure to save shouldn't throw an exception or mark + // the chain as invalid. + try + { + string crlFile = GetCachedCrlPath(crlFileName, mkDir: true); - Interop.Crypto.ErrClearError(); - } + using (SafeBioHandle bio = Interop.Crypto.BioNewFile(crlFile, "wb")) + { + if (bio.IsInvalid || Interop.Crypto.PemWriteBioX509Crl(bio, crl) == 0) + { + // No bio, or write failed + + if (OpenSslX509ChainEventSource.Log.IsEnabled()) + { + OpenSslX509ChainEventSource.Log.CrlCacheWriteFailed(crlFile); } - } - catch (UnauthorizedAccessException) { } - catch (IOException) { } - if (OpenSslX509ChainEventSource.Log.IsEnabled()) - { - OpenSslX509ChainEventSource.Log.CrlCacheWriteSucceeded(); + Interop.Crypto.ErrClearError(); } } } + catch (UnauthorizedAccessException) { } + catch (IOException) { } + + if (OpenSslX509ChainEventSource.Log.IsEnabled()) + { + OpenSslX509ChainEventSource.Log.CrlCacheWriteSucceeded(); + } + + return new CachedCrlEntry(crl, expiryTime); + } + + private static DateTime ExpirationTimeFromCacheFileTime(DateTime cacheFileTime) + { + // CA/Browser Forum says that CRLs should be updated every 4 to 7 days, + // so recheck any cached CRL, that doesn't have a NextUpdate, every 3 days. + return cacheFileTime.AddDays(3); } internal static string GetCachedOcspResponseDirectory() @@ -379,5 +479,300 @@ private static string GetCachedCrlPath(string localFileName, bool mkDir = false) return null; } + + // The MRU CRL cache always does a DangerousAddReference before returning the value, + // so that neither cooperative GC pruning nor a cache-value refresh trigger ReleaseHandle + // on a CRL entry in use. + private sealed class MruCrlCache + { + // Each CRL is only a SafeHandle to the GC, but represents a non-trivial amount of + // native memory, so keep the cache small. + private const int MaxItems = 30; + + private readonly Lock _lock = new(); + + private int _count = -1; + private Node? _head; + private Node? _expire; + + internal CachedCrlEntry AddOrUpdateAndUpRef(string key, CachedCrlEntry value) + { + Debug.Assert(key is not null); + Debug.Assert(value is not null); + Debug.Assert(value.CrlHandle is not null && !value.CrlHandle.IsInvalid); + // Don't assert/enforce anything about expiration, because a) clock-skew, or b) + // the caller might have a verification time that's in the past. + + int hashCode = key.GetHashCode(); + CachedCrlEntry ret = value; + string? fullMemberKey = null; + SafeX509CrlHandle? toDispose = null; + + lock (_lock) + { + // The first time we add something, create the object to monitor for GC events. + if (_count < 0) + { + new GCWatcher(this); + _count = 0; + } + + bool ignore = false; + + if (TryGetNode(hashCode, key, out Node? current)) + { + Debug.Assert(current is not null); + + if (current.Value.Expiration >= value.Expiration) + { + toDispose = value.CrlHandle; + ret = current.Value; + } + else + { + toDispose = current.Value.CrlHandle; + current.Value = value; + } + } + else + { + Node node = new Node(hashCode, key, value); + node.Next = _head; + + if (_count < MaxItems) + { + _count++; + } + else + { + // Because MaxItems is small, it's better to just iterate from head + // instead of using a doubly-linked list. + + Node? previous = null; + Node? cur = _head; + Node? next = cur?.Next; + + while (next is not null) + { + previous = cur; + cur = next; + next = cur.Next; + } + + Debug.Assert(previous is not null); + Debug.Assert(cur is not null); + + previous.Next = null; + toDispose = cur.Value.CrlHandle; + fullMemberKey = cur.Key; + if (cur == _expire) + { + _expire = null; + } + } + + _head = node; + } + + ret.CrlHandle.DangerousAddRef(ref ignore); + } + + toDispose?.Dispose(); + + if (fullMemberKey is not null && OpenSslX509ChainEventSource.Log.IsEnabled()) + { + OpenSslX509ChainEventSource.Log.CrlCacheInMemoryFull(fullMemberKey); + } + + return ret; + } + + internal bool TryGetValueAndUpRef(string key, [NotNullWhen(true)] out CachedCrlEntry? value) + { + int hashCode = key.GetHashCode(); + + lock (_lock) + { + if (TryGetNode(hashCode, key, out Node? node)) + { + bool ignore = false; + node.Value.CrlHandle.DangerousAddRef(ref ignore); + value = node.Value; + return true; + } + } + + value = null; + return false; + } + + private bool TryGetNode(int hashCode, string key, [NotNullWhen(true)] out Node? value) + { + Debug.Assert(_lock.IsHeldByCurrentThread); + + Node? previous = null; + Node? current = _head; + + while (current is not null) + { + if (current.MatchesKey(hashCode, key)) + { + // If we find the expire node, move expiration to after it, so that promoting it to + // most recent doesn't prune the whole list. + // + // This might, of course, make _expire null. + if (current == _expire) + { + _expire = current.Next; + } + + // Move the found node to the head of the list, maintaining MRU ordering. + if (previous != null) + { + previous.Next = current.Next; + current.Next = _head; + _head = current; + } + + value = current; + return true; + } + + previous = current; + current = current.Next; + } + + value = null; + return false; + } + + private void PruneForGC() + { + // The general flow: + // * The current head is where we expire next time. + // * Under the lock: If there is an expire node, determine the new count by walking to it, + // and unlink it from the previous node. + // * After the lock: Dispose all the values from the prune node onward. + + Node? prune; + int countStart; + int countEnd; + + lock (_lock) + { + prune = _expire; + _expire = _head; + countStart = _count; + + if (prune is null) + { + return; + } + + if (prune == _head) + { + _count = 0; + _head = null; + _expire = null; + } + else + { + Debug.Assert(_head is not null); + int count = 1; + Node current = _head; + + while (current.Next != prune && current.Next is not null) + { + count++; + current = current.Next; + } + + Debug.Assert(current.Next == prune, "The prune node should be in the list"); + current.Next = null; + _count = count; + } + + countEnd = _count; + } + + // `prune` and beyond are now unlinked from the list, so we can dispose its values without holding the lock. + while (prune is not null) + { + prune.Value.CrlHandle.Dispose(); + prune = prune.Next; + } + + if (OpenSslX509ChainEventSource.Log.IsEnabled()) + { + OpenSslX509ChainEventSource.Log.CrlCacheInMemoryPruned(countStart - countEnd, countEnd); + } + } + + private sealed class Node + { + private readonly int _keyHashCode; + + internal string Key { get; } + internal CachedCrlEntry Value { get; set; } + internal Node? Next { get; set; } + + internal Node(int hashCode, string key, CachedCrlEntry value) + { + Debug.Assert(key.GetHashCode() == hashCode); + + Key = key; + _keyHashCode = hashCode; + Value = value; + } + + internal bool MatchesKey(int hashCode, string key) + { + return _keyHashCode == hashCode && Key.Equals(key, StringComparison.Ordinal); + } + } + + private sealed class GCWatcher + { + private readonly MruCrlCache _owner; + + internal GCWatcher(MruCrlCache owner) + { + _owner = owner; + } + + ~GCWatcher() + { + GC.ReRegisterForFinalize(this); + + if (GC.GetGeneration(this) == GC.MaxGeneration) + { + try + { + _owner.PruneForGC(); + } + catch + { + // Eat any exception so we don't terminate the finalizer thread. +#if DEBUG + // Except in DEBUG, as we really shouldn't be hitting any exceptions here. + throw; +#endif + } + } + } + } + } + + private sealed class CachedCrlEntry + { + internal SafeX509CrlHandle CrlHandle { get; } + internal DateTime Expiration { get; } + + internal CachedCrlEntry(SafeX509CrlHandle crlHandle, DateTime expiration) + { + CrlHandle = crlHandle; + Expiration = expiration; + } + } } } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainEventSource.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainEventSource.cs index 0e1cdc25efb832..8b2fb68dd5c7d1 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainEventSource.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainEventSource.cs @@ -60,6 +60,11 @@ internal sealed class OpenSslX509ChainEventSource : EventSource private const int EventId_RevocationCheckStop = 46; private const int EventId_CrlIdentifiersDetermined = 47; private const int EventId_StapledOcspPresent = 48; + private const int EventId_CrlCacheInMemoryHit = 49; + private const int EventId_CrlCacheInMemoryExpired = 50; + private const int EventId_CrlCacheInMemoryMiss = 51; + private const int EventId_CrlCacheInMemoryPruned = 52; + private const int EventId_CrlCacheInMemoryFull = 53; private static string GetCertificateSubject(SafeX509Handle certHandle) { @@ -429,7 +434,7 @@ internal void NoMatchingCdpEntry() EventId_CrlCacheCheckStart, Level = EventLevel.Verbose, Opcode = EventOpcode.Start, - Message = "Checking for a cached CRL.")] + Message = "Checking for a CRL cached on disk.")] internal void CrlCacheCheckStart() { if (IsEnabled()) @@ -477,7 +482,7 @@ internal void CrlCacheDecodeError() [Event( EventId_CrlCacheExpired, Level = EventLevel.Verbose, - Message = "The cached CRL's nextUpdate value ({1:O}) is not after the verification time ({0:O}).")] + Message = "The CRL cached on disk has a nextUpdate value ({1:O}) that is before the verification time ({0:O}).")] internal void CrlCacheExpired(DateTime verificationTime, DateTime nextUpdate) { if (IsEnabled()) @@ -489,7 +494,7 @@ internal void CrlCacheExpired(DateTime verificationTime, DateTime nextUpdate) [Event( EventId_CrlCacheFileBasedExpiry, Level = EventLevel.Verbose, - Message = "The cached crl has no nextUpdate value, basing nextUpdate on the file write time.")] + Message = "The CRL cached on disk has no nextUpdate value, basing nextUpdate on the file write time.")] internal void CrlCacheFileBasedExpiry() { if (IsEnabled()) @@ -501,7 +506,7 @@ internal void CrlCacheFileBasedExpiry() [Event( EventId_CrlCacheAcceptedFile, Level = EventLevel.Verbose, - Message = "The cached crl nextUpdate value ({0:O}) is acceptable, using the cached file.")] + Message = "The CRL cached on disk has a nextUpdate value ({0:O}) that is acceptable, using the cached file.")] internal void CrlCacheAcceptedFile(DateTime nextUpdate) { if (IsEnabled()) @@ -525,7 +530,7 @@ internal void CrlCacheWriteFailed(string cacheFile) [Event( EventId_CrlCacheWriteSucceeded, Level = EventLevel.Verbose, - Message = "The downloaded CRL was successfully written to the cache.")] + Message = "The downloaded CRL was successfully written to the disk cache.")] internal void CrlCacheWriteSucceeded() { if (IsEnabled()) @@ -752,5 +757,65 @@ internal void StapledOcspPresent() WriteEvent(EventId_StapledOcspPresent); } } + + [Event( + EventId_CrlCacheInMemoryHit, + Level = EventLevel.Verbose, + Message = "The in-memory CRL cache has a valid entry for the requested CRL, expiration at {0:O}.")] + internal void CrlCacheInMemoryHit(DateTime expiration) + { + if (IsEnabled()) + { + WriteEvent(EventId_CrlCacheInMemoryHit, expiration); + } + } + + [Event( + EventId_CrlCacheInMemoryExpired, + Level = EventLevel.Verbose, + Message = "The in-memory cached CRL's expiration time ({1:O}) is before the verification time ({0:O}).")] + internal void CrlCacheInMemoryExpired(DateTime verificationTime, DateTime expirationTime) + { + if (IsEnabled()) + { + WriteEvent(EventId_CrlCacheInMemoryExpired, verificationTime, expirationTime); + } + } + + [Event( + EventId_CrlCacheInMemoryPruned, + Level = EventLevel.Verbose, + Message = "The in-memory CRL cache was pruned. {0} entries removed, {1} entries remain.")] + internal void CrlCacheInMemoryPruned(int prunedCount, int remainingCount) + { + if (IsEnabled()) + { + WriteEvent(EventId_CrlCacheInMemoryPruned, prunedCount, remainingCount); + } + } + + [Event( + EventId_CrlCacheInMemoryMiss, + Level = EventLevel.Verbose, + Message = "The in-memory CRL cache has no entry for the requested CRL.")] + internal void CrlCacheInMemoryMiss() + { + if (IsEnabled()) + { + WriteEvent(EventId_CrlCacheInMemoryMiss); + } + } + + [Event( + EventId_CrlCacheInMemoryFull, + Level = EventLevel.Verbose, + Message = "The in-memory CRL cache is full, dismissing {0}.")] + internal void CrlCacheInMemoryFull(string cacheFileName) + { + if (IsEnabled()) + { + WriteEvent(EventId_CrlCacheInMemoryFull, cacheFileName); + } + } } } diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509FilesystemTests.Unix.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509FilesystemTests.Unix.cs index ae532f1d3bb8af..5895a58e432694 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509FilesystemTests.Unix.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509FilesystemTests.Unix.cs @@ -1,9 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.Tracing; using System.IO; -using System.Linq; +using System.Net.Http; +using System.Net.Security; using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.DotNet.RemoteExecutor; using Xunit; namespace System.Security.Cryptography.X509Certificates.Tests @@ -80,6 +85,76 @@ public static void VerifyCrlCache() } } + [OuterLoop] + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public static async Task CrlDiskCacheRecovers() + { + using X509Certificate2 getDotNetCert = await GetGetDotNetCert(); + string crlFileName; + + using (CrlCacheNameFinderEventListener listener = new(getDotNetCert.Subject)) + using (CancellationTokenSource tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(10))) + using (ChainHolder chainHolder = new ChainHolder()) + { + Task nameTask = listener.GetCacheFileNameAsync(tokenSource.Token); + + _ = chainHolder.Chain.Build(getDotNetCert); + crlFileName = await nameTask.ConfigureAwait(false); + } + + string crlDirectory = PersistedFiles.GetUserFeatureDirectory("cryptography", "crls"); + string crlFile = Path.Combine(crlDirectory, crlFileName); + string crlPem = await File.ReadAllTextAsync(crlFile).ConfigureAwait(false); + + await File.WriteAllTextAsync(crlFile, crlPem.AsMemory(0, crlPem.Length / 2)).ConfigureAwait(false); + + RemoteExecutor.Invoke( + static base64Cert => + { + using (X509Certificate2 cert = X509CertificateLoader.LoadCertificate(Convert.FromBase64String(base64Cert))) + using (ChainHolder chainHolder = new ChainHolder()) + { + bool valid = chainHolder.Chain.Build(cert); + + return valid ? RemoteExecutor.SuccessExitCode : 0; + } + }, + Convert.ToBase64String(getDotNetCert.RawDataMemory.Span)) + .Dispose(); + + string pem2 = await File.ReadAllTextAsync(crlFile).ConfigureAwait(false); + + // Rather than assert the CRL didn't change, just check that it's a valid CRL: + CertificateRevocationListBuilder.LoadPem(pem2, out _); + + static async Task GetGetDotNetCert() + { + X509Certificate2 getDotNetCert = null; + + SocketsHttpHandler handler = new SocketsHttpHandler + { + SslOptions = + { + RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => + { + getDotNetCert = X509CertificateLoader.LoadCertificate(((X509Certificate2)certificate).RawData); + return errors == SslPolicyErrors.None; + } + } + }; + + using (HttpClient client = new HttpClient(handler)) + using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))) + { + using HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Head, "https://get.dot.net/"); + using HttpResponseMessage response = await client.SendAsync(req, cts.Token).ConfigureAwait(false); + } + + Assert.NotNull(getDotNetCert); + return getDotNetCert; + } + } + [Fact] public static void X509Store_OpenExisting_Fails() { @@ -672,6 +747,53 @@ private static void RunX509StoreTest(Action testAction) } } + private class CrlCacheNameFinderEventListener : EventListener + { + private readonly string _certificateName; + private string _cacheName; + + internal CrlCacheNameFinderEventListener(string certificateName) + { + _certificateName = certificateName; + } + + protected override void OnEventSourceCreated(EventSource eventSource) + { + if (eventSource.Name.Equals("System.Security.Cryptography.X509Certificates.X509Chain.OpenSsl")) + { + EnableEvents(eventSource, EventLevel.Verbose); + } + } + + protected override void OnEventWritten(EventWrittenEventArgs eventData) + { + if (eventData.EventName == "CrlIdentifiersDetermined") + { + if (eventData.Payload?.Count == 3) + { + if (eventData.Payload[0] is string certName && + certName == _certificateName && + eventData.Payload[1] is string cdp && + eventData.Payload[2] is string cacheName) + { + _cacheName = cacheName; + } + } + } + } + + internal async Task GetCacheFileNameAsync(CancellationToken cancellationToken) + { + while (_cacheName == null) + { + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + } + + Dispose(); + return _cacheName; + } + } + // `openssl crl -in [MicrosoftDotComRootCrlPem] -noout -hash`.[SHA-256(CDPURL)[0..4].ToHex()].crl private const string MicrosoftDotComRootCrlFilename = "b204d74a.daa2bce5.crl"; diff --git a/src/libraries/sendtohelix-browser.targets b/src/libraries/sendtohelix-browser.targets index 6d0b3c40e74608..8f4aa0bf526755 100644 --- a/src/libraries/sendtohelix-browser.targets +++ b/src/libraries/sendtohelix-browser.targets @@ -35,7 +35,6 @@ $(Scenario)-ST- $(Scenario)-MT- - true true @@ -177,9 +176,8 @@ + Text="Only supported scenarios are WasmTestOnV8, WasmTestOnChrome, WasmTestOnFirefox and BuildWasmApps at the moment. It was $(Scenario)." /> - <_BaseProjectsToBuild Include="$(PerScenarioProjectFile)" Condition="'%(_Scenarios.Identity)' != 'buildwasmapps' and '%(_Scenarios.Identity)' != 'buildiosapps' and '%(_Scenarios.Identity)' != 'wasmdebuggertests'"> + <_BaseProjectsToBuild Include="$(PerScenarioProjectFile)" Condition="'%(_Scenarios.Identity)' != 'buildwasmapps' and '%(_Scenarios.Identity)' != 'buildiosapps'"> $(_PropertiesToPass);Scenario=%(_Scenarios.Identity);TestArchiveRuntimeFile=$(TestArchiveRuntimeFile) %(_BaseProjectsToBuild.AdditionalProperties);NeedsToBuildWasmAppsOnHelix=$(NeedsToBuildWasmAppsOnHelix) @@ -109,14 +109,6 @@ - - <_DebuggerHostsItem Include="$(_DebuggerHosts.Split('/'))" /> - - <_WasmDebuggerTestsProjectsToBuild Include="$(PerScenarioProjectFile)"> - $(_PropertiesToPass);Scenario=WasmDebuggerTests;TestArchiveRuntimeFile=$(TestArchiveRuntimeFile);DebuggerHost=%(_DebuggerHostsItem.Identity) - - - <_TestUsingWorkloadsValues Include="false" /> @@ -128,7 +120,7 @@ - <_ProjectsToBuild Include="@(_BuildWasmAppsProjectsToBuild);@(_WasmDebuggerTestsProjectsToBuild);@(_BuildiOSAppsProjectsToBuild);@(_BaseProjectsToBuild)" /> + <_ProjectsToBuild Include="@(_BuildWasmAppsProjectsToBuild);@(_BuildiOSAppsProjectsToBuild);@(_BaseProjectsToBuild)" /> diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index c52212e3a18e48..8b6f00768d38e5 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -25,7 +25,7 @@ false - true + true @@ -681,13 +681,6 @@ (('$(ContinuousIntegrationBuild)' == 'true' and '$(TestWasmBuildTests)' == 'true') or ('$(ContinuousIntegrationBuild)' != 'true' and '$(TestAssemblies)' == 'true'))" BuildInParallel="false" /> - - diff --git a/src/mono/browser/Makefile b/src/mono/browser/Makefile index 1401a1b36a431f..3abcd3541657cd 100644 --- a/src/mono/browser/Makefile +++ b/src/mono/browser/Makefile @@ -113,22 +113,6 @@ run-browser-tests-%: build-runtime-tests: $(TOP)/src/tests/build.sh -mono os browser wasm $(CONFIG) $(MSBUILD_ARGS) -build-debugger-tests-helix: - $(DOTNET) build -restore -bl:$(LOG_PATH)/Wasm.Debugger.Tests.binlog \ - /p:ContinuousIntegrationBuild=true /p:ArchiveTests=true \ - $(TOP)/src/mono/browser/debugger/Wasm.Debugger.Tests/Wasm.Debugger.Tests.csproj \ - $(_MSBUILD_WASM_BUILD_ARGS) $(MSBUILD_ARGS) - -submit-debugger-tests-helix: build-debugger-tests-helix - EMSDK_PATH=$(EMSDK_PATH) BUILD_REASON=wasm-test SYSTEM_TEAMPROJECT=public BUILD_REPOSITORY_NAME=dotnet/runtime BUILD_SOURCEBRANCH=main \ - $(TOP)/eng/common/msbuild.sh --ci -restore $(TOP)/src/libraries/sendtohelix.proj \ - /p:TestRunNamePrefixSuffix=WasmDebugger /p:HelixBuild=`date "+%Y%m%d.%H%M"` /p:Creator=`whoami` \ - /bl:$(LOG_PATH)/SendToHelix.binlog -p:HelixTargetQueue=$(HELIX_TARGET_QUEUE) \ - /p:RuntimeFlavor=mono /p:TargetRuntimeIdentifier= /p:MonoForceInterpreter= /p:TestScope=innerloop \ - /p:_Scenarios=wasmdebuggertests \ - $(_MSBUILD_WASM_BUILD_ARGS) \ - $(MSBUILD_ARGS) - submit-wbt-helix: PATH="$(JSVU):$(PATH)" \ $(DOTNET) build $(TOP)/src/mono/wasm/Wasm.Build.Tests/ /v:m /p:ArchiveTests=true /t:ArchiveTests $(_MSBUILD_WASM_BUILD_ARGS) $(MSBUILD_ARGS) && \ diff --git a/src/mono/browser/debugger/Wasm.Debugger.Tests/Wasm.Debugger.Tests.csproj b/src/mono/browser/debugger/Wasm.Debugger.Tests/Wasm.Debugger.Tests.csproj index 008a633de76263..3183d12fb9d7bc 100644 --- a/src/mono/browser/debugger/Wasm.Debugger.Tests/Wasm.Debugger.Tests.csproj +++ b/src/mono/browser/debugger/Wasm.Debugger.Tests/Wasm.Debugger.Tests.csproj @@ -16,7 +16,6 @@ BundleDebuggerTestsForHelix true $(Configuration) - wasm.helix.targets diff --git a/src/mono/browser/debugger/Wasm.Debugger.Tests/wasm.helix.targets b/src/mono/browser/debugger/Wasm.Debugger.Tests/wasm.helix.targets deleted file mode 100644 index 4c36a8937fc1fd..00000000000000 --- a/src/mono/browser/debugger/Wasm.Debugger.Tests/wasm.helix.targets +++ /dev/null @@ -1,31 +0,0 @@ - - - true - true - $(DebuggerHost)- - true - <_DebuggerTestsWorkItemTimeout Condition="'$(Scenario)' == 'WasmDebuggerTests'">00:50:00 - <_DebuggerTestsWorkItemTimeout Condition="'$(Scenario)' == 'WasmDebuggerTests' and '$(BrowserHost)' == 'windows'">00:50:00 - - $(HelixExtensionTargets);_AddWorkItemsForWasmDebuggerTests - - - - - - - - - - - - - $(TestArchiveTestsDir)Wasm.Debugger.Tests.zip - $(HelixCommand) - $(_DebuggerTestsWorkItemTimeout) - set "TEST_ARGS=--filter category^^!=failing^&FullyQualifiedName~%(Identity)" - export "TEST_ARGS=--filter category!=failing&FullyQualifiedName~%(Identity)" - - - - diff --git a/src/mono/wasi/Makefile b/src/mono/wasi/Makefile index 13e2d9cb613ea1..327bac18216baa 100644 --- a/src/mono/wasi/Makefile +++ b/src/mono/wasi/Makefile @@ -73,16 +73,6 @@ build-debugger-tests-helix: $(TOP)/src/mono/wasm/debugger/Wasm.Debugger.Tests/Wasm.Debugger.Tests.csproj \ $(_MSBUILD_WASM_BUILD_ARGS) $(MSBUILD_ARGS) -submit-debugger-tests-helix: build-debugger-tests-helix - BUILD_REASON=wasm-test SYSTEM_TEAMPROJECT=public BUILD_REPOSITORY_NAME=dotnet/runtime BUILD_SOURCEBRANCH=main \ - $(TOP)/eng/common/msbuild.sh --ci -restore $(TOP)/src/libraries/sendtohelix.proj \ - /p:TestRunNamePrefixSuffix=WasmDebugger /p:HelixBuild=`date "+%Y%m%d.%H%M"` /p:Creator=`whoami` \ - /bl:$(TOP)/artifacts/log/$(CONFIG)/SendToHelix.binlog -p:HelixTargetQueue=$(HELIX_TARGET_QUEUE) \ - /p:RuntimeFlavor=mono /p:TargetRuntimeIdentifier= /p:MonoForceInterpreter= /p:TestScope=innerloop \ - /p:_Scenarios=wasmdebuggertests \ - $(_MSBUILD_WASM_BUILD_ARGS) \ - $(MSBUILD_ARGS) - submit-wbt-helix: PATH="$(JSVU):$(PATH)" \ $(DOTNET) build $(TOP)/src/mono/wasi/Wasi.Build.Tests/ /v:m /p:ArchiveTests=true /t:ArchiveTests $(_MSBUILD_WASM_BUILD_ARGS) $(MSBUILD_ARGS) && \ diff --git a/src/tests/JIT/opt/Cloning/DownCounted.cs b/src/tests/JIT/opt/Cloning/DownCounted.cs new file mode 100644 index 00000000000000..50d14e99d39b9f --- /dev/null +++ b/src/tests/JIT/opt/Cloning/DownCounted.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using Xunit; + +public class DownCounted +{ + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + static bool ArrayProblem(int[] a, int n) + { + bool result = false; + for (int i = n; i > 0; i--) + { + a[i] = 44; + result |= (i == n); + } + return result; + } + + [Fact] + public static int ArrayTest() + { + int[] a = new int[100]; + int result = -1; + try + { + bool hasProblem = ArrayProblem(a, 100); + Console.WriteLine($"failed, has problem={hasProblem}"); + } + catch (IndexOutOfRangeException e) + { + Console.WriteLine("passed"); + result = 100; + } + return result; + } + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + static bool SpanProblem(Span a, int n) + { + bool result = false; + for (int i = n; i > 0; i--) + { + a[i] = 44; + result |= (i == n); + } + return result; + } + + [Fact] + public static int SpanTest() + { + int[] a = new int[100]; + int result = -1; + try + { + bool hasProblem = SpanProblem(a, 100); + Console.WriteLine($"failed, has problem={hasProblem}"); + } + catch (IndexOutOfRangeException e) + { + Console.WriteLine("passed"); + result = 100; + } + return result; + } + + +} + diff --git a/src/tests/JIT/opt/Cloning/DownCounted.csproj b/src/tests/JIT/opt/Cloning/DownCounted.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/opt/Cloning/DownCounted.csproj @@ -0,0 +1,8 @@ + + + True + + + + +