diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index e21dd9e89bf8a1..3bff7a26fb1843 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "9.0.0-prerelease.25269.3", + "version": "9.0.0-prerelease.25375.3", "commands": [ "xharness" ] diff --git a/NuGet.config b/NuGet.config index e4806514865c0f..52627ab5e8c7a3 100644 --- a/NuGet.config +++ b/NuGet.config @@ -9,11 +9,12 @@ - + + + + - - - + https://github.com/dotnet/cecil - bbb895e8e9f2d566eae04f09977b8c5f895057d2 + 788a8a7481c01a7d235110cdea2ca5bfb34210d4 - + https://github.com/dotnet/emsdk - b567cdb6b8b461de79f2a2536a22ca3a67f2f33e + dc8e3478c4aa5f6a103329333c2bdbcd07a07741 - + https://github.com/dotnet/emsdk - b567cdb6b8b461de79f2a2536a22ca3a67f2f33e + dc8e3478c4aa5f6a103329333c2bdbcd07a07741 - + https://github.com/dotnet/emsdk - b567cdb6b8b461de79f2a2536a22ca3a67f2f33e + dc8e3478c4aa5f6a103329333c2bdbcd07a07741 - + https://github.com/dotnet/source-build-reference-packages - 1cec3b4a8fb07138136a1ca1e04763bfcf7841db + 9859d82ffce48f49b5e93fa46a38bdddc4ba26be @@ -92,195 +92,195 @@ - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - daa0939940ad46ff17734d8eb0b795d711d3ca69 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 https://github.com/dotnet/runtime @@ -320,21 +320,21 @@ https://github.com/dotnet/runtime b030c4dfdfa1bf287f10f96006619a06bc2000ae - + https://github.com/dotnet/xharness - 4d797652fa667e94a39db06cbb5a3cad4f72a51f + 604c13925074041a51e4533959477c8b6888dcf5 - + https://github.com/dotnet/xharness - 4d797652fa667e94a39db06cbb5a3cad4f72a51f + 604c13925074041a51e4533959477c8b6888dcf5 - + https://github.com/dotnet/xharness - 4d797652fa667e94a39db06cbb5a3cad4f72a51f + 604c13925074041a51e4533959477c8b6888dcf5 - + https://github.com/dotnet/arcade - 0d52a8b262d35fa2fde84e398cb2e791b8454bd2 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -352,25 +352,25 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 9d7532585ce71e30ab55f0364d3cecccaf0775d1 - + https://github.com/dotnet/hotreload-utils - 46df3d5e763fdd0e57eeafcb898a86bb955483cb + 3eb23e965fcc8cf3f6bec6e3e2543a81e52b6d20 - + https://github.com/dotnet/runtime-assets - 7f6eab719b1c6834f694cfddb73c3891942e31e4 + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/roslyn - 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 + 5f78534e8ac55b615a3540e7c1ffedee9ced6e1e - + https://github.com/dotnet/roslyn - 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 + 5f78534e8ac55b615a3540e7c1ffedee9ced6e1e - + https://github.com/dotnet/roslyn - 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 + 5f78534e8ac55b615a3540e7c1ffedee9ced6e1e https://github.com/dotnet/roslyn-analyzers @@ -381,19 +381,19 @@ 16865ea61910500f1022ad2b96c499e5df02c228 - + https://github.com/dotnet/roslyn - 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 + 5f78534e8ac55b615a3540e7c1ffedee9ced6e1e - + https://github.com/dotnet/sdk - 38e51fe4e1fa36644ea66191001e82078989f051 + 8128984181a05a7dc0de748ad3371e0a7f153f35 - + https://github.com/dotnet/sdk - 38e51fe4e1fa36644ea66191001e82078989f051 + 8128984181a05a7dc0de748ad3371e0a7f153f35 diff --git a/eng/Versions.props b/eng/Versions.props index 1658031bdfbee1..64002194d43947 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,11 +1,11 @@ - 9.0.7 + 9.0.9 9 0 - 7 + 9 9.0.100 8.0.$([MSBuild]::Add($(PatchVersion),11)) 7.0.20 @@ -44,9 +44,9 @@ Any tools that contribute to the design-time experience should use the MicrosoftCodeAnalysisVersion_LatestVS property above to ensure they do not break the local dev experience. --> - 4.12.0-3.25275.3 - 4.12.0-3.25275.3 - 4.12.0-3.25275.3 + 4.12.0-3.25377.4 + 4.12.0-3.25377.4 + 4.12.0-3.25377.4 - 9.0.107 + 9.0.109 - 9.0.0-beta.25302.2 - 9.0.0-beta.25302.2 - 9.0.0-beta.25302.2 - 9.0.0-beta.25302.2 - 2.9.0-beta.25302.2 - 9.0.0-beta.25302.2 - 2.9.0-beta.25302.2 - 9.0.0-beta.25302.2 - 9.0.0-beta.25302.2 - 9.0.0-beta.25302.2 - 9.0.0-beta.25302.2 - 9.0.0-beta.25302.2 - 9.0.0-beta.25302.2 - 9.0.0-beta.25302.2 - 9.0.0-beta.25302.2 - 9.0.0-beta.25302.2 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 2.9.0-beta.25366.1 + 9.0.0-beta.25366.1 + 2.9.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 1.4.0 @@ -141,20 +141,20 @@ 8.0.0 8.0.0 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 - 9.0.0-beta.25266.2 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 1.0.0-prerelease.24462.2 1.0.0-prerelease.24462.2 @@ -184,10 +184,10 @@ 1.4.0 17.4.0-preview-20220707-01 - 9.0.0-prerelease.25269.3 - 9.0.0-prerelease.25269.3 - 9.0.0-prerelease.25269.3 - 9.0.0-alpha.0.25209.2 + 9.0.0-prerelease.25375.3 + 9.0.0-prerelease.25375.3 + 9.0.0-prerelease.25375.3 + 9.0.0-alpha.0.25330.3 3.12.0 4.5.0 6.0.0 @@ -215,55 +215,55 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25275.2 + 0.11.5-alpha.25370.2 9.0.0-rtm.24511.16 - 9.0.0-rtm.25304.1 + 9.0.0-rtm.25371.1 9.0.0-rtm.24466.4 2.4.8 9.0.0-alpha.1.24167.3 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 - 9.0.7-servicing.25304.2 - 9.0.7 + 9.0.9-servicing.25418.4 + 9.0.9 $(MicrosoftNETWorkloadEmscriptenCurrentManifest90100Version) 1.1.87-gba258badda 1.0.0-v3.14.0.5722 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 - 19.1.0-alpha.1.25266.1 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 3.1.7 1.0.406601 - 9.0.106 + 9.0.107 9.0.0-alpha.1.24175.1 $(MicrosoftNETRuntimeEmscriptenVersion) $(runtimewinx64MicrosoftNETCoreRuntimeWasmNodeTransportPackageVersion) diff --git a/eng/common/core-templates/job/job.yml b/eng/common/core-templates/job/job.yml index ba53ebfbd51334..abe80a2a0e09c9 100644 --- a/eng/common/core-templates/job/job.yml +++ b/eng/common/core-templates/job/job.yml @@ -134,6 +134,10 @@ jobs: signType: $(_SignType) zipSources: false feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + ConnectedPMEServiceName: 6cc74545-d7b9-4050-9dfa-ebefcc8961ea + ${{ else }}: + ConnectedPMEServiceName: 248d384a-b39b-46e3-8ad5-c2c210d5e7ca env: TeamName: $(_TeamName) MicroBuildOutputFolderOverride: '$(Agent.TempDirectory)' diff --git a/eng/common/internal/NuGet.config b/eng/common/internal/NuGet.config index 19d3d311b166f5..f70261ed689bce 100644 --- a/eng/common/internal/NuGet.config +++ b/eng/common/internal/NuGet.config @@ -4,4 +4,7 @@ + + + diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 22b49e09d09b58..9b3ad8840fdb28 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -416,7 +416,7 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = # Locate Visual Studio installation or download x-copy msbuild. $vsInfo = LocateVisualStudio $vsRequirements - if ($vsInfo -ne $null) { + if ($vsInfo -ne $null -and $env:ForceUseXCopyMSBuild -eq $null) { # Ensure vsInstallDir has a trailing slash $vsInstallDir = Join-Path $vsInfo.installationPath "\" $vsMajorVersion = $vsInfo.installationVersion.Split('.')[0] diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml index 18bcf3a5e5ff05..b99d425f52b58f 100644 --- a/eng/pipelines/common/templates/pipeline-with-resources.yml +++ b/eng/pipelines/common/templates/pipeline-with-resources.yml @@ -21,11 +21,6 @@ extends: env: ROOTFS_DIR: /crossrootfs/arm - linux_armv6: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-cross-armv6-raspbian-10 - env: - ROOTFS_DIR: /crossrootfs/armv6 - linux_arm64: image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net9.0-cross-arm64 env: @@ -72,7 +67,7 @@ extends: image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04 linux_musl_x64_dev_innerloop: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.19-WithNode + image: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-amd64 linux_x64_sanitizer: image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net9.0-cross-amd64-sanitizer @@ -84,7 +79,7 @@ extends: image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9 # AlmaLinux 8 is a RHEL 8 rebuild, so we use it to test building from source on RHEL 8. SourceBuild_linux_x64: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:almalinux-8-source-build + image: mcr.microsoft.com/dotnet-buildtools/prereqs:almalinux-9-source-build-amd64 linux_s390x: image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net9.0-cross-s390x diff --git a/eng/pipelines/coreclr/templates/helix-queues-setup.yml b/eng/pipelines/coreclr/templates/helix-queues-setup.yml index 9ccad909568543..4d05678f0b7293 100644 --- a/eng/pipelines/coreclr/templates/helix-queues-setup.yml +++ b/eng/pipelines/coreclr/templates/helix-queues-setup.yml @@ -70,37 +70,37 @@ jobs: # Linux arm64 - ${{ if eq(parameters.platform, 'linux_arm64') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - (Ubuntu.2004.Arm64.Open)Ubuntu.2204.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-arm64v8 + - (Ubuntu.2204.Arm64.Open)Ubuntu.2204.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8 - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - (Ubuntu.2004.Arm64)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-arm64v8 + - (Ubuntu.2204.Arm64)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8 # Linux musl x64 - ${{ if eq(parameters.platform, 'linux_musl_x64') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - (Alpine.321.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-amd64 + - (Alpine.322.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-amd64 - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - (Alpine.321.Amd64)Ubuntu.2204.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-amd64 + - (Alpine.322.Amd64)AzureLinux.3.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-amd64 # Linux musl arm32 - ${{ if eq(parameters.platform, 'linux_musl_arm') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - (Alpine.321.Arm32.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-arm32v7 + - (Alpine.322.Arm32.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-arm32v7 - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - (Alpine.321.Arm32)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-arm32v7 + - (Alpine.322.Arm32)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-arm32v7 # Linux musl arm64 - ${{ if eq(parameters.platform, 'linux_musl_arm64') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - (Alpine.320.Arm64.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.20-helix-arm64v8 + - (Alpine.322.Arm64.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-arm64v8 - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - (Alpine.320.Arm64)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.20-helix-arm64v8 + - (Alpine.322.Arm64)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-arm64v8 # Linux x64 - ${{ if eq(parameters.platform, 'linux_x64') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - Ubuntu.2204.Amd64.Open + - AzureLinux.3.Amd64.Open - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - Ubuntu.2204.Amd64 + - AzureLinux.3.Amd64 # OSX arm64 - ${{ if eq(parameters.platform, 'osx_arm64') }}: diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index 7b849e1bea38c5..cb8447877b09d4 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -27,53 +27,49 @@ jobs: - ${{ if eq(parameters.platform, 'linux_arm') }}: - ${{ if or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - (Debian.12.Arm32.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-arm32v7 - - # Linux armv6 - - ${{ if eq(parameters.platform, 'linux_armv6') }}: - - (Raspbian.10.Armv6.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:raspbian-10-helix-arm32v6 - # Linux arm64 - ${{ if eq(parameters.platform, 'linux_arm64') }}: - - (Ubuntu.2204.Arm64.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8 + - ${{ if or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: + - (Ubuntu.2204.ArmArch.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8 - ${{ if or(ne(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Debian.12.Arm64.Open)Ubuntu.2204.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-arm64v8 + - (AzureLinux.3.0.ArmArch.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-helix-arm64v8 # Linux musl x64 - ${{ if eq(parameters.platform, 'linux_musl_x64') }}: - - ${{ if or(ne(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Alpine.321.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-amd64 - - ${{ if or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Alpine.321.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-amd64 + - (Alpine.322.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-amd64 # Linux musl arm64 - - ${{ if and(eq(parameters.platform, 'linux_musl_arm64'), or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true))) }}: - - (Alpine.320.Arm64.Open)ubuntu.2004.armarch.open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.20-helix-arm64v8 + - ${{ if eq(parameters.platform, 'linux_musl_arm64') }}: + - ${{ if or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: + - (Alpine.322.Arm64.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-arm64v8 + # Linux x64 - ${{ if eq(parameters.platform, 'linux_x64') }}: - - ${{ if and(eq(parameters.jobParameters.interpreter, ''), ne(parameters.jobParameters.isSingleFile, true)) }}: - - ${{ if and(eq(parameters.jobParameters.testScope, 'outerloop'), eq(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - - SLES.15.Amd64.Open - - (Centos.9.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9-helix - - (Fedora.41.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-41-helix - - (Ubuntu.2204.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-amd64 - - (Debian.12.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 - - ${{ if or(ne(parameters.jobParameters.testScope, 'outerloop'), ne(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - - ${{ if or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - SLES.15.Amd64.Open - - (Fedora.41.Amd64.Open)ubuntu.2204.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-41-helix - - Ubuntu.2204.Amd64.Open - - (Debian.12.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 - - (Mariner.2.0.Amd64.Open)Ubuntu.2204.Amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-helix-amd64 - - (AzureLinux.3.0.Amd64.Open)Ubuntu.2204.Amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-helix-amd64 - - (openSUSE.15.6.Amd64.Open)Ubuntu.2204.Amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:opensuse-15.6-helix-amd64 - - ${{ if or(ne(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Centos.9.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9-helix - - (Debian.12.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 - - Ubuntu.2204.Amd64.Open - ${{ if or(eq(parameters.jobParameters.interpreter, 'true'), eq(parameters.jobParameters.isSingleFile, true)) }}: # Limiting interp runs as we don't need as much coverage. - - (Debian.12.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 + - (Debian.12.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 + + - ${{ else }}: + - ${{ if eq(parameters.jobParameters.runtimeFlavor, 'mono') }}: + # Mono path - test minimal scenario + - Ubuntu.2204.Amd64.Open + - ${{ else }}: + # CoreCLR path + - ${{ if and(eq(parameters.jobParameters.isExtraPlatformsBuild, true), ne(parameters.jobParameters.testScope, 'outerloop'))}}: + # extra-platforms CoreCLR (inner loop only) + - (Debian.12.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 + - (Mariner.2.0.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-helix-amd64 + + - ${{ if eq(parameters.jobParameters.testScope, 'outerloop') }}: + # outerloop only CoreCLR + - AzureLinux.3.Amd64.Open + + - ${{ if or(ne(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true))}}: + # inner and outer loop CoreCLR (general set) + - Ubuntu.2204.Amd64.Open + - (AzureLinux.3.0.Amd64.Open)AzureLinux.3.Amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-helix-amd64 + - (Centos.10.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-helix-amd64 # OSX arm64 - ${{ if eq(parameters.platform, 'osx_arm64') }}: @@ -156,15 +152,15 @@ jobs: # WASI - ${{ if eq(parameters.platform, 'wasi_wasm') }}: - - (Ubuntu.2204.Amd64)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly + - (Ubuntu.2204.Amd64)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly # Browser WebAssembly - ${{ if eq(parameters.platform, 'browser_wasm') }}: - - (Ubuntu.2204.Amd64)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly + - (Ubuntu.2204.Amd64)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly # Browser WebAssembly Firefox - ${{ if eq(parameters.platform, 'browser_wasm_firefox') }}: - - (Ubuntu.2204.Amd64)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly + - (Ubuntu.2204.Amd64)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly # Browser WebAssembly windows - ${{ if in(parameters.platform, 'browser_wasm_win', 'wasi_wasm_win') }}: diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml index e3c7dc5050005f..22375d5c37c81a 100644 --- a/eng/pipelines/runtime-official.yml +++ b/eng/pipelines/runtime-official.yml @@ -382,7 +382,6 @@ extends: parameters: name: MonoRuntimePacks - # Build Mono AOT offset headers once, for consumption elsewhere # - template: /eng/pipelines/common/platform-matrix.yml diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index 4a1010323440f3..8f6e4ab408dd08 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -836,21 +836,22 @@ extends: scenarios: - WasmTestOnChrome + # disabled: https://github.com/dotnet/runtime/issues/116492 # Library tests with full threading - - template: /eng/pipelines/common/templates/wasm-library-tests.yml - parameters: - platforms: - - browser_wasm - #- browser_wasm_win - nameSuffix: _Threading - extraBuildArgs: /p:WasmEnableThreads=true /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS) - extraHelixArguments: /p:WasmEnableThreads=true - alwaysRun: ${{ variables.isRollingBuild }} - shouldRunSmokeOnly: onLibrariesAndIllinkChanges - scenarios: - - WasmTestOnChrome - - WasmTestOnFirefox - #- WasmTestOnNodeJS - this is not supported yet, https://github.com/dotnet/runtime/issues/85592 + # - template: /eng/pipelines/common/templates/wasm-library-tests.yml + # parameters: + # platforms: + # - browser_wasm + # #- browser_wasm_win + # nameSuffix: _Threading + # extraBuildArgs: /p:WasmEnableThreads=true /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS) + # extraHelixArguments: /p:WasmEnableThreads=true + # alwaysRun: ${{ variables.isRollingBuild }} + # shouldRunSmokeOnly: onLibrariesAndIllinkChanges + # scenarios: + # - WasmTestOnChrome + # - WasmTestOnFirefox + # #- WasmTestOnNodeJS - this is not supported yet, https://github.com/dotnet/runtime/issues/85592 # EAT Library tests - only run on linux - template: /eng/pipelines/common/templates/wasm-library-aot-tests.yml diff --git a/global.json b/global.json index e7a948a8c83a06..fbcea3f120a495 100644 --- a/global.json +++ b/global.json @@ -1,16 +1,16 @@ { "sdk": { - "version": "9.0.106", + "version": "9.0.107", "allowPrerelease": true, "rollForward": "major" }, "tools": { - "dotnet": "9.0.106" + "dotnet": "9.0.107" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25302.2", - "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.25302.2", - "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.25302.2", + "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25366.1", + "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.25366.1", + "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.25366.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/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index ec518417ef8386..9504e6995c5506 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -105,6 +105,9 @@ extern "C" } \ } while (false) +// On macOS 26, sem_open fails if debugger and debugee are signed with different team ids. +// Use fifos instead of semaphores to avoid this issue, https://github.com/dotnet/runtime/issues/116545 +#define ENABLE_RUNTIME_EVENTS_OVER_PIPES #endif // __APPLE__ #ifdef __NetBSD__ @@ -1432,21 +1435,217 @@ static uint64_t HashSemaphoreName(uint64_t a, uint64_t b) static const char *const TwoWayNamedPipePrefix = "clr-debug-pipe"; static const char* IpcNameFormat = "%s-%d-%llu-%s"; -/*++ - PAL_NotifyRuntimeStarted +#ifdef ENABLE_RUNTIME_EVENTS_OVER_PIPES +static const char* RuntimeStartupPipeName = "st"; +static const char* RuntimeContinuePipeName = "co"; - Signals the debugger waiting for runtime startup notification to continue and - waits until the debugger signals us to continue. +#define PIPE_OPEN_RETRY_DELAY_NS 500000000 // 500 ms -Parameters: - None +typedef enum +{ + RuntimeEventsOverPipes_Disabled = 0, + RuntimeEventsOverPipes_Succeeded = 1, + RuntimeEventsOverPipes_Failed = 2, +} RuntimeEventsOverPipes; -Return value: - TRUE - successfully launched by debugger, FALSE - not launched or some failure in the handshake ---*/ +typedef enum +{ + RuntimeEvent_Unknown = 0, + RuntimeEvent_Started = 1, + RuntimeEvent_Continue = 2, +} RuntimeEvent; + +static +int +OpenPipe(const char* name, int mode) +{ + int fd = -1; + int flags = mode | O_NONBLOCK; + +#if defined(FD_CLOEXEC) + flags |= O_CLOEXEC; +#endif + + while (fd == -1) + { + fd = open(name, flags); + if (fd == -1) + { + if (mode == O_WRONLY && errno == ENXIO) + { + PAL_nanosleep(PIPE_OPEN_RETRY_DELAY_NS); + continue; + } + else if (errno == EINTR) + { + continue; + } + else + { + break; + } + } + } + + if (fd != -1) + { + flags = fcntl(fd, F_GETFL); + if (flags != -1) + { + flags &= ~O_NONBLOCK; + if (fcntl(fd, F_SETFL, flags) == -1) + { + close(fd); + fd = -1; + } + } + else + { + close(fd); + fd = -1; + } + } + + return fd; +} + +static +void +ClosePipe(int fd) +{ + if (fd != -1) + { + while (close(fd) < 0 && errno == EINTR); + } +} + +static +RuntimeEventsOverPipes +NotifyRuntimeUsingPipes() +{ + RuntimeEventsOverPipes result = RuntimeEventsOverPipes_Disabled; + char startupPipeName[MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH]; + char continuePipeName[MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH]; + int startupPipeFd = -1; + int continuePipeFd = -1; + size_t offset = 0; + + LPCSTR applicationGroupId = PAL_GetApplicationGroupId(); + + PAL_GetTransportPipeName(continuePipeName, gPID, applicationGroupId, RuntimeContinuePipeName); + TRACE("NotifyRuntimeUsingPipes: opening continue '%s' pipe\n", continuePipeName); + + continuePipeFd = OpenPipe(continuePipeName, O_RDONLY); + if (continuePipeFd == -1) + { + if (errno == ENOENT || errno == EACCES) + { + TRACE("NotifyRuntimeUsingPipes: pipe %s not found/accessible, runtime events over pipes disabled\n", continuePipeName); + } + else + { + TRACE("NotifyRuntimeUsingPipes: open(%s) failed: %d (%s)\n", continuePipeName, errno, strerror(errno)); + result = RuntimeEventsOverPipes_Failed; + } + + goto exit; + } + + PAL_GetTransportPipeName(startupPipeName, gPID, applicationGroupId, RuntimeStartupPipeName); + TRACE("NotifyRuntimeUsingPipes: opening startup '%s' pipe\n", startupPipeName); + + startupPipeFd = OpenPipe(startupPipeName, O_WRONLY); + if (startupPipeFd == -1) + { + if (errno == ENOENT || errno == EACCES) + { + TRACE("NotifyRuntimeUsingPipes: pipe %s not found/accessible, runtime events over pipes disabled\n", startupPipeName); + } + else + { + TRACE("NotifyRuntimeUsingPipes: open(%s) failed: %d (%s)\n", startupPipeName, errno, strerror(errno)); + result = RuntimeEventsOverPipes_Failed; + } + + goto exit; + } + + TRACE("NotifyRuntimeUsingPipes: sending started event\n"); + + { + unsigned char event = (unsigned char)RuntimeEvent_Started; + unsigned char *buffer = &event; + int bytesToWrite = sizeof(event); + int bytesWritten = 0; + + do + { + bytesWritten = write(startupPipeFd, buffer + offset, bytesToWrite - offset); + if (bytesWritten > 0) + { + offset += bytesWritten; + } + } + while ((bytesWritten > 0 && offset < bytesToWrite) || (bytesWritten == -1 && errno == EINTR)); + + if (offset != bytesToWrite) + { + TRACE("NotifyRuntimeUsingPipes: write(%s) failed: %d (%s)\n", startupPipeName, errno, strerror(errno)); + goto exit; + } + } + + TRACE("NotifyRuntimeUsingPipes: waiting on continue event\n"); + + { + unsigned char event = (unsigned char)RuntimeEvent_Unknown; + unsigned char *buffer = &event; + int bytesToRead = sizeof(event); + int bytesRead = 0; + + offset = 0; + do + { + bytesRead = read(continuePipeFd, buffer + offset, bytesToRead - offset); + if (bytesRead > 0) + { + offset += bytesRead; + } + } + while ((bytesRead > 0 && offset < bytesToRead) || (bytesRead == -1 && errno == EINTR)); + + if (offset == bytesToRead && event == (unsigned char)RuntimeEvent_Continue) + { + TRACE("NotifyRuntimeUsingPipes: received continue event\n"); + } + else + { + TRACE("NotifyRuntimeUsingPipes: received invalid event\n"); + goto exit; + } + } + + result = RuntimeEventsOverPipes_Succeeded; + +exit: + + if (startupPipeFd != -1) + { + ClosePipe(startupPipeFd); + } + + if (continuePipeFd != -1) + { + ClosePipe(continuePipeFd); + } + + return result; +} +#endif // ENABLE_RUNTIME_EVENTS_OVER_PIPES + +static BOOL -PALAPI -PAL_NotifyRuntimeStarted() +NotifyRuntimeUsingSemaphores() { char startupSemName[CLR_SEM_MAX_NAMELEN]; char continueSemName[CLR_SEM_MAX_NAMELEN]; @@ -1467,13 +1666,13 @@ PAL_NotifyRuntimeStarted() CreateSemaphoreName(startupSemName, RuntimeStartupSemaphoreName, unambiguousProcessDescriptor, applicationGroupId); CreateSemaphoreName(continueSemName, RuntimeContinueSemaphoreName, unambiguousProcessDescriptor, applicationGroupId); - TRACE("PAL_NotifyRuntimeStarted opening continue '%s' startup '%s'\n", continueSemName, startupSemName); + TRACE("NotifyRuntimeUsingSemaphores: opening continue '%s' startup '%s'\n", continueSemName, startupSemName); // Open the debugger startup semaphore. If it doesn't exists, then we do nothing and return startupSem = sem_open(startupSemName, 0); if (startupSem == SEM_FAILED) { - TRACE("sem_open(%s) failed: %d (%s)\n", startupSemName, errno, strerror(errno)); + TRACE("NotifyRuntimeUsingSemaphores: sem_open(%s) failed: %d (%s)\n", startupSemName, errno, strerror(errno)); goto exit; } @@ -1496,7 +1695,7 @@ PAL_NotifyRuntimeStarted() { if (EINTR == errno) { - TRACE("sem_wait() failed with EINTR; re-waiting"); + TRACE("NotifyRuntimeUsingSemaphores: sem_wait() failed with EINTR; re-waiting"); continue; } ASSERT("sem_wait(continueSem) failed: errno is %d (%s)\n", errno, strerror(errno)); @@ -1518,6 +1717,45 @@ PAL_NotifyRuntimeStarted() return launched; } +/*++ + PAL_NotifyRuntimeStarted + + Signals the debugger waiting for runtime startup notification to continue and + waits until the debugger signals us to continue. + +Parameters: + None + +Return value: + TRUE - successfully launched by debugger, FALSE - not launched or some failure in the handshake +--*/ +BOOL +PALAPI +PAL_NotifyRuntimeStarted() +{ +#ifdef ENABLE_RUNTIME_EVENTS_OVER_PIPES + // Test pipes as runtime event transport. + RuntimeEventsOverPipes result = NotifyRuntimeUsingPipes(); + switch (result) + { + case RuntimeEventsOverPipes_Disabled: + TRACE("PAL_NotifyRuntimeStarted: pipe handshake disabled, try semaphores\n"); + return NotifyRuntimeUsingSemaphores(); + case RuntimeEventsOverPipes_Failed: + TRACE("PAL_NotifyRuntimeStarted: pipe handshake failed\n"); + return FALSE; + case RuntimeEventsOverPipes_Succeeded: + TRACE("PAL_NotifyRuntimeStarted: pipe handshake succeeded\n"); + return TRUE; + default: + // Unexpected result. + return FALSE; + } +#else + return NotifyRuntimeUsingSemaphores(); +#endif // ENABLE_RUNTIME_EVENTS_OVER_PIPES +} + LPCSTR PALAPI PAL_GetApplicationGroupId() diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 4143d763fbca04..3df24664ff2df5 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -862,36 +862,19 @@ void EEStartupHelper() #ifdef PROFILING_SUPPORTED // Initialize the profiling services. + // This must happen before Thread::HasStarted() that fires profiler notifications is called on the finalizer thread. hr = ProfilingAPIUtility::InitializeProfiling(); _ASSERTE(SUCCEEDED(hr)); IfFailGo(hr); #endif // PROFILING_SUPPORTED - InitializeExceptionHandling(); - - // - // Install our global exception filter - // - if (!InstallUnhandledExceptionFilter()) - { - IfFailGo(E_FAIL); - } - - // throws on error - SetupThread(); - -#ifdef DEBUGGING_SUPPORTED - // Notify debugger once the first thread is created to finish initialization. - if (g_pDebugInterface != NULL) - { - g_pDebugInterface->StartupPhase2(GetThread()); - } -#endif - - // This isn't done as part of InitializeGarbageCollector() above because - // debugger must be initialized before creating EE thread objects +#ifdef TARGET_WINDOWS + // Create the finalizer thread on windows earlier, as we will need to wait for + // the completion of its initialization part that initializes COM as that has to be done + // before the first Thread is attached. Thus we want to give the thread a bit more time. FinalizerThread::FinalizerThreadCreate(); +#endif InitPreStubManager(); @@ -906,8 +889,6 @@ void EEStartupHelper() InitJITHelpers1(); InitJITHelpers2(); - SyncBlockCache::Attach(); - // Set up the sync block SyncBlockCache::Start(); @@ -922,6 +903,48 @@ void EEStartupHelper() IfFailGo(hr); + InitializeExceptionHandling(); + + // + // Install our global exception filter + // + if (!InstallUnhandledExceptionFilter()) + { + IfFailGo(E_FAIL); + } + +#ifdef TARGET_WINDOWS + // g_pGCHeap->Initialize() above could take nontrivial time, so by now the finalizer thread + // should have initialized FLS slot for thread cleanup notifications. + // And ensured that COM is initialized (must happen before allocating FLS slot). + // Make sure that this was done before we start creating Thread objects + // Ex: The call to SetupThread below will create and attach a Thread object. + // Event pipe might also do that. + FinalizerThread::WaitForFinalizerThreadStart(); +#endif + + // throws on error + _ASSERTE(GetThreadNULLOk() == NULL); + SetupThread(); + +#ifdef DEBUGGING_SUPPORTED + // Notify debugger once the first thread is created to finish initialization. + if (g_pDebugInterface != NULL) + { + g_pDebugInterface->StartupPhase2(GetThread()); + } +#endif + +#ifndef TARGET_WINDOWS + // This isn't done as part of InitializeGarbageCollector() above because + // debugger must be initialized before creating EE thread objects + FinalizerThread::FinalizerThreadCreate(); +#else + // On windows the finalizer thread is already partially created and is waiting + // right before doing HasStarted(). We will release it now. + FinalizerThread::EnableFinalization(); +#endif + #ifdef FEATURE_PERFTRACING // Finish setting up rest of EventPipe - specifically enable SampleProfiler if it was requested at startup. // SampleProfiler needs to cooperate with the GC which hasn't fully finished setting up in the first part of the @@ -982,12 +1005,6 @@ void EEStartupHelper() g_MiniMetaDataBuffMaxSize, MEM_COMMIT, PAGE_READWRITE); #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS -#ifdef TARGET_WINDOWS - // By now finalizer thread should have initialized FLS slot for thread cleanup notifications. - // And ensured that COM is initialized (must happen before allocating FLS slot). - // Make sure that this was done. - FinalizerThread::WaitForFinalizerThreadStart(); -#endif g_fEEStarted = TRUE; g_EEStartupStatus = S_OK; hr = S_OK; @@ -1794,6 +1811,8 @@ void InitFlsSlot() // thread - thread to attach static void OsAttachThread(void* thread) { + _ASSERTE(g_flsIndex != FLS_OUT_OF_INDEXES); + if (t_flsState == FLS_STATE_INVOKED) { _ASSERTE_ALL_BUILDS(!"Attempt to execute managed code after the .NET runtime thread state has been destroyed."); diff --git a/src/coreclr/vm/finalizerthread.cpp b/src/coreclr/vm/finalizerthread.cpp index 546a8d1eba240f..ef666c863eed2e 100644 --- a/src/coreclr/vm/finalizerthread.cpp +++ b/src/coreclr/vm/finalizerthread.cpp @@ -445,6 +445,7 @@ DWORD WINAPI FinalizerThread::FinalizerThreadStart(void *args) // handshake with EE initialization, as now we can attach Thread objects to native threads. hEventFinalizerDone->Set(); + WaitForFinalizerEvent (hEventFinalizer); #endif s_FinalizerThreadOK = GetFinalizerThread()->HasStarted(); diff --git a/src/coreclr/vm/syncblk.cpp b/src/coreclr/vm/syncblk.cpp index 868fffca0c0552..4186bccd8846a9 100644 --- a/src/coreclr/vm/syncblk.cpp +++ b/src/coreclr/vm/syncblk.cpp @@ -625,13 +625,6 @@ void SyncBlockCache::CleanupSyncBlocks() } EE_END_FINALLY; } -// create the sync block cache -/* static */ -void SyncBlockCache::Attach() -{ - LIMITED_METHOD_CONTRACT; -} - // create the sync block cache /* static */ void SyncBlockCache::Start() diff --git a/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-sles.12.proj b/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-sles.12.proj index 912692f5d7f26f..f007b2acb63ee8 100644 --- a/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-sles.12.proj +++ b/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-sles.12.proj @@ -5,6 +5,6 @@ - + \ No newline at end of file diff --git a/src/installer/tests/HostActivation.Tests/FrameworkDependentAppLaunch.cs b/src/installer/tests/HostActivation.Tests/FrameworkDependentAppLaunch.cs index 2f486fda3bd327..57e7172faf0e43 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkDependentAppLaunch.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkDependentAppLaunch.cs @@ -191,6 +191,33 @@ public void AppHost_DisableCetCompat() .And.HaveStdOutContaining(TestContext.MicrosoftNETCoreAppVersion); } + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void AppHost_DotNetRoot_DevicePath() + { + string appExe = sharedTestState.App.AppExe; + + string dotnetPath = $@"\\?\{TestContext.BuiltDotNet.BinPath}"; + Command.Create(appExe) + .CaptureStdErr() + .CaptureStdOut() + .DotNetRoot(dotnetPath, TestContext.BuildArchitecture) + .Execute() + .Should().Pass() + .And.HaveStdOutContaining("Hello World") + .And.HaveStdOutContaining(TestContext.MicrosoftNETCoreAppVersion); + + dotnetPath = $@"\\.\{TestContext.BuiltDotNet.BinPath}"; + Command.Create(appExe) + .CaptureStdErr() + .CaptureStdOut() + .DotNetRoot(dotnetPath, TestContext.BuildArchitecture) + .Execute() + .Should().Pass() + .And.HaveStdOutContaining("Hello World") + .And.HaveStdOutContaining(TestContext.MicrosoftNETCoreAppVersion); + } + [Fact] public void RuntimeConfig_FilePath_Breaks_MAX_PATH_Threshold() { diff --git a/src/installer/tests/HostActivation.Tests/SelfContainedAppLaunch.cs b/src/installer/tests/HostActivation.Tests/SelfContainedAppLaunch.cs index 0ebb0912af4f3f..fe18bf10fdd73c 100644 --- a/src/installer/tests/HostActivation.Tests/SelfContainedAppLaunch.cs +++ b/src/installer/tests/HostActivation.Tests/SelfContainedAppLaunch.cs @@ -156,6 +156,29 @@ public void DotNetRoot_IncorrectLayout_Fails() .And.HaveStdErrContaining($"The required library {Binaries.HostFxr.FileName} could not be found."); } + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void DevicePath() + { + string appExe = $@"\\?\{sharedTestState.App.AppExe}"; + Command.Create(appExe) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should().Pass() + .And.HaveStdOutContaining("Hello World") + .And.HaveStdOutContaining(TestContext.MicrosoftNETCoreAppVersion); + + appExe = $@"\\.\{sharedTestState.App.AppExe}"; + Command.Create(appExe) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should().Pass() + .And.HaveStdOutContaining("Hello World") + .And.HaveStdOutContaining(TestContext.MicrosoftNETCoreAppVersion); + } + public class SharedTestState : IDisposable { public TestApp App { get; } diff --git a/src/libraries/Common/src/Interop/OSX/Interop.libobjc.cs b/src/libraries/Common/src/Interop/OSX/Interop.libobjc.cs index 7274cb569051d7..73c57af7ec249c 100644 --- a/src/libraries/Common/src/Interop/OSX/Interop.libobjc.cs +++ b/src/libraries/Common/src/Interop/OSX/Interop.libobjc.cs @@ -46,14 +46,17 @@ internal static Version GetOperatingSystemVersion() } } - if (major == 10 && minor == 16) +#if TARGET_OSX + if (major == 16) { - // We get "compat" version for 11.0 unless we build with updated SDK. - // Hopefully that will be before 11.x comes out - // For now, this maps 10.16 to 11.0. - major = 11; - minor = 0; + // MacOS Tahoe returns a compatibility version unless it is built with a new SDK. Map the compatibility + // version to the "correct" version. This assumes the minor versions will map unchanged. + // 16.0 => 26.0 + // 16.1 => 26.1 + // etc + major = 26; } +#endif return new Version(major, minor, patch); } diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs index 20f5fc2989f6db..db6f7b863a0891 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs @@ -51,9 +51,11 @@ public static partial class PlatformDetection private static readonly Version s_openssl3Version = new Version(3, 0, 0); private static readonly Version s_openssl3_4Version = new Version(3, 4, 0); + private static readonly Version s_openssl3_5Version = new Version(3, 5, 0); public static bool IsOpenSsl3 => IsOpenSslVersionAtLeast(s_openssl3Version); public static bool IsOpenSsl3_4 => IsOpenSslVersionAtLeast(s_openssl3_4Version); + public static bool IsOpenSsl3_5 => IsOpenSslVersionAtLeast(s_openssl3_5Version); /// /// If gnulibc is available, returns the release, such as "stable". diff --git a/src/libraries/System.Data.Odbc/tests/CommandBuilderTests.cs b/src/libraries/System.Data.Odbc/tests/CommandBuilderTests.cs index 5b3c38bf894059..48f7dd90506e93 100644 --- a/src/libraries/System.Data.Odbc/tests/CommandBuilderTests.cs +++ b/src/libraries/System.Data.Odbc/tests/CommandBuilderTests.cs @@ -7,6 +7,7 @@ namespace System.Data.Odbc.Tests { public class CommandBuilderTests : IntegrationTestBase { + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ConditionalFact] public void QuoteIdentifier_UseConnection() { @@ -36,6 +37,7 @@ public void QuoteIdentifier_UseConnection() Assert.Throws(() => commandBuilder.UnquoteIdentifier("Test")); } + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ConditionalFact] public void QuoteIdentifier_CustomPrefixSuffix() { diff --git a/src/libraries/System.Data.Odbc/tests/ConnectionTests.cs b/src/libraries/System.Data.Odbc/tests/ConnectionTests.cs index 24c42a5bc72401..a468a0f0e2a39d 100644 --- a/src/libraries/System.Data.Odbc/tests/ConnectionTests.cs +++ b/src/libraries/System.Data.Odbc/tests/ConnectionTests.cs @@ -9,6 +9,7 @@ namespace System.Data.Odbc.Tests { public class ConnectionTests : IntegrationTestBase { + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] // Bug #96278 fixed only on .NET, not on .NET Framework [ConditionalFact] [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] diff --git a/src/libraries/System.Data.Odbc/tests/DependencyCheckTest.cs b/src/libraries/System.Data.Odbc/tests/DependencyCheckTest.cs index d2eee47618689f..2937d2a15c6232 100644 --- a/src/libraries/System.Data.Odbc/tests/DependencyCheckTest.cs +++ b/src/libraries/System.Data.Odbc/tests/DependencyCheckTest.cs @@ -8,6 +8,7 @@ namespace System.Data.Odbc.Tests public class DependencyCheckTest { [ConditionalFact(Helpers.OdbcNotAvailable)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] public void OdbcConnection_OpenWhenOdbcNotInstalled_ThrowsException() { if (PlatformDetection.IsWindowsServerCore && !Environment.Is64BitProcess) diff --git a/src/libraries/System.Data.Odbc/tests/ReaderTests.cs b/src/libraries/System.Data.Odbc/tests/ReaderTests.cs index 79ea6ffa93c485..1010e02870f5d8 100644 --- a/src/libraries/System.Data.Odbc/tests/ReaderTests.cs +++ b/src/libraries/System.Data.Odbc/tests/ReaderTests.cs @@ -8,6 +8,7 @@ namespace System.Data.Odbc.Tests { public class ReaderTests : IntegrationTestBase { + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ConditionalFact] public void EmptyReader() { @@ -42,6 +43,7 @@ public void EmptyReader() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ConditionalFact] public void GetValues() { @@ -75,6 +77,7 @@ public void GetValues() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ConditionalFact] public void GetValueFailsWithBigIntWithBackwardsCompatibility() { @@ -110,6 +113,7 @@ public void GetValueFailsWithBigIntWithBackwardsCompatibility() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ConditionalFact] public void GetDataTypeName() { @@ -136,6 +140,7 @@ public void GetDataTypeName() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ConditionalFact] public void GetFieldTypeIsNotSupportedInSqlite() { @@ -167,6 +172,7 @@ public void GetFieldTypeIsNotSupportedInSqlite() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ConditionalFact] public void IsDbNullIsNotSupportedInSqlite() { @@ -198,6 +204,7 @@ public void IsDbNullIsNotSupportedInSqlite() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ConditionalFact] public void InvalidRowIndex() { @@ -230,6 +237,7 @@ public void InvalidRowIndex() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ConditionalFact] public void InvalidRowName() { diff --git a/src/libraries/System.Data.Odbc/tests/SmokeTest.cs b/src/libraries/System.Data.Odbc/tests/SmokeTest.cs index f508673fbde2f5..2733b0a0aa620e 100644 --- a/src/libraries/System.Data.Odbc/tests/SmokeTest.cs +++ b/src/libraries/System.Data.Odbc/tests/SmokeTest.cs @@ -7,6 +7,7 @@ namespace System.Data.Odbc.Tests { public class SmokeTest : IntegrationTestBase { + [ActiveIssue("https://github.com/dotnet/runtime/issues/116482", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ConditionalFact] public void CreateInsertSelectTest() { diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs index 84c1073b0ef67a..c46d13f443e119 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs @@ -91,8 +91,10 @@ internal static MemberTypeInfo Decode(BinaryReader reader, int count, PayloadOpt const AllowedRecordTypes SystemClass = Classes | AllowedRecordTypes.SystemClassWithMembersAndTypes // All primitive types can be stored by using one of the interfaces they implement. // Example: `new IEnumerable[1] { "hello" }` or `new IComparable[1] { int.MaxValue }`. - | AllowedRecordTypes.BinaryObjectString | AllowedRecordTypes.MemberPrimitiveTyped; - const AllowedRecordTypes NonSystemClass = Classes | AllowedRecordTypes.ClassWithMembersAndTypes; + | AllowedRecordTypes.BinaryObjectString | AllowedRecordTypes.MemberPrimitiveTyped + // System.Nullable is a special case of SystemClassWithMembersAndTypes + | AllowedRecordTypes.ClassWithMembersAndTypes; + const AllowedRecordTypes NonSystemClass = Classes | AllowedRecordTypes.ClassWithMembersAndTypes; return binaryType switch { diff --git a/src/libraries/System.Formats.Nrbf/tests/EdgeCaseTests.cs b/src/libraries/System.Formats.Nrbf/tests/EdgeCaseTests.cs index f091d47ded8c5f..1d14993a0890c3 100644 --- a/src/libraries/System.Formats.Nrbf/tests/EdgeCaseTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/EdgeCaseTests.cs @@ -144,4 +144,48 @@ public void CanReadAllKindsOfDateTimes_DateTimeIsMemberOfTheRootRecord(DateTime Assert.Equal(input.Ticks, classRecord.GetDateTime(nameof(ClassWithDateTime.Value)).Ticks); Assert.Equal(input.Kind, classRecord.GetDateTime(nameof(ClassWithDateTime.Value)).Kind); } + + [Fact] + public void CanReadUserClassStoredAsSystemClass() + { + // For the following data, BinaryFormatter serializes the ClassWithNullableStructField class + // as a record with a single field called "NullableField" with BinaryType.SystemClass (!!!) + // and TypeName being System.Nullable`1[[SampleStruct, $AssemblyName]]. + // It most likely does so, because it's System.Nullable<$NonSystemStruct>. + // But later it serializes the SampleStruct as a ClassWithMembersAndTypes record, + // not SystemClassWithMembersAndTypes. + // It does so, only when the payload contains at least one class with the nullable field being null. + + using MemoryStream stream = Serialize( + new ClassWithNullableStructField[] + { + new ClassWithNullableStructField() { NullableField = null }, // having a null here is crucial for the test + new ClassWithNullableStructField() { NullableField = new ClassWithNullableStructField.SampleStruct() { Value = 42 } } + } + ); + + SZArrayRecord arrayRecord = (SZArrayRecord)NrbfDecoder.Decode(stream); + SerializationRecord[] records = arrayRecord.GetArray(); + Assert.Equal(2, arrayRecord.Length); + Assert.All(records, record => Assert.True(record.TypeNameMatches(typeof(ClassWithNullableStructField)))); + Assert.Null(((ClassRecord)records[0]).GetClassRecord(nameof(ClassWithNullableStructField.NullableField))); + + ClassRecord? notNullRecord = ((ClassRecord)records[1]).GetClassRecord(nameof(ClassWithNullableStructField.NullableField)); + Assert.NotNull(notNullRecord); + Assert.Equal(42, notNullRecord.GetInt32(nameof(ClassWithNullableStructField.SampleStruct.Value))); + } + + [Serializable] + public class ClassWithNullableStructField + { +#pragma warning disable IDE0001 // Simplify names + public System.Nullable NullableField; +#pragma warning restore IDE0001 + + [Serializable] + public struct SampleStruct + { + public int Value; + } + } } diff --git a/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs b/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs index f21cbce950a543..808887732dd5fd 100644 --- a/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs +++ b/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs @@ -745,53 +745,64 @@ public async Task SendPingToExternalHostWithLowTtlTest() Assert.NotEqual(IPAddress.Any, pingReply.Address); } - [Fact] - [OuterLoop] - public void Ping_TimedOut_Sync_Success() + private async Task Ping_TimedOut_Core(Func> sendPing) { - var sender = new Ping(); - PingReply reply = sender.Send(TestSettings.UnreachableAddress); + Ping sender = new Ping(); + PingReply reply = await sendPing(sender, TestSettings.UnreachableAddress); + if (reply.Status == IPStatus.DestinationNetworkUnreachable) + { + // A network middleware has dropped the packed and replied with DestinationNetworkUnreachable. Repeat the PING attempt on another address. + reply = await sendPing(sender, TestSettings.UnreachableAddress2); + } + + if (reply.Status == IPStatus.DestinationNetworkUnreachable) + { + // Do yet another attempt. + reply = await sendPing(sender, TestSettings.UnreachableAddress3); + } + Assert.Equal(IPStatus.TimedOut, reply.Status); } [Fact] [OuterLoop] - public async Task Ping_TimedOut_EAP_Success() - { - var sender = new Ping(); - sender.PingCompleted += (s, e) => - { - var tcs = (TaskCompletionSource)e.UserState; + public Task Ping_TimedOut_Sync_Success() + => Ping_TimedOut_Core((sender, address) => Task.Run(() => sender.Send(address))); - if (e.Cancelled) - { - tcs.TrySetCanceled(); - } - else if (e.Error != null) - { - tcs.TrySetException(e.Error); - } - else + [Fact] + [OuterLoop] + public Task Ping_TimedOut_EAP_Success() + => Ping_TimedOut_Core(async (sender, address) => + { + static void PingCompleted(object sender, PingCompletedEventArgs e) { - tcs.TrySetResult(e.Reply); - } - }; + var tcs = (TaskCompletionSource)e.UserState; - var tcs = new TaskCompletionSource(); - sender.SendAsync(TestSettings.UnreachableAddress, tcs); - - PingReply reply = await tcs.Task; - Assert.Equal(IPStatus.TimedOut, reply.Status); - } + if (e.Cancelled) + { + tcs.TrySetCanceled(); + } + else if (e.Error != null) + { + tcs.TrySetException(e.Error); + } + else + { + tcs.TrySetResult(e.Reply); + } + } + sender.PingCompleted += PingCompleted; + var tcs = new TaskCompletionSource(); + sender.SendAsync(address, tcs); + PingReply reply = await tcs.Task; + sender.PingCompleted -= PingCompleted; + return reply; + }); [Fact] [OuterLoop] - public async Task Ping_TimedOut_TAP_Success() - { - var sender = new Ping(); - PingReply reply = await sender.SendPingAsync(TestSettings.UnreachableAddress); - Assert.Equal(IPStatus.TimedOut, reply.Status); - } + public Task Ping_TimedOut_TAP_Success() + => Ping_TimedOut_Core((sender, address) => sender.SendPingAsync(address)); private static bool IsRemoteExecutorSupportedAndPrivilegedProcess => RemoteExecutor.IsSupported && PlatformDetection.IsPrivilegedProcess; diff --git a/src/libraries/System.Net.Ping/tests/FunctionalTests/TestSettings.cs b/src/libraries/System.Net.Ping/tests/FunctionalTests/TestSettings.cs index 0e48bb4777b2e1..78b2be986651e6 100644 --- a/src/libraries/System.Net.Ping/tests/FunctionalTests/TestSettings.cs +++ b/src/libraries/System.Net.Ping/tests/FunctionalTests/TestSettings.cs @@ -11,6 +11,9 @@ internal static class TestSettings { public static readonly string LocalHost = "localhost"; public static readonly string UnreachableAddress = "192.0.2.0"; // TEST-NET-1 + public static readonly string UnreachableAddress2 = "100.64.0.1"; // CGNAT block + public static readonly string UnreachableAddress3 = "10.255.255.1"; // High address in the private 10.0.0.0/8 range. Likely unused and unrouted. + public const int PingTimeout = 10 * 1000; public const string PayloadAsString = "'Post hoc ergo propter hoc'. 'After it, therefore because of it'. It means one thing follows the other, therefore it was caused by the other. But it's not always true. In fact it's hardly ever true."; diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamRemoteExecutorTests.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamRemoteExecutorTests.cs index 87ec6605e37aad..46a4707b43cf01 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamRemoteExecutorTests.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamRemoteExecutorTests.cs @@ -25,6 +25,7 @@ public SslStreamRemoteExecutorTests() [PlatformSpecific(TestPlatforms.Linux)] // SSLKEYLOGFILE is only supported on Linux for SslStream [InlineData(true)] [InlineData(false)] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/116473")] public async Task SslKeyLogFile_IsCreatedAndFilled(bool enabledBySwitch) { if (PlatformDetection.IsDebugLibrary(typeof(SslStream).Assembly) && !enabledBySwitch) @@ -34,6 +35,13 @@ public async Task SslKeyLogFile_IsCreatedAndFilled(bool enabledBySwitch) return; } + if (PlatformDetection.IsOpenSsl3_5 && !enabledBySwitch) + { + // OpenSSL 3.5 and later versions log into file in SSLKEYLOGFILE environment variable by default, + // regardless of AppContext switch. + return; + } + var psi = new ProcessStartInfo(); var tempFile = Path.GetTempFileName(); psi.Environment.Add("SSLKEYLOGFILE", tempFile); diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index 73cf14403d59e8..a9159790641707 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -1568,7 +1568,7 @@ public static int ILogB(Half x) } Debug.Assert(IsSubnormal(x)); - return MinExponent - (BitOperations.TrailingZeroCount(x.TrailingSignificand) - BiasedExponentLength); + return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength); } return x.Exponent; diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs index e06187b5a3de54..147e3815812d0c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs @@ -168,37 +168,30 @@ internal static unsafe void WriteGatherAtOffset(SafeFileHandle handle, IReadOnly var handles = new MemoryHandle[buffersCount]; Span vectors = buffersCount <= IovStackThreshold ? - stackalloc Interop.Sys.IOVector[IovStackThreshold] : + stackalloc Interop.Sys.IOVector[IovStackThreshold].Slice(0, buffersCount) : new Interop.Sys.IOVector[buffersCount]; try { - int buffersOffset = 0, firstBufferOffset = 0; - while (true) + long totalBytesToWrite = 0; + for (int i = 0; i < buffersCount; i++) { - long totalBytesToWrite = 0; - - for (int i = buffersOffset; i < buffersCount; i++) - { - ReadOnlyMemory buffer = buffers[i]; - totalBytesToWrite += buffer.Length; - - MemoryHandle memoryHandle = buffer.Pin(); - vectors[i] = new Interop.Sys.IOVector { Base = firstBufferOffset + (byte*)memoryHandle.Pointer, Count = (UIntPtr)(buffer.Length - firstBufferOffset) }; - handles[i] = memoryHandle; - - firstBufferOffset = 0; - } + ReadOnlyMemory buffer = buffers[i]; + totalBytesToWrite += buffer.Length; - if (totalBytesToWrite == 0) - { - break; - } + MemoryHandle memoryHandle = buffer.Pin(); + vectors[i] = new Interop.Sys.IOVector { Base = (byte*)memoryHandle.Pointer, Count = (UIntPtr)buffer.Length }; + handles[i] = memoryHandle; + } + int buffersOffset = 0; + while (totalBytesToWrite > 0) + { long bytesWritten; - fixed (Interop.Sys.IOVector* pinnedVectors = &MemoryMarshal.GetReference(vectors)) + Span left = vectors.Slice(buffersOffset); + fixed (Interop.Sys.IOVector* pinnedVectors = &MemoryMarshal.GetReference(left)) { - bytesWritten = Interop.Sys.PWriteV(handle, pinnedVectors, buffersCount, fileOffset); + bytesWritten = Interop.Sys.PWriteV(handle, pinnedVectors, left.Length, fileOffset); } FileStreamHelpers.CheckFileCall(bytesWritten, handle.Path); @@ -208,22 +201,31 @@ internal static unsafe void WriteGatherAtOffset(SafeFileHandle handle, IReadOnly } // The write completed successfully but for fewer bytes than requested. + // We need to perform next write where the previous one has finished. + fileOffset += bytesWritten; + totalBytesToWrite -= bytesWritten; // We need to try again for the remainder. - for (int i = 0; i < buffersCount; i++) + while (buffersOffset < buffersCount && bytesWritten > 0) { - int n = buffers[i].Length; + int n = (int)vectors[buffersOffset].Count; if (n <= bytesWritten) { - buffersOffset++; bytesWritten -= n; - if (bytesWritten == 0) - { - break; - } + buffersOffset++; } else { - firstBufferOffset = (int)(bytesWritten - n); + // A partial read: the vector needs to point to the new offset. + // But that offset needs to be relative to the previous attempt. + // Example: we have a single buffer with 30 bytes and the first read returned 10. + // The next read should try to read the remaining 20 bytes, but in case it also reads just 10, + // the third attempt should read last 10 bytes (not 20 again). + Interop.Sys.IOVector current = vectors[buffersOffset]; + vectors[buffersOffset] = new Interop.Sys.IOVector + { + Base = current.Base + (int)(bytesWritten), + Count = current.Count - (UIntPtr)(bytesWritten) + }; break; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs index 3b02cf579934ba..56a72756f10be6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs @@ -435,7 +435,7 @@ internal static long ReadScatterAtOffset(SafeFileHandle handle, IReadOnlyList> buffers, long fileOffset) { // WriteFileGather does not support sync handles, so we just call WriteFile in a loop - int bytesWritten = 0; + long bytesWritten = 0; int buffersCount = buffers.Count; for (int i = 0; i < buffersCount; i++) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 32c3eee4712bfc..d87123697c9812 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -880,7 +880,7 @@ public static int ILogB(double x) } Debug.Assert(double.IsSubnormal(x)); - return double.MinExponent - (BitOperations.TrailingZeroCount(x.TrailingSignificand) - double.BiasedExponentLength); + return double.MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - double.BiasedExponentLength); } return x.Exponent; diff --git a/src/libraries/System.Private.CoreLib/src/System/MathF.cs b/src/libraries/System.Private.CoreLib/src/System/MathF.cs index 31e74906022666..6a26c29cfef535 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MathF.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MathF.cs @@ -210,7 +210,7 @@ public static int ILogB(float x) } Debug.Assert(float.IsSubnormal(x)); - return float.MinExponent - (BitOperations.TrailingZeroCount(x.TrailingSignificand) - float.BiasedExponentLength); + return float.MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - float.BiasedExponentLength); } return x.Exponent; diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/RandomAccess/WriteGatherAsync.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/RandomAccess/WriteGatherAsync.cs index abf945b2d46bcc..8cf7d5233c6d3a 100644 --- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/RandomAccess/WriteGatherAsync.cs +++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/RandomAccess/WriteGatherAsync.cs @@ -1,17 +1,20 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; +using Microsoft.DotNet.XUnitExtensions; using Microsoft.Win32.SafeHandles; using Xunit; namespace System.IO.Tests { [SkipOnPlatform(TestPlatforms.Browser, "async file IO is not supported on browser")] + [Collection(nameof(DisableParallelization))] // don't run in parallel, as some of these tests use a LOT of resources public class RandomAccess_WriteGatherAsync : RandomAccess_Base { protected override ValueTask MethodUnderTest(SafeFileHandle handle, byte[] bytes, long fileOffset) @@ -133,5 +136,172 @@ public async Task DuplicatedBufferDuplicatesContentAsync(FileOptions options) Assert.Equal(repeatCount, actualContent.Length); Assert.All(actualContent, actual => Assert.Equal(value, actual)); } + + [OuterLoop("It consumes a lot of resources (disk space and memory).")] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess), nameof(PlatformDetection.IsReleaseRuntime))] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, true)] + [InlineData(true, false)] + public async Task NoInt32OverflowForLargeInputs(bool asyncFile, bool asyncMethod) + { + // We need to write more than Int32.MaxValue bytes to the disk to reproduce the problem. + // To reduce the number of used memory, we allocate only one write buffer and simply repeat it multiple times. + // For reading, we need unique buffers to ensure that all of them are getting populated with the right data. + + const int BufferCount = 1002; + const int BufferSize = int.MaxValue / 1000; + const long FileSize = (long)BufferCount * BufferSize; + string filePath = GetTestFilePath(); + + FileOptions options = asyncFile ? FileOptions.Asynchronous : FileOptions.None; // we need to test both code paths + options |= FileOptions.DeleteOnClose; + + SafeFileHandle? sfh; + try + { + sfh = File.OpenHandle(filePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None, options, preallocationSize: FileSize); + } + catch (IOException) + { + throw new SkipTestException("Not enough disk space."); + } + + using (sfh) + { + ReadOnlyMemory writeBuffer = RandomNumberGenerator.GetBytes(BufferSize); + List> writeBuffers = Enumerable.Repeat(writeBuffer, BufferCount).ToList(); + + List memoryManagers = new List(BufferCount); + List> readBuffers = new List>(BufferCount); + + try + { + try + { + for (int i = 0; i < BufferCount; i++) + { + // We are using native memory here to get OOM as soon as possible. + NativeMemoryManager nativeMemoryManager = new(BufferSize); + memoryManagers.Add(nativeMemoryManager); + readBuffers.Add(nativeMemoryManager.Memory); + } + } + catch (OutOfMemoryException) + { + throw new SkipTestException("Not enough memory."); + } + + await Verify(asyncMethod, FileSize, sfh, writeBuffer, writeBuffers, readBuffers); + } + finally + { + foreach (IDisposable memoryManager in memoryManagers) + { + memoryManager.Dispose(); + } + } + } + + static async Task Verify(bool asyncMethod, long FileSize, SafeFileHandle sfh, ReadOnlyMemory writeBuffer, List> writeBuffers, List> readBuffers) + { + if (asyncMethod) + { + await RandomAccess.WriteAsync(sfh, writeBuffers, 0); + } + else + { + RandomAccess.Write(sfh, writeBuffers, 0); + } + + Assert.Equal(FileSize, RandomAccess.GetLength(sfh)); + + long fileOffset = 0; + while (fileOffset < FileSize) + { + long bytesRead = asyncMethod + ? await RandomAccess.ReadAsync(sfh, readBuffers, fileOffset) + : RandomAccess.Read(sfh, readBuffers, fileOffset); + + Assert.InRange(bytesRead, 0, FileSize); + + while (bytesRead > 0) + { + Memory readBuffer = readBuffers[0]; + if (bytesRead >= readBuffer.Length) + { + AssertExtensions.SequenceEqual(writeBuffer.Span, readBuffer.Span); + + bytesRead -= readBuffer.Length; + fileOffset += readBuffer.Length; + + readBuffers.RemoveAt(0); + } + else + { + // A read has finished somewhere in the middle of one of the read buffers. + // Example: buffer had 30 bytes and only 10 were read. + // We don't read the missing part, but try to read the whole buffer again. + // It's not optimal from performance perspective, but it keeps the test logic simple. + break; + } + } + } + } + } + + [Theory] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, true)] + [InlineData(true, false)] + public async Task IovLimitsAreRespected(bool asyncFile, bool asyncMethod) + { + // We need to write and read more than IOV_MAX buffers at a time. + // IOV_MAX typical value is 1024. + const int BufferCount = 1026; + const int BufferSize = 1; // the less resources we use, the better + const int FileSize = BufferCount * BufferSize; + + ReadOnlyMemory writeBuffer = RandomNumberGenerator.GetBytes(BufferSize); + ReadOnlyMemory[] writeBuffers = Enumerable.Repeat(writeBuffer, BufferCount).ToArray(); + Memory[] readBuffers = Enumerable.Range(0, BufferCount).Select(_ => new byte[BufferSize].AsMemory()).ToArray(); + + FileOptions options = asyncFile ? FileOptions.Asynchronous : FileOptions.None; // we need to test both code paths + options |= FileOptions.DeleteOnClose; + + using SafeFileHandle sfh = File.OpenHandle(GetTestFilePath(), FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None, options); + + if (asyncMethod) + { + await RandomAccess.WriteAsync(sfh, writeBuffers, 0); + } + else + { + RandomAccess.Write(sfh, writeBuffers, 0); + } + + Assert.Equal(FileSize, RandomAccess.GetLength(sfh)); + + long fileOffset = 0; + int bufferOffset = 0; + while (fileOffset < FileSize) + { + ArraySegment> left = new ArraySegment>(readBuffers, bufferOffset, readBuffers.Length - bufferOffset); + + long bytesRead = asyncMethod + ? await RandomAccess.ReadAsync(sfh, left, fileOffset) + : RandomAccess.Read(sfh, left, fileOffset); + + fileOffset += bytesRead; + // The following operation is correct only because the BufferSize is 1. + bufferOffset += (int)bytesRead; + } + + for (int i = 0; i < BufferCount; ++i) + { + Assert.Equal(writeBuffers[i], readBuffers[i]); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs index 2550b706b41063..316650591fd64f 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs @@ -2287,6 +2287,7 @@ public static void FusedMultiplyAdd(double x, double y, double z, double expecte [InlineData( 0.561760, -1)] [InlineData( 0.774152, -1)] [InlineData( -0.678764, -1)] + [InlineData( 1e-308, -1024)] public static void ILogB(double value, int expectedResult) { Assert.Equal(expectedResult, Math.ILogB(value)); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs index 1363a2b407b016..e5d2b224734b13 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs @@ -742,6 +742,7 @@ public static void IEEERemainder() [InlineData(0.561760f, -1)] [InlineData(0.774152f, -1)] [InlineData(-0.678764f, -1)] + [InlineData(1e-44f, -147)] public static void ILogB(float value, int expectedResult) { Assert.Equal(expectedResult, MathF.ILogB(value)); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/TimeZoneInfoTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/TimeZoneInfoTests.cs index 2ff5d459fdb50d..6380157b7b23f1 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/TimeZoneInfoTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/TimeZoneInfoTests.cs @@ -89,7 +89,7 @@ public static void Names() // Name abbreviations, if available, are used instead public static IEnumerable Platform_TimeZoneNamesTestData() { - if (PlatformDetection.IsBrowser || (PlatformDetection.IsNotHybridGlobalizationOnApplePlatform && (PlatformDetection.IsMacCatalyst || PlatformDetection.IsiOS || PlatformDetection.IstvOS))) + if (PlatformDetection.IsBrowser) return new TheoryData { { TimeZoneInfo.FindSystemTimeZoneById(s_strPacific), "(UTC-08:00) America/Los_Angeles", null, "PST", "PDT", null }, @@ -100,7 +100,7 @@ public static IEnumerable Platform_TimeZoneNamesTestData() { s_NewfoundlandTz, "(UTC-03:30) America/St_Johns", null, "NST", "NDT", null }, { s_catamarcaTz, "(UTC-03:00) America/Argentina/Catamarca", null, "-03", "-02", null } }; - else if (PlatformDetection.IsHybridGlobalizationOnApplePlatform && (PlatformDetection.IsMacCatalyst || PlatformDetection.IsiOS || PlatformDetection.IstvOS)) + else if (PlatformDetection.IsAppleMobile) return new TheoryData { { TimeZoneInfo.FindSystemTimeZoneById(s_strPacific), "(UTC-08:00) America/Los_Angeles", null, "Pacific Standard Time", "Pacific Daylight Time", "Pacific Summer Time" }, @@ -125,7 +125,7 @@ public static IEnumerable Platform_TimeZoneNamesTestData() return new TheoryData { { TimeZoneInfo.FindSystemTimeZoneById(s_strPacific), "(UTC-08:00) Pacific Time (Los Angeles)", null, "Pacific Standard Time", "Pacific Daylight Time", "Pacific Summer Time" }, - { TimeZoneInfo.FindSystemTimeZoneById(s_strSydney), "(UTC+10:00) Eastern Australia Time (Sydney)", null, "Australian Eastern Standard Time", "Australian Eastern Daylight Time", null }, + { TimeZoneInfo.FindSystemTimeZoneById(s_strSydney), "(UTC+10:00) Eastern Australia Time (Sydney)", "(UTC+10:00) Australian Eastern Time (Sydney)", "Australian Eastern Standard Time", "Australian Eastern Daylight Time", null }, { TimeZoneInfo.FindSystemTimeZoneById(s_strPerth), "(UTC+08:00) Australian Western Standard Time (Perth)", null, "Australian Western Standard Time", "Australian Western Daylight Time", null }, { TimeZoneInfo.FindSystemTimeZoneById(s_strIran), "(UTC+03:30) Iran Time", "(UTC+03:30) Iran Standard Time (Tehran)", "Iran Standard Time", "Iran Daylight Time", "Iran Summer Time" }, { s_NewfoundlandTz, "(UTC-03:30) Newfoundland Time (St. John’s)", null, "Newfoundland Standard Time", "Newfoundland Daylight Time", null }, @@ -3171,6 +3171,7 @@ public static void AdjustmentRuleBaseUtcOffsetDeltaTest() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/64111", TestPlatforms.Linux)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/117731", TestPlatforms.Android)] public static void NoBackwardTimeZones() { if (OperatingSystem.IsAndroid() && !OperatingSystem.IsAndroidVersionAtLeast(26)) diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.cs index de1d0b55bf2f62..34ce9021b14b51 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.cs @@ -344,6 +344,8 @@ public static void BuildChainCustomTrustStore( chainTest.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; chainTest.ChainPolicy.ExtraStore.Add(issuerCert); + X509ChainStatusFlags allowedFlags = X509ChainStatusFlags.NoError; + switch (testArguments) { case BuildChainCustomTrustStoreTestArguments.TrustedIntermediateUntrustedRoot: @@ -361,6 +363,9 @@ public static void BuildChainCustomTrustStore( chainHolder.DisposeChainElements(); chainTest.ChainPolicy.CustomTrustStore.Remove(rootCert); chainTest.ChainPolicy.TrustMode = X509ChainTrustMode.System; + chainTest.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; + chainTest.ChainPolicy.ExtraStore.Add(rootCert); + allowedFlags |= X509ChainStatusFlags.UntrustedRoot; break; default: throw new InvalidDataException(); @@ -368,7 +373,11 @@ public static void BuildChainCustomTrustStore( Assert.Equal(chainBuildsSuccessfully, chainTest.Build(endCert)); Assert.Equal(3, chainTest.ChainElements.Count); - Assert.Equal(chainFlags, chainTest.AllStatusFlags()); + + X509ChainStatusFlags actualFlags = chainTest.AllStatusFlags(); + actualFlags &= ~allowedFlags; + + Assert.Equal(chainFlags, actualFlags); } } diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index fe952d04c25a41..8ff1295057db10 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -906,9 +906,13 @@ compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int guint32 field_iter = 1; guint32 field_instance_offset = field_offset; + int field_size = 0; // If struct has InlineArray attribute, iterate `length` times to set a bitmap - if (m_class_is_inlinearray (p)) + if (m_class_is_inlinearray (p)) { + int align; field_iter = m_class_inlinearray_value (p); + field_size = mono_type_size (field->type, &align); + } if (field_iter > 500) g_warning ("Large number of iterations detected when creating a GC bitmap, might affect performance."); @@ -973,7 +977,7 @@ compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int break; } - field_instance_offset += field_offset; + field_instance_offset += field_size; field_iter--; } } diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs index 46c8f2ce132870..e2406c873b986c 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs @@ -46,11 +46,11 @@ public void InitBlazorWasmProjectDir(string id, string targetFramework = Default public string CreateBlazorWasmTemplateProject(string id) { InitBlazorWasmProjectDir(id); - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("new blazorwasm") - .EnsureSuccessful(); + using DotNetCommand dotnetCommand = new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false); + CommandResult result = dotnetCommand.WithWorkingDirectory(_projectDir!) + .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .ExecuteWithCapturedOutput("new blazorwasm") + .EnsureSuccessful(); return Path.Combine(_projectDir!, $"{id}.csproj"); } @@ -195,12 +195,12 @@ public async Task BlazorRunTest(string runArgs, runOptions.ServerEnvironment?.ToList().ForEach( kv => s_buildEnv.EnvVars[kv.Key] = kv.Value); - using var runCommand = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(workingDirectory); + using RunCommand runCommand = new RunCommand(s_buildEnv, _testOutput); + ToolCommand cmd = runCommand.WithWorkingDirectory(workingDirectory); await using var runner = new BrowserRunner(_testOutput); var page = await runner.RunAsync( - runCommand, + cmd, runArgs, onConsoleMessage: OnConsoleMessage, onServerMessage: runOptions.OnServerMessage, diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/CleanTests.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/CleanTests.cs index db3c7da2243ac0..122aa274962373 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/CleanTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/CleanTests.cs @@ -40,11 +40,11 @@ public void Blazor_BuildThenClean_NativeRelinking(string config) Assert.True(Directory.Exists(relinkDir), $"Could not find expected relink dir: {relinkDir}"); string logPath = Path.Combine(s_buildEnv.LogRootPath, id, $"{id}-clean.binlog"); - new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("build", "-t:Clean", $"-p:Configuration={config}", $"-bl:{logPath}") - .EnsureSuccessful(); + using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput) + .WithWorkingDirectory(_projectDir!); + cmd.WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .ExecuteWithCapturedOutput("build", "-t:Clean", $"-p:Configuration={config}", $"-bl:{logPath}") + .EnsureSuccessful(); AssertEmptyOrNonExistentDirectory(relinkDir); } @@ -88,9 +88,9 @@ private void Blazor_BuildNativeNonNative_ThenCleanTest(string config, bool first Assert.True(Directory.Exists(relinkDir), $"Could not find expected relink dir: {relinkDir}"); string logPath = Path.Combine(s_buildEnv.LogRootPath, id, $"{id}-clean.binlog"); - new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _projectDir!) + using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput) + .WithWorkingDirectory(_projectDir!); + cmd.WithEnvironmentVariable("NUGET_PACKAGES", _projectDir!) .ExecuteWithCapturedOutput("build", "-t:Clean", $"-p:Configuration={config}", $"-bl:{logPath}") .EnsureSuccessful(); diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests2.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests2.cs index 23c002b454d91c..00a47837523ce4 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests2.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests2.cs @@ -59,11 +59,11 @@ private CommandResult PublishForRequiresWorkloadTest(string config, string extra extraItems: extraItems); string publishLogPath = Path.Combine(s_buildEnv.LogRootPath, id, $"{id}.binlog"); - return new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("publish", - $"-bl:{publishLogPath}", - $"-p:Configuration={config}"); + using DotNetCommand cmd = new DotNetCommand(s_buildEnv, _testOutput); + return cmd.WithWorkingDirectory(_projectDir!) + .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .ExecuteWithCapturedOutput("publish", + $"-bl:{publishLogPath}", + $"-p:Configuration={config}"); } } diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs index 4d82356b103790..a7f39ce9d3341a 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs @@ -99,17 +99,16 @@ public void BugRegression_60479_WithRazorClassLib() string wasmProjectDir = Path.Combine(_projectDir!, "wasm"); string wasmProjectFile = Path.Combine(wasmProjectDir, "wasm.csproj"); Directory.CreateDirectory(wasmProjectDir); - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(wasmProjectDir) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("new blazorwasm") - .EnsureSuccessful(); + using DotNetCommand cmd = new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false); + cmd.WithWorkingDirectory(wasmProjectDir) + .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .ExecuteWithCapturedOutput("new blazorwasm") + .EnsureSuccessful(); string razorProjectDir = Path.Combine(_projectDir!, "RazorClassLibrary"); Directory.CreateDirectory(razorProjectDir); - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(razorProjectDir) + cmd.WithWorkingDirectory(razorProjectDir) .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) .ExecuteWithCapturedOutput("new razorclasslib") .EnsureSuccessful(); diff --git a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs index 4ac3be17fb615e..53f25caa3a525f 100644 --- a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs @@ -164,10 +164,10 @@ public BuildTestBase(ProjectProviderBase providerBase, ITestOutputHelper output, if (buildProjectOptions.Publish && buildProjectOptions.BuildOnlyAfterPublish) commandLineArgs.Append("-p:WasmBuildOnlyAfterPublish=true"); - var cmd = new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .WithEnvironmentVariables(buildProjectOptions.ExtraBuildEnvironmentVariables); + using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput) + .WithWorkingDirectory(_projectDir!); + cmd.WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .WithEnvironmentVariables(buildProjectOptions.ExtraBuildEnvironmentVariables); if (UseWBTOverridePackTargets && s_buildEnv.IsWorkload) cmd.WithEnvironmentVariable("WBTOverrideRuntimePack", "true"); @@ -487,6 +487,7 @@ public static (int exitCode, string buildOutput) RunProcess(string path, _testOutput.WriteLine($"WorkingDirectory: {workingDir}"); StringBuilder outputBuilder = new(); object syncObj = new(); + bool isDisposed = false; var processStartInfo = new ProcessStartInfo { @@ -542,11 +543,13 @@ public static (int exitCode, string buildOutput) RunProcess(string path, using CancellationTokenSource cts = new(); cts.CancelAfter(timeoutMs ?? s_defaultPerTestTimeoutMs); - await process.WaitForExitAsync(cts.Token); - - if (cts.IsCancellationRequested) + try + { + await process.WaitForExitAsync(cts.Token); + } + catch (OperationCanceledException) { - // process didn't exit + // process didn't exit within timeout process.Kill(entireProcessTree: true); lock (syncObj) { @@ -560,6 +563,12 @@ public static (int exitCode, string buildOutput) RunProcess(string path, // https://learn.microsoft.com/dotnet/api/system.diagnostics.process.waitforexit?view=net-5.0#System_Diagnostics_Process_WaitForExit_System_Int32_ process.WaitForExit(); + // Mark as disposed before detaching handlers to prevent further TestOutput access + lock (syncObj) + { + isDisposed = true; + } + process.ErrorDataReceived -= logStdErr; process.OutputDataReceived -= logStdOut; process.CancelErrorRead(); @@ -573,7 +582,12 @@ public static (int exitCode, string buildOutput) RunProcess(string path, } catch (Exception ex) { - _testOutput.WriteLine($"-- exception -- {ex}"); + // Mark as disposed before writing to avoid potential race condition + lock (syncObj) + { + isDisposed = true; + } + TryWriteToTestOutput(_testOutput, $"-- exception -- {ex}", outputBuilder); throw; } @@ -581,9 +595,11 @@ void LogData(string label, string? message) { lock (syncObj) { + if (isDisposed) + return; if (message != null) { - _testOutput.WriteLine($"{label} {message}"); + TryWriteToTestOutput(_testOutput, $"{label} {message}", outputBuilder, label); } outputBuilder.AppendLine($"{label} {message}"); } @@ -627,6 +643,24 @@ public static string AddItemsPropertiesToProject(string projectFile, string? ext return projectFile; } + private static void TryWriteToTestOutput(ITestOutputHelper testOutput, string message, StringBuilder? outputBuffer = null, string? warningPrefix = null) + { + try + { + testOutput.WriteLine(message); + } + catch (InvalidOperationException) + { + // Test context has expired, but we still want to capture output in buffer + // for potential debugging purposes + if (outputBuffer != null) + { + string prefix = warningPrefix ?? ""; + outputBuffer.AppendLine($"{prefix}[WARNING: Test context expired, subsequent output may be incomplete]"); + } + } + } + public void Dispose() { if (_projectDir != null && _enablePerTestCleanup) diff --git a/src/mono/wasm/Wasm.Build.Tests/Common/RunHost.cs b/src/mono/wasm/Wasm.Build.Tests/Common/RunHost.cs index 137316ebb546c5..1208060464a9e7 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Common/RunHost.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Common/RunHost.cs @@ -15,6 +15,6 @@ public enum RunHost Firefox = 8, NodeJS = 16, - All = V8 | NodeJS | Chrome//| Firefox//Safari + All = V8 | Chrome//| NodeJS//Firefox//Safari } } diff --git a/src/mono/wasm/Wasm.Build.Tests/Common/ToolCommand.cs b/src/mono/wasm/Wasm.Build.Tests/Common/ToolCommand.cs index c8289da17350d6..4c7531a889007d 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Common/ToolCommand.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Common/ToolCommand.cs @@ -13,6 +13,8 @@ namespace Wasm.Build.Tests { public class ToolCommand : IDisposable { + private bool isDisposed = false; + private readonly object _lock = new object(); private string _label; protected ITestOutputHelper _testOutput; @@ -93,41 +95,45 @@ public virtual CommandResult ExecuteWithCapturedOutput(params string[] args) public virtual void Dispose() { - if (CurrentProcess is not null && !CurrentProcess.HasExited) + lock (_lock) { - CurrentProcess.Kill(entireProcessTree: true); - CurrentProcess.Dispose(); - CurrentProcess = null; + if (isDisposed) + return; + if (CurrentProcess is not null && !CurrentProcess.HasExited) + { + CurrentProcess.Kill(entireProcessTree: true); + CurrentProcess.Dispose(); + CurrentProcess = null; + } + isDisposed = true; } } protected virtual string GetFullArgs(params string[] args) => string.Join(" ", args); - private async Task ExecuteAsyncInternal(string executable, string args) { var output = new List(); CurrentProcess = CreateProcess(executable, args); - DataReceivedEventHandler errorHandler = (s, e) => + + void HandleDataReceived(DataReceivedEventArgs e, DataReceivedEventHandler? additionalHandler) { - if (e.Data == null) + if (e.Data == null || isDisposed) return; - string msg = $"[{_label}] {e.Data}"; - output.Add(msg); - _testOutput.WriteLine(msg); - ErrorDataReceived?.Invoke(s, e); - }; + lock (_lock) + { + if (e.Data == null || isDisposed) + return; - DataReceivedEventHandler outputHandler = (s, e) => - { - if (e.Data == null) - return; + string msg = $"[{_label}] {e.Data}"; + output.Add(msg); + TryWriteToTestOutput(msg, output); + additionalHandler?.Invoke(this, e); + } + } - string msg = $"[{_label}] {e.Data}"; - output.Add(msg); - _testOutput.WriteLine(msg); - OutputDataReceived?.Invoke(s, e); - }; + DataReceivedEventHandler errorHandler = (s, e) => HandleDataReceived(e, ErrorDataReceived); + DataReceivedEventHandler outputHandler = (s, e) => HandleDataReceived(e, OutputDataReceived); CurrentProcess.ErrorDataReceived += errorHandler; CurrentProcess.OutputDataReceived += outputHandler; @@ -148,6 +154,20 @@ private async Task ExecuteAsyncInternal(string executable, string string.Join(System.Environment.NewLine, output)); } + private void TryWriteToTestOutput(string message, List output) + { + try + { + _testOutput.WriteLine(message); + } + catch (InvalidOperationException) + { + // Test context may have expired, continue without logging to test output + // Add a marker to the output buffer so we know this happened + output.Add($"[{_label}] [WARNING: Test context expired, subsequent output may be incomplete]"); + } + } + private Process CreateProcess(string executable, string args) { var psi = new ProcessStartInfo diff --git a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs index dbaeba4bb1165b..6381b1ac41b944 100644 --- a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs @@ -35,8 +35,8 @@ public IcuShardingTests(ITestOutputHelper output, SharedBuildPerTestClassFixture .UnwrapItemsAsArrays(); [Theory] - [MemberData(nameof(IcuExpectedAndMissingCustomShardTestData), parameters: new object[] { false, RunHost.NodeJS | RunHost.Chrome })] - [MemberData(nameof(IcuExpectedAndMissingCustomShardTestData), parameters: new object[] { true, RunHost.NodeJS | RunHost.Chrome })] + [MemberData(nameof(IcuExpectedAndMissingCustomShardTestData), parameters: new object[] { false, RunHost.Chrome })] + [MemberData(nameof(IcuExpectedAndMissingCustomShardTestData), parameters: new object[] { true, RunHost.Chrome })] public void CustomIcuShard(BuildArgs buildArgs, string shardName, string testedLocales, bool onlyPredefinedCultures, RunHost host, string id) => TestIcuShards(buildArgs, shardName, testedLocales, host, id, onlyPredefinedCultures); diff --git a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs index c04d5c1114dc00..221850f27a188d 100644 --- a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs +++ b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs @@ -32,8 +32,8 @@ public IcuShardingTests2(ITestOutputHelper output, SharedBuildPerTestClassFixtur [Theory] - [MemberData(nameof(IcuExpectedAndMissingShardFromRuntimePackTestData), parameters: new object[] { false, RunHost.NodeJS | RunHost.Chrome })] - [MemberData(nameof(IcuExpectedAndMissingShardFromRuntimePackTestData), parameters: new object[] { true, RunHost.NodeJS | RunHost.Chrome })] + [MemberData(nameof(IcuExpectedAndMissingShardFromRuntimePackTestData), parameters: new object[] { false, RunHost.Chrome })] + [MemberData(nameof(IcuExpectedAndMissingShardFromRuntimePackTestData), parameters: new object[] { true, RunHost.Chrome })] public void DefaultAvailableIcuShardsFromRuntimePack(BuildArgs buildArgs, string shardName, string testedLocales, RunHost host, string id) => TestIcuShards(buildArgs, shardName, testedLocales, host, id); } \ No newline at end of file diff --git a/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs b/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs index 0f58d24ac9f3d0..5137de3c096a2b 100644 --- a/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs @@ -37,8 +37,8 @@ public IcuTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildCo .UnwrapItemsAsArrays(); [Theory] - [MemberData(nameof(FullIcuWithInvariantTestData), parameters: new object[] { false, RunHost.NodeJS | RunHost.Chrome })] - [MemberData(nameof(FullIcuWithInvariantTestData), parameters: new object[] { true, RunHost.NodeJS | RunHost.Chrome })] + [MemberData(nameof(FullIcuWithInvariantTestData), parameters: new object[] { false, RunHost.Chrome })] + [MemberData(nameof(FullIcuWithInvariantTestData), parameters: new object[] { true, RunHost.Chrome })] public void FullIcuFromRuntimePackWithInvariant(BuildArgs buildArgs, bool invariant, bool fullIcu, string testedLocales, RunHost host, string id) { string projectName = $"fullIcuInvariant_{fullIcu}_{invariant}_{buildArgs.Config}_{buildArgs.AOT}"; @@ -60,8 +60,8 @@ public void FullIcuFromRuntimePackWithInvariant(BuildArgs buildArgs, bool invari } [Theory] - [MemberData(nameof(FullIcuWithICustomIcuTestData), parameters: new object[] { false, RunHost.NodeJS | RunHost.Chrome })] - [MemberData(nameof(FullIcuWithICustomIcuTestData), parameters: new object[] { true, RunHost.NodeJS | RunHost.Chrome })] + [MemberData(nameof(FullIcuWithICustomIcuTestData), parameters: new object[] { false, RunHost.Chrome })] + [MemberData(nameof(FullIcuWithICustomIcuTestData), parameters: new object[] { true, RunHost.Chrome })] public void FullIcuFromRuntimePackWithCustomIcu(BuildArgs buildArgs, bool fullIcu, RunHost host, string id) { string projectName = $"fullIcuCustom_{fullIcu}_{buildArgs.Config}_{buildArgs.AOT}"; diff --git a/src/mono/wasm/Wasm.Build.Tests/MainWithArgsTests.cs b/src/mono/wasm/Wasm.Build.Tests/MainWithArgsTests.cs index fc6099fb727987..c931fe0beeb6de 100644 --- a/src/mono/wasm/Wasm.Build.Tests/MainWithArgsTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/MainWithArgsTests.cs @@ -38,13 +38,13 @@ public static async System.Threading.Tasks.Task Main(string[] args) }", buildArgs, args, host, id); - [Theory] - [MemberData(nameof(MainWithArgsTestData), parameters: new object[] { /*aot*/ false, RunHost.NodeJS })] - //[MemberData(nameof(MainWithArgsTestData), parameters: new object[] { /*aot*/ true, RunHost.All })] - public void TopLevelWithArgs(BuildArgs buildArgs, string[] args, RunHost host, string id) - => TestMainWithArgs("top_level_args", - @"##CODE## return await System.Threading.Tasks.Task.FromResult(42 + count);", - buildArgs, args, host, id); + // [Theory] + // [MemberData(nameof(MainWithArgsTestData), parameters: new object[] { /*aot*/ false, RunHost.NodeJS })] + // //[MemberData(nameof(MainWithArgsTestData), parameters: new object[] { /*aot*/ true, RunHost.All })] + // public void TopLevelWithArgs(BuildArgs buildArgs, string[] args, RunHost host, string id) + // => TestMainWithArgs("top_level_args", + // @"##CODE## return await System.Threading.Tasks.Task.FromResult(42 + count);", + // buildArgs, args, host, id); [Theory] [MemberData(nameof(MainWithArgsTestData), parameters: new object[] { /*aot*/ false, RunHost.All })] diff --git a/src/mono/wasm/Wasm.Build.Tests/NonWasmTemplateBuildTests.cs b/src/mono/wasm/Wasm.Build.Tests/NonWasmTemplateBuildTests.cs index 90ce88af865f72..e85a212f83d49f 100644 --- a/src/mono/wasm/Wasm.Build.Tests/NonWasmTemplateBuildTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/NonWasmTemplateBuildTests.cs @@ -112,22 +112,18 @@ private void NonWasmConsoleBuild(string config, File.WriteAllText(Path.Combine(_projectDir, "Directory.Build.props"), ""); File.WriteAllText(Path.Combine(_projectDir, "Directory.Build.targets"), directoryBuildTargets); - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput("new console --no-restore") - .EnsureSuccessful(); + using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) + .WithWorkingDirectory(_projectDir!); + cmd.ExecuteWithCapturedOutput("new console --no-restore") + .EnsureSuccessful(); - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"build -restore -c {config} -bl:{Path.Combine(s_buildEnv.LogRootPath, $"{id}.binlog")} {extraBuildArgs} -f {targetFramework}") - .EnsureSuccessful(); + cmd.ExecuteWithCapturedOutput($"build -restore -c {config} -bl:{Path.Combine(s_buildEnv.LogRootPath, $"{id}.binlog")} {extraBuildArgs} -f {targetFramework}") + .EnsureSuccessful(); if (shouldRun) { - var result = new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"run -c {config} -f {targetFramework} --no-build") - .EnsureSuccessful(); + CommandResult result = cmd.ExecuteWithCapturedOutput($"run -c {config} -f {targetFramework} --no-build") + .EnsureSuccessful(); Assert.Contains("Hello, World!", result.Output); } diff --git a/src/mono/wasm/Wasm.Build.Tests/Templates/NativeBuildTests.cs b/src/mono/wasm/Wasm.Build.Tests/Templates/NativeBuildTests.cs index 37f9b6aa46ca25..5a72a3da5a7713 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Templates/NativeBuildTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Templates/NativeBuildTests.cs @@ -45,10 +45,10 @@ public void BuildWithUndefinedNativeSymbol(bool allowUndefined) File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), code); File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "native-libs", "undefined-symbol.c"), Path.Combine(_projectDir!, "undefined_xyz.c")); - CommandResult result = new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("build", "-c Release"); + using DotNetCommand cmd = new DotNetCommand(s_buildEnv, _testOutput); + CommandResult result = cmd.WithWorkingDirectory(_projectDir!) + .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .ExecuteWithCapturedOutput("build", "-c Release"); if (allowUndefined) { @@ -61,41 +61,5 @@ public void BuildWithUndefinedNativeSymbol(bool allowUndefined) Assert.Contains("Use '-p:WasmAllowUndefinedSymbols=true' to allow undefined symbols", result.Output); } } - - [Theory] - [InlineData("Debug")] - [InlineData("Release")] - public void ProjectWithDllImportsRequiringMarshalIlGen_ArrayTypeParameter(string config) - { - string id = $"dllimport_incompatible_{GetRandomId()}"; - string projectPath = CreateWasmTemplateProject(id, template: "wasmconsole"); - - string nativeSourceFilename = "incompatible_type.c"; - string nativeCode = "void call_needing_marhsal_ilgen(void *x) {}"; - File.WriteAllText(path: Path.Combine(_projectDir!, nativeSourceFilename), nativeCode); - - AddItemsPropertiesToProject( - projectPath, - extraItems: "" - ); - - File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "marshal_ilgen_test.cs"), - Path.Combine(_projectDir!, "Program.cs"), - overwrite: true); - - CommandResult result = new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("build", $"-c {config} -bl"); - - Assert.True(result.ExitCode == 0, "Expected build to succeed"); - - CommandResult res = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {config}") - .EnsureSuccessful(); - Assert.Contains("Hello, Console!", res.Output); - Assert.Contains("Hello, World! Greetings from node version", res.Output); - } } } diff --git a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs index b32b95debd879f..64c7a954325ea3 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs @@ -167,117 +167,9 @@ public void BrowserBuildThenPublish(string config) UseCache: false)); } - [Theory] - [InlineData("Debug")] - [InlineData("Release")] - public void ConsoleBuildThenPublish(string config) - { - string id = $"{config}_{GetRandomId()}"; - string projectFile = CreateWasmTemplateProject(id, "wasmconsole"); - string projectName = Path.GetFileNameWithoutExtension(projectFile); - - UpdateConsoleMainJs(); - - var buildArgs = new BuildArgs(projectName, config, false, id, null); - buildArgs = ExpandBuildArgs(buildArgs); - - BuildTemplateProject(buildArgs, - id: id, - new BuildProjectOptions( - DotnetWasmFromRuntimePack: true, - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: false, - TargetFramework: BuildTestBase.DefaultTargetFramework, - IsBrowserProject: false - )); - - CommandResult res = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {config}") - .EnsureSuccessful(); - Assert.Contains("Hello, Console!", res.Output); - - if (!_buildContext.TryGetBuildFor(buildArgs, out BuildProduct? product)) - throw new XunitException($"Test bug: could not get the build product in the cache"); - - File.Move(product!.LogFile, Path.ChangeExtension(product.LogFile!, ".first.binlog")); - - _testOutput.WriteLine($"{Environment.NewLine}Publishing with no changes ..{Environment.NewLine}"); - - bool expectRelinking = config == "Release"; - BuildTemplateProject(buildArgs, - id: id, - new BuildProjectOptions( - DotnetWasmFromRuntimePack: !expectRelinking, - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: true, - TargetFramework: BuildTestBase.DefaultTargetFramework, - UseCache: false, - IsBrowserProject: false)); - } - - [Theory] - [InlineData("Debug", false)] - [InlineData("Debug", true)] - [InlineData("Release", false)] - [InlineData("Release", true)] - public void ConsoleBuildAndRunDefault(string config, bool relinking) - => ConsoleBuildAndRun(config, relinking, string.Empty, DefaultTargetFramework, addFrameworkArg: true); - - [Theory] - // [ActiveIssue("https://github.com/dotnet/runtime/issues/79313")] - // [InlineData("Debug", "-f net7.0", "net7.0")] - //[InlineData("Debug", "-f net8.0", "net8.0")] - [InlineData("Debug", "-f net9.0", "net9.0")] - public void ConsoleBuildAndRunForSpecificTFM(string config, string extraNewArgs, string expectedTFM) - => ConsoleBuildAndRun(config, false, extraNewArgs, expectedTFM, addFrameworkArg: extraNewArgs?.Length == 0); - - private void ConsoleBuildAndRun(string config, bool relinking, string extraNewArgs, string expectedTFM, bool addFrameworkArg) - { - string id = $"{config}_{GetRandomId()}"; - string projectFile = CreateWasmTemplateProject(id, "wasmconsole", extraNewArgs, addFrameworkArg: addFrameworkArg); - string projectName = Path.GetFileNameWithoutExtension(projectFile); - - UpdateConsoleProgramCs(); - UpdateConsoleMainJs(); - if (relinking) - AddItemsPropertiesToProject(projectFile, "true"); - - var buildArgs = new BuildArgs(projectName, config, false, id, null); - buildArgs = ExpandBuildArgs(buildArgs); - - BuildTemplateProject(buildArgs, - id: id, - new BuildProjectOptions( - DotnetWasmFromRuntimePack: !relinking, - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: false, - TargetFramework: expectedTFM, - IsBrowserProject: false - )); - - CommandResult res = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {config} x y z") - .EnsureExitCode(42); - - Assert.Contains("args[0] = x", res.Output); - Assert.Contains("args[1] = y", res.Output); - Assert.Contains("args[2] = z", res.Output); - } - public static TheoryData TestDataForAppBundleDir() { var data = new TheoryData(); - AddTestData(forConsole: true, runOutsideProjectDirectory: false); - AddTestData(forConsole: true, runOutsideProjectDirectory: true); - AddTestData(forConsole: false, runOutsideProjectDirectory: false); AddTestData(forConsole: false, runOutsideProjectDirectory: true); @@ -355,7 +247,7 @@ private Task ConsoleRunWithAndThenWithoutBuildAsync(string config, string extraP using var cmd = new RunCommand(s_buildEnv, _testOutput, label: id) .WithWorkingDirectory(workingDir) .WithEnvironmentVariables(s_buildEnv.EnvVars); - var res = cmd.ExecuteWithCapturedOutput(runArgs).EnsureExitCode(42); + CommandResult res = cmd.ExecuteWithCapturedOutput(runArgs).EnsureExitCode(42); Assert.Contains("args[0] = x", res.Output); Assert.Contains("args[1] = y", res.Output); @@ -370,7 +262,7 @@ private Task ConsoleRunWithAndThenWithoutBuildAsync(string config, string extraP runArgs += " x y z"; using var cmd = new RunCommand(s_buildEnv, _testOutput, label: id) .WithWorkingDirectory(workingDir); - var res = cmd.ExecuteWithCapturedOutput(runArgs).EnsureExitCode(42); + CommandResult res = cmd.ExecuteWithCapturedOutput(runArgs).EnsureExitCode(42); Assert.Contains("args[0] = x", res.Output); Assert.Contains("args[1] = y", res.Output); @@ -380,74 +272,6 @@ private Task ConsoleRunWithAndThenWithoutBuildAsync(string config, string extraP return Task.CompletedTask; } - public static TheoryData TestDataForConsolePublishAndRun() - { - var data = new TheoryData(); - data.Add("Debug", false, false); - data.Add("Debug", false, true); - data.Add("Release", false, false); // Release relinks by default - data.Add("Release", true, false); - - return data; - } - - [Theory] - [MemberData(nameof(TestDataForConsolePublishAndRun))] - public void ConsolePublishAndRun(string config, bool aot, bool relinking) - { - string id = $"{config}_{GetRandomId()}"; - string projectFile = CreateWasmTemplateProject(id, "wasmconsole"); - string projectName = Path.GetFileNameWithoutExtension(projectFile); - - UpdateConsoleProgramCs(); - UpdateConsoleMainJs(); - - if (aot) - { - // FIXME: pass envvars via the environment, once that is supported - UpdateMainJsEnvironmentVariables(("MONO_LOG_MASK", "aot"), ("MONO_LOG_LEVEL", "debug")); - AddItemsPropertiesToProject(projectFile, "true"); - } - else if (relinking) - { - AddItemsPropertiesToProject(projectFile, "true"); - } - - var buildArgs = new BuildArgs(projectName, config, aot, id, null); - buildArgs = ExpandBuildArgs(buildArgs); - - bool expectRelinking = config == "Release" || aot || relinking; - BuildTemplateProject(buildArgs, - id: id, - new BuildProjectOptions( - DotnetWasmFromRuntimePack: !expectRelinking, - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: true, - TargetFramework: BuildTestBase.DefaultTargetFramework, - UseCache: false, - IsBrowserProject: false)); - - new RunCommand(s_buildEnv, _testOutput, label: id) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput("--info") - .EnsureExitCode(0); - - string runArgs = $"run --no-silent --no-build -c {config} -v diag"; - runArgs += " x y z"; - var res = new RunCommand(s_buildEnv, _testOutput, label: id) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput(runArgs) - .EnsureExitCode(42); - - if (aot) - Assert.Contains($"AOT: image '{Path.GetFileNameWithoutExtension(projectFile)}' found", res.Output); - Assert.Contains("args[0] = x", res.Output); - Assert.Contains("args[1] = y", res.Output); - Assert.Contains("args[2] = z", res.Output); - } - public static IEnumerable BrowserBuildAndRunTestData() { yield return new object?[] { "", BuildTestBase.DefaultTargetFramework, DefaultRuntimeAssetsRelativePath }; @@ -474,10 +298,10 @@ public async Task BrowserBuildAndRun(string extraNewArgs, string targetFramework UpdateBrowserMainJs(targetFramework, runtimeAssetsRelativePath); - new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .Execute($"build -c {config} -bl:{Path.Combine(s_buildEnv.LogRootPath, $"{id}.binlog")} {(runtimeAssetsRelativePath != DefaultRuntimeAssetsRelativePath ? "-p:WasmRuntimeAssetsLocation=" + runtimeAssetsRelativePath : "")}") - .EnsureSuccessful(); + using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput) + .WithWorkingDirectory(_projectDir!); + cmd.Execute($"build -c {config} -bl:{Path.Combine(s_buildEnv.LogRootPath, $"{id}.binlog")} {(runtimeAssetsRelativePath != DefaultRuntimeAssetsRelativePath ? "-p:WasmRuntimeAssetsLocation=" + runtimeAssetsRelativePath : "")}") + .EnsureSuccessful(); using var runCommand = new RunCommand(s_buildEnv, _testOutput) .WithWorkingDirectory(_projectDir!); @@ -488,106 +312,6 @@ public async Task BrowserBuildAndRun(string extraNewArgs, string targetFramework Assert.Contains("Hello, Browser!", string.Join(Environment.NewLine, runner.OutputLines)); } - [Theory] - [InlineData("Debug", /*appendRID*/ true, /*useArtifacts*/ false)] - [InlineData("Debug", /*appendRID*/ true, /*useArtifacts*/ true)] - [InlineData("Debug", /*appendRID*/ false, /*useArtifacts*/ true)] - [InlineData("Debug", /*appendRID*/ false, /*useArtifacts*/ false)] - public void BuildAndRunForDifferentOutputPaths(string config, bool appendRID, bool useArtifacts) - { - string id = $"{config}_{GetRandomId()}"; - string projectFile = CreateWasmTemplateProject(id, "wasmconsole"); - string projectName = Path.GetFileNameWithoutExtension(projectFile); - - string extraPropertiesForDBP = ""; - if (appendRID) - extraPropertiesForDBP += "true"; - if (useArtifacts) - extraPropertiesForDBP += "true."; - - string projectDirectory = Path.GetDirectoryName(projectFile)!; - if (!string.IsNullOrEmpty(extraPropertiesForDBP)) - AddItemsPropertiesToProject(Path.Combine(projectDirectory, "Directory.Build.props"), - extraPropertiesForDBP); - - var buildOptions = new BuildProjectOptions( - DotnetWasmFromRuntimePack: true, - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: false, - TargetFramework: DefaultTargetFramework, - IsBrowserProject: false); - if (useArtifacts) - { - buildOptions = buildOptions with - { - BinFrameworkDir = Path.Combine( - projectDirectory, - "bin", - id, - $"{config.ToLower()}_{BuildEnvironment.DefaultRuntimeIdentifier}", - "AppBundle", - "_framework") - }; - } - - var buildArgs = new BuildArgs(projectName, config, false, id, null); - buildArgs = ExpandBuildArgs(buildArgs); - BuildTemplateProject(buildArgs, id: id, buildOptions); - - CommandResult res = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {config} x y z") - .EnsureSuccessful(); - } - - [Theory] - [InlineData("", true)] // Default case - [InlineData("false", false)] // the other case - public void Test_WasmStripILAfterAOT(string stripILAfterAOT, bool expectILStripping) - { - string config = "Release"; - string id = $"strip_{config}_{GetRandomId()}"; - string projectFile = CreateWasmTemplateProject(id, "wasmconsole"); - string projectName = Path.GetFileNameWithoutExtension(projectFile); - string projectDirectory = Path.GetDirectoryName(projectFile)!; - bool aot = true; - - UpdateConsoleProgramCs(); - UpdateConsoleMainJs(); - - string extraProperties = "true"; - if (!string.IsNullOrEmpty(stripILAfterAOT)) - extraProperties += $"{stripILAfterAOT}"; - AddItemsPropertiesToProject(projectFile, extraProperties); - - var buildArgs = new BuildArgs(projectName, config, aot, id, null); - buildArgs = ExpandBuildArgs(buildArgs); - - BuildTemplateProject(buildArgs, - id: id, - new BuildProjectOptions( - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: true, - TargetFramework: BuildTestBase.DefaultTargetFramework, - UseCache: false, - IsBrowserProject: false, - AssertAppBundle: false)); - - string runArgs = $"run --no-silent --no-build -c {config}"; - var res = new RunCommand(s_buildEnv, _testOutput, label: id) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput(runArgs) - .EnsureExitCode(42); - - string frameworkDir = Path.Combine(projectDirectory, "bin", config, BuildTestBase.DefaultTargetFramework, "browser-wasm", "AppBundle", "_framework"); - string objBuildDir = Path.Combine(projectDirectory, "obj", config, BuildTestBase.DefaultTargetFramework, "browser-wasm", "wasm", "for-publish"); - TestWasmStripILAfterAOTOutput(objBuildDir, frameworkDir, expectILStripping, _testOutput); - } - internal static void TestWasmStripILAfterAOTOutput(string objBuildDir, string frameworkDir, bool expectILStripping, ITestOutputHelper testOutput) { string origAssemblyDir = Path.Combine(objBuildDir, "aot-in"); diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs index 4ef606b784e45b..ea1037e27872ac 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs @@ -77,8 +77,8 @@ public async Task LoadSatelliteAssemblyFromReference() // Build the library var libraryCsprojPath = Path.GetFullPath(Path.Combine(_projectDir!, "..", "ResourceLibrary")); - new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(libraryCsprojPath) + using DotNetCommand cmd = new DotNetCommand(s_buildEnv, _testOutput); + CommandResult res = cmd.WithWorkingDirectory(libraryCsprojPath) .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) .ExecuteWithCapturedOutput("build -c Release") .EnsureSuccessful(); diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmAppBuilderDebugLevelTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmAppBuilderDebugLevelTests.cs index 83809b3c2a9a3a..bf8c3272960b36 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmAppBuilderDebugLevelTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmAppBuilderDebugLevelTests.cs @@ -35,8 +35,8 @@ protected override void SetupProject(string projectId) protected override Task RunForBuild(string configuration) { - CommandResult res = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) + using RunCommand cmd = new RunCommand(s_buildEnv, _testOutput); + CommandResult res = cmd.WithWorkingDirectory(_projectDir!) .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {configuration}"); return Task.FromResult(ProcessRunOutput(res)); @@ -61,8 +61,8 @@ protected override Task RunForPublish(string configuration) { // WasmAppBuilder does publish to the same folder as build (it overrides the output), // and thus using dotnet run work correctly for publish as well. - CommandResult res = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) + using RunCommand cmd = new RunCommand(s_buildEnv, _testOutput); + CommandResult res = cmd.WithWorkingDirectory(_projectDir!) .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {configuration}"); return Task.FromResult(ProcessRunOutput(res)); diff --git a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs index 894097fed554b6..3ea5078b4da3e2 100644 --- a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs @@ -43,8 +43,8 @@ public string CreateWasmTemplateProject(string id, string template = "wasmbrowse if (addFrameworkArg) extraArgs += $" -f {DefaultTargetFramework}"; - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(_projectDir!) + using DotNetCommand cmd = new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false); + CommandResult result = cmd.WithWorkingDirectory(_projectDir!) .ExecuteWithCapturedOutput($"new {template} {extraArgs}") .EnsureSuccessful(); diff --git a/src/native/corehost/apphost/standalone/hostfxr_resolver.cpp b/src/native/corehost/apphost/standalone/hostfxr_resolver.cpp index c8e5000805289a..84c726ddbf75c0 100644 --- a/src/native/corehost/apphost/standalone/hostfxr_resolver.cpp +++ b/src/native/corehost/apphost/standalone/hostfxr_resolver.cpp @@ -118,7 +118,7 @@ hostfxr_resolver_t::hostfxr_resolver_t(const pal::string_t& app_root) { m_status_code = StatusCode::CoreHostLibMissingFailure; } - else if (!pal::is_path_rooted(m_fxr_path)) + else if (!pal::is_path_fully_qualified(m_fxr_path)) { // We should always be loading hostfxr from an absolute path m_status_code = StatusCode::CoreHostLibMissingFailure; diff --git a/src/native/corehost/corehost.cpp b/src/native/corehost/corehost.cpp index c233a52237a9fb..c359c30fd7dd89 100644 --- a/src/native/corehost/corehost.cpp +++ b/src/native/corehost/corehost.cpp @@ -200,6 +200,7 @@ int exe_start(const int argc, const pal::char_t* argv[]) int rc = fxr.status_code(); if (rc != StatusCode::Success) { + trace::error(_X("Failed to resolve %s [%s]. Error code: 0x%x"), LIBFXR_NAME, fxr.fxr_path().empty() ? _X("not found") : fxr.fxr_path().c_str(), rc); return rc; } diff --git a/src/native/corehost/fxr/standalone/hostpolicy_resolver.cpp b/src/native/corehost/fxr/standalone/hostpolicy_resolver.cpp index 6092fea3cd8d9f..ff68220193d47b 100644 --- a/src/native/corehost/fxr/standalone/hostpolicy_resolver.cpp +++ b/src/native/corehost/fxr/standalone/hostpolicy_resolver.cpp @@ -181,7 +181,7 @@ int hostpolicy_resolver::load( } // We should always be loading hostpolicy from an absolute path - if (!pal::is_path_rooted(host_path)) + if (!pal::is_path_fully_qualified(host_path)) return StatusCode::CoreHostLibMissingFailure; // Load library diff --git a/src/native/corehost/fxr_resolver.h b/src/native/corehost/fxr_resolver.h index 88fc9f8781efdd..4764783b2afc7f 100644 --- a/src/native/corehost/fxr_resolver.h +++ b/src/native/corehost/fxr_resolver.h @@ -56,7 +56,7 @@ int load_fxr_and_get_delegate(hostfxr_delegate_type type, THostPathToConfigCallb } // We should always be loading hostfxr from an absolute path - if (!pal::is_path_rooted(fxr_path)) + if (!pal::is_path_fully_qualified(fxr_path)) return StatusCode::CoreHostLibMissingFailure; // Load library diff --git a/src/native/corehost/hostmisc/pal.h b/src/native/corehost/hostmisc/pal.h index bde8446cc22cdf..94166e65d6f63a 100644 --- a/src/native/corehost/hostmisc/pal.h +++ b/src/native/corehost/hostmisc/pal.h @@ -335,6 +335,7 @@ namespace pal bool get_default_breadcrumb_store(string_t* recv); bool is_path_rooted(const string_t& path); + bool is_path_fully_qualified(const string_t& path); // Returns a platform-specific, user-private directory // that can be used for extracting out components of a single-file app. diff --git a/src/native/corehost/hostmisc/pal.unix.cpp b/src/native/corehost/hostmisc/pal.unix.cpp index 613902b5eaf3ac..265ad809d9af19 100644 --- a/src/native/corehost/hostmisc/pal.unix.cpp +++ b/src/native/corehost/hostmisc/pal.unix.cpp @@ -192,7 +192,7 @@ bool pal::get_loaded_library( { pal::string_t library_name_local; #if defined(TARGET_OSX) - if (!pal::is_path_rooted(library_name)) + if (!pal::is_path_fully_qualified(library_name)) library_name_local.append("@rpath/"); #endif library_name_local.append(library_name); @@ -200,7 +200,7 @@ bool pal::get_loaded_library( dll_t dll_maybe = dlopen(library_name_local.c_str(), RTLD_LAZY | RTLD_NOLOAD); if (dll_maybe == nullptr) { - if (pal::is_path_rooted(library_name)) + if (pal::is_path_fully_qualified(library_name)) return false; // dlopen on some systems only finds loaded libraries when given the full path @@ -265,6 +265,11 @@ bool pal::is_path_rooted(const pal::string_t& path) return path.front() == '/'; } +bool pal::is_path_fully_qualified(const pal::string_t& path) +{ + return is_path_rooted(path); +} + bool pal::get_default_breadcrumb_store(string_t* recv) { recv->clear(); diff --git a/src/native/corehost/hostmisc/pal.windows.cpp b/src/native/corehost/hostmisc/pal.windows.cpp index 3479c72aced1de..dacafb182899ec 100644 --- a/src/native/corehost/hostmisc/pal.windows.cpp +++ b/src/native/corehost/hostmisc/pal.windows.cpp @@ -641,9 +641,31 @@ pal::string_t pal::get_current_os_rid_platform() return ridOS; } +namespace +{ + bool is_directory_separator(pal::char_t c) + { + return c == DIR_SEPARATOR || c == L'/'; + } +} + bool pal::is_path_rooted(const string_t& path) { - return path.length() >= 2 && path[1] == L':'; + return (path.length() >= 1 && is_directory_separator(path[0])) // UNC or device paths + || (path.length() >= 2 && path[1] == L':'); // Drive letter paths +} + +bool pal::is_path_fully_qualified(const string_t& path) +{ + if (path.length() < 2) + return false; + + // Check for UNC and DOS device paths + if (is_directory_separator(path[0])) + return path[1] == L'?' || is_directory_separator(path[1]); + + // Check for drive absolute path - for example C:\. + return path.length() >= 3 && path[1] == L':' && is_directory_separator(path[2]); } // Returns true only if an env variable can be read successfully to be non-empty. diff --git a/src/native/corehost/hostpolicy/deps_resolver.cpp b/src/native/corehost/hostpolicy/deps_resolver.cpp index 0e87b791cfbfc4..88cb29ce6bffdb 100644 --- a/src/native/corehost/hostpolicy/deps_resolver.cpp +++ b/src/native/corehost/hostpolicy/deps_resolver.cpp @@ -601,7 +601,7 @@ void deps_resolver_t::init_known_entry_path(const deps_entry_t& entry, const pal return; } - assert(pal::is_path_rooted(path)); + assert(pal::is_path_fully_qualified(path)); if (m_coreclr_path.empty() && utils::ends_with(path, DIR_SEPARATOR_STR LIBCORECLR_NAME, false)) { m_coreclr_path = path; diff --git a/src/native/corehost/hostpolicy/standalone/coreclr_resolver.cpp b/src/native/corehost/hostpolicy/standalone/coreclr_resolver.cpp index 8df8e395e3f259..adcebeb9a029c5 100644 --- a/src/native/corehost/hostpolicy/standalone/coreclr_resolver.cpp +++ b/src/native/corehost/hostpolicy/standalone/coreclr_resolver.cpp @@ -14,7 +14,7 @@ bool coreclr_resolver_t::resolve_coreclr(const pal::string_t& libcoreclr_path, c append_path(&coreclr_dll_path, LIBCORECLR_NAME); // We should always be loading coreclr from an absolute path - if (!pal::is_path_rooted(coreclr_dll_path)) + if (!pal::is_path_fully_qualified(coreclr_dll_path)) return false; if (!pal::load_library(&coreclr_dll_path, &coreclr_resolver_contract.coreclr)) diff --git a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt index c8239e4ee04b4a..8cd64461b55694 100644 --- a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt +++ b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt @@ -14,6 +14,10 @@ set(NATIVECOMPRESSION_SOURCES pal_zlib.c ) +if (CLR_CMAKE_TARGET_WIN32 AND NOT CLR_CMAKE_TARGET_ARCH_I386) + list(APPEND NATIVECOMPRESSION_SOURCES "zlib_allocator_win.c") +endif() + if (NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI) if (CLR_CMAKE_USE_SYSTEM_BROTLI) diff --git a/src/native/libs/System.IO.Compression.Native/pal_zlib.c b/src/native/libs/System.IO.Compression.Native/pal_zlib.c index a04f60aa876a88..8910bab7b6d7cb 100644 --- a/src/native/libs/System.IO.Compression.Native/pal_zlib.c +++ b/src/native/libs/System.IO.Compression.Native/pal_zlib.c @@ -8,6 +8,9 @@ #ifdef _WIN32 #define c_static_assert(e) static_assert((e),"") #include "../Common/pal_utilities.h" + #if _WIN64 + #include + #endif #else #include "pal_utilities.h" #endif @@ -39,6 +42,11 @@ static int32_t Init(PAL_ZStream* stream) { z_stream* zStream = (z_stream*)calloc(1, sizeof(z_stream)); +#ifdef _WIN64 + zStream->zalloc = z_custom_calloc; + zStream->zfree = z_custom_cfree; +#endif + stream->internalState = zStream; if (zStream != NULL) diff --git a/src/native/libs/System.IO.Compression.Native/zlib_allocator.h b/src/native/libs/System.IO.Compression.Native/zlib_allocator.h new file mode 100644 index 00000000000000..cadd00bb5879c5 --- /dev/null +++ b/src/native/libs/System.IO.Compression.Native/zlib_allocator.h @@ -0,0 +1,8 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include // voidpf + +voidpf z_custom_calloc(voidpf opaque, unsigned items, unsigned size); + +void z_custom_cfree(voidpf opaque, voidpf ptr); diff --git a/src/native/libs/System.IO.Compression.Native/zlib_allocator_win.c b/src/native/libs/System.IO.Compression.Native/zlib_allocator_win.c new file mode 100644 index 00000000000000..239a46e0bfb64b --- /dev/null +++ b/src/native/libs/System.IO.Compression.Native/zlib_allocator_win.c @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include +#include +#include +#include /* _ASSERTE */ + +#include + +/* A custom allocator for zlib that uses a dedicated heap. + This provides better performance and avoids fragmentation + that can occur on Windows when using the default process heap. + */ + +// Gets the special heap we'll allocate from. +HANDLE GetZlibHeap() +{ + static HANDLE s_hPublishedHeap = NULL; + + // If already initialized, return immediately. + // We don't need a volatile read here since the publish is performed with release semantics. + if (s_hPublishedHeap != NULL) { return s_hPublishedHeap; } + + // Attempt to create a new heap. The heap will be dynamically sized. + HANDLE hNewHeap = HeapCreate(0, 0, 0); + + if (hNewHeap != NULL) + { + // We created a new heap. Attempt to publish it. + if (InterlockedCompareExchangePointer(&s_hPublishedHeap, hNewHeap, NULL) != NULL) + { + HeapDestroy(hNewHeap); // Somebody published before us. Destroy our heap. + hNewHeap = NULL; // Guard against accidental use later in the method. + } + } + else + { + // If we can't create a new heap, fall back to the process default heap. + InterlockedCompareExchangePointer(&s_hPublishedHeap, GetProcessHeap(), NULL); + } + + // Some thread - perhaps us, perhaps somebody else - published the heap. Return it. + // We don't need a volatile read here since the publish is performed with release semantics. + _ASSERTE(s_hPublishedHeap != NULL); + return s_hPublishedHeap; +} + +voidpf z_custom_calloc(opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + + SIZE_T cbRequested; + if (sizeof(items) + sizeof(size) <= sizeof(cbRequested)) + { + // multiplication can't overflow; no need for safeint + cbRequested = (SIZE_T)items * (SIZE_T)size; + } + else + { + // multiplication can overflow; go through safeint + if (FAILED(SIZETMult(items, size, &cbRequested))) { return NULL; } + } + + return HeapAlloc(GetZlibHeap(), 0, cbRequested); +} + +void z_custom_cfree(opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + if (ptr == NULL) { return; } // ok to free nullptr + + if (!HeapFree(GetZlibHeap(), 0, ptr)) { goto Fail; } + return; + +Fail: + __fastfail(FAST_FAIL_HEAP_METADATA_CORRUPTION); +} diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c index 0b6eab7e8c22bd..9bdd28616ad475 100644 --- a/src/native/libs/System.Native/pal_io.c +++ b/src/native/libs/System.Native/pal_io.c @@ -1883,6 +1883,53 @@ int32_t SystemNative_PWrite(intptr_t fd, void* buffer, int32_t bufferSize, int64 return (int32_t)count; } +#if (HAVE_PREADV || HAVE_PWRITEV) && !defined(TARGET_WASM) +static int GetAllowedVectorCount(IOVector* vectors, int32_t vectorCount) +{ +#if defined(IOV_MAX) + const int IovMax = IOV_MAX; +#else + // In theory all the platforms that we support define IOV_MAX, + // but we want to be extra safe and provde a fallback + // in case it turns out to not be true. + // 16 is low, but supported on every platform. + const int IovMax = 16; +#endif + + int allowedCount = (int)vectorCount; + + // We need to respect the limit of items that can be passed in iov. + // In case of writes, the managed code is responsible for handling incomplete writes. + // In case of reads, we simply returns the number of bytes read and it's up to the users. + if (IovMax < allowedCount) + { + allowedCount = IovMax; + } + +#if defined(TARGET_APPLE) + // For macOS preadv and pwritev can fail with EINVAL when the total length + // of all vectors overflows a 32-bit integer. + size_t totalLength = 0; + for (int i = 0; i < allowedCount; i++) + { + assert(INT_MAX >= vectors[i].Count); + + totalLength += vectors[i].Count; + + if (totalLength > INT_MAX) + { + allowedCount = i; + break; + } + } +#else + (void)vectors; +#endif + + return allowedCount; +} +#endif // (HAVE_PREADV || HAVE_PWRITEV) && !defined(TARGET_WASM) + int64_t SystemNative_PReadV(intptr_t fd, IOVector* vectors, int32_t vectorCount, int64_t fileOffset) { assert(vectors != NULL); @@ -1891,7 +1938,8 @@ int64_t SystemNative_PReadV(intptr_t fd, IOVector* vectors, int32_t vectorCount, int64_t count = 0; int fileDescriptor = ToFileDescriptor(fd); #if HAVE_PREADV && !defined(TARGET_WASM) // preadv is buggy on WASM - while ((count = preadv(fileDescriptor, (struct iovec*)vectors, (int)vectorCount, (off_t)fileOffset)) < 0 && errno == EINTR); + int allowedVectorCount = GetAllowedVectorCount(vectors, vectorCount); + while ((count = preadv(fileDescriptor, (struct iovec*)vectors, allowedVectorCount, (off_t)fileOffset)) < 0 && errno == EINTR); #else int64_t current; for (int i = 0; i < vectorCount; i++) @@ -1931,7 +1979,8 @@ int64_t SystemNative_PWriteV(intptr_t fd, IOVector* vectors, int32_t vectorCount int64_t count = 0; int fileDescriptor = ToFileDescriptor(fd); #if HAVE_PWRITEV && !defined(TARGET_WASM) // pwritev is buggy on WASM - while ((count = pwritev(fileDescriptor, (struct iovec*)vectors, (int)vectorCount, (off_t)fileOffset)) < 0 && errno == EINTR); + int allowedVectorCount = GetAllowedVectorCount(vectors, vectorCount); + while ((count = pwritev(fileDescriptor, (struct iovec*)vectors, allowedVectorCount, (off_t)fileOffset)) < 0 && errno == EINTR); #else int64_t current; for (int i = 0; i < vectorCount; i++) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 2e41771ee39634..ef88f6d4d007c4 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -417,8 +417,8 @@ bool ProcessPrimaryQueue () while (!QueueIsEmpty ()) { ProcessQueue (); - ProcessInterfaceMethods (); ProcessMarkedTypesWithInterfaces (); + ProcessInterfaceMethods (); ProcessDynamicCastableImplementationInterfaces (); ProcessPendingBodies (); DoAdditionalProcessing (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs index 6b58c1dbf0de9c..1a97ef3fa1e972 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs @@ -6,6 +6,11 @@ namespace Mono.Linker.Tests.Cases.Attributes.OnlyKeepUsed { [SetupCSharpCompilerToUse ("csc")] [SetupLinkerArgument ("--used-attrs-only", "true")] + + // Necessary to allow trimming the attribute instance from types in CoreLib. + [SetupLinkerTrimMode ("link")] + // When we allow trimming CoreLib, some well-known types expected by ILVerify are removed. + [SkipILVerify] public class MethodWithUnmanagedConstraint { public static void Main ()