diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8a4cf597d06..212c88b581d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,2 @@ # All files in the repo require review by the WPF Developers team -* @dotnet/wpf-developers +* @dotnet/wpf-developers @dotnet/dotnet-wpf-maintainers diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml index 54dd186a2ac..919e0ef67ac 100644 --- a/.github/policies/resourceManagement.yml +++ b/.github/policies/resourceManagement.yml @@ -215,23 +215,6 @@ configuration: - inPrLabel: label: ':construction: work in progress' description: In-PR label - - if: - - payloadType: Pull_Request - - targetsBranch: - branch: main - - and: - - isAction: - action: Closed - - isMerged - - not: - titleContains: - pattern: '[main] Update dependencies' - isRegex: False - then: - - addMilestone: - milestone: 7.0 Preview4 - description: Apply milestone '7.0' to PRs on the main branch - triggerOnOwnActions: true - if: - payloadType: Pull_Request - isActivitySender: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bac60f9c038..edd95ee8193 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -44,10 +44,3 @@ extends: publishAssetsImmediately: true isAssetlessBuild: true enableTelemetry: true - enableSourceIndex: true - sourceIndexParams: - condition: eq(variables['Build.SourceBranch'], 'refs/heads/main') - binlogPath: artifacts/log/Debug/x86/Build.binlog - pool: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals windows.vs2026preview.scout.amd64 diff --git a/eng/Version.Details.props b/eng/Version.Details.props index 5509fa51b2e..01c8222c118 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -8,32 +8,32 @@ This file should be imported by eng/Versions.props 15.9.20 15.9.20 - 11.0.0-beta.26229.113 - 11.0.0-beta.26229.113 - 11.0.0-beta.26229.113 - 11.0.0-beta.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 + 11.0.0-beta.26313.102 + 11.0.0-beta.26313.102 + 11.0.0-beta.26313.102 + 11.0.0-beta.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 8.0.0-beta.23409.2 8.0.0-beta.23409.2 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 - 11.0.0-preview.5.26229.113 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 + 11.0.0-preview.6.26313.102 - 11.0.0-preview.2.26262.2 + 11.0.0-preview.2.26270.1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 0f841adfce1..4010bb35346 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,78 +1,78 @@ - + - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://dev.azure.com/dnceng/internal/_git/dotnet-wpf-int - 0f3efdfc3b5fe2e9ff10112b632914d6c26b230b + a6da41e859712fcb3f2e5ed3474bdf86b4e5046a - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd https://github.com/dotnet/dotnet @@ -84,21 +84,21 @@ - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd @@ -109,9 +109,9 @@ https://github.com/dotnet/dotnet e9f665e52848a3615736c099e5631af531b66a5c - + https://github.com/dotnet/dotnet - 4c4e7f410fc876590f219fc6022b6c18d6f6a475 + 06787fc66d5364230924d00f2c5c251aeb7a31cd diff --git a/eng/Versions.props b/eng/Versions.props index 1b8b3e04b08..53e200aa057 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -7,7 +7,7 @@ 0 0 preview - 5 + 6 $(MajorVersion).$(MinorVersion).$(PatchVersion) @@ -66,7 +66,7 @@ - 3.0.13 + 4.0.5-beta @@ -81,7 +81,7 @@ - 17.14.2 + 18.7.0 1.12.3 5.2.0 diff --git a/eng/WpfArcadeSdk/tools/Packaging.targets b/eng/WpfArcadeSdk/tools/Packaging.targets index 20956d37781..a069bdc8c70 100644 --- a/eng/WpfArcadeSdk/tools/Packaging.targets +++ b/eng/WpfArcadeSdk/tools/Packaging.targets @@ -89,6 +89,21 @@ $(PreparePackageAssetsDependsOn): runtimes\win-arm64\native\ + + + runtimes\win-x86\native\ + runtimes\win-x64\native\ + runtimes\win-arm64\native\ + + + + + + + + + + + + + clang + $(ROOTFS_DIR) + + + + + + + + $(_CC_LDFLAGS.SubString(0, $(_CC_LDFLAGS.IndexOf(';')))) + <_LDFLAGS>$(_CC_LDFLAGS.SubString($([MSBuild]::Add($(_CC_LDFLAGS.IndexOf(';')), 1)))) + lld + + + diff --git a/eng/common/native/install-dependencies.sh b/eng/common/native/install-dependencies.sh index 4742177a768..aff839fa097 100755 --- a/eng/common/native/install-dependencies.sh +++ b/eng/common/native/install-dependencies.sh @@ -24,16 +24,16 @@ case "$os" in apt update apt install -y build-essential gettext locales cmake llvm clang lld lldb liblldb-dev libunwind8-dev libicu-dev liblttng-ust-dev \ - libssl-dev libkrb5-dev pigz cpio ninja-build + libssl-dev libkrb5-dev pigz cpio ninja-build file localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 elif [ "$ID" = "fedora" ] || [ "$ID" = "rhel" ] || [ "$ID" = "azurelinux" ] || [ "$ID" = "centos" ]; then pkg_mgr="$(command -v tdnf 2>/dev/null || command -v dnf)" - $pkg_mgr install -y cmake llvm lld lldb clang python curl libicu-devel openssl-devel krb5-devel lttng-ust-devel pigz cpio ninja-build + $pkg_mgr install -y cmake llvm lld lldb clang python curl libicu-devel openssl-devel krb5-devel lttng-ust-devel pigz cpio ninja-build file elif [ "$ID" = "amzn" ]; then - dnf install -y cmake llvm lld lldb clang python libicu-devel openssl-devel krb5-devel lttng-ust-devel pigz cpio ninja-build + dnf install -y cmake llvm lld lldb clang python libicu-devel openssl-devel krb5-devel lttng-ust-devel pigz cpio ninja-build file elif [ "$ID" = "alpine" ]; then - apk add build-base cmake bash curl clang llvm llvm-dev lld lldb-dev krb5-dev lttng-ust-dev icu-dev openssl-dev pigz cpio ninja + apk add build-base cmake bash curl clang llvm llvm-dev lld lldb-dev krb5-dev lttng-ust-dev icu-dev openssl-dev pigz cpio ninja file else echo "Unsupported distro. distro: $ID" exit 1 diff --git a/eng/common/pipeline-logging-functions.ps1 b/eng/common/pipeline-logging-functions.ps1 index 8e422c561e4..9f85c291708 100644 --- a/eng/common/pipeline-logging-functions.ps1 +++ b/eng/common/pipeline-logging-functions.ps1 @@ -32,7 +32,7 @@ function Write-PipelineTelemetryError { $PSBoundParameters.Remove('Category') | Out-Null if ($Force -Or ((Test-Path variable:ci) -And $ci)) { - $Message = "(NETCORE_ENGINEERING_TELEMETRY=$Category) $Message" + $Message = "($Category) $Message" } $PSBoundParameters.Remove('Message') | Out-Null $PSBoundParameters.Add('Message', $Message) diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml index 5e261f34db4..85501406a54 100644 --- a/eng/common/templates/job/job.yml +++ b/eng/common/templates/job/job.yml @@ -21,11 +21,6 @@ jobs: - ${{ each step in parameters.steps }}: - ${{ step }} - # we don't run CG in public - - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - script: echo "##vso[task.setvariable variable=skipComponentGovernanceDetection]true" - displayName: Set skipComponentGovernanceDetection variable - artifactPublishSteps: - ${{ if ne(parameters.artifacts.publish, '') }}: - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}: diff --git a/eng/common/templates/steps/vmr-sync.yml b/eng/common/templates/steps/vmr-sync.yml index eb619c50268..cdc6a28ff1f 100644 --- a/eng/common/templates/steps/vmr-sync.yml +++ b/eng/common/templates/steps/vmr-sync.yml @@ -45,11 +45,11 @@ steps: workingDirectory: ${{ parameters.vmrPath }} - script: | - ./eng/common/vmr-sync.sh \ - --vmr ${{ parameters.vmrPath }} \ - --tmp $(Agent.TempDirectory) \ - --azdev-pat '$(dn-bot-all-orgs-code-r)' \ - --ci \ + ./eng/common/vmr-sync.sh \ + --vmr ${{ parameters.vmrPath }} \ + --tmp $(Agent.TempDirectory) \ + --azdev-pat '$(AzdoToken)' \ + --ci \ --debug if [ "$?" -ne 0 ]; then @@ -67,11 +67,11 @@ steps: condition: eq(variables['Agent.OS'], 'Windows_NT') - powershell: | - ./eng/common/vmr-sync.ps1 ` - -vmr ${{ parameters.vmrPath }} ` - -tmp $(Agent.TempDirectory) ` - -azdevPat '$(dn-bot-all-orgs-code-r)' ` - -ci ` + ./eng/common/vmr-sync.ps1 ` + -vmr ${{ parameters.vmrPath }} ` + -tmp $(Agent.TempDirectory) ` + -azdevPat '$(AzdoToken)' ` + -ci ` -debugOutput if ($LASTEXITCODE -ne 0) { diff --git a/eng/common/templates/vmr-build-pr.yml b/eng/common/templates/vmr-build-pr.yml index 2f3694fa132..d24de935248 100644 --- a/eng/common/templates/vmr-build-pr.yml +++ b/eng/common/templates/vmr-build-pr.yml @@ -33,7 +33,7 @@ resources: - repository: vmr type: github name: dotnet/dotnet - endpoint: dotnet + endpoint: public ref: refs/heads/main # Set to whatever VMR branch the PR build should insert into stages: diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 65adefc7f26..fc72fe63049 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -13,12 +13,6 @@ # Set to true to output binary log from msbuild. Note that emitting binary log slows down the build. [bool]$binaryLog = if (Test-Path variable:binaryLog) { $binaryLog } else { $ci -and !$excludeCIBinarylog } -# Set to true to use the pipelines logger which will enable Azure logging output. -# https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md -# This flag is meant as a temporary opt-opt for the feature while validate it across -# our consumers. It will be deleted in the future. -[bool]$pipelinesLog = if (Test-Path variable:pipelinesLog) { $pipelinesLog } else { $ci } - # Turns on machine preparation/clean up code that changes the machine state (e.g. kills build processes). [bool]$prepareMachine = if (Test-Path variable:prepareMachine) { $prepareMachine } else { $false } @@ -596,16 +590,16 @@ function GetDefaultMSBuildEngine() { ExitWithExitCode 1 } -function GetNuGetPackageCachePath() { +function InitializeNuGetPackageCachePath() { if ($env:NUGET_PACKAGES -eq $null) { # Use local cache on CI to ensure deterministic build. - # Avoid using the http cache as workaround for https://github.com/NuGet/Home/issues/3116 # use global cache in dev builds to avoid cost of downloading packages. # For directory normalization, see also: https://github.com/NuGet/Home/issues/7968 if ($useGlobalNuGetCache) { - $env:NUGET_PACKAGES = Join-Path $env:UserProfile '.nuget\packages\' + $userProfile = if (IsWindowsPlatform) { $env:UserProfile } else { $env:HOME } + $env:NUGET_PACKAGES = [IO.Path]::Combine($userProfile, '.nuget', 'packages') + [IO.Path]::DirectorySeparatorChar } else { - $env:NUGET_PACKAGES = Join-Path $RepoRoot '.packages\' + $env:NUGET_PACKAGES = [IO.Path]::Combine($RepoRoot, '.packages') + [IO.Path]::DirectorySeparatorChar } } @@ -619,11 +613,7 @@ function GetSdkTaskProject([string]$taskName) { if (Test-Path $proj) { return $proj } - # TODO: Remove this fallback once all supported versions use the new layout. - $legacyProj = Join-Path $toolsetDir "SdkTasks\$taskName.proj" - if (Test-Path $legacyProj) { - return $legacyProj - } + throw "Unable to find $taskName.proj in toolset at: $toolsetDir" } @@ -658,8 +648,6 @@ function InitializeToolset() { return $global:_InitializeToolset } - $nugetCache = GetNuGetPackageCachePath - $toolsetVersion = Read-ArcadeSdkVersion $toolsetToolsDir = Join-Path $ToolsetDir $toolsetVersion @@ -680,7 +668,7 @@ function InitializeToolset() { ExitWithExitCode 1 } - $downloadArgs = @("package", "download", "Microsoft.DotNet.Arcade.Sdk@$toolsetVersion", "--verbosity", "minimal", "--prerelease", "--output", "$nugetCache") + $downloadArgs = @("package", "download", "Microsoft.DotNet.Arcade.Sdk@$toolsetVersion", "--verbosity", "minimal", "--prerelease", "--output", "$nugetPackageCachePath") $nugetConfig = $env:NUGET_CONFIG if (-not $nugetConfig) { # Search for any variation of nuget.config in the RepoRoot @@ -697,25 +685,16 @@ function InitializeToolset() { } DotNet @downloadArgs - $packageDir = Join-Path $nugetCache (Join-Path 'microsoft.dotnet.arcade.sdk' $toolsetVersion) + $packageDir = Join-Path $nugetPackageCachePath (Join-Path 'microsoft.dotnet.arcade.sdk' $toolsetVersion) $packageToolsetDir = Join-Path $packageDir 'toolset' - $packageToolsDir = Join-Path $packageDir 'tools' - # TODO: Remove the tools/ check once all supported versions have the toolset folder. - if (!(Test-Path $packageToolsetDir) -and !(Test-Path $packageToolsDir)) { + if (!(Test-Path $packageToolsetDir)) { Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Arcade SDK package does not contain a toolset or tools folder: $packageDir" ExitWithExitCode 3 } New-Item -ItemType Directory -Path $toolsetToolsDir -Force | Out-Null - - # Copy toolset if present at the package root (new layout), otherwise fall back to tools - if (Test-Path $packageToolsetDir) { - Copy-Item -Path "$packageToolsetDir\*" -Destination $toolsetToolsDir -Recurse -Force - } else { - # TODO: Remove this fallback once all supported versions have the toolset folder. - Copy-Item -Path "$packageToolsDir\*" -Destination $toolsetToolsDir -Recurse -Force - } + Copy-Item -Path "$packageToolsetDir\*" -Destination $toolsetToolsDir -Recurse -Force if (Test-Path $buildProjPath) { $toolsetBuildProj = $buildProjPath @@ -757,73 +736,6 @@ function Stop-Processes() { # Terminates the script if the build fails. # function MSBuild() { - if ($pipelinesLog) { - $buildTool = InitializeBuildTool - - if ($ci -and $buildTool.Tool -eq 'dotnet') { - $env:NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS = 20 - $env:NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS = 20 - Write-PipelineSetVariable -Name 'NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS' -Value '20' - Write-PipelineSetVariable -Name 'NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS' -Value '20' - } - - Enable-Nuget-EnhancedRetry - - $toolsetBuildProject = InitializeToolset - $basePath = Split-Path -parent $toolsetBuildProject - $selectedPath = Join-Path $basePath (Join-Path $buildTool.Framework 'Microsoft.DotNet.ArcadeLogging.dll') - - if (-not $selectedPath) { - Write-PipelineTelemetryError -Category 'Build' -Message "Unable to find arcade sdk logger assembly: $selectedPath" - ExitWithExitCode 1 - } - - $args += "/logger:$selectedPath" - } - - MSBuild-Core @args -} - -# -# Executes a dotnet command with arguments passed to the function. -# Terminates the script if the command fails. -# -function DotNet() { - $dotnetRoot = InitializeDotNetCli -install:$restore - $dotnetPath = Join-Path $dotnetRoot (GetExecutableFileName 'dotnet') - - $cmdArgs = "" - foreach ($arg in $args) { - if ($null -ne $arg -and $arg.Trim() -ne "") { - if ($arg.EndsWith('\')) { - $arg = $arg + "\" - } - $cmdArgs += " `"$arg`"" - } - } - - $env:ARCADE_BUILD_TOOL_COMMAND = "`"$dotnetPath`" $cmdArgs" - - $exitCode = Exec-Process $dotnetPath $cmdArgs - - if ($exitCode -ne 0) { - Write-Host "dotnet command failed with exit code $exitCode. Check errors above." -ForegroundColor Red - - if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$fromVMR) { - Write-PipelineSetResult -Result "Failed" -Message "dotnet command execution failed." - ExitWithExitCode 0 - } else { - ExitWithExitCode $exitCode - } - } -} - -# -# Executes msbuild (or 'dotnet msbuild') with arguments passed to the function. -# The arguments are automatically quoted. -# Terminates the script if the build fails. -# -function MSBuild-Core() { if ($ci) { if (!$binaryLog -and !$excludeCIBinarylog) { Write-PipelineTelemetryError -Category 'Build' -Message 'Binary log must be enabled in CI build, or explicitly opted-out from with the -excludeCIBinarylog switch.' @@ -836,8 +748,6 @@ function MSBuild-Core() { } } - Enable-Nuget-EnhancedRetry - $buildTool = InitializeBuildTool $cmdArgs = "$($buildTool.Command) /m /nologo /clp:Summary /v:$verbosity /nr:$nodeReuse /p:ContinuousIntegrationBuild=$ci" @@ -895,6 +805,40 @@ function MSBuild-Core() { } } +# +# Executes a dotnet command with arguments passed to the function. +# Terminates the script if the command fails. +# +function DotNet() { + $dotnetRoot = InitializeDotNetCli -install:$restore + $dotnetPath = Join-Path $dotnetRoot (GetExecutableFileName 'dotnet') + + $cmdArgs = "" + foreach ($arg in $args) { + if ($null -ne $arg -and $arg.Trim() -ne "") { + if ($arg.EndsWith('\')) { + $arg = $arg + "\" + } + $cmdArgs += " `"$arg`"" + } + } + + $env:ARCADE_BUILD_TOOL_COMMAND = "`"$dotnetPath`" $cmdArgs" + + $exitCode = Exec-Process $dotnetPath $cmdArgs + + if ($exitCode -ne 0) { + Write-Host "dotnet command failed with exit code $exitCode. Check errors above." -ForegroundColor Red + + if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$fromVMR) { + Write-PipelineSetResult -Result "Failed" -Message "dotnet command execution failed." + ExitWithExitCode 0 + } else { + ExitWithExitCode $exitCode + } + } +} + function GetMSBuildBinaryLogCommandLineArgument($arguments) { foreach ($argument in $arguments) { if ($argument -ne $null) { @@ -952,6 +896,12 @@ Create-Directory $ToolsetDir Create-Directory $TempDir Create-Directory $LogDir +# Direct MSBuild crash diagnostics (MSB4166 failure.txt files) to a known location +# under artifacts/log so they are captured as build artifacts in CI. +if (-not $env:MSBUILDDEBUGPATH) { + $env:MSBUILDDEBUGPATH = Join-Path $LogDir 'MsbuildDebugLogs' +} + Write-PipelineSetVariable -Name 'Artifacts' -Value $ArtifactsDir Write-PipelineSetVariable -Name 'Artifacts.Toolset' -Value $ToolsetDir Write-PipelineSetVariable -Name 'Artifacts.Log' -Value $LogDir @@ -973,19 +923,5 @@ if (!$disableConfigureToolsetImport) { } } -# -# If $ci flag is set, turn on (and log that we did) special environment variables for improved Nuget client retry logic. -# -function Enable-Nuget-EnhancedRetry() { - if ($ci) { - Write-Host "Setting NUGET enhanced retry environment variables" - $env:NUGET_ENABLE_ENHANCED_HTTP_RETRY = 'true' - $env:NUGET_ENHANCED_MAX_NETWORK_TRY_COUNT = 6 - $env:NUGET_ENHANCED_NETWORK_RETRY_DELAY_MILLISECONDS = 1000 - $env:NUGET_RETRY_HTTP_429 = 'true' - Write-PipelineSetVariable -Name 'NUGET_ENABLE_ENHANCED_HTTP_RETRY' -Value 'true' - Write-PipelineSetVariable -Name 'NUGET_ENHANCED_MAX_NETWORK_TRY_COUNT' -Value '6' - Write-PipelineSetVariable -Name 'NUGET_ENHANCED_NETWORK_RETRY_DELAY_MILLISECONDS' -Value '1000' - Write-PipelineSetVariable -Name 'NUGET_RETRY_HTTP_429' -Value 'true' - } -} +# Initialize the nuget package cache vars +$nugetPackageCachePath = InitializeNuGetPackageCachePath diff --git a/eng/common/tools.sh b/eng/common/tools.sh index 95c55ce9b4d..48cab70ebf4 100755 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -8,16 +8,6 @@ ci=${ci:-false} # Build mode source_build=${source_build:-false} -# Set to true to use the pipelines logger which will enable Azure logging output. -# https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md -# This flag is meant as a temporary opt-opt for the feature while validate it across -# our consumers. It will be deleted in the future. -if [[ "$ci" == true ]]; then - pipelines_log=${pipelines_log:-true} -else - pipelines_log=${pipelines_log:-false} -fi - # Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names. configuration=${configuration:-'Debug'} @@ -374,7 +364,7 @@ function InitializeBuildTool { _InitializeBuildToolCommand="msbuild" } -function GetNuGetPackageCachePath { +function InitializeNuGetPackageCachePath { if [[ -z ${NUGET_PACKAGES:-} ]]; then if [[ "$use_global_nuget_cache" == true ]]; then export NUGET_PACKAGES="$HOME/.nuget/packages/" @@ -384,7 +374,7 @@ function GetNuGetPackageCachePath { fi # return value - _GetNuGetPackageCachePath=$NUGET_PACKAGES + _InitializeNuGetPackageCachePath=$NUGET_PACKAGES } function InitializeNativeTools() { @@ -406,8 +396,6 @@ function InitializeToolset { return fi - GetNuGetPackageCachePath - ReadGlobalVersion "Microsoft.DotNet.Arcade.Sdk" local toolset_version=$_ReadGlobalVersion @@ -430,7 +418,7 @@ function InitializeToolset { ExitWithExitCode 2 fi - local download_args=("package" "download" "Microsoft.DotNet.Arcade.Sdk@$toolset_version" "--verbosity" "minimal" "--prerelease" "--output" "$_GetNuGetPackageCachePath") + local download_args=("package" "download" "Microsoft.DotNet.Arcade.Sdk@$toolset_version" "--verbosity" "minimal" "--prerelease" "--output" "$_InitializeNuGetPackageCachePath") local nuget_config="${NUGET_CONFIG:-}" if [[ -z "$nuget_config" ]]; then # Search for any variation of nuget.config in the RepoRoot @@ -447,23 +435,15 @@ function InitializeToolset { fi DotNet "${download_args[@]}" - local package_dir="$_GetNuGetPackageCachePath/microsoft.dotnet.arcade.sdk/$toolset_version" + local package_dir="$_InitializeNuGetPackageCachePath/microsoft.dotnet.arcade.sdk/$toolset_version" - # TODO: Remove the tools/ check once all supported versions have the toolset folder. - if [[ ! -d "$package_dir/toolset" && ! -d "$package_dir/tools" ]]; then - Write-PipelineTelemetryError -category 'InitializeToolset' "Arcade SDK package does not contain a toolset or tools folder: $package_dir" + if [[ ! -d "$package_dir/toolset" ]]; then + Write-PipelineTelemetryError -category 'InitializeToolset' "Arcade SDK package does not contain a toolset folder: $package_dir" ExitWithExitCode 3 fi mkdir -p "$toolset_tools_dir" - - # Copy toolset if present at the package root (new layout), otherwise fall back to tools - if [[ -d "$package_dir/toolset" ]]; then - cp -r "$package_dir/toolset/." "$toolset_tools_dir" - else - # TODO: Remove this fallback once all supported versions have the toolset folder. - cp -r "$package_dir/tools/." "$toolset_tools_dir" - fi + cp -r "$package_dir/toolset/." "$toolset_tools_dir" if [[ -a "$toolset_tools_dir/Build.proj" ]]; then toolset_build_proj="$toolset_tools_dir/Build.proj" @@ -511,33 +491,6 @@ function DotNet { } function MSBuild { - local args=( "$@" ) - if [[ "$pipelines_log" == true ]]; then - InitializeBuildTool - InitializeToolset - - if [[ "$ci" == true ]]; then - export NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS=20 - export NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS=20 - Write-PipelineSetVariable -name "NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS" -value "20" - Write-PipelineSetVariable -name "NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS" -value "20" - fi - - local toolset_dir="${_InitializeToolset%/*}" - local selectedPath="$toolset_dir/net/Microsoft.DotNet.ArcadeLogging.dll" - - if [[ -z "$selectedPath" ]]; then - Write-PipelineTelemetryError -category 'Build' "Unable to find arcade sdk logger assembly: $selectedPath" - ExitWithExitCode 1 - fi - - args+=( "-logger:$selectedPath" ) - fi - - MSBuild-Core "${args[@]}" -} - -function MSBuild-Core { if [[ "$ci" == true ]]; then if [[ "$binary_log" != true && "$exclude_ci_binary_log" != true ]]; then Write-PipelineTelemetryError -category 'Build' "Binary log must be enabled in CI build, or explicitly opted-out from with the -noBinaryLog switch." @@ -615,12 +568,7 @@ function GetSdkTaskProject { echo "$proj" return fi - # TODO: Remove this fallback once all supported versions use the new layout. - local legacyProj="$toolsetDir/SdkTasks/$taskName.proj" - if [[ -a "$legacyProj" ]]; then - echo "$legacyProj" - return - fi + Write-PipelineTelemetryError -category 'Build' "Unable to find $taskName.proj in toolset at: $toolsetDir" ExitWithExitCode 3 } @@ -660,6 +608,12 @@ mkdir -p "$toolset_dir" mkdir -p "$temp_dir" mkdir -p "$log_dir" +# Direct MSBuild crash diagnostics (MSB4166 failure.txt files) to a known location +# under artifacts/log so they are captured as build artifacts in CI. +if [[ -z "${MSBUILDDEBUGPATH:-}" ]]; then + export MSBUILDDEBUGPATH="$log_dir/MsbuildDebugLogs" +fi + Write-PipelineSetVariable -name "Artifacts" -value "$artifacts_dir" Write-PipelineSetVariable -name "Artifacts.Toolset" -value "$toolset_dir" Write-PipelineSetVariable -name "Artifacts.Log" -value "$log_dir" @@ -680,3 +634,6 @@ fi if [[ -n "${useInstalledDotNetCli:-}" ]]; then use_installed_dotnet_cli="$useInstalledDotNetCli" fi + +# Initialize the nuget package cache vars +InitializeNuGetPackageCachePath diff --git a/eng/restore-toolset.ps1 b/eng/restore-toolset.ps1 index dee45c85d19..3ba22914117 100644 --- a/eng/restore-toolset.ps1 +++ b/eng/restore-toolset.ps1 @@ -7,7 +7,6 @@ function InitializeWpfCustomToolset() { if (Test-Path variable:global:_WpfToolsetBuildProj) { return $global:_WpfToolsetBuildProj } - $nugetCache = GetNuGetPackageCachePath # Get all sdks listed in repo's 'global.json' file $msbuild_sdks = $GlobalJson.'msbuild-sdks' diff --git a/eng/wpfautomatedtests.yml b/eng/wpfautomatedtests.yml index 37d8215860a..3ee0e97f991 100644 --- a/eng/wpfautomatedtests.yml +++ b/eng/wpfautomatedtests.yml @@ -18,17 +18,6 @@ jobs: enablePublishBuildAssets: true enablePublishUsingPipelines: true enableTelemetry: true - enableSourceIndex: true - sourceIndexParams: - condition: eq(variables['Build.SourceBranch'], 'refs/heads/main') - binlogPath: artifacts/log/Debug/x86/Build.binlog - pool: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - name: NetCore-Public - demands: ImageOverride -equals windows.vs2022preview.amd64.Open - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals windows.vs2022preview.amd64 helixRepo: $(repoName) jobs: diff --git a/global.json b/global.json index 66115c8df01..cbd26fa3ecf 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "11.0.100-preview.4.26210.111", + "version": "11.0.100-preview.5.26227.104", "allowPrerelease": true, "rollForward": "latestFeature", "paths": [ @@ -10,7 +10,7 @@ "errorMessage": "The required .NET SDK wasn't found. Please run ./eng/common/dotnet.cmd/sh to install it." }, "tools": { - "dotnet": "11.0.100-preview.4.26210.111", + "dotnet": "11.0.100-preview.5.26227.104", "runtimes": { "dotnet/x64": [ "$(MicrosoftNETCorePlatformsVersion)" @@ -27,8 +27,8 @@ "runner": "Microsoft.Testing.Platform" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "11.0.0-beta.26229.113", - "Microsoft.DotNet.Helix.Sdk": "11.0.0-beta.26229.113", + "Microsoft.DotNet.Arcade.Sdk": "11.0.0-beta.26313.102", + "Microsoft.DotNet.Helix.Sdk": "11.0.0-beta.26313.102", "Microsoft.Build.NoTargets": "3.7.56" }, "native-tools": { diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.cs.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.cs.json index cac2a6dadb4..52e4ae3377d 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.cs.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.cs.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Cíl net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Cíl net11.0", + "symbols/Framework/choices/net11.0/description": "Cílový net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Nastaví langVersion ve vytvořeném souboru projektu.", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.de.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.de.json index ce39991d0a8..9e490caff97 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.de.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.de.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Ziel.-NET10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Ziel.-NET11.0", + "symbols/Framework/choices/net11.0/description": "Ziel net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Legt „langVersion“ in der erstellten Projektdatei fest", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.fr.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.fr.json index 7dddaf29d75..ab490c42fa3 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.fr.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.fr.json @@ -14,7 +14,7 @@ "symbols/Framework/choices/net10.0/description": "Net10.0 cible", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", "symbols/Framework/choices/net11.0/description": "Net11.0 cible", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Définit langVersion dans le fichier projet créé", "symbols/langVersion/displayName": "Version du Langage", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.pt-BR.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.pt-BR.json index f1723461c50..0919fc64594 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Net10.0 de destino", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", + "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Define a langVersion no arquivo do projeto criado", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 2a081aaf727..dea0edf828b 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -13,8 +13,8 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "目標 net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "目標 net11.0", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/description": " 目標 net11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0 ", "symbols/Framework/displayName": "架構", "symbols/langVersion/description": "在建立的專案檔中設定 langVersion", "symbols/langVersion/displayName": "語言版本", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.cs.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.cs.json index 68c5eb9f233..af739921f8e 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.cs.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.cs.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Cíl net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Cíl net11.0", + "symbols/Framework/choices/net11.0/description": "Cílový net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Nastaví langVersion ve vytvořeném souboru projektu.", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.de.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.de.json index 33348c8def9..d6d03006bf4 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.de.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.de.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Ziel.-NET10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Ziel.-NET11.0", + "symbols/Framework/choices/net11.0/description": "Ziel net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Legt „langVersion“ in der erstellten Projektdatei fest", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.fr.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.fr.json index a9022431f89..db14d1b28fb 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.fr.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.fr.json @@ -14,7 +14,7 @@ "symbols/Framework/choices/net10.0/description": "Net10.0 cible", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", "symbols/Framework/choices/net11.0/description": "Net11.0 cible", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Définit langVersion dans le fichier projet créé", "symbols/langVersion/displayName": "Version du Langage", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.pt-BR.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.pt-BR.json index c471cfa5e8d..80101603484 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.pt-BR.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.pt-BR.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Net10.0 de destino", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", + "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Define a langVersion no arquivo do projeto criado", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json index 5ef285169c3..505adad0962 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfApplication-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json @@ -13,8 +13,8 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "目標 net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "目標 net11.0", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/description": " 目標 net11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0 ", "symbols/Framework/displayName": "架構", "symbols/langVersion/description": "在建立的專案檔中設定 langVersion", "symbols/langVersion/displayName": "語言版本", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.cs.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.cs.json index 02864f492a0..648a4e23193 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.cs.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.cs.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Cíl net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Cíl net11.0", + "symbols/Framework/choices/net11.0/description": "Cílový net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Nastaví langVersion ve vytvořeném souboru projektu.", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.de.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.de.json index bb1af9fadd8..0e191a8c119 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.de.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.de.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Ziel.-NET10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Ziel.-NET11.0", + "symbols/Framework/choices/net11.0/description": "Ziel net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Legt „langVersion“ in der erstellten Projektdatei fest", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.fr.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.fr.json index 65886d6fddc..a287465ad35 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.fr.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.fr.json @@ -14,7 +14,7 @@ "symbols/Framework/choices/net10.0/description": "Net10.0 cible", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", "symbols/Framework/choices/net11.0/description": "Net11.0 cible", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Définit langVersion dans le fichier projet créé", "symbols/langVersion/displayName": "Version du Langage", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json index 63aa29fe30b..8a913540a7a 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Net10.0 de destino", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", + "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Define a langVersion no arquivo do projeto criado", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 10831f2aa20..330e5291d4e 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -13,8 +13,8 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "目標 net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "目標 net11.0", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/description": " 目標 net11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0 ", "symbols/Framework/displayName": "架構", "symbols/langVersion/description": "在建立的專案檔中設定 langVersion", "symbols/langVersion/displayName": "語言版本", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json index d6c2182d59b..c2e72437049 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Cíl net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Cíl net11.0", + "symbols/Framework/choices/net11.0/description": "Cílový net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Nastaví langVersion ve vytvořeném souboru projektu.", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.de.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.de.json index c9c6932fa60..60431ee7293 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.de.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.de.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Ziel.-NET10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Ziel.-NET11.0", + "symbols/Framework/choices/net11.0/description": "Ziel net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Legt „langVersion“ in der erstellten Projektdatei fest", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json index c2f59d9e1d3..53d752cb311 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json @@ -14,7 +14,7 @@ "symbols/Framework/choices/net10.0/description": "Net10.0 cible", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", "symbols/Framework/choices/net11.0/description": "Net11.0 cible", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Définit langVersion dans le fichier projet créé", "symbols/langVersion/displayName": "Version du Langage", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json index 857b274f0ea..a4542a70665 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Net10.0 de destino", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", + "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Define a langVersion no arquivo do projeto criado", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json index 03d752e75bf..fd0af861be4 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfClassLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json @@ -13,8 +13,8 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "目標 net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "目標 net11.0", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/description": " 目標 net11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0 ", "symbols/Framework/displayName": "架構", "symbols/langVersion/description": "在建立的專案檔中設定 langVersion", "symbols/langVersion/displayName": "語言版本", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.cs.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.cs.json index 26b2e4d94f7..8867dabd028 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.cs.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.cs.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Cíl net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Cíl net11.0", + "symbols/Framework/choices/net11.0/description": "Cílový net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Nastaví langVersion ve vytvořeném souboru projektu.", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.de.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.de.json index ec0e99b3958..0ac5ae7686a 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.de.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.de.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Ziel.-NET10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Ziel.-NET11.0", + "symbols/Framework/choices/net11.0/description": "Ziel net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Legt „langVersion“ in der erstellten Projektdatei fest", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.fr.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.fr.json index fff35e64812..d3c2d1e3241 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.fr.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.fr.json @@ -14,7 +14,7 @@ "symbols/Framework/choices/net10.0/description": "Net10.0 cible", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", "symbols/Framework/choices/net11.0/description": "Net11.0 cible", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Définit langVersion dans le fichier projet créé", "symbols/langVersion/displayName": "Version du Langage", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json index 752320ec0e6..b309b6fa091 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Net10.0 de destino", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", + "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Define a langVersion no arquivo do projeto criado", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 7233a287fc5..b2425df4b13 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -13,8 +13,8 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "目標 net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "目標 net11.0", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/description": " 目標 net11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0 ", "symbols/Framework/displayName": "架構", "symbols/langVersion/description": "在建立的專案檔中設定 langVersion", "symbols/langVersion/displayName": "語言版本", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json index ee296353f11..ecdb4a76210 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Cíl net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Cíl net11.0", + "symbols/Framework/choices/net11.0/description": "Cílový net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Nastaví langVersion ve vytvořeném souboru projektu.", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.de.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.de.json index 02ac01371fd..95b082fa63b 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.de.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.de.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Ziel.-NET10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Ziel.-NET11.0", + "symbols/Framework/choices/net11.0/description": "Ziel net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Legt „langVersion“ in der erstellten Projektdatei fest", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json index f4eb446e34a..35e01b275a5 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json @@ -14,7 +14,7 @@ "symbols/Framework/choices/net10.0/description": "Net10.0 cible", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", "symbols/Framework/choices/net11.0/description": "Net11.0 cible", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Définit langVersion dans le fichier projet créé", "symbols/langVersion/displayName": "Version du Langage", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json index de630dadd75..9b0800379a6 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Net10.0 de destino", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", + "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Define a langVersion no arquivo do projeto criado", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json index 3de35d3ac80..43929977ec8 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfCustomControlLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json @@ -13,8 +13,8 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "目標 net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "目標 net11.0", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/description": " 目標 net11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0 ", "symbols/Framework/displayName": "架構", "symbols/langVersion/description": "在建立的專案檔中設定 langVersion", "symbols/langVersion/displayName": "語言版本", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.cs.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.cs.json index e401e815320..a45ed825dcb 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.cs.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.cs.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Cíl net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Cíl net11.0", + "symbols/Framework/choices/net11.0/description": "Cílový net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Nastaví langVersion ve vytvořeném souboru projektu.", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.de.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.de.json index 5f1a2227521..88c7fb26053 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.de.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.de.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Ziel.-NET10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Ziel.-NET11.0", + "symbols/Framework/choices/net11.0/description": "Ziel net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Legt „langVersion“ in der erstellten Projektdatei fest", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.fr.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.fr.json index 4da6523f7dd..74b470b2f59 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.fr.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.fr.json @@ -14,7 +14,7 @@ "symbols/Framework/choices/net10.0/description": "Net10.0 cible", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", "symbols/Framework/choices/net11.0/description": "Net11.0 cible", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Définit langVersion dans le fichier projet créé", "symbols/langVersion/displayName": "Version du Langage", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json index 53df1ee73b3..eeca6dad51f 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Net10.0 de destino", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", + "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Define a langVersion no arquivo do projeto criado", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 24ff53c9c80..0f4457bf3da 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -13,8 +13,8 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "目標 net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "目標 net11.0", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/description": " 目標 net11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0 ", "symbols/Framework/displayName": "架構", "symbols/langVersion/description": "在建立的專案檔中設定 langVersion", "symbols/langVersion/displayName": "語言版本", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json index a6287d68870..afa1db0e0d7 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.cs.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Cíl net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Cíl net11.0", + "symbols/Framework/choices/net11.0/description": "Cílový net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Nastaví langVersion ve vytvořeném souboru projektu.", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.de.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.de.json index 36a1033405f..8cbf3cf94dc 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.de.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.de.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Ziel.-NET10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Ziel.-NET11.0", + "symbols/Framework/choices/net11.0/description": "Ziel net11.0", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Legt „langVersion“ in der erstellten Projektdatei fest", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json index 23f1e5f6aa1..159679708f7 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.fr.json @@ -14,7 +14,7 @@ "symbols/Framework/choices/net10.0/description": "Net10.0 cible", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", "symbols/Framework/choices/net11.0/description": "Net11.0 cible", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Définit langVersion dans le fichier projet créé", "symbols/langVersion/displayName": "Version du Langage", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json index 77af15b6863..21ac450aed4 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.pt-BR.json @@ -13,7 +13,7 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "Net10.0 de destino", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", + "symbols/Framework/choices/net11.0/description": "Net11.0 de destino", "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", "symbols/Framework/displayName": "Framework", "symbols/langVersion/description": "Define a langVersion no arquivo do projeto criado", diff --git a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json index 4a3ad52004e..4fb29e14bfa 100644 --- a/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json +++ b/packaging/Microsoft.Dotnet.Wpf.ProjectTemplates/content/WpfUserControlLibrary-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json @@ -13,8 +13,8 @@ "symbols/Framework/choices/net9.0/displayName": ".NET 9.0", "symbols/Framework/choices/net10.0/description": "目標 net10.0", "symbols/Framework/choices/net10.0/displayName": ".NET 10.0", - "symbols/Framework/choices/net11.0/description": "目標 net11.0", - "symbols/Framework/choices/net11.0/displayName": ".NET 11.0", + "symbols/Framework/choices/net11.0/description": " 目標 net11.0", + "symbols/Framework/choices/net11.0/displayName": ".NET 11.0 ", "symbols/Framework/displayName": "架構", "symbols/langVersion/description": "在建立的專案檔中設定 langVersion", "symbols/langVersion/displayName": "語言版本", diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/automap.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/automap.cpp index 00ec1e7b5a4..a6bce80485d 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/automap.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/automap.cpp @@ -22,6 +22,8 @@ #include "ttferror.h" /* for error codes */ #include "ttmem.h" #include "automap.h" +#include "intsafe_private_copy.h" +#include "ttf_safe_checks.h" int16 MortAutoMap(TTFACC_FILEBUFFERINFO * pInputBufferInfo, /* ttfacc info */ @@ -41,6 +43,11 @@ int16 errCode = NO_ERROR; ulOffset = TTTableOffset( pInputBufferInfo, MORT_TAG ); ulLength = TTTableLength( pInputBufferInfo, MORT_TAG ); ulLastOffset = ulOffset+ulLength; + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ulLastOffset < ulOffset) /* overflow check */ + return ERR_GENERIC; + } if (ulOffset == DIRECTORY_ERROR || ulLength == 0) /* nothing to map, we're done */ return NO_ERROR; @@ -68,7 +75,7 @@ int16 errCode = NO_ERROR; /* Static function to syncronize the Keep Glyph List with the Coverage list */ /* (add in values if necessary) */ /* ------------------------------------------------------------------- */ -static int16 UpdateKeepWithCoverage(TTFACC_FILEBUFFERINFO * pInputBufferInfo, uint8 * pabKeepGlyphs, uint16 usnGlyphs, uint16 fKeepFlag, uint32 ulBaseOffset, uint32 ulCoverageOffset, uint16 *pArray, uint16 usLookupType, uint16 usSubstFormat) +static int16 UpdateKeepWithCoverage(TTFACC_FILEBUFFERINFO * pInputBufferInfo, uint8 * pabKeepGlyphs, uint16 usnGlyphs, uint16 fKeepFlag, uint32 ulBaseOffset, uint32 ulCoverageOffset, uint16 *pArray, uint16 usArrayCount, uint16 usLookupType, uint16 usSubstFormat) { uint32 ulOffset; uint16 usCoverageFormat; @@ -82,6 +89,7 @@ GSUBRANGERECORD *pRangeRecordArray = NULL; uint16 i, j, k, l; uint16 usBytesRead; uint32 ulBytesRead; +uint32 ulAllocSize; int16 errCode = NO_ERROR; if ((ulCoverageOffset == 0) || (pArray == NULL)) @@ -97,7 +105,16 @@ int16 errCode = NO_ERROR; return errCode; ulOffset += usBytesRead; usCount = Coverage1.GlyphCount; - pGlyphIDArray = (uint16 *)Mem_Alloc(usCount * sizeof(uint16)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)usCount, (uint32)sizeof(uint16), &ulAllocSize) != S_OK) + return ERR_MEM; + pGlyphIDArray = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + pGlyphIDArray = (uint16 *)Mem_Alloc(usCount * sizeof(uint16)); + } if (pGlyphIDArray == NULL) return ERR_MEM; if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)pGlyphIDArray, WORD_CONTROL, ulOffset, &ulBytesRead, usCount, sizeof(uint16)) )!= NO_ERROR) @@ -111,7 +128,16 @@ int16 errCode = NO_ERROR; return errCode; ulOffset += usBytesRead; usCount = Coverage2.CoverageRangeCount; - pRangeRecordArray = (GSUBRANGERECORD *)Mem_Alloc(usCount * SIZEOF_GSUBRANGERECORD); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)usCount, (uint32)SIZEOF_GSUBRANGERECORD, &ulAllocSize) != S_OK) + return ERR_MEM; + pRangeRecordArray = (GSUBRANGERECORD *)Mem_Alloc(ulAllocSize); + } + else + { + pRangeRecordArray = (GSUBRANGERECORD *)Mem_Alloc(usCount * SIZEOF_GSUBRANGERECORD); + } if (pRangeRecordArray == NULL) return ERR_MEM; if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *) pRangeRecordArray, GSUBRANGERECORD_CONTROL, ulOffset, &ulBytesRead, usCount, SIZEOF_GSUBRANGERECORD) )!= NO_ERROR) @@ -154,11 +180,28 @@ int16 errCode = NO_ERROR; case GSUBSingleLookupType: if (usSubstFormat == 1) { - if ((usGlyphID + (int16) *pArray) < usnGlyphs && pabKeepGlyphs[usGlyphID + (int16) *pArray] == 0) - pabKeepGlyphs[usGlyphID + (int16) *pArray] = (uint8)(fKeepFlag + 1); + if (TTF_SAFE_CHECKS_ENABLED()) + { + int32 sTargetGlyphID = (int32)usGlyphID + (int16) *pArray; + if (sTargetGlyphID >= 0 && sTargetGlyphID < usnGlyphs && pabKeepGlyphs[sTargetGlyphID] == 0) + pabKeepGlyphs[sTargetGlyphID] = (uint8)(fKeepFlag + 1); + } + else + { + if ((usGlyphID + (int16) *pArray) < usnGlyphs && pabKeepGlyphs[usGlyphID + (int16) *pArray] == 0) + pabKeepGlyphs[usGlyphID + (int16) *pArray] = (uint8)(fKeepFlag + 1); + } } else { + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (usGlyphCount >= usArrayCount) + { + errCode = ERR_INVALID_GSUB; + break; + } + } if (pArray[usGlyphCount] < usnGlyphs && pabKeepGlyphs[pArray[usGlyphCount]] == 0) pabKeepGlyphs[pArray[usGlyphCount]] = (uint8)(fKeepFlag + 1); } @@ -168,13 +211,33 @@ int16 errCode = NO_ERROR; uint16 usSequenceGlyphCount; uint16 *pausGlyphID = NULL; + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (usGlyphCount >= usArrayCount) + { + errCode = ERR_INVALID_GSUB; + break; + } + } if (pArray[usGlyphCount] == 0) break; ulOffset = ulBaseOffset + pArray[usGlyphCount]; if ((errCode = ReadWord( pInputBufferInfo, &usSequenceGlyphCount, ulOffset ) )!= NO_ERROR) break; ulOffset += sizeof(uint16); - pausGlyphID = (uint16 *)Mem_Alloc(usSequenceGlyphCount * sizeof(uint16)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)usSequenceGlyphCount, (uint32)sizeof(uint16), &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + pausGlyphID = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + pausGlyphID = (uint16 *)Mem_Alloc(usSequenceGlyphCount * sizeof(uint16)); + } if (pausGlyphID == NULL) { errCode = ERR_MEM; @@ -197,13 +260,33 @@ int16 errCode = NO_ERROR; uint16 usAlternateGlyphCount; uint16 *pausGlyphID = NULL; + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (usGlyphCount >= usArrayCount) + { + errCode = ERR_INVALID_GSUB; + break; + } + } if (pArray[usGlyphCount] == 0) break; ulOffset = ulBaseOffset + pArray[usGlyphCount]; if ((errCode = ReadWord( pInputBufferInfo, &usAlternateGlyphCount, ulOffset ) )!= NO_ERROR) break; ulOffset += sizeof(uint16); - pausGlyphID = (uint16 *)Mem_Alloc(usAlternateGlyphCount * sizeof(uint16)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)usAlternateGlyphCount, (uint32)sizeof(uint16), &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + pausGlyphID = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + pausGlyphID = (uint16 *)Mem_Alloc(usAlternateGlyphCount * sizeof(uint16)); + } if (pausGlyphID == NULL) { errCode = ERR_MEM; @@ -229,13 +312,33 @@ int16 errCode = NO_ERROR; uint16 *pausLigatureOffsetArray = NULL; GSUBLIGATURE GSUBLigature; + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (usGlyphCount >= usArrayCount) + { + errCode = ERR_INVALID_GSUB; + break; + } + } if (pArray[usGlyphCount] == 0) break; ulOffset = ulBaseOffset + pArray[usGlyphCount]; if ((errCode = ReadWord( pInputBufferInfo, &usLigatureCount, ulOffset ) )!= NO_ERROR) break; ulOffset += sizeof(uint16); - pausLigatureOffsetArray = (uint16 *)Mem_Alloc(usLigatureCount * sizeof(uint16)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)usLigatureCount, (uint32)sizeof(uint16), &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + pausLigatureOffsetArray = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + pausLigatureOffsetArray = (uint16 *)Mem_Alloc(usLigatureCount * sizeof(uint16)); + } if (pausLigatureOffsetArray == NULL) { errCode = ERR_MEM; @@ -247,7 +350,14 @@ int16 errCode = NO_ERROR; { if (pausLigatureOffsetArray[l] == 0) continue; - ulOffset = ulBaseOffset + (pArray)[usGlyphCount] + pausLigatureOffsetArray[l]; + if (TTF_SAFE_CHECKS_ENABLED()) + { + ulOffset = ulBaseOffset + (uint32)(pArray)[usGlyphCount] + (uint32)pausLigatureOffsetArray[l]; + } + else + { + ulOffset = ulBaseOffset + (pArray)[usGlyphCount] + pausLigatureOffsetArray[l]; + } if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBLigature, SIZEOF_GSUBLIGATURE, GSUBLIGATURE_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR) { Mem_Free (pausLigatureOffsetArray); @@ -260,7 +370,30 @@ int16 errCode = NO_ERROR; usLigatureGlyphID = GSUBLigature.GlyphID; if (usLigatureGlyphID >= usnGlyphs || pabKeepGlyphs[usLigatureGlyphID] != 0) continue; /* already in list, go to next ligature */ - pausCompGlyphID = (uint16 *)Mem_Alloc((usLigatureCompCount - 1) * sizeof(uint16)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (usLigatureCompCount < 2) /* need at least 2 components; 0 or 1 means no comp array */ + { + if (usLigatureCompCount == 1 && pabKeepGlyphs[usLigatureGlyphID] == 0) + pabKeepGlyphs[usLigatureGlyphID] = (uint8)(fKeepFlag+1); + continue; + } + } + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)(usLigatureCompCount - 1), (uint32)sizeof(uint16), &ulAllocSize) != S_OK) + { + Mem_Free (pausLigatureOffsetArray); + Mem_Free(pGlyphIDArray); + Mem_Free(pRangeRecordArray); + return ERR_MEM; + } + pausCompGlyphID = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + pausCompGlyphID = (uint16 *)Mem_Alloc((usLigatureCompCount - 1) * sizeof(uint16)); + } if (pausCompGlyphID == NULL) { Mem_Free (pausLigatureOffsetArray); @@ -385,6 +518,7 @@ uint32 ulCurrentOffset; uint32 ulLangSysOffset; uint16 usMaxLookupCount; uint32 ulOffset; +uint32 ulAllocSize; uint16 i, j, k; uint16 usBytesRead; uint32 ulBytesRead; @@ -420,7 +554,20 @@ int16 errCode = NO_ERROR; uint16 *SubstTableOffsetArray = NULL; ulOffset = ulHeaderOffset + GSUBHeader.LookupListOffset; - pGSUBLookupList = (GSUBLOOKUPLIST *)Mem_Alloc(SIZEOF_GSUBLOOKUPLIST + usMaxLookupCount * sizeof(uint16)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)usMaxLookupCount, (uint32)sizeof(uint16), &ulAllocSize) != S_OK || + UIntAdd32(ulAllocSize, (uint32)SIZEOF_GSUBLOOKUPLIST, &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + pGSUBLookupList = (GSUBLOOKUPLIST *)Mem_Alloc(ulAllocSize); + } + else + { + pGSUBLookupList = (GSUBLOOKUPLIST *)Mem_Alloc(SIZEOF_GSUBLOOKUPLIST + usMaxLookupCount * sizeof(uint16)); + } if (pGSUBLookupList == NULL) { errCode = ERR_MEM; @@ -449,7 +596,19 @@ int16 errCode = NO_ERROR; if (GSUBLookup.LookupType == GSUBContextLookupType) /* not looking for context lookups */ continue; usSubTableCount = GSUBLookup.SubTableCount; - SubstTableOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usSubTableCount); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)sizeof(uint16), (uint32)usSubTableCount, &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + SubstTableOffsetArray = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + SubstTableOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usSubTableCount); + } if (SubstTableOffsetArray == NULL) { errCode = ERR_MEM; @@ -481,7 +640,7 @@ int16 errCode = NO_ERROR; GSUBSINGLESUBSTFORMAT1 GSUBSubstTable; if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBSubstTable, SIZEOF_GSUBSINGLESUBSTFORMAT1, GSUBSINGLESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )== NO_ERROR) - errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , (uint16 *) &(GSUBSubstTable.DeltaGlyphID), GSUBLookup.LookupType, Format); + errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , (uint16 *) &(GSUBSubstTable.DeltaGlyphID), 1, GSUBLookup.LookupType, Format); break; } case 2: @@ -493,14 +652,26 @@ int16 errCode = NO_ERROR; if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBSubstTable, SIZEOF_GSUBSINGLESUBSTFORMAT2, GSUBSINGLESUBSTFORMAT2_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR) break; usGlyphCount = GSUBSubstTable.GlyphCount; - pGlyphIDArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usGlyphCount); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)sizeof(uint16), (uint32)usGlyphCount, &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + pGlyphIDArray = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + pGlyphIDArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usGlyphCount); + } if (pGlyphIDArray == NULL) { errCode = ERR_MEM; break; } if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)pGlyphIDArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usGlyphCount, sizeof(uint16)) )== NO_ERROR) - errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pGlyphIDArray, GSUBLookup.LookupType, Format); + errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pGlyphIDArray, usGlyphCount, GSUBLookup.LookupType, Format); Mem_Free(pGlyphIDArray); break; } @@ -522,14 +693,26 @@ int16 errCode = NO_ERROR; if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBSubstTable, SIZEOF_GSUBMULTIPLESUBSTFORMAT1, GSUBMULTIPLESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR) break; usCount = GSUBSubstTable.SequenceCount; - pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)sizeof(uint16), (uint32)usCount, &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + pOffsetArray = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount); + } if (pOffsetArray == NULL) { errCode = ERR_MEM; break; } if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)pOffsetArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usCount, sizeof(uint16)) )== NO_ERROR) - errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, GSUBLookup.LookupType, Format); + errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, usCount, GSUBLookup.LookupType, Format); Mem_Free(pOffsetArray); break; } @@ -544,14 +727,26 @@ int16 errCode = NO_ERROR; if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBSubstTable, SIZEOF_GSUBALTERNATESUBSTFORMAT1, GSUBALTERNATESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR) break; usCount = GSUBSubstTable.AlternateSetCount; - pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)sizeof(uint16), (uint32)usCount, &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + pOffsetArray = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount); + } if (pOffsetArray == NULL) { errCode = ERR_MEM; break; } if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)pOffsetArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usCount, sizeof(uint16)) )== NO_ERROR) - errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, GSUBLookup.LookupType, Format); + errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, usCount, GSUBLookup.LookupType, Format); Mem_Free(pOffsetArray); break; } @@ -566,14 +761,26 @@ int16 errCode = NO_ERROR; if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&GSUBSubstTable, SIZEOF_GSUBLIGATURESUBSTFORMAT1, GSUBLIGATURESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR) break; usCount = GSUBSubstTable.LigatureSetCount; - pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)sizeof(uint16), (uint32)usCount, &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + pOffsetArray = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount); + } if (pOffsetArray == NULL) { errCode = ERR_MEM; break; } if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)pOffsetArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usCount, sizeof(uint16)) )== NO_ERROR) - errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, GSUBLookup.LookupType, Format); + errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, usCount, GSUBLookup.LookupType, Format); Mem_Free(pOffsetArray); break; } @@ -606,7 +813,19 @@ int16 errCode = NO_ERROR; if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&JSTFHeader, SIZEOF_JSTFHEADER, JSTFHEADER_CONTROL, ulHeaderOffset, &usBytesRead ) )!= NO_ERROR) break; - ScriptRecordArray = (JSTFSCRIPTRECORD *)Mem_Alloc(SIZEOF_JSTFSCRIPTRECORD * JSTFHeader.ScriptCount); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)SIZEOF_JSTFSCRIPTRECORD, (uint32)JSTFHeader.ScriptCount, &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + ScriptRecordArray = (JSTFSCRIPTRECORD *)Mem_Alloc(ulAllocSize); + } + else + { + ScriptRecordArray = (JSTFSCRIPTRECORD *)Mem_Alloc(SIZEOF_JSTFSCRIPTRECORD * JSTFHeader.ScriptCount); + } if (ScriptRecordArray == NULL) { errCode = ERR_MEM; @@ -631,7 +850,19 @@ int16 errCode = NO_ERROR; if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&JSTFExtenderGlyph, SIZEOF_JSTFEXTENDERGLYPH, JSTFEXTENDERGLYPH_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR) break; - GlyphIDArray = (uint16 *)Mem_Alloc((sizeof(uint16) * JSTFExtenderGlyph.ExtenderGlyphCount)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ULongMult32((uint32)sizeof(uint16), (uint32)JSTFExtenderGlyph.ExtenderGlyphCount, &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + GlyphIDArray = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + GlyphIDArray = (uint16 *)Mem_Alloc((sizeof(uint16) * JSTFExtenderGlyph.ExtenderGlyphCount)); + } if (GlyphIDArray == NULL) { errCode = ERR_MEM; diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/intsafe_private_copy.h b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/intsafe_private_copy.h index 7128dfe5eb4..a1eeacbf717 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/intsafe_private_copy.h +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/intsafe_private_copy.h @@ -138,4 +138,18 @@ ULongSub( return hr; } + +// +// Convenience wrappers for the codebase's uint32 type (unsigned long). +// These forward to the UINT/ULONG versions above, bridging the type mismatch. +// +static __inline HRESULT UIntAdd32(uint32 a, uint32 b, uint32 *pResult) +{ + return UIntAdd((UINT)a, (UINT)b, (UINT *)pResult); +} +static __inline HRESULT ULongMult32(uint32 a, uint32 b, uint32 *pResult) +{ + return ULongMult((ULONG)a, (ULONG)b, (ULONG *)pResult); +} + #endif //__INTSAFE_PRIVATE_COPY_H diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/makeglst.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/makeglst.cpp index 6ea0dde0f34..d25c606011c 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/makeglst.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/makeglst.cpp @@ -148,6 +148,8 @@ Thanks, #include "ttferror.h" /* for error codes */ #include "ttfdelta.h" #include "sfntoff.h" +#include "intsafe_private_copy.h" +#include "ttf_safe_checks.h" #define WIN_ANSI_MIDDLEDOT 0xB7 #define WIN_ANSI_BULLET 0x2219 @@ -176,7 +178,18 @@ USHORT usHighByte; { if (usFirstChar >= 0xf000) { - if (*ppulKeepSymbolCodeList = (CHAR_ID *)Mem_Alloc(usCharListCount * sizeof(CHAR_ID))) + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)usCharListCount, (uint32)sizeof(CHAR_ID), &ulAllocSize) != S_OK) + return ERR_MEM; + *ppulKeepSymbolCodeList = (CHAR_ID *)Mem_Alloc(ulAllocSize); + } + else + { + *ppulKeepSymbolCodeList = (CHAR_ID *)Mem_Alloc(usCharListCount * sizeof(CHAR_ID)); + } + if (*ppulKeepSymbolCodeList) { /* In user range -> this is a symbol font so go ahead offseting it */ usHighByte = (unsigned short)(usFirstChar & 0xff00); @@ -220,7 +233,18 @@ int16 EnsureNonEmptyGlyfTable( uint32 * aulLoca; /* allocate memory for and read loca table */ - aulLoca = (uint32 *)Mem_Alloc( (usGlyphCount + 1) * sizeof( uint32 )); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulLocaCount = (uint32)usGlyphCount + 1; + uint32 ulAllocSize; + if (ULongMult32(ulLocaCount, (uint32)sizeof( uint32 ), &ulAllocSize) != S_OK) + return ERR_MEM; + aulLoca = (uint32 *)Mem_Alloc( ulAllocSize ); + } + else + { + aulLoca = (uint32 *)Mem_Alloc( (usGlyphCount + 1) * sizeof(uint32) ); + } if ( aulLoca == NULL ) return ERR_MEM; @@ -328,8 +352,22 @@ CMAP_SUBHEADER_GEN CmapSubHeader; if ((ulGlyfOffset = TTTableOffset( pInputBufferInfo, GLYF_TAG )) == DIRECTORY_ERROR) return (ERR_MISSING_GLYF); - usnMaxComponents = Maxp.maxComponentElements * Maxp.maxComponentDepth; /* maximum total possible */ - pausComponents = (uint16 *)Mem_Alloc(usnMaxComponents * sizeof(uint16)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulMaxComp, ulAllocSize; + if (ULongMult32((uint32)Maxp.maxComponentElements, (uint32)Maxp.maxComponentDepth, &ulMaxComp) != S_OK || + ULongMult32(ulMaxComp, (uint32)sizeof(uint16), &ulAllocSize) != S_OK) + return(ERR_MEM); + if (ulMaxComp > (uint32)USHRT_MAX) + return(ERR_INVALID_MAXP); + usnMaxComponents = (uint16)ulMaxComp; + pausComponents = (uint16 *)Mem_Alloc(ulAllocSize); + } + else + { + usnMaxComponents = Maxp.maxComponentElements * Maxp.maxComponentDepth; + pausComponents = (uint16 *)Mem_Alloc(usnMaxComponents * sizeof(uint16)); + } if (pausComponents == NULL) return(ERR_MEM); diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modcmap.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modcmap.cpp index c0922b8dc52..b79ac87097d 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modcmap.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modcmap.cpp @@ -14,6 +14,8 @@ #include /* for qsort */ #include "typedefs.h" +#include "intsafe_private_copy.h" +#include "ttf_safe_checks.h" #include "ttff.h" #include "ttfacc.h" #include "ttfcntrl.h" @@ -46,7 +48,17 @@ struct cmapoffsetrecordkeeper /* housekeeping structure */ PRIVATE int16 InitCmapOffsetArray(PCMAPOFFSETRECORDKEEPER pKeeper, uint16 usRecordCount) { - pKeeper->pCmapOffsetArray = (CmapOffsetRecord *) Mem_Alloc(usRecordCount * sizeof(*(pKeeper->pCmapOffsetArray))); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)usRecordCount, (uint32)sizeof(*(pKeeper->pCmapOffsetArray)), &ulAllocSize) != S_OK) + return ERR_MEM; + pKeeper->pCmapOffsetArray = (CmapOffsetRecord *) Mem_Alloc(ulAllocSize); + } + else + { + pKeeper->pCmapOffsetArray = (CmapOffsetRecord *) Mem_Alloc(usRecordCount * sizeof(*(pKeeper->pCmapOffsetArray))); + } if (pKeeper->pCmapOffsetArray == NULL) return ERR_MEM; pKeeper->usCmapOffsetArrayLen = usRecordCount; @@ -152,7 +164,17 @@ uint16 i,j; uint16 usBytesRead; uint16 usPadBytes; - pIndexArray = (IndexOffset *) Mem_Alloc(usSubTableCount * sizeof(*pIndexArray)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)usSubTableCount, (uint32)sizeof(*pIndexArray), &ulAllocSize) != S_OK) + return ERR_MEM; + pIndexArray = (IndexOffset *) Mem_Alloc(ulAllocSize); + } + else + { + pIndexArray = (IndexOffset *) Mem_Alloc(usSubTableCount * sizeof(*pIndexArray)); + } if (pIndexArray == NULL) return ERR_MEM; @@ -384,7 +406,17 @@ uint16 usBytesRead; return ERR_INVALID_CMAP; /* huh?*/ usSubTableCount = GetCmapSubtableCount(pOutputBufferInfo, ulCmapOffset); - pCmapTableLoc = (CMAP_TABLELOC *)Mem_Alloc(SIZEOF_CMAP_TABLELOC * usSubTableCount); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)SIZEOF_CMAP_TABLELOC, (uint32)usSubTableCount, &ulAllocSize) != S_OK) + return ERR_MEM; + pCmapTableLoc = (CMAP_TABLELOC *)Mem_Alloc(ulAllocSize); + } + else + { + pCmapTableLoc = (CMAP_TABLELOC *)Mem_Alloc(SIZEOF_CMAP_TABLELOC * usSubTableCount); + } if (pCmapTableLoc == NULL) return ERR_MEM; ulCmapSubTableDirOffset = ulCmapOffset + GetGenericSize( CMAP_HEADER_CONTROL ); @@ -434,8 +466,24 @@ uint16 usBytesRead; if (errCode != NO_ERROR) break; - NewFormat4Segments = (FORMAT4_SEGMENTS *) Mem_Alloc( (usnCharGlyphMapListCount+1) * SIZEOF_FORMAT4_SEGMENTS ); /* add one for the extra dummy segment */ - NewFormat4GlyphIdArray = (GLYPH_ID *) Mem_Alloc( usnCharGlyphMapListCount * sizeof( *NewFormat4GlyphIdArray ) ); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulSegAllocSize, ulGlyphAllocSize; + uint32 ulSegCount32 = (uint32)usnCharGlyphMapListCount + 1; /* add one for extra dummy segment */ + if (ULongMult32(ulSegCount32, (uint32)SIZEOF_FORMAT4_SEGMENTS, &ulSegAllocSize) != S_OK || + ULongMult32((uint32)usnCharGlyphMapListCount, (uint32)sizeof( *NewFormat4GlyphIdArray ), &ulGlyphAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + NewFormat4Segments = (FORMAT4_SEGMENTS *) Mem_Alloc( ulSegAllocSize ); + NewFormat4GlyphIdArray = (GLYPH_ID *) Mem_Alloc( ulGlyphAllocSize ); + } + else + { + NewFormat4Segments = (FORMAT4_SEGMENTS *) Mem_Alloc( (usnCharGlyphMapListCount + 1) * SIZEOF_FORMAT4_SEGMENTS ); /* add one for the extra dummy segment */ + NewFormat4GlyphIdArray = (GLYPH_ID *) Mem_Alloc( usnCharGlyphMapListCount * sizeof( *NewFormat4GlyphIdArray ) ); + } if ( NewFormat4Segments == NULL || NewFormat4GlyphIdArray == NULL ) { @@ -453,7 +501,7 @@ uint16 usBytesRead; if (CmapFormat4.length <= CmapSubHeader.length) /* if the new length is smaller than the old, we can write it in the old place */ { - if (pCmapTableLoc[i].platformID == MS_PLATFORMID) /* only applies to this platform */ + if (pCmapTableLoc[i].platformID == MS_PLATFORMID && (!TTF_SAFE_CHECKS_ENABLED() || usnCharGlyphMapListCount > 0)) /* only applies to this platform */ { *pOS2MinChr = pCharGlyphMapList[0].usCharCode; *pOS2MaxChr = pCharGlyphMapList[usnCharGlyphMapListCount-1].usCharCode; @@ -482,7 +530,20 @@ uint16 usBytesRead; if (errCode != NO_ERROR) break; - NewFormat12Groups = (FORMAT12_GROUPS *) Mem_Alloc( (ulnCharGlyphMapListCount) * SIZEOF_FORMAT12_GROUPS ); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)ulnCharGlyphMapListCount, (uint32)SIZEOF_FORMAT12_GROUPS, &ulAllocSize) != S_OK) + { + errCode = ERR_MEM; + break; + } + NewFormat12Groups = (FORMAT12_GROUPS *) Mem_Alloc(ulAllocSize); + } + else + { + NewFormat12Groups = (FORMAT12_GROUPS *) Mem_Alloc(ulnCharGlyphMapListCount * SIZEOF_FORMAT12_GROUPS); + } if ( NewFormat12Groups == NULL) { errCode = ERR_MEM; @@ -495,7 +556,7 @@ uint16 usBytesRead; /* Donald, if you don't care if the Cmap subtable grows, you could comment out the next line */ if (CmapFormat12.length <= CmapSubHeader.length) /* if the new length is smaller than the old, we can write it in the old place */ { - if (pCmapTableLoc[i].platformID == MS_PLATFORMID) /* only applies to this platform */ + if (pCmapTableLoc[i].platformID == MS_PLATFORMID && (!TTF_SAFE_CHECKS_ENABLED() || ulnCharGlyphMapListCount > 0)) /* only applies to this platform */ { *pOS2MinChr = (uint16)pCharGlyphMapListEx[0].ulCharCode; *pOS2MaxChr = (uint16)pCharGlyphMapListEx[ulnCharGlyphMapListCount-1].ulCharCode; diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modglyf.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modglyf.cpp index eaf87f2de70..0cef3bbf07b 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modglyf.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modglyf.cpp @@ -23,6 +23,8 @@ #include "util.h" #include "modglyf.h" #include "ttferror.h" /* for error codes */ +#include "intsafe_private_copy.h" +#include "ttf_safe_checks.h" /* ------------------------------------------------------------------- */ /* this function modifies the glyf and loca tables by copying only glyfs @@ -60,7 +62,18 @@ HEAD Head; /* allocate memory for and read loca table */ - aulLoca = (uint32 *)Mem_Alloc( (usGlyphCount + 1) * sizeof( uint32 )); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulLocaCount = (uint32)usGlyphCount + 1; + uint32 ulAllocSize; + if (ULongMult32(ulLocaCount, (uint32)sizeof( uint32 ), &ulAllocSize) != S_OK) + return ERR_MEM; + aulLoca = (uint32 *)Mem_Alloc( ulAllocSize ); + } + else + { + aulLoca = (uint32 *)Mem_Alloc( (usGlyphCount + 1) * sizeof( uint32 )); + } if ( aulLoca == NULL ) return ERR_MEM; @@ -120,18 +133,56 @@ HEAD Head; if ( ulGlyphLength ) { - if ((errCode = CopyBlockOver( pOutputBufferInfo, pInputBufferInfo, ulOutGlyfOffset + ulOutLoca, - ulGlyfOffset + aulLoca[ i ], ulGlyphLength )) != NO_ERROR) - break; + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulOutOff, ulInOff; + if (UIntAdd32(ulOutGlyfOffset, ulOutLoca, &ulOutOff) != S_OK || + UIntAdd32(ulGlyfOffset, aulLoca[i], &ulInOff) != S_OK) + { + errCode = ERR_GENERIC; + break; + } + if ((errCode = CopyBlockOver( pOutputBufferInfo, pInputBufferInfo, ulOutOff, + ulInOff, ulGlyphLength )) != NO_ERROR) + break; + } + else + { + if ((errCode = CopyBlockOver( pOutputBufferInfo, pInputBufferInfo, ulOutGlyfOffset + ulOutLoca, + ulGlyfOffset + aulLoca[ i ], ulGlyphLength )) != NO_ERROR) + break; + } } } assert((ulOutLoca & 1) != 1); aulLoca[ i ] = ulOutLoca; ulOutLoca += ulGlyphLength; + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ulOutLoca < ulGlyphLength) + { + errCode = ERR_GENERIC; + break; + } + } if (ulOutLoca & 1) { /* the glyph offset is on an odd-byte boundry. get ready for next time */ - if ((errCode = WriteByte( pOutputBufferInfo, 0, ulOutGlyfOffset + ulOutLoca)) != NO_ERROR) - break; + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulPadOff; + if (UIntAdd32(ulOutGlyfOffset, ulOutLoca, &ulPadOff) != S_OK) + { + errCode = ERR_GENERIC; + break; + } + if ((errCode = WriteByte( pOutputBufferInfo, 0, ulPadOff)) != NO_ERROR) + break; + } + else + { + if ((errCode = WriteByte( pOutputBufferInfo, 0, ulOutGlyfOffset + ulOutLoca)) != NO_ERROR) + break; + } ++ulOutLoca; } } diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modsbit.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modsbit.cpp index b50aeb50257..c6ea1bd42d9 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modsbit.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modsbit.cpp @@ -24,6 +24,61 @@ // mark them as SecurityCritical because they have unverfiable code and we could // not negotiate with the CRT team to fix it. #include "intsafe_private_copy.h" +#include "ttf_safe_checks.h" + +/* ------------------------------------------------------------------- */ + +/* Helper function for bounds checking EBDT buffer ranges */ +PRIVATE int16 CheckEBDTBounds(uint32 ulOffset, uint32 ulLength, uint32 ulAllocatedSize) +{ + uint32 ulEndOffset; + + /* Check for integer overflow in offset + length */ + if (FAILED(UIntAdd32(ulOffset, ulLength, &ulEndOffset))) + { + return ERR_INVALID_EBLC; + } + + /* Check if write would exceed buffer bounds */ + if (ulEndOffset > ulAllocatedSize) + { + return ERR_INVALID_EBLC; + } + + return NO_ERROR; +} + +/* Helper function for copying EBDT bytes with read/write bounds and overflow checks */ +PRIVATE int16 CopyEBDTBytesChecked( + TTFACC_FILEBUFFERINFO *pInputBufferInfo, + uint8 *puchEBDTDestPtr, + uint32 ulEBDTSrcOffset, + uint32 ulEBDTAllocatedSize, + uint32 ulDestImageDataOffset, + uint32 ulDestGlyphOffset, + uint32 ulSrcImageDataOffset, + uint32 ulSrcGlyphOffset, + uint32 ulGlyphLength) +{ + uint32 ulWriteOffset; + uint32 ulReadRelativeOffset; + uint32 ulReadOffset; + int16 errCode; + + if (FAILED(UIntAdd32(ulDestImageDataOffset, ulDestGlyphOffset, &ulWriteOffset))) + return ERR_INVALID_EBLC; + if ((errCode = CheckEBDTBounds(ulWriteOffset, ulGlyphLength, ulEBDTAllocatedSize)) != NO_ERROR) + return errCode; + + if (FAILED(UIntAdd32(ulSrcImageDataOffset, ulSrcGlyphOffset, &ulReadRelativeOffset))) + return ERR_INVALID_EBLC; + if ((errCode = CheckEBDTBounds(ulReadRelativeOffset, ulGlyphLength, ulEBDTAllocatedSize)) != NO_ERROR) + return errCode; + if (FAILED(UIntAdd32(ulEBDTSrcOffset, ulReadRelativeOffset, &ulReadOffset))) + return ERR_INVALID_EBLC; + + return ReadBytes(pInputBufferInfo, puchEBDTDestPtr + ulWriteOffset, ulReadOffset, ulGlyphLength); +} /* ------------------------------------------------------------------- */ @@ -57,11 +112,30 @@ PRIVATE int16 RecordGlyphOffset(PGLYPHOFFSETRECORDKEEPER pKeeper, if (pKeeper->ulNextArrayIndex >= pKeeper->ulOffsetArrayLen) { - pKeeper->pGlyphOffsetArray = (GlyphOffsetRecord *) Mem_ReAlloc(pKeeper->pGlyphOffsetArray, (pKeeper->ulOffsetArrayLen + 100) * sizeof(*(pKeeper->pGlyphOffsetArray))); - if (pKeeper->pGlyphOffsetArray == NULL) - return ERR_MEM; /* ("EBLC: Not enough memory to allocate Offset Array."); */ - memset((char *)(pKeeper->pGlyphOffsetArray) + (sizeof(*(pKeeper->pGlyphOffsetArray)) * pKeeper->ulOffsetArrayLen), '\0', sizeof(*(pKeeper->pGlyphOffsetArray)) * 100); - pKeeper->ulOffsetArrayLen += 100; + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulNewLen; + uint32 ulAllocSize; + if (UIntAdd32(pKeeper->ulOffsetArrayLen, 100, &ulNewLen) != S_OK || + ULongMult32(ulNewLen, (uint32)sizeof(*(pKeeper->pGlyphOffsetArray)), &ulAllocSize) != S_OK) + return ERR_MEM; + { + GlyphOffsetRecord *pNewArray = (GlyphOffsetRecord *) Mem_ReAlloc(pKeeper->pGlyphOffsetArray, ulAllocSize); + if (pNewArray == NULL) + return ERR_MEM; /* ("EBLC: Not enough memory to allocate Offset Array."); */ + pKeeper->pGlyphOffsetArray = pNewArray; + } + memset((char *)(pKeeper->pGlyphOffsetArray) + (sizeof(*(pKeeper->pGlyphOffsetArray)) * pKeeper->ulOffsetArrayLen), '\0', sizeof(*(pKeeper->pGlyphOffsetArray)) * 100); + pKeeper->ulOffsetArrayLen = ulNewLen; + } + else + { + pKeeper->pGlyphOffsetArray = (GlyphOffsetRecord *) Mem_ReAlloc(pKeeper->pGlyphOffsetArray, (pKeeper->ulOffsetArrayLen + 100) * sizeof(*(pKeeper->pGlyphOffsetArray))); + if (pKeeper->pGlyphOffsetArray == NULL) + return ERR_MEM; /* ("EBLC: Not enough memory to allocate Offset Array."); */ + memset((char *)(pKeeper->pGlyphOffsetArray) + (sizeof(*(pKeeper->pGlyphOffsetArray)) * pKeeper->ulOffsetArrayLen), '\0', sizeof(*(pKeeper->pGlyphOffsetArray)) * 100); + pKeeper->ulOffsetArrayLen += 100; + } } pKeeper->pGlyphOffsetArray[pKeeper->ulNextArrayIndex].ulOldOffset = ulOldOffset; pKeeper->pGlyphOffsetArray[pKeeper->ulNextArrayIndex].ImageDataBlock.ulNewImageDataOffset = pImageDataBlock->ulNewImageDataOffset ; @@ -123,6 +197,7 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, / uint32 *pulEBDTBytesWritten, /* number of bytes written to the EBDT table buffer */ uint8 *puchEBDTDestPtr, /* EBDT data byffer */ uint32 ulEBDTSrcOffset, /* beginning of EBDT table in the InputBufferInfo */ + uint32 ulEBDTAllocatedSize, /* allocated size of EBDT buffer for bounds checking */ PGLYPHOFFSETRECORDKEEPER pKeeper) /* structure to keep track of multiply referenced EBDT data */ { INDEXSUBHEADER IndexSubHeader; @@ -208,11 +283,23 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, / return errCode; ulOffset += usBytesRead; IndexSubTable1.header.ulImageDataOffset = ulCurrentImageDataOffset; /* set to the new one */ - if (FAILED(UIntAdd(ulLocalCurrentOffset,SIZEOF_INDEXSUBTABLE1,(UINT *)&ulIndexSubtableAfterEnd)) || - (ulIndexSubtableAfterEnd > *pulIndexSubTableSize) - ) + if (TTF_SAFE_CHECKS_ENABLED()) { - return ERR_INVALID_EBLC; + if (FAILED(UIntAdd32(ulLocalCurrentOffset, SIZEOF_INDEXSUBTABLE1, &ulIndexSubtableAfterEnd)) || + (ulIndexSubtableAfterEnd > *pulIndexSubTableSize) + ) + { + return ERR_INVALID_EBLC; + } + } + else + { + if (FAILED(UIntAdd(ulLocalCurrentOffset, SIZEOF_INDEXSUBTABLE1, (UINT *)&ulIndexSubtableAfterEnd)) || + (ulIndexSubtableAfterEnd > *pulIndexSubTableSize) + ) + { + return ERR_INVALID_EBLC; + } } memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset, &IndexSubTable1, SIZEOF_INDEXSUBTABLE1); ulTableSize = SIZEOF_INDEXSUBTABLE1; @@ -233,12 +320,25 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, / { /* if the indexTableSize length field was incorrect */ /* use 2* to account for the extra offset at the end */ - if (FAILED(UIntAdd(ulLocalCurrentOffset, ulTableSize, (UINT *)&ulIndexSubtableAfterEnd)) || - FAILED(UIntAdd(ulIndexSubtableAfterEnd, 2*sizeof(ulNewGlyphOffset), (UINT *)&ulIndexSubtableAfterEnd)) || - (ulIndexSubtableAfterEnd > *pulIndexSubTableSize) - ) + if (TTF_SAFE_CHECKS_ENABLED()) { - return ERR_INVALID_EBLC; + if (FAILED(UIntAdd32(ulLocalCurrentOffset, ulTableSize, &ulIndexSubtableAfterEnd)) || + FAILED(UIntAdd32(ulIndexSubtableAfterEnd, 2*sizeof(ulNewGlyphOffset), &ulIndexSubtableAfterEnd)) || + (ulIndexSubtableAfterEnd > *pulIndexSubTableSize) + ) + { + return ERR_INVALID_EBLC; + } + } + else + { + if (FAILED(UIntAdd(ulLocalCurrentOffset, ulTableSize, (UINT *)&ulIndexSubtableAfterEnd)) || + FAILED(UIntAdd(ulIndexSubtableAfterEnd, 2*sizeof(ulNewGlyphOffset), (UINT *)&ulIndexSubtableAfterEnd)) || + (ulIndexSubtableAfterEnd > *pulIndexSubTableSize) + ) + { + return ERR_INVALID_EBLC; + } } memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset+ulTableSize, &ulNewGlyphOffset, @@ -254,10 +354,28 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, / ulGlyphLength = ulNextGlyphOffset-ulOldGlyphOffset; if (DoCopy) { - if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable1.header.ulImageDataOffset + ulNewGlyphOffset, - ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset, - ulGlyphLength)) != NO_ERROR) - return errCode; + if (TTF_SAFE_CHECKS_ENABLED()) + { + errCode = CopyEBDTBytesChecked( + (TTFACC_FILEBUFFERINFO *)pInputBufferInfo, + puchEBDTDestPtr, + ulEBDTSrcOffset, + ulEBDTAllocatedSize, + IndexSubTable1.header.ulImageDataOffset, + ulNewGlyphOffset, + ulOldImageDataOffset, + ulOldGlyphOffset, + ulGlyphLength); + if (errCode != NO_ERROR) + return errCode; + } + else + { + if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable1.header.ulImageDataOffset + ulNewGlyphOffset, + ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset, + ulGlyphLength)) != NO_ERROR) + return errCode; + } } ulNewGlyphOffset += ulGlyphLength; } @@ -300,14 +418,38 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, / /* check if there are any gaps */ if (IndexSubTable5.ulNumGlyphs != (uint32) (*pusNewLastGlyphIndex - *pusNewFirstGlyphIndex + 1)) /* not sparse, we got everyone */ { - ausGlyphCodeArray = (uint16 *) Mem_Alloc(sizeof(uint16) * IndexSubTable5.ulNumGlyphs); - /* Need to enlarge pointer too by the difference between Format 2 and format 5 */ - *pulIndexSubTableSize += (IndexSubTable5.ulNumGlyphs * sizeof(uint16) + sizeof(uint32)); - *ppuchIndexSubTable = (uint8 *)Mem_ReAlloc(*ppuchIndexSubTable, *pulIndexSubTableSize); - if ((ausGlyphCodeArray == NULL) || (*ppuchIndexSubTable == NULL)) + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulGlyphAllocSize, ulExtraSize; + if (ULongMult32((uint32)sizeof(uint16), IndexSubTable5.ulNumGlyphs, &ulGlyphAllocSize) != S_OK) + return ERR_MEM; + ausGlyphCodeArray = (uint16 *) Mem_Alloc(ulGlyphAllocSize); + /* Need to enlarge pointer too by the difference between Format 2 and format 5 */ + if (UIntAdd32(ulGlyphAllocSize, (uint32)sizeof(uint32), &ulExtraSize) != S_OK || + UIntAdd32(*pulIndexSubTableSize, ulExtraSize, pulIndexSubTableSize) != S_OK) + { + Mem_Free(ausGlyphCodeArray); + return ERR_MEM; + } + uint8 *pNewSubTable = (uint8 *)Mem_ReAlloc(*ppuchIndexSubTable, *pulIndexSubTableSize); + if ((ausGlyphCodeArray == NULL) || (pNewSubTable == NULL)) + { + Mem_Free(ausGlyphCodeArray); + return ERR_MEM; + } + *ppuchIndexSubTable = pNewSubTable; + } + else { - Mem_Free(ausGlyphCodeArray); - return ERR_MEM; + ausGlyphCodeArray = (uint16 *) Mem_Alloc(sizeof(uint16) * IndexSubTable5.ulNumGlyphs); + /* Need to enlarge pointer too by the difference between Format 2 and format 5 */ + *pulIndexSubTableSize += (IndexSubTable5.ulNumGlyphs * sizeof(uint16) + sizeof(uint32)); + *ppuchIndexSubTable = (uint8 *)Mem_ReAlloc(*ppuchIndexSubTable, *pulIndexSubTableSize); + if ((ausGlyphCodeArray == NULL) || (*ppuchIndexSubTable == NULL)) + { + Mem_Free(ausGlyphCodeArray); + return ERR_MEM; + } } } @@ -320,12 +462,33 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, / ausGlyphCodeArray[IndexSubTable5.ulNumGlyphs++] = i; if (DoCopy) /* if this glyph is supposed to be kept, copy glyph. */ { - if ((errCode = ReadBytes( (TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable2.header.ulImageDataOffset + ulNewGlyphOffset, - ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset, - ulGlyphLength)) != NO_ERROR) + if (TTF_SAFE_CHECKS_ENABLED()) + { + errCode = CopyEBDTBytesChecked( + (TTFACC_FILEBUFFERINFO *)pInputBufferInfo, + puchEBDTDestPtr, + ulEBDTSrcOffset, + ulEBDTAllocatedSize, + IndexSubTable2.header.ulImageDataOffset, + ulNewGlyphOffset, + ulOldImageDataOffset, + ulOldGlyphOffset, + ulGlyphLength); + if (errCode != NO_ERROR) + { + Mem_Free(ausGlyphCodeArray); /* in case it got allocated */ + return errCode; + } + } + else { - Mem_Free(ausGlyphCodeArray); /* in case it got allocated */ - return errCode; + if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable2.header.ulImageDataOffset + ulNewGlyphOffset, + ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset, + ulGlyphLength)) != NO_ERROR) + { + Mem_Free(ausGlyphCodeArray); /* in case it got allocated */ + return errCode; + } } } ulNewGlyphOffset += ulGlyphLength; @@ -340,14 +503,34 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, / if (ausGlyphCodeArray != NULL) /* we changed to format 5 */ { - ulTableSize = SIZEOF_INDEXSUBTABLE5 + sizeof(*ausGlyphCodeArray) * IndexSubTable5.ulNumGlyphs; - if (ulLocalCurrentOffset + ulTableSize > *pulIndexSubTableSize) + if (TTF_SAFE_CHECKS_ENABLED()) { - Mem_Free(ausGlyphCodeArray); /* in case it got allocated */ - return ERR_INVALID_EBLC; + uint32 ulGlyphDataSize; + if (ULongMult32((uint32)sizeof(*ausGlyphCodeArray), IndexSubTable5.ulNumGlyphs, &ulGlyphDataSize) != S_OK || + UIntAdd32(SIZEOF_INDEXSUBTABLE5, ulGlyphDataSize, &ulTableSize) != S_OK) + { + Mem_Free(ausGlyphCodeArray); + return ERR_INVALID_EBLC; + } + if (ulLocalCurrentOffset + ulTableSize > *pulIndexSubTableSize) + { + Mem_Free(ausGlyphCodeArray); /* in case it got allocated */ + return ERR_INVALID_EBLC; + } + memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset, &IndexSubTable5, SIZEOF_INDEXSUBTABLE5); + memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset + SIZEOF_INDEXSUBTABLE5, ausGlyphCodeArray, ulGlyphDataSize); + } + else + { + ulTableSize = SIZEOF_INDEXSUBTABLE5 + sizeof(*ausGlyphCodeArray) * IndexSubTable5.ulNumGlyphs; + if (ulLocalCurrentOffset + ulTableSize > *pulIndexSubTableSize) + { + Mem_Free(ausGlyphCodeArray); /* in case it got allocated */ + return ERR_INVALID_EBLC; + } + memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset, &IndexSubTable5, SIZEOF_INDEXSUBTABLE5); + memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset + SIZEOF_INDEXSUBTABLE5, ausGlyphCodeArray, sizeof(*ausGlyphCodeArray) * IndexSubTable5.ulNumGlyphs); } - memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset, &IndexSubTable5, SIZEOF_INDEXSUBTABLE5); - memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset + SIZEOF_INDEXSUBTABLE5, ausGlyphCodeArray, sizeof(*ausGlyphCodeArray) * IndexSubTable5.ulNumGlyphs); Mem_Free(ausGlyphCodeArray); } else @@ -396,16 +579,47 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, / ulTableSize +=sizeof(usNewGlyphOffset); /* update the size of the table */ if (usGlyphIndex < usGlyphListCount && puchKeepGlyphList[usGlyphIndex]) /* if this glyph is supposed to be kept, copy glyph. */ { - assert(usNextGlyphOffset>=usOldGlyphOffset); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (usNextGlyphOffset < usOldGlyphOffset) + return ERR_INVALID_EBLC; + } + else + { + assert(usNextGlyphOffset>=usOldGlyphOffset); + } usGlyphLength = usNextGlyphOffset-usOldGlyphOffset; if (DoCopy) { - if ((errCode = ReadBytes( (TTFACC_FILEBUFFERINFO *) pInputBufferInfo, puchEBDTDestPtr + IndexSubTable3.header.ulImageDataOffset + usNewGlyphOffset, - ulEBDTSrcOffset + ulOldImageDataOffset + usOldGlyphOffset, - usGlyphLength)) != NO_ERROR) - return errCode; + if (TTF_SAFE_CHECKS_ENABLED()) + { + errCode = CopyEBDTBytesChecked( + (TTFACC_FILEBUFFERINFO *)pInputBufferInfo, + puchEBDTDestPtr, + ulEBDTSrcOffset, + ulEBDTAllocatedSize, + IndexSubTable3.header.ulImageDataOffset, + (uint32)usNewGlyphOffset, + ulOldImageDataOffset, + (uint32)usOldGlyphOffset, + (uint32)usGlyphLength); + if (errCode != NO_ERROR) + return errCode; + } + else + { + if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable3.header.ulImageDataOffset + usNewGlyphOffset, + ulEBDTSrcOffset + ulOldImageDataOffset + usOldGlyphOffset, + usGlyphLength)) != NO_ERROR) + return errCode; + } } usNewGlyphOffset = (uint16)(usNewGlyphOffset + usGlyphLength); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (usNewGlyphOffset < usGlyphLength) /* uint16 wrap check */ + return ERR_INVALID_EBLC; + } } } usOldGlyphOffset = usNextGlyphOffset; @@ -457,16 +671,44 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, / ulTableSize +=sizeof(usGlyphIndex); memcpy(*ppuchIndexSubTable + ulLocalCurrentOffset+ulTableSize, &usNewGlyphOffset, sizeof(usNewGlyphOffset)); ulTableSize +=sizeof(usNewGlyphOffset); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (usNextGlyphOffset < usOldGlyphOffset) + return ERR_INVALID_EBLC; + } usGlyphLength = usNextGlyphOffset-usOldGlyphOffset; if (DoCopy) { - if ((errCode = ReadBytes( (TTFACC_FILEBUFFERINFO *) pInputBufferInfo, puchEBDTDestPtr + IndexSubTable4.header.ulImageDataOffset + usNewGlyphOffset, - ulEBDTSrcOffset + ulOldImageDataOffset + usOldGlyphOffset, - usGlyphLength)) != NO_ERROR) - return errCode; + if (TTF_SAFE_CHECKS_ENABLED()) + { + errCode = CopyEBDTBytesChecked( + (TTFACC_FILEBUFFERINFO *)pInputBufferInfo, + puchEBDTDestPtr, + ulEBDTSrcOffset, + ulEBDTAllocatedSize, + IndexSubTable4.header.ulImageDataOffset, + (uint32)usNewGlyphOffset, + ulOldImageDataOffset, + (uint32)usOldGlyphOffset, + (uint32)usGlyphLength); + if (errCode != NO_ERROR) + return errCode; + } + else + { + if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable4.header.ulImageDataOffset + usNewGlyphOffset, + ulEBDTSrcOffset + ulOldImageDataOffset + usOldGlyphOffset, + usGlyphLength)) != NO_ERROR) + return errCode; + } } usNewGlyphOffset = (uint16)(usNewGlyphOffset + usGlyphLength); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (usNewGlyphOffset < usGlyphLength) /* uint16 wrap check */ + return ERR_INVALID_EBLC; + } ++ulNumGlyphs; *pusNewLastGlyphIndex = usGlyphIndex; } @@ -521,10 +763,28 @@ PRIVATE int16 FixSbitSubTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, / ulTableSize += sizeof(usGlyphIndex); if (DoCopy) { - if ((errCode = ReadBytes( (TTFACC_FILEBUFFERINFO *) pInputBufferInfo, puchEBDTDestPtr + IndexSubTable5.header.ulImageDataOffset + ulNewGlyphOffset, - ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset, - ulGlyphLength)) != NO_ERROR) - return errCode; + if (TTF_SAFE_CHECKS_ENABLED()) + { + errCode = CopyEBDTBytesChecked( + (TTFACC_FILEBUFFERINFO *)pInputBufferInfo, + puchEBDTDestPtr, + ulEBDTSrcOffset, + ulEBDTAllocatedSize, + IndexSubTable5.header.ulImageDataOffset, + ulNewGlyphOffset, + ulOldImageDataOffset, + ulOldGlyphOffset, + ulGlyphLength); + if (errCode != NO_ERROR) + return errCode; + } + else + { + if ((errCode = ReadBytes((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, puchEBDTDestPtr + IndexSubTable5.header.ulImageDataOffset + ulNewGlyphOffset, + ulEBDTSrcOffset + ulOldImageDataOffset + ulOldGlyphOffset, + ulGlyphLength)) != NO_ERROR) + return errCode; + } } ++ulNumGlyphs; ulNewGlyphOffset += ulGlyphLength; @@ -580,6 +840,7 @@ typedef struct { PRIVATE uint32 FixSbitSubTableFormat1(uint16 usFirstIndex, /* index of first Glyph in table */ uint16 * pusLastIndex, /* pointer to index of last glyph in table - will set if not all table will fit */ uint8 * puchIndexSubTable, /* buffer into which to stuff the Format 3 table(s) - does not include IndexSubTableArray */ + uint32 ulIndexSubTableBufferSize, /* size of puchIndexSubTable buffer for bounds checking */ uint16 usImageFormat, /* in order to set the Format 3 header */ uint32 ulCurrAdditionalOffset, /* offset from indexSubTableArray of the IndexSubTable */ uint32 ulInitialOffset, /* relative offset from IndexSubTableArray of first IndexSubTable - same as CurrAdditionalOffset for first SubTable */ @@ -593,21 +854,42 @@ uint32 ulLocalCurrentOffset; uint32 ulTableSize; uint32 ulAdjustGlyphOffset; /* amount to subtract to get the relative offset */ uint16 usIndex; +uint32 ulWriteEnd; ulLocalCurrentOffset = ulCurrAdditionalOffset - ulInitialOffset; /* offset within memory buffer */ + /* Bounds check: ensure header write fits in buffer */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ulLocalCurrentOffset + SIZEOF_INDEXSUBTABLE3 > ulIndexSubTableBufferSize) + return 0; + } + IndexSubTable3.header.usImageFormat = usImageFormat; IndexSubTable3.header.usIndexFormat = 3; IndexSubTable3.header.ulImageDataOffset = *pulNewImageDataOffset; /* set to the new one */ memcpy(puchIndexSubTable + ulLocalCurrentOffset, &IndexSubTable3, SIZEOF_INDEXSUBTABLE3); ulTableSize = SIZEOF_INDEXSUBTABLE3; + /* Bounds check: ensure source reads are within buffer */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (*pulSourceOffset + sizeof(uint32) > ulIndexSubTableBufferSize) + return 0; + } ulAdjustGlyphOffset = * ((uint32 *) (puchIndexSubTable + *pulSourceOffset)); /* first offset is what we adjust from */ ulNewGlyphOffset = (* ((uint32 *) (puchIndexSubTable + *pulSourceOffset))) - ulAdjustGlyphOffset; /* first one of array */ *pulSourceOffset += sizeof(uint32); for( usIndex = usFirstIndex; usIndex <= (* pusLastIndex); ++usIndex ) { + /* Bounds check: ensure source read fits in buffer */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (*pulSourceOffset + sizeof(uint32) > ulIndexSubTableBufferSize) + return 0; + } + usNewGlyphOffset = (uint16) ulNewGlyphOffset; /* short version of the new glyph offset */ /* now grab the next one */ ulNewGlyphOffset = (* ((uint32 *) (puchIndexSubTable + *pulSourceOffset))) - ulAdjustGlyphOffset; @@ -617,6 +899,14 @@ uint16 usIndex; *pulSourceOffset += sizeof(uint32); /* copied this one */ + /* Bounds check: ensure write fits in buffer */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + ulWriteEnd = ulLocalCurrentOffset + ulTableSize + sizeof(usNewGlyphOffset); + if (ulWriteEnd > ulIndexSubTableBufferSize) + return 0; + } + memcpy(puchIndexSubTable + ulLocalCurrentOffset+ulTableSize, &usNewGlyphOffset, sizeof(usNewGlyphOffset)); /* copy over the table entry */ ulTableSize +=sizeof(usNewGlyphOffset); /* update the size of the table */ @@ -630,6 +920,13 @@ uint16 usIndex; if (usIndex > (* pusLastIndex)) /* we need to copy one more */ /* Do the last table entry, which is just for Glyph size calculation purposes */ { + /* Bounds check for final entry */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + ulWriteEnd = ulLocalCurrentOffset + ulTableSize + sizeof(usNewGlyphOffset); + if (ulWriteEnd > ulIndexSubTableBufferSize) + return 0; + } memcpy(puchIndexSubTable + ulLocalCurrentOffset+ulTableSize, &usNewGlyphOffset,sizeof(usNewGlyphOffset)); ulTableSize +=sizeof(usNewGlyphOffset); } @@ -652,6 +949,7 @@ PRIVATE int16 FixSbitSubTableArray(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInf uint32 *pulNewImageDataOffset, uint8 *puchEBDTDestPtr, uint32 ulEBDTSrcOffset, + uint32 ulEBDTAllocatedSize, PGLYPHOFFSETRECORDKEEPER pKeeper, uint32 ulEBLCEndOffset) { @@ -724,6 +1022,7 @@ PRIVATE int16 FixSbitSubTableArray(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInf &ulEBDTBytesWritten, puchEBDTDestPtr, ulEBDTSrcOffset, + ulEBDTAllocatedSize, pKeeper); if (errCode != NO_ERROR) return errCode; @@ -753,6 +1052,7 @@ PRIVATE int16 FixSbitSubTableArray(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInf usFirstIndex, &usLastIndex, pSubTablePointers->puchIndexSubTables, + pSubTablePointers->nIndexSubTablesLen, ((INDEXSUBHEADER *) (pSubTablePointers->puchIndexSubTables + ulCurrAdditionalOffset-ulInitialOffset))->usImageFormat, ulCurrAdditionalOffset, ulInitialOffset, @@ -777,9 +1077,19 @@ PRIVATE int16 FixSbitSubTableArray(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInf { return ERR_MEM; } - pSubTablePointers->pIndexSubTableArray = (INDEXSUBTABLEARRAY *)Mem_ReAlloc(pSubTablePointers->pIndexSubTableArray, ulSubTableArrayLength); - if (pSubTablePointers->pIndexSubTableArray == NULL) - return ERR_MEM; /* ("EBLC: Unable to allocate memory for IndexSubTableArray."); */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + INDEXSUBTABLEARRAY *pNewArray = (INDEXSUBTABLEARRAY *)Mem_ReAlloc(pSubTablePointers->pIndexSubTableArray, ulSubTableArrayLength); + if (pNewArray == NULL) + return ERR_MEM; /* ("EBLC: Unable to allocate memory for IndexSubTableArray."); */ + pSubTablePointers->pIndexSubTableArray = pNewArray; + } + else + { + pSubTablePointers->pIndexSubTableArray = (INDEXSUBTABLEARRAY *)Mem_ReAlloc(pSubTablePointers->pIndexSubTableArray, ulSubTableArrayLength); + if (pSubTablePointers->pIndexSubTableArray == NULL) + return ERR_MEM; + } usFirstIndex = usLastIndex; usLastIndex = usSaveLastIndex; } @@ -887,7 +1197,7 @@ uint32 ulStartOffset; /* ------------------------------------------------------------------- */ void Cleanup_SubTablePointers(SubTablePointers *pSubTablePointers,uint32 ulNumSizes) { -uint16 ulSizeIndex; +uint32 ulSizeIndex; if (pSubTablePointers == NULL) return; @@ -954,6 +1264,7 @@ uint32 ulIndexSubTableArrayLength; uint32 ulIndexSubTablesDataSize; uint32 ulSubtablePointersArraySize; uint16 i; +uint32 ulEBDTAllocatedSize = 0; /* Track allocated EBDT buffer size for bounds checking */ GLYPHOFFSETRECORDKEEPER keeper; char *EBDTTag; char *EBLCTag; @@ -1031,8 +1342,24 @@ uint32 ulEBLCEndOffset; keeper.ulOffsetArrayLen = 0; keeper.ulNextArrayIndex = 0; - /* create a buffer for the EBDT table */ - puchEBDTDestPtr = (uint8 *) Mem_Alloc(TTTableLength((TTFACC_FILEBUFFERINFO *) pInputBufferInfo, EBDTTag)); /* we'll be copying the EBDT (raw bytes) table here temporarily */ + /* Validate EBDT table size before allocation */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + /* Validate EBDT table size before allocation */ + ulEBDTAllocatedSize = TTTableLength((TTFACC_FILEBUFFERINFO*)pInputBufferInfo, EBDTTag); + if (ulEBDTAllocatedSize < SIZEOF_EBDTHEADER) + { + errCode = ERR_INVALID_EBLC; + break; + } + /* create a buffer for the EBDT table */ + puchEBDTDestPtr = (uint8*)Mem_Alloc(ulEBDTAllocatedSize); /* we'll be copying the EBDT (raw bytes) table here temporarily */ + } + else + { + /* create a buffer for the EBDT table */ + puchEBDTDestPtr = (uint8 *) Mem_Alloc(TTTableLength((TTFACC_FILEBUFFERINFO *) pInputBufferInfo, EBDTTag)); /* we'll be copying the EBDT (raw bytes) table here temporarily */ + } if (!puchEBDTDestPtr) { errCode = ERR_MEM; @@ -1163,6 +1490,7 @@ uint32 ulEBLCEndOffset; &ulNewImageDataOffset, puchEBDTDestPtr, ulEBDTSrcOffset, + ulEBDTAllocatedSize, &keeper, ulEBLCEndOffset) == NO_ERROR) /* valid table */ && diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modtable.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modtable.cpp index f61c38cd718..0eda170eb15 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modtable.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/modtable.cpp @@ -37,6 +37,8 @@ #include "ttmem.h" #include "ttfdelta.h" /* for format */ #include "ttferror.h" /* for error codes */ +#include "intsafe_private_copy.h" +#include "ttf_safe_checks.h" /* here's the deal: This function may do one of many things. @@ -170,7 +172,17 @@ const char * xhea_tag; /* now collapse the table if we are in Compact form for Subsetting and Delta fonts */ /* we will use an interrum table for simplification */ ulCrntOffset = ulXmtxOffset; - LongMetricsArray = (LONGXMETRIC *)Mem_Alloc(sizeof(LONGXMETRIC) * usDttfGlyphIndexCount); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)sizeof(LONGXMETRIC), (uint32)usDttfGlyphIndexCount, &ulAllocSize) != S_OK) + return ERR_MEM; + LongMetricsArray = (LONGXMETRIC *)Mem_Alloc(ulAllocSize); + } + else + { + LongMetricsArray = (LONGXMETRIC *)Mem_Alloc(sizeof(LONGXMETRIC) * usDttfGlyphIndexCount); + } if (LongMetricsArray == NULL) return ERR_MEM; nNewLongMetrics = 0; @@ -278,8 +290,22 @@ uint16 usBytesWritten; /* recompute maxp info */ /* figure a conservative maximum total possible. 3x3 at minimum */ - usnMaxComponents = max(3,MaxP.maxComponentElements) * max(3,MaxP.maxComponentDepth); - pausComponents = (uint16 *) Mem_Alloc(usnMaxComponents * sizeof(uint16)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulMaxComp, ulAllocSize; + if (ULongMult32((uint32)max(3,MaxP.maxComponentElements), (uint32)max(3,MaxP.maxComponentDepth), &ulMaxComp) != S_OK || + ULongMult32(ulMaxComp, (uint32)sizeof(uint16), &ulAllocSize) != S_OK) + return ERR_MEM; + if (ulMaxComp > (uint32)USHRT_MAX) + return ERR_INVALID_MAXP; + usnMaxComponents = (uint16)ulMaxComp; + pausComponents = (uint16 *) Mem_Alloc(ulAllocSize); + } + else + { + usnMaxComponents = max(3,MaxP.maxComponentElements) * max(3,MaxP.maxComponentDepth); + pausComponents = (uint16 *) Mem_Alloc(usnMaxComponents * sizeof(uint16)); + } if (pausComponents == NULL) return ERR_MEM; @@ -716,7 +742,16 @@ uint32 ulOutSizeDeviceRecord; DevRecord.maxWidth = maxWidth; if ((errCode = WriteGeneric( pOutputBufferInfo, (uint8 *)&DevRecord, SIZEOF_HDMX_DEVICE_REC, HDMX_DEVICE_REC_CONTROL, ulOutDevOffset, &usBytesWritten )) != NO_ERROR) return errCode; - ulInOffset = ulInDevOffset + Hdmx.sizeDeviceRecord; + if (TTF_SAFE_CHECKS_ENABLED()) + { + ulInOffset = ulInDevOffset + (uint32)Hdmx.sizeDeviceRecord; + if (ulInOffset < ulInDevOffset) /* overflow check */ + return ERR_GENERIC; + } + else + { + ulInOffset = ulInDevOffset + Hdmx.sizeDeviceRecord; + } ulOutOffset = ulOutDevOffset + ulOutSizeDeviceRecord; } /* now need to update hdmx record */ @@ -762,7 +797,16 @@ uint32 ulOutSizeDeviceRecord; if ((errCode = WriteGeneric( pOutputBufferInfo, (uint8 *)&DevRecord, SIZEOF_HDMX_DEVICE_REC, HDMX_DEVICE_REC_CONTROL, ulDevOffset, &usBytesWritten )) != NO_ERROR) return errCode; } - ulOffset = ulDevOffset + Hdmx.sizeDeviceRecord; + if (TTF_SAFE_CHECKS_ENABLED()) + { + ulOffset = ulDevOffset + (uint32)Hdmx.sizeDeviceRecord; + if (ulOffset < ulDevOffset) /* overflow check */ + return ERR_GENERIC; + } + else + { + ulOffset = ulDevOffset + Hdmx.sizeDeviceRecord; + } } *pulNewOutOffset = ulOffset; } @@ -893,7 +937,17 @@ struct groupoffsetrecordkeeper /* housekeeping structure */ PRIVATE int16 InitGroupOffsetArray(PGROUPOFFSETRECORDKEEPER pKeeper, uint16 usRecordCount) { - pKeeper->pGroupOffsetArray = (GroupOffsetRecord *) Mem_Alloc(usRecordCount * sizeof(*(pKeeper->pGroupOffsetArray))); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)usRecordCount, (uint32)sizeof(*(pKeeper->pGroupOffsetArray)), &ulAllocSize) != S_OK) + return ERR_MEM; + pKeeper->pGroupOffsetArray = (GroupOffsetRecord *) Mem_Alloc(ulAllocSize); + } + else + { + pKeeper->pGroupOffsetArray = (GroupOffsetRecord *) Mem_Alloc(usRecordCount * sizeof(*(pKeeper->pGroupOffsetArray))); + } if (pKeeper->pGroupOffsetArray == NULL) return ERR_MEM; pKeeper->usGroupOffsetArrayLen = usRecordCount; @@ -1018,7 +1072,19 @@ TTFACC_FILEBUFFERINFO * pUnCONSTInputBufferInfo; ulSrcOffsetGroups = ulSrcOffsetOffsets + sizeof(uint16) * Vdmx.numRatios; memset(&keeper, 0, sizeof(keeper)); - SrcRatioArray = (VDMXRatio *)Mem_Alloc(Vdmx.numRatios * sizeof(VDMXRatio)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)Vdmx.numRatios, (uint32)sizeof(VDMXRatio), &ulAllocSize) != S_OK) + { + return ERR_MEM; + } + SrcRatioArray = (VDMXRatio *)Mem_Alloc(ulAllocSize); + } + else + { + SrcRatioArray = (VDMXRatio *)Mem_Alloc(Vdmx.numRatios * sizeof(VDMXRatio)); + } if (SrcRatioArray == NULL) errCode = ERR_MEM; else @@ -1111,7 +1177,19 @@ TTFACC_FILEBUFFERINFO * pUnCONSTInputBufferInfo; if ((errCode = ReadGeneric(pUnCONSTInputBufferInfo, (uint8 *) &GroupHeader, SIZEOF_VDMXGROUP, VDMXGROUP_CONTROL, ulSrcOffset + usCurrGroupSrcOffset, &usBytesRead)) != NO_ERROR) break; - ulGroupLength = usBytesRead + (GroupHeader.recs * GetGenericSize(VDMXVTABLE_CONTROL)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + ulGroupLength = usBytesRead + ((uint32)GroupHeader.recs * GetGenericSize(VDMXVTABLE_CONTROL)); + if (ulGroupLength < usBytesRead) /* overflow check */ + { + errCode = ERR_INVALID_VDMX; + break; + } + } + else + { + ulGroupLength = usBytesRead + (GroupHeader.recs * GetGenericSize(VDMXVTABLE_CONTROL)); + } /* read the group data into a buffer */ if (ulGroupLength > ulGroupBufferLength) { diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttf_safe_checks.h b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttf_safe_checks.h new file mode 100644 index 00000000000..947624e5fde --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttf_safe_checks.h @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef TTF_SAFE_CHECKS_H +#define TTF_SAFE_CHECKS_H + +/* + * TtfDelta safety switch — read once from managed code (AppContext), + * then checked from native C code via the global. + * + * AppContext switch name: + * Switch.MS.Internal.TtfDelta.DisableDirectWriteForwarderBoundsCheckProtection + * + * Default (false / absent): Safe checks ON (new behavior). + * Set to true: Safe checks OFF (old behavior / opt-out). + */ + +/* -1 = uninitialized, 0 = safe checks disabled (old), 1 = safe checks enabled (new) */ +extern int g_fDWFBoundsCheckEnabled; + +#define TTF_SAFE_CHECKS_ENABLED() (g_fDWFBoundsCheckEnabled != 0) + +#endif /* TTF_SAFE_CHECKS_H */ diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfacc.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfacc.cpp index 8a2bce89d10..23562d736b0 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfacc.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfacc.cpp @@ -23,6 +23,8 @@ #ifdef _DEBUG #include #endif +#include "intsafe_private_copy.h" +#include "ttf_safe_checks.h" #if 0 /* turn back into a macro, because it gets called so much */ @@ -73,7 +75,7 @@ int16 CheckOutOffset(TTFACC_FILEBUFFERINFO *a, register uint32 b, register uint3 { #ifdef _DEBUG #if !defined(ARGITERATOR_SUPPORTED) || (defined(ARGITERATOR_SUPPORTED) && ARGITERATOR_SUPPORTED) - printf("we're reallocating 10 percent (%lu) more bytes\n", (uint32)(a->ulBufferSize * .1)); + printf("we're reallocating 10 percent (%lu) more bytes\n", (uint32)(a->ulBufferSize * .1)); #endif #endif a->ulBufferSize = (uint32) (a->ulBufferSize * 11/10); @@ -86,14 +88,14 @@ int16 CheckOutOffset(TTFACC_FILEBUFFERINFO *a, register uint32 b, register uint3 #endif #endif a->ulBufferSize = b + c; - } - + } + if ((a->puchBuffer = (uint8 *)a->lpfnReAllocate(a->puchBuffer, a->ulBufferSize)) == NULL) { a->ulBufferSize = 0L; return ERR_MEM; } - } + } return NO_ERROR; } @@ -242,14 +244,30 @@ UNALIGNED uint32 *pulBuffer; uint16 i; int16 errCode; - usControlCount = puchControl[0]; +if (TTF_SAFE_CHECKS_ENABLED()) +{ + if (pInputBufferInfo == NULL || puchControl == NULL || pusBytesRead == NULL) + return ERR_READCONTROL; + if (usBufferSize != 0 && puchBuffer == NULL) + return ERR_READCONTROL; +} + + usControlCount = puchControl[0]; for (i = 1; i <= usControlCount; ++i) { switch (puchControl[i] & TTFACC_DATA) { case TTFACC_BYTE: - if (usBufferOffset + sizeof(uint8) > usBufferSize) - return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (static_cast(usBufferOffset) + static_cast(sizeof(uint8)) > static_cast(usBufferSize)) + return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */ + } + else + { + if (usBufferOffset + sizeof(uint8) > usBufferSize) + return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */ + } if (puchControl[i] & TTFACC_PAD) /* don't read, just pad */ *(puchBuffer + usBufferOffset) = 0; else @@ -257,13 +275,30 @@ int16 errCode; if ((errCode = ReadByte(pInputBufferInfo, puchBuffer + usBufferOffset, ulCurrOffset))!=NO_ERROR) return errCode; - ulCurrOffset += sizeof(uint8); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ulCurrOffset + static_cast(sizeof(uint8)) < ulCurrOffset) + return ERR_READOUTOFBOUNDS; + ulCurrOffset += static_cast(sizeof(uint8)); + } + else + { + ulCurrOffset += sizeof(uint8); + } } usBufferOffset += sizeof(uint8); break; case TTFACC_WORD: - if (usBufferOffset + sizeof(uint16) > usBufferSize) - return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (static_cast(usBufferOffset) + static_cast(sizeof(uint16)) > static_cast(usBufferSize)) + return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */ + } + else + { + if (usBufferOffset + sizeof(uint16) > usBufferSize) + return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */ + } pusBuffer = (uint16 *) (puchBuffer + usBufferOffset); if (puchControl[i] & TTFACC_PAD) /* don't read, just pad */ *pusBuffer = 0; @@ -279,13 +314,30 @@ int16 errCode; if ((errCode = ReadWord(pInputBufferInfo, pusBuffer, ulCurrOffset))!=NO_ERROR) return errCode; } - ulCurrOffset += sizeof(uint16); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ulCurrOffset + static_cast(sizeof(uint16)) < ulCurrOffset) + return ERR_READOUTOFBOUNDS; + ulCurrOffset += static_cast(sizeof(uint16)); + } + else + { + ulCurrOffset += sizeof(uint16); + } } usBufferOffset += sizeof(uint16); break; case TTFACC_LONG: - if (usBufferOffset + sizeof(uint32) > usBufferSize) - return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (static_cast(usBufferOffset) + static_cast(sizeof(uint32)) > static_cast(usBufferSize)) + return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */ + } + else + { + if (usBufferOffset + sizeof(uint32) > usBufferSize) + return ERR_READCONTROL; /* trying to stuff too many bytes into target buffer */ + } pulBuffer = (uint32 *) (puchBuffer + usBufferOffset); if (puchControl[i] & TTFACC_PAD) /* don't read, just pad */ *pulBuffer = 0; @@ -302,7 +354,16 @@ int16 errCode; if ((errCode = ReadLong(pInputBufferInfo, pulBuffer, ulCurrOffset))!=NO_ERROR) return errCode; } - ulCurrOffset += sizeof(uint32); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ulCurrOffset + static_cast(sizeof(uint32)) < ulCurrOffset) + return ERR_READOUTOFBOUNDS; + ulCurrOffset += static_cast(sizeof(uint32)); + } + else + { + ulCurrOffset += sizeof(uint32); + } } usBufferOffset += sizeof(uint32); break; @@ -312,7 +373,17 @@ int16 errCode; } /* end for i */ if (usBufferOffset < usBufferSize) /* didn't fill up the buffer */ return ERR_READCONTROL; /* control thing doesn't fit the buffer */ - * pusBytesRead = (uint16) (ulCurrOffset - ulOffset); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulBytesRead = ulCurrOffset - ulOffset; + *pusBytesRead = static_cast(ulBytesRead); + if (static_cast(*pusBytesRead) != ulBytesRead) + return ERR_READCONTROL; + } + else + { + * pusBytesRead = (uint16) (ulCurrOffset - ulOffset); + } return NO_ERROR; } /* ---------------------------------------------------------------------- */ @@ -348,7 +419,17 @@ uint16 usBytesRead; puchBuffer += usItemSize; } - *pulBytesRead = usItemSize * usItemCount; + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulTotalBytesRead; + if (ULongMult32((uint32)usItemSize, (uint32)usItemCount, &ulTotalBytesRead) != S_OK) + return ERR_READOUTOFBOUNDS; + *pulBytesRead = ulTotalBytesRead; + } + else + { + *pulBytesRead = usItemSize * usItemCount; + } return NO_ERROR; } /* ---------------------------------------------------------------------- */ @@ -378,7 +459,15 @@ uint16 i; uint32 ulBytesWritten; int16 errCode; - usControlCount = puchControl[0]; +if (TTF_SAFE_CHECKS_ENABLED()) +{ + if (pOutputBufferInfo == NULL || puchControl == NULL || pusBytesWritten == NULL) + return ERR_WRITECONTROL; + if (usBufferSize != 0 && puchBuffer == NULL) + return ERR_WRITECONTROL; +} + + usControlCount = puchControl[0]; for (i = 1; i <= usControlCount; ++i) { switch (puchControl[i] & TTFACC_DATA) @@ -386,20 +475,45 @@ int16 errCode; case TTFACC_BYTE: if (!(puchControl[i] & TTFACC_PAD)) { - if (usBufferOffset + sizeof(uint8) > usBufferSize) - return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (static_cast(usBufferOffset) + static_cast(sizeof(uint8)) > static_cast(usBufferSize)) + return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */ + } + else + { + if (usBufferOffset + sizeof(uint8) > usBufferSize) + return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */ + } if ((errCode = WriteByte(pOutputBufferInfo, *(puchBuffer + usBufferOffset), ulCurrOffset))!=NO_ERROR) return errCode; - ulCurrOffset += sizeof(uint8); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ulCurrOffset + static_cast(sizeof(uint8)) < ulCurrOffset) + return ERR_WRITEOUTOFBOUNDS; + ulCurrOffset += static_cast(sizeof(uint8)); + } + else + { + ulCurrOffset += sizeof(uint8); + } } usBufferOffset += sizeof(uint8); break; case TTFACC_WORD: if (!(puchControl[i] & TTFACC_PAD)) { - if (usBufferOffset + sizeof(uint16) > usBufferSize) - return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (static_cast(usBufferOffset) + static_cast(sizeof(uint16)) > static_cast(usBufferSize)) + return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */ + } + else + { + if (usBufferOffset + sizeof(uint16) > usBufferSize) + return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */ + } pusBuffer = (uint16 *) (puchBuffer + usBufferOffset); if (puchControl[i] & TTFACC_NO_XLATE) @@ -412,15 +526,32 @@ int16 errCode; if ((errCode = WriteWord(pOutputBufferInfo, *pusBuffer, ulCurrOffset))!=NO_ERROR) return errCode; } - ulCurrOffset += sizeof(uint16); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ulCurrOffset + static_cast(sizeof(uint16)) < ulCurrOffset) + return ERR_WRITEOUTOFBOUNDS; + ulCurrOffset += static_cast(sizeof(uint16)); + } + else + { + ulCurrOffset += sizeof(uint16); + } } usBufferOffset += sizeof(uint16); break; case TTFACC_LONG: if (!(puchControl[i] & TTFACC_PAD)) { - if (usBufferOffset + sizeof(uint32) > usBufferSize) - return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (static_cast(usBufferOffset) + static_cast(sizeof(uint32)) > static_cast(usBufferSize)) + return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */ + } + else + { + if (usBufferOffset + sizeof(uint32) > usBufferSize) + return ERR_WRITECONTROL; /* trying to read too many bytes from source buffer */ + } pulBuffer = (uint32 *) (puchBuffer + usBufferOffset); if (puchControl[i] & TTFACC_NO_XLATE) @@ -433,7 +564,16 @@ int16 errCode; if ((errCode = WriteLong(pOutputBufferInfo, *pulBuffer, ulCurrOffset))!=NO_ERROR) return errCode; } - ulCurrOffset += sizeof(uint32); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ulCurrOffset + static_cast(sizeof(uint32)) < ulCurrOffset) + return ERR_WRITEOUTOFBOUNDS; + ulCurrOffset += static_cast(sizeof(uint32)); + } + else + { + ulCurrOffset += sizeof(uint32); + } } usBufferOffset += sizeof(uint32); break; @@ -482,7 +622,17 @@ uint16 usBytesWritten; puchBuffer += usItemSize; } - *pulBytesWritten = usItemSize * usItemCount; + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulTotalBytesWritten; + if (ULongMult32((uint32)usItemSize, (uint32)usItemCount, &ulTotalBytesWritten) != S_OK) + return ERR_WRITEOUTOFBOUNDS; + *pulBytesWritten = ulTotalBytesWritten; + } + else + { + *pulBytesWritten = usItemSize * usItemCount; + } return NO_ERROR; } diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfdelta.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfdelta.cpp index 3e3530dbec6..a841c171915 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfdelta.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttfdelta.cpp @@ -19,6 +19,9 @@ #include /* for memcpy */ #include "typedefs.h" +#include "intsafe_private_copy.h" +#include "ttf_safe_checks.h" + #include "ttff.h" #include "ttfacc.h" #include "ttfcntrl.h" @@ -111,7 +114,14 @@ int16 errCode; ulOffset += usBytesRead; /* Create a list of valid tables */ - aDirectory = (DIRECTORY *) Mem_Alloc((usnTables + (ulDttfOffset == 0)) * sizeof(DIRECTORY)); /* one extra for possible private table */ + if (TTF_SAFE_CHECKS_ENABLED()) { + uint32 ulAllocSize; + if (ULongMult32((uint32)(usnTables + (ulDttfOffset == 0)), (uint32)sizeof(DIRECTORY), &ulAllocSize) != S_OK) + return(ERR_MEM); + aDirectory = (DIRECTORY *) Mem_Alloc(ulAllocSize); /* one extra for possible private table */ + } else { + aDirectory = (DIRECTORY *) Mem_Alloc((usnTables + (ulDttfOffset == 0)) * sizeof(DIRECTORY)); + } if (aDirectory == NULL) return(ERR_MEM); @@ -213,7 +223,14 @@ char szTag[5]; usnTables = OffsetTable.numTables; /* Create a list of valid tables */ - aDirectory = (DIRECTORY *) Mem_Alloc((usnTables) * sizeof(DIRECTORY)); + if (TTF_SAFE_CHECKS_ENABLED()) { + uint32 ulAllocSize; + if (ULongMult32((uint32)usnTables, (uint32)sizeof(DIRECTORY), &ulAllocSize) != S_OK) + return(ERR_MEM); + aDirectory = (DIRECTORY *) Mem_Alloc(ulAllocSize); + } else { + aDirectory = (DIRECTORY *) Mem_Alloc((usnTables) * sizeof(DIRECTORY)); + } if (aDirectory == NULL) return(ERR_MEM); @@ -297,7 +314,15 @@ HEAD Head; if ((ulHeadOffset = GetHead(pOutputBufferInfo, &Head)) == 0L) return ERR_MISSING_HEAD; - aulLoca = (uint32 *)Mem_Alloc( (usGlyphListCount + 1) * sizeof( uint32 )); + if (TTF_SAFE_CHECKS_ENABLED()) { + uint32 ulLocaCount = (uint32)usGlyphListCount + 1; + uint32 ulAllocSize; + if (ULongMult32(ulLocaCount, (uint32)sizeof( uint32 ), &ulAllocSize) != S_OK) + return ERR_MEM; + aulLoca = (uint32 *)Mem_Alloc( ulAllocSize ); + } else { + aulLoca = (uint32 *)Mem_Alloc( (usGlyphListCount + 1) * sizeof( uint32 ) ); + } if ( aulLoca == NULL ) return ERR_MEM; @@ -316,8 +341,16 @@ HEAD Head; if ((j == usDttfGlyphIndexCount) || (i < usGlyphListCount && puchKeepGlyphList[i])) { usOffset = (uint16) (aulLoca[ i ] / 2L); - if ((errCode = WriteWord( pOutputBufferInfo, usOffset, ulLocaOffset + j*sizeof(uint16) )) != NO_ERROR) - break; + if (TTF_SAFE_CHECKS_ENABLED()) + { + if ((errCode = WriteWord( pOutputBufferInfo, usOffset, ulLocaOffset + (uint32)j*sizeof(uint16) )) != NO_ERROR) + break; + } + else + { + if ((errCode = WriteWord( pOutputBufferInfo, usOffset, ulLocaOffset + j*sizeof(uint16) )) != NO_ERROR) + break; + } ++j; } } @@ -329,8 +362,16 @@ HEAD Head; { if ((j == usDttfGlyphIndexCount) || (i < usGlyphListCount && puchKeepGlyphList[i])) { - if ((errCode = WriteLong( pOutputBufferInfo, aulLoca[ i ], ulLocaOffset + j*sizeof(uint32) )) != NO_ERROR) - break; + if (TTF_SAFE_CHECKS_ENABLED()) + { + if ((errCode = WriteLong( pOutputBufferInfo, aulLoca[ i ], ulLocaOffset + (uint32)j*sizeof(uint32) )) != NO_ERROR) + break; + } + else + { + if ((errCode = WriteLong( pOutputBufferInfo, aulLoca[ i ], ulLocaOffset + j*sizeof(uint32) )) != NO_ERROR) + break; + } ++j; } } @@ -385,11 +426,23 @@ uint16 usBytesWritten; if (usFormat != TTFDELTA_SUBSET1 && usFormat != TTFDELTA_DELTA) /* formats with dttf tables */ return NO_ERROR; + if (TTF_SAFE_CHECKS_ENABLED()) { + if (usDttfGlyphIndexCount == 0) + return ERR_GENERIC; + } + ulOffset = GetTTDirectory( pOutputBufferInfo, DTTF_TAG, &DttfDirectory); if ((errCode = ZeroLongWordAlign(pOutputBufferInfo, *pulNewOutOffset, &(DttfDirectory.offset))) != NO_ERROR) return errCode; - DttfDirectory.length = GetGenericSize(DTTF_HEADER_CONTROL) + usDttfGlyphIndexCount * sizeof(uint16); + if (TTF_SAFE_CHECKS_ENABLED()) + { + DttfDirectory.length = GetGenericSize(DTTF_HEADER_CONTROL) + (uint32)usDttfGlyphIndexCount * sizeof(uint16); + } + else + { + DttfDirectory.length = GetGenericSize(DTTF_HEADER_CONTROL) + usDttfGlyphIndexCount * sizeof(uint16); + } if (ulOffset == DIRECTORY_ERROR) /* there wasn't one there - don't really need this code - its obsolete */ return ERR_GENERIC; @@ -427,7 +480,7 @@ uint16 usBytesWritten; /* in addition any array tables (LTSH, loca, hmtx, hdmx, vmtx) will have a percentage discarded */ /* Format Delta will keep only a list of tables, and the Subset1 compacted and Glyf tables will keep only a portion */ /* ---------------------------------------------------------------------- */ -PRIVATE void CalcOutputBufferSize(CONST_TTFACC_FILEBUFFERINFO *pInputBufferInfo, +PRIVATE int16 CalcOutputBufferSize(CONST_TTFACC_FILEBUFFERINFO *pInputBufferInfo, uint16 usGlyphListCount, uint16 usGlyphKeepCount, uint16 usFormat, @@ -458,37 +511,93 @@ uint32 ulKeepTablesLength = 0; if (ulEBDTTableOffset != TTTableOffset((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, BDAT_TAG)) ulBdatTableLength = 0; } - ulAllGlyphsLength = ulEBDTTableLength + ulBdatTableLength; - ulAllGlyphsLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, GLYF_TAG); + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (UIntAdd32(ulEBDTTableLength, ulBdatTableLength, &ulAllGlyphsLength) != S_OK) + return ERR_GENERIC; + if (UIntAdd32(ulAllGlyphsLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, GLYF_TAG), &ulAllGlyphsLength) != S_OK) + return ERR_GENERIC; + + if (usFormat == TTFDELTA_DELTA || usFormat == TTFDELTA_SUBSET1) + { /* these formats will compact some tables, discarding a percentage of these tables as well */ + /* tables compacted */ + ulGlyphDependentDataLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LTSH_TAG); + if (UIntAdd32(ulGlyphDependentDataLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HMTX_TAG), &ulGlyphDependentDataLength) != S_OK) + return ERR_GENERIC; + if (UIntAdd32(ulGlyphDependentDataLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VMTX_TAG), &ulGlyphDependentDataLength) != S_OK) + return ERR_GENERIC; + if (UIntAdd32(ulGlyphDependentDataLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HDMX_TAG), &ulGlyphDependentDataLength) != S_OK) + return ERR_GENERIC; + if (UIntAdd32(ulGlyphDependentDataLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LOCA_TAG), &ulGlyphDependentDataLength) != S_OK) + return ERR_GENERIC; + } + if (UIntAdd32(ulGlyphDependentDataLength, ulAllGlyphsLength, &ulGlyphDependentDataLength) != S_OK) /* all formats will discard a percentage of the glyph data */ + return ERR_GENERIC; - if (usFormat == TTFDELTA_DELTA || usFormat == TTFDELTA_SUBSET1) - { /* these formats will compact some tables, discarding a percentage of these tables as well */ - /* tables compacted */ - ulGlyphDependentDataLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LTSH_TAG); - ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HMTX_TAG); - ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VMTX_TAG); - ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HDMX_TAG); - ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LOCA_TAG); + if (usFormat == TTFDELTA_DELTA) /* we're going to keep just a handfull of tables tables */ + { + ulKeepTablesLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HEAD_TAG); + if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, MAXP_TAG), &ulKeepTablesLength) != S_OK) + return ERR_GENERIC; + if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HHEA_TAG), &ulKeepTablesLength) != S_OK) + return ERR_GENERIC; + if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VHEA_TAG), &ulKeepTablesLength) != S_OK) + return ERR_GENERIC; + if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, CMAP_TAG), &ulKeepTablesLength) != S_OK) + return ERR_GENERIC; + if (ulEBDTTableLength > 0) + { + if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, EBLC_TAG), &ulKeepTablesLength) != S_OK) + return ERR_GENERIC; + } + if (ulBdatTableLength > 0) + { + if (UIntAdd32(ulKeepTablesLength, TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, BLOC_TAG), &ulKeepTablesLength) != S_OK) + return ERR_GENERIC; + } + + if (UIntAdd32(ulKeepTablesLength, (uint32)(flKeepPercent * ulGlyphDependentDataLength/100), pulOutputBufferLength) != S_OK) + return ERR_GENERIC; + } + else + /* for straight subset, this will be: ulSrcBufferSize - (discard % * (Glyf table size + EBDT table size + bdat table size)) */ + *pulOutputBufferLength = ulSrcBufferSize - (uint32)(flDiscardPercent * ulGlyphDependentDataLength/100); } - ulGlyphDependentDataLength += ulAllGlyphsLength; /* all formats will discard a percentage of the glyph data */ - - if (usFormat == TTFDELTA_DELTA) /* we're going to keep just a handfull of tables tables */ + else { - ulKeepTablesLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HEAD_TAG); - ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, MAXP_TAG); - ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HHEA_TAG); - ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VHEA_TAG); - ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, CMAP_TAG); - if (ulEBDTTableLength > 0) - ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, EBLC_TAG); - if (ulBdatTableLength > 0) - ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, BLOC_TAG); - - *pulOutputBufferLength = ulKeepTablesLength + (uint32)(flKeepPercent * ulGlyphDependentDataLength/100); + ulAllGlyphsLength = ulEBDTTableLength + ulBdatTableLength; + ulAllGlyphsLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, GLYF_TAG); + + if (usFormat == TTFDELTA_DELTA || usFormat == TTFDELTA_SUBSET1) + { /* these formats will compact some tables, discarding a percentage of these tables as well */ + /* tables compacted */ + ulGlyphDependentDataLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LTSH_TAG); + ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HMTX_TAG); + ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VMTX_TAG); + ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HDMX_TAG); + ulGlyphDependentDataLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, LOCA_TAG); + } + ulGlyphDependentDataLength += ulAllGlyphsLength; /* all formats will discard a percentage of the glyph data */ + + if (usFormat == TTFDELTA_DELTA) /* we're going to keep just a handfull of tables tables */ + { + ulKeepTablesLength = TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HEAD_TAG); + ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, MAXP_TAG); + ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, HHEA_TAG); + ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, VHEA_TAG); + ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, CMAP_TAG); + if (ulEBDTTableLength > 0) + ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, EBLC_TAG); + if (ulBdatTableLength > 0) + ulKeepTablesLength += TTTableLength((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, BLOC_TAG); + + *pulOutputBufferLength = ulKeepTablesLength + (uint32)(flKeepPercent * ulGlyphDependentDataLength/100); + } + else + /* for straight subset, this will be: ulSrcBufferSize - (discard % * (Glyf table size + EBDT table size + bdat table size)) */ + *pulOutputBufferLength = ulSrcBufferSize - (uint32)(flDiscardPercent * ulGlyphDependentDataLength/100); } - else - /* for straight subset, this will be: ulSrcBufferSize - (discard % * (Glyf table size + EBDT table size + bdat table size)) */ - *pulOutputBufferLength = ulSrcBufferSize - (uint32)(flDiscardPercent * ulGlyphDependentDataLength/100); + return NO_ERROR; } @@ -613,8 +722,29 @@ int16 CreateDeltaTTF(CONST uint8 * puchSrcBuffer, } // make room for the extra glyph list - usCharCount = usListCount + usGlyphKeepCount; - pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc(usCharCount * sizeof(CHAR_ID)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulCharCount = (uint32)usListCount + (uint32)usGlyphKeepCount; + if (ulCharCount > (uint32)USHRT_MAX) + { + Mem_Free(puchKeepGlyphList); + return ExitCleanup(ERR_PARAMETER11); + } + usCharCount = (uint16)ulCharCount; + + uint32 ulCharAllocSize; + if (ULongMult32((uint32)usCharCount, (uint32)sizeof(CHAR_ID), &ulCharAllocSize) != S_OK) + { + Mem_Free(puchKeepGlyphList); + return ExitCleanup(ERR_MEM); + } + pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc(ulCharAllocSize); + } + else + { + usCharCount = usListCount + usGlyphKeepCount; + pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc(usCharCount * sizeof(CHAR_ID)); + } if (!pulKeepCharCodeList) { Mem_Free(puchKeepGlyphList); @@ -644,7 +774,15 @@ int16 CreateDeltaTTF(CONST uint8 * puchSrcBuffer, else { // allocate for extra 4 chars - pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc((usListCount + 4) * sizeof(CHAR_ID)); + if (TTF_SAFE_CHECKS_ENABLED()) { + if (usListCount > (uint16)(USHRT_MAX - 4)) + { + return ERR_PARAMETER11; + } + pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc(((size_t)usListCount + 4u) * sizeof(CHAR_ID)); + } else { + pulKeepCharCodeList = (CHAR_ID *)Mem_Alloc((usListCount + 4) * sizeof(CHAR_ID)); + } if (!pulKeepCharCodeList) { return ERR_MEM; @@ -769,7 +907,15 @@ CONST_TTFACC_FILEBUFFERINFO InputBufferInfo; if (*ppuchDestBuffer == NULL || *pulDestBufferSize == 0) /* need to allocate some memory */ { - CalcOutputBufferSize(&InputBufferInfo, usGlyphListCount, usGlyphKeepCount, usFormat, ulSrcBufferSize, pulDestBufferSize); + if (TTF_SAFE_CHECKS_ENABLED()) { + if ((errCode = CalcOutputBufferSize(&InputBufferInfo, usGlyphListCount, usGlyphKeepCount, usFormat, ulSrcBufferSize, pulDestBufferSize)) != NO_ERROR) + { + Mem_Free(puchKeepGlyphList); + return ExitCleanup(errCode); + } + } else { + CalcOutputBufferSize(&InputBufferInfo, usGlyphListCount, usGlyphKeepCount, usFormat, ulSrcBufferSize, pulDestBufferSize); + } #ifdef _DEBUG #if !defined(ARGITERATOR_SUPPORTED) || (defined(ARGITERATOR_SUPPORTED) && ARGITERATOR_SUPPORTED) printf("Allocating %lu bytes for output buffer.\n", *pulDestBufferSize); @@ -896,7 +1042,15 @@ CONST_TTFACC_FILEBUFFERINFO InputBufferInfo; if (errCode == NO_ERROR) { /* now we need to allocate an array to keep a list of the actual glyphs we are keeping in the font */ - pusGlyphIndexArray = (uint16 *)Mem_Alloc(usDttfGlyphIndexCount * sizeof(*pusGlyphIndexArray)); /* big as we would ever need */ + if (TTF_SAFE_CHECKS_ENABLED()) { + uint32 ulGlyphArrayAllocSize; + if (ULongMult32((uint32)usDttfGlyphIndexCount, (uint32)sizeof(*pusGlyphIndexArray), &ulGlyphArrayAllocSize) != S_OK) + errCode = ERR_MEM; + else + pusGlyphIndexArray = (uint16 *)Mem_Alloc(ulGlyphArrayAllocSize); + } else { + pusGlyphIndexArray = (uint16 *)Mem_Alloc(usDttfGlyphIndexCount * sizeof(*pusGlyphIndexArray)); + } if (pusGlyphIndexArray == NULL) errCode = ERR_MEM; else diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftabl1.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftabl1.cpp index 54f3800a14d..f3bc5b7bae9 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftabl1.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftabl1.cpp @@ -28,6 +28,7 @@ #include "ttftabl1.h" #include "ttfcntrl.h" #include "ControlTableInit.h" +#include "ttf_safe_checks.h" /* if the _INDEX defines are changed, the Control_Table array below must be updated to match */ @@ -251,8 +252,19 @@ uint32 ulLength; for ( ul = 0; ul < (ulLength+3) / 4; ul++ ) { - if ( ReadLong( pInputBufferInfo, &ulWord, ulOffset + ul * sizeof(uint32)) != 0 ) - break; + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulReadOffset = ulOffset + ul * sizeof(uint32); + if (ulReadOffset < ulOffset) /* overflow check */ + break; + if ( ReadLong( pInputBufferInfo, &ulWord, ulReadOffset) != 0 ) + break; + } + else + { + if ( ReadLong( pInputBufferInfo, &ulWord, ulOffset + ul * sizeof(uint32)) != 0 ) + break; + } *pulChecksum = *pulChecksum + ulWord; } return ulOffset; /* any non zero number will do */ diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftable.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftable.cpp index cbb2de39061..89dc68877f1 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftable.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/TtfDelta/ttftable.cpp @@ -28,6 +28,8 @@ #include "ttfdelta.h" /* for Dont care info */ #include "ttferror.h" #include "ttfdcnfg.h" +#include "intsafe_private_copy.h" +#include "ttf_safe_checks.h" /* ---------------------------------------------------------------------- */ PRIVATE int CRTCB AscendingTagCompare( CONST void *arg1, CONST void *arg2 ) @@ -269,6 +271,11 @@ uint32 ulBytesRead; } else { + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (ulGlyphCount + 1 > 0xFFFF) + return 0L; + } if (ReadGenericRepeat(pInputBufferInfo, (uint8 *)pulLoca, LONG_CONTROL, ulOffset, &ulBytesRead, (uint16) (ulGlyphCount + 1), sizeof(uint32)) != NO_ERROR) return 0L; } @@ -315,9 +322,17 @@ FORMAT4_SEGMENTS KeySegment; sIDIdx = (int32)(pFormat4Segment - (Format4Segments + usnSegments)); /* sIDIdx = (uint16) i - (uint16) usnSegments; */ sIDIdx += (int32) (pFormat4Segment->idRangeOffset / 2) + usCharCode - pFormat4Segment->startCount; - /* check against bounds */ - if (sIDIdx >= usnGlyphs) - return INVALID_GLYPH_INDEX; + /* check against bounds (both negative and too large) */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + if (sIDIdx < 0 || sIDIdx >= usnGlyphs) + return INVALID_GLYPH_INDEX; + } + else + { + if (sIDIdx >= usnGlyphs) + return INVALID_GLYPH_INDEX; + } usGlyphIdx = GlyphId[ sIDIdx ]; if (usGlyphIdx) /* Only add in idDelta if we've really got a glyph! */ @@ -401,7 +416,17 @@ int16 errCode; if ( *pusnIds == 0 ) return(NO_ERROR); - *ppGlyphId = (GLYPH_ID *)Mem_Alloc(*pusnIds * sizeof( (*ppGlyphId)[0] )); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)*pusnIds, (uint32)sizeof( (*ppGlyphId)[0] ), &ulAllocSize) != S_OK) + return ERR_MEM; + *ppGlyphId = (GLYPH_ID *)Mem_Alloc(ulAllocSize); + } + else + { + *ppGlyphId = (GLYPH_ID *)Mem_Alloc(*pusnIds * sizeof( (*ppGlyphId)[0] )); + } if ( *ppGlyphId == NULL ) return(ERR_MEM); @@ -431,7 +456,17 @@ uint32 ulBytesRead; /* allocate memory for variable length part of table */ - *Format4Segments = (FORMAT4_SEGMENTS *)Mem_Alloc( usSegCount * SIZEOF_FORMAT4_SEGMENTS); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)usSegCount, (uint32)SIZEOF_FORMAT4_SEGMENTS, &ulAllocSize) != S_OK) + return ERR_MEM; + *Format4Segments = (FORMAT4_SEGMENTS *)Mem_Alloc( ulAllocSize ); + } + else + { + *Format4Segments = (FORMAT4_SEGMENTS *)Mem_Alloc( usSegCount * SIZEOF_FORMAT4_SEGMENTS); + } if ( *Format4Segments == NULL ) return( ERR_MEM ); @@ -661,7 +696,17 @@ int16 errCode; if (pCmap->format != FORMAT6_CMAP_FORMAT) return( ERR_FORMAT ); - *glyphIndexArray = (uint16 *)Mem_Alloc( pCmap->entryCount * sizeof( uint16 )); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)pCmap->entryCount, (uint32)sizeof( uint16 ), &ulAllocSize) != S_OK) + return ERR_MEM; + *glyphIndexArray = (uint16 *)Mem_Alloc( ulAllocSize ); + } + else + { + *glyphIndexArray = (uint16 *)Mem_Alloc( pCmap->entryCount * sizeof( uint16 )); + } if ( *glyphIndexArray == NULL ) return( ERR_MEM ); @@ -1030,7 +1075,20 @@ int16 errCode = NO_ERROR; usCharCodeCount += (pFormat4Segments[ i ].endCount - pFormat4Segments[ i ].startCount + 1); } - *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST)Mem_Alloc(usCharCodeCount * sizeof(**ppCharGlyphMapList)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)usCharCodeCount, (uint32)sizeof(**ppCharGlyphMapList), &ulAllocSize) != S_OK) + { + FreeCmapFormat4(pFormat4Segments, pFormat4GlyphIdArray); + return ERR_MEM; + } + *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST)Mem_Alloc(ulAllocSize); + } + else + { + *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST)Mem_Alloc(usCharCodeCount * sizeof(**ppCharGlyphMapList)); + } if (*ppCharGlyphMapList == NULL) { FreeCmapFormat4(pFormat4Segments, pFormat4GlyphIdArray); @@ -1134,7 +1192,20 @@ int16 errCode = NO_ERROR; ulCharCodeCount += (pFormat12Groups[ i ].endCharCode - pFormat12Groups[ i ].startCharCode + 1); } - *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST_EX)Mem_Alloc(ulCharCodeCount * sizeof(**ppCharGlyphMapList)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32(ulCharCodeCount, (uint32)sizeof(**ppCharGlyphMapList), &ulAllocSize) != S_OK) + { + FreeCmapFormat12Groups( pFormat12Groups ); + return ERR_MEM; + } + *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST_EX)Mem_Alloc(ulAllocSize); + } + else + { + *ppCharGlyphMapList = (PCHAR_GLYPH_MAP_LIST_EX)Mem_Alloc(ulCharCodeCount * sizeof(**ppCharGlyphMapList)); + } if (*ppCharGlyphMapList == NULL) { FreeCmapFormat12Groups( pFormat12Groups ); @@ -1658,7 +1729,17 @@ char *pStr1, *pStr2; /* temps to point to either new or old string from PNAMEREC ulOffset = ulNameOffset + GetGenericSize(NAME_HEADER_CONTROL); /* first create the NameRecordStrings array to sort */ - pNameRecordStrings = (NAMERECORDSTRINGS *)Mem_Alloc(NameRecordCount * sizeof(*pNameRecordStrings)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)NameRecordCount, (uint32)sizeof(*pNameRecordStrings), &ulAllocSize) != S_OK) + return ERR_GENERIC; + pNameRecordStrings = (NAMERECORDSTRINGS *)Mem_Alloc(ulAllocSize); + } + else + { + pNameRecordStrings = (NAMERECORDSTRINGS *)Mem_Alloc(NameRecordCount * sizeof(*pNameRecordStrings)); + } if (pNameRecordStrings == NULL) return ERR_MEM; @@ -1845,7 +1926,17 @@ int32 lCopySize; ulOffset += usBytesRead; - aDirectory = (DIRECTORY *) Mem_Alloc(((int32)usnNewTables) * sizeof(DIRECTORY)); /* one extra for new table */ + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)usnNewTables, (uint32)sizeof(DIRECTORY), &ulAllocSize) != S_OK) + return ERR_MEM; + aDirectory = (DIRECTORY *) Mem_Alloc(ulAllocSize); + } + else + { + aDirectory = (DIRECTORY *) Mem_Alloc(((int32)usnNewTables) * sizeof(DIRECTORY)); /* one extra for new table */ + } if (aDirectory == NULL) return(ERR_MEM); @@ -2150,7 +2241,17 @@ int16 errCode; ulOffset += usBytesRead; /* Create a list of valid tables */ - aDirectory = (DIRECTORY *) Mem_Alloc((usnTables) * sizeof(DIRECTORY)); + if (TTF_SAFE_CHECKS_ENABLED()) + { + uint32 ulAllocSize; + if (ULongMult32((uint32)usnTables, (uint32)sizeof(DIRECTORY), &ulAllocSize) != S_OK) + return ERR_MEM; + aDirectory = (DIRECTORY *) Mem_Alloc(ulAllocSize); + } + else + { + aDirectory = (DIRECTORY *) Mem_Alloc((usnTables) * sizeof(DIRECTORY)); + } if (aDirectory == NULL) return(ERR_MEM); diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/truetype.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/truetype.cpp index 28ca4ab6f4e..3bec436548b 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/truetype.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/TrueTypeSubsetter/truetype.cpp @@ -57,16 +57,37 @@ using MS::Internal::TtfDelta::Mem_Free; using MS::Internal::TtfDelta::Mem_Alloc; using MS::Internal::TtfDelta::Mem_ReAlloc; using MS::Internal::TtfDelta::CreateDeltaTTF; +using MS::Internal::TtfDelta::g_fDWFBoundsCheckEnabled; namespace MS { namespace Internal { array ^ TrueTypeSubsetter::ComputeSubset(void * fontData, int fileSize, System::Uri ^ sourceUri, int directoryOffset, array ^ glyphArray) { + // Initialize the bounds check switch from AppContext (once). + static bool s_switchInitialized = false; + if (!s_switchInitialized) + { + s_switchInitialized = true; + bool switchValue = false; + System::AppContext::TryGetSwitch( + "Switch.MS.Internal.TtfDelta.DisableDirectWriteForwarderBoundsCheckProtection", + switchValue); + MS::Internal::TtfDelta::g_fDWFBoundsCheckEnabled = switchValue ? 0 : 1; + } + uint8 * puchDestBuffer = NULL; unsigned long ulDestBufferSize = 0, ulBytesWritten = 0; assert(glyphArray != nullptr && glyphArray->Length > 0 && glyphArray->Length <= USHRT_MAX); + if ((g_fDWFBoundsCheckEnabled != 0)) + { + if (fileSize <= 0) + { + throw gcnew FileFormatException(sourceUri); + } + } + pin_ptr pinnedGlyphArray = &glyphArray[0]; int16 errCode = CreateDeltaTTF( static_cast(fontData), @@ -91,10 +112,25 @@ array ^ TrueTypeSubsetter::ComputeSubset(void * fontData, int file try { - if (errCode == NO_ERROR) + if ((g_fDWFBoundsCheckEnabled != 0)) + { + if (errCode == NO_ERROR && ulBytesWritten <= INT_MAX) + { + retArray = gcnew array(ulBytesWritten); + System::Runtime::InteropServices::Marshal::Copy((System::IntPtr)puchDestBuffer, retArray, 0, ulBytesWritten); + } + else if (errCode == NO_ERROR) + { + errCode = static_cast(ERR_GENERIC); + } + } + else { - retArray = gcnew array(ulBytesWritten); - System::Runtime::InteropServices::Marshal::Copy((System::IntPtr)puchDestBuffer, retArray, 0, ulBytesWritten); + if (errCode == NO_ERROR) + { + retArray = gcnew array(ulBytesWritten); + System::Runtime::InteropServices::Marshal::Copy((System::IntPtr)puchDestBuffer, retArray, 0, ulBytesWritten); + } } } finally diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/DirectWriteForwarder.vcxproj b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/DirectWriteForwarder.vcxproj index fa961964860..a2ff827ffff 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/DirectWriteForwarder.vcxproj +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/DirectWriteForwarder.vcxproj @@ -92,7 +92,7 @@ - + diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp index 61ff8727d81..63426a64279 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp @@ -13,6 +13,7 @@ // We cannot simply put this namespace specification in these 2 header files // or elase we will break the compilation of truetype subsetter. namespace MS { namespace Internal { namespace TtfDelta { +int g_fDWFBoundsCheckEnabled = 1; // definition for linker (initialized in truetype.cpp) #include "CPP\TrueTypeSubsetter\TtfDelta\GlobalInit.h" #include "CPP\TrueTypeSubsetter\TtfDelta\ControlTableInit.h" }}} // namespace MS::Internal::TtfDelta diff --git a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.cpp b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.cpp index 37ef3140bbd..b1de3cb5ca9 100644 --- a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.cpp +++ b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.cpp @@ -216,3 +216,15 @@ STDMETHODIMP CPimcManagerFactory::LockServer(BOOL fLock) } #endif // WANT_SINGLETON +///////////////////////////////////////////////////////////////////////////// +// Security mitigation switch - static storage and exported setter + +#include "PenImcSwitches.h" + +bool PenImcSwitches::s_boundsCheckDisabled = false; + +extern "C" void WINAPI SetDisablePenImcBoundsCheckProtection(BOOL fDisable) +{ + PenImcSwitches::SetPenImcBoundsCheckProtectionDisabled(!!fDisable); +} + diff --git a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.def b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.def index 193a703c902..ec3ce6c124d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.def +++ b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImc.def @@ -22,4 +22,5 @@ EXPORTS LockWispObjectFromGit PRIVATE UnlockWispObjectFromGit PRIVATE RegisterDllForSxSCOM PRIVATE + SetDisablePenImcBoundsCheckProtection PRIVATE diff --git a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImcSwitches.h b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImcSwitches.h new file mode 100644 index 00000000000..d9a5f970167 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PenImcSwitches.h @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +/// +/// Switch for PenImc security fixes, set from managed CoreAppContextSwitches +/// via P/Invoke at startup. +/// +class PenImcSwitches +{ +public: + static bool IsPenImcBoundsCheckProtectionDisabled() + { + return s_boundsCheckDisabled; + } + + static void SetPenImcBoundsCheckProtectionDisabled(bool disabled) + { + s_boundsCheckDisabled = disabled; + } + +private: + static bool s_boundsCheckDisabled; +}; diff --git a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcContext.cpp b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcContext.cpp index 9578b17934e..454be79de5a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcContext.cpp +++ b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcContext.cpp @@ -12,6 +12,9 @@ #include "PimcContext.h" #include "..\tablib\sidutils.h" #include "..\tablib\scopes.h" +#include + +#include "PenImcSwitches.h" using namespace ComUtils; @@ -524,7 +527,16 @@ HRESULT CPimcContext::EnsurePackets(DWORD cb) { if (m_pbPackets) delete [] m_pbPackets; - m_cbPackets = max(256, cb * 2); + if (!PenImcSwitches::IsPenImcBoundsCheckProtectionDisabled()) + { + UINT cbDoubled; + CHR(UIntMult(cb, 2, &cbDoubled)); + m_cbPackets = max(256, (DWORD)cbDoubled); + } + else + { + m_cbPackets = max(256, cb * 2); + } CHR_MEMALLOC(m_pbPackets = new BYTE[m_cbPackets]); } CLEANUP: diff --git a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcTablet.cpp b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcTablet.cpp index 1cb2d9f4901..4f975793d02 100644 --- a/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcTablet.cpp +++ b/src/Microsoft.DotNet.Wpf/src/PenImc/dll/PimcTablet.cpp @@ -10,6 +10,7 @@ #include "PimcTablet.h" #include #include +#include "PenImcSwitches.h" using namespace ComUtils; @@ -46,6 +47,11 @@ static const WCHAR* MOUSEDEVICE_BUTTON_ONE_NAME = L"Tip Switch"; static const WCHAR* MOUSEDEVICE_BUTTON_TWO_NAME = L"Barrel Switch"; static const WCHAR* MOUSEDEVICE_PLUGANDPLAYID = L"SCREEN"; +// Reasonable upper bounds for COM-returned counts to guard against +// integer overflow in allocation size calculations. +static const DWORD MAX_TABLET_CURSORS = 128; +static const DWORD MAX_CURSOR_BUTTONS = 64; + static void EnsureNoDuplicateGUIDs(__in GUID *pGUID, __inout ULONG &cGUID) { ULONG iIndex = 0; @@ -545,6 +551,10 @@ STDMETHODIMP CPimcTablet::RefreshCursorInfo() if (m_pTabS) { CHR(m_pTabS->GetCursorCount(&m_cCursors)); + if (!PenImcSwitches::IsPenImcBoundsCheckProtectionDisabled()) + { + CHR(m_cCursors <= MAX_TABLET_CURSORS ? S_OK : E_UNEXPECTED); + } m_apCursorInfo = new PCURSORINFO[m_cCursors](); CHR(m_apCursorInfo ? S_OK : E_OUTOFMEMORY); @@ -566,6 +576,10 @@ STDMETHODIMP CPimcTablet::RefreshCursorInfo() DWORD cButtons; CHR(pCursorS->GetButtonCount(&cButtons)); + if (!PenImcSwitches::IsPenImcBoundsCheckProtectionDisabled()) + { + CHR(cButtons <= MAX_CURSOR_BUTTONS ? S_OK : E_UNEXPECTED); + } pCursorInfo->cButtons = cButtons; pCursorInfo->apButtonInfo = new PCURSORBUTTONINFO[cButtons](); @@ -839,7 +853,14 @@ STDMETHODIMP CPimcTablet::IsPropertySupported(GUID guid, __out BOOL * pfSupporte DHR; CHR(pfSupported ? S_OK : E_INVALIDARG); PROPERTY_METRICS metric; - *pfSupported = S_OK == m_pTabS->GetPropertyMetrics(guid, &metric); + if (!PenImcSwitches::IsPenImcBoundsCheckProtectionDisabled()) + { + *pfSupported = m_pTabS ? (S_OK == m_pTabS->GetPropertyMetrics(guid, &metric)) : FALSE; + } + else + { + *pfSupported = S_OK == m_pTabS->GetPropertyMetrics(guid, &metric); + } CLEANUP: RHR; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/Win32/UnsafeNativeMethodsPenimc.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/Win32/UnsafeNativeMethodsPenimc.cs index e3bf8b4934f..7d19615cb34 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/Win32/UnsafeNativeMethodsPenimc.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/Win32/UnsafeNativeMethodsPenimc.cs @@ -81,6 +81,9 @@ internal static class UnsafeNativeMethods [DllImport(ExternDll.Penimc, CharSet=CharSet.Auto)] internal static extern IntPtr RegisterDllForSxSCOM(); + [DllImport(ExternDll.Penimc, CharSet = CharSet.Auto)] + internal static extern void SetDisablePenImcBoundsCheckProtection([MarshalAs(UnmanagedType.Bool)] bool value); + #endregion /// @@ -107,6 +110,9 @@ internal static void EnsurePenImcClassesActivated() { throw new InvalidOperationException(SR.Format(SR.PenImcSxSRegistrationFailed, ExternDll.Penimc)); } + + // Pass security mitigation switch to native PenImc code. + SetDisablePenImcBoundsCheckProtection(CoreAppContextSwitches.DisablePenImcBoundsCheckProtection); } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Automation/ElementProxy.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Automation/ElementProxy.cs index cbc1e67b909..da66a8e47cf 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Automation/ElementProxy.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Automation/ElementProxy.cs @@ -540,9 +540,22 @@ internal static ReferenceType AutomationInteropReferenceType // //------------------------------------------------------ + #region Internal Methods for Disconnect + + // Called during UIA disconnect to sever the strong reference from this + // proxy to the automation peer. This allows the peer (and its associated + // data items) to be garbage collected even if UIA/client still holds a + // COM reference to this CCW temporarily. + internal void ClearPeer() + { + _peer = null; + } + + #endregion Internal Methods for Disconnect + #region Private Fields - private readonly object _peer; + private object _peer; #endregion Private Fields } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/CoreAppContextSwitches.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/CoreAppContextSwitches.cs index 98984b5c4bc..9d4ea1525f5 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/CoreAppContextSwitches.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/CoreAppContextSwitches.cs @@ -177,6 +177,24 @@ public static bool UseNetFx472CompatibleAccessibilityFeatures #endregion + #region UseLegacyAutomationPeerDisconnect + + /// + /// Switch to opt-out of the automation peer disconnect behavior. + /// When true, removed automation peers are NOT disconnected from UIA (legacy behavior). + /// When false (default), removed automation peers are disconnected via UiaDisconnectProvider. + /// + public static bool UseLegacyAutomationPeerDisconnect + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return AccessibilitySwitches.UseLegacyAutomationPeerDisconnect; + } + } + + #endregion + #endregion #region ShouldRenderEvenWhenNoDisplayDevicesAreAvailable and ShouldNotRenderInNonInteractiveWindowStation @@ -400,5 +418,50 @@ public static bool DisableSpecialCharacterLigature } #endregion + + #region DisableDirectWriteForwarderBoundsCheckProtection + + internal const string DisableDirectWriteForwarderBoundsCheckProtectionSwitchName = "Switch.MS.Internal.TtfDelta.DisableDirectWriteForwarderBoundsCheckProtection"; + private static int _disableDirectWriteForwarderBoundsCheckProtection; + public static bool DisableDirectWriteForwarderBoundsCheckProtection + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(DisableDirectWriteForwarderBoundsCheckProtectionSwitchName, ref _disableDirectWriteForwarderBoundsCheckProtection); + } + } + + #endregion + + #region DisablePenImcBoundsCheckProtection + + internal const string DisablePenImcBoundsCheckProtectionSwitchName = "Switch.MS.Internal.PenImc.DisablePenImcBoundsCheckProtection"; + private static int _disablePenImcBoundsCheckProtection; + public static bool DisablePenImcBoundsCheckProtection + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(DisablePenImcBoundsCheckProtectionSwitchName, ref _disablePenImcBoundsCheckProtection); + } + } + + #endregion + + #region DisableWpfGfxBoundsCheckProtection + + internal const string DisableWpfGfxBoundsCheckProtectionSwitchName = "Switch.MS.Internal.WpfGfx.DisableWpfGfxBoundsCheckProtection"; + private static int _disableWpfGfxBoundsCheckProtection; + public static bool DisableWpfGfxBoundsCheckProtection + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(DisableWpfGfxBoundsCheckProtectionSwitchName, ref _disableWpfGfxBoundsCheckProtection); + } + } + + #endregion } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Automation/Peers/AutomationPeer.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Automation/Peers/AutomationPeer.cs index 5d4ce668f6c..3a592f0868b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Automation/Peers/AutomationPeer.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Automation/Peers/AutomationPeer.cs @@ -4,6 +4,7 @@ //#define ENABLE_AUTOMATIONPEER_LOGGING // uncomment to include logging of various activities using System.Collections; +using System.Runtime.InteropServices; using System.Windows.Threading; using System.Windows.Automation.Provider; using MS.Internal; @@ -1483,6 +1484,7 @@ private void EnsureChildren() // UpdateSubtree is not called on it yet. if (!_childrenValid || _ancestorsInvalid) { + List oldChildren = _children; _children = GetChildrenCore(); if (_children != null) { @@ -1495,6 +1497,20 @@ private void EnsureChildren() } } _childrenValid = true; + + // Disconnect removed peers (same logic as UpdateChildrenInternal) + if (oldChildren != null && !CoreAppContextSwitches.UseLegacyAutomationPeerDisconnect) + { + HashSet newSet = _children != null ? + new HashSet(_children) : null; + foreach (var old in oldChildren) + { + if (newSet == null || !newSet.Contains(old)) + { + DisconnectPeerFromUia(old); + } + } + } } } @@ -1812,6 +1828,59 @@ private IRawElementProviderSimple ProviderFromPeerNoDelegation(AutomationPeer pe return ElementProxy.StaticWrap(peer, referencePeer); } + /// + /// Disconnects a peer from the UI Automation framework by calling + /// UiaDisconnectProvider on its ElementProxy CCW. + /// This causes the UIA client-side to release its COM references, allowing + /// the CCW ref count to drop to zero so the managed objects can be GC'd. + /// + /// + /// After disconnecting a peer from UIA, this method also clears the peer's + /// _children list to sever references to child peers. Without this, a + /// disconnected ItemAutomationPeer would still root its cached cell peers, + /// which in turn root DataGridCell/DataGridRow containers via their _owner + /// field — preventing GC of recycled/discarded containers. + /// We do NOT call UiaDisconnectProvider on children (they may be shared with + /// recycled containers that are still live), but clearing the parent's + /// _children list removes the strong reference chain. + /// + private static void DisconnectPeerFromUia(AutomationPeer peer) + { + if (peer == null) + return; + + // UiaDisconnectProvider MUST NOT be called during a UIA callback + // (e.g., during Navigate/FindAll handling). EnsureChildren and + // UpdateChildrenInternal are invoked from within UIA callbacks, so + // we must defer the actual disconnect to a separate dispatcher operation. + WeakReference proxyWeakRef = peer._elementProxyWeakReference; + if (proxyWeakRef?.Target is ElementProxy proxy) + { + // Sever the strong reference from proxy back to the peer immediately. + // This allows the peer (and its data items) to be GC'd even before + // the deferred UiaDisconnectProvider call executes. + proxy.ClearPeer(); + + // Defer the UIA disconnect to run outside the UIA callback context. + peer.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, + new Action(() => + { + UiaDisconnectProvider(proxy); + })); + } + + peer._elementProxyWeakReference = null; + + // Sever the reference from this peer to its cached children. + // This breaks the chain: disconnected peer → child peers → _owner → UI containers, + // allowing old containers (DataGridRow/Cell) to be collected. + peer._children = null; + peer._childrenValid = false; + } + + [DllImport("UIAutomationCore.dll", EntryPoint = "UiaDisconnectProvider", CharSet = CharSet.Unicode)] + private static extern int UiaDisconnectProvider(IRawElementProviderSimple provider); + /// /// When one AutomationPeer is using the pattern of another AutomationPeer instead of exposing /// it in the children collection (example - ListBox exposes IScrollProvider from internal ScrollViewer @@ -1892,10 +1961,6 @@ internal void UpdateChildrenInternal(int invalidateLimit) _childrenValid = false; EnsureChildren(); - // Callers have only checked if automation clients are present so filter for any interest in this particular event. - if (!EventMap.HasRegisteredEvent(AutomationEvents.StructureChanged)) - return; - //store old children in a hashset if(oldChildren != null) { @@ -1937,6 +2002,23 @@ internal void UpdateChildrenInternal(int invalidateLimit) //calls for "bulk" notification, use per-child notification, otherwise use "bulk" int removedCount = (hs == null ? 0 : hs.Count); + // Disconnect removed children from UIA so the client-side releases its + // COM references to the ElementProxy CCWs. Without this the CCW ref count + // never drops to zero, which prevents the managed peer (and its entire + // visual sub-tree) from being garbage collected. + // This must happen regardless of StructureChanged event registration. + if (removedCount > 0 && !CoreAppContextSwitches.UseLegacyAutomationPeerDisconnect) + { + foreach (AutomationPeer removedChild in hs) + { + DisconnectPeerFromUia(removedChild); + } + } + + // Callers have only checked if automation clients are present so filter for any interest in this particular event. + if (!EventMap.HasRegisteredEvent(AutomationEvents.StructureChanged)) + return; + if(removedCount + addedCount > invalidateLimit) //bilk invalidation { StructureChangeType flags; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaSystem.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaSystem.cs index 40edd7976b3..9b980fda541 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaSystem.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaSystem.cs @@ -70,6 +70,9 @@ public static bool Startup(MediaContext mc) // Setting renderOption for Hardware acceleration in RDP as per appcontext switch. UnsafeNativeMethods.RenderOptions_EnableHardwareAccelerationInRdp(CoreAppContextSwitches.EnableHardwareAccelerationInRdp); + // Pass security mitigation switch to native WpfGfx code. + UnsafeNativeMethods.WpfGfx_SetDisableBoundsCheckProtection(CoreAppContextSwitches.DisableWpfGfxBoundsCheckProtection); + // Consider making MediaSystem.ConnectTransport return the state of transport connectedness so // that we can initialize the media system to a disconnected state. diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Resources/ColorProfiles/LICENSE.TXT b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Resources/ColorProfiles/LICENSE.TXT new file mode 100644 index 00000000000..e43592c9467 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Resources/ColorProfiles/LICENSE.TXT @@ -0,0 +1 @@ +The sRGB.icm binary is licensed to Microsoft by Hewlett Packard for broad use and re-licensed using the MIT license. diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UnsafeNativeMethodsMilCoreApi.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UnsafeNativeMethodsMilCoreApi.cs index a17613aec1c..3b2964686d4 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UnsafeNativeMethodsMilCoreApi.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UnsafeNativeMethodsMilCoreApi.cs @@ -198,6 +198,9 @@ internal static extern unsafe void RenderOptions_ForceSoftwareRenderingModeForPr [DllImport(DllImport.MilCore, EntryPoint = "RenderOptions_EnableHardwareAccelerationInRdp")] internal static extern unsafe void RenderOptions_EnableHardwareAccelerationInRdp(bool value); + [DllImport(DllImport.MilCore, EntryPoint = "WpfGfx_SetDisableBoundsCheckProtection")] + internal static extern unsafe void WpfGfx_SetDisableBoundsCheckProtection(bool value); + [DllImport(DllImport.MilCore, EntryPoint = "MilResource_CreateCWICWrapperBitmap")] internal static extern unsafe int /* HRESULT */ CreateCWICWrapperBitmap( BitmapSourceSafeMILHandle /* IWICBitmapSource */ pIWICBitmapSource, diff --git a/src/Microsoft.DotNet.Wpf/src/System.Printing/System.Printing.vcxproj b/src/Microsoft.DotNet.Wpf/src/System.Printing/System.Printing.vcxproj index 16c743024d6..3bb8c085842 100644 --- a/src/Microsoft.DotNet.Wpf/src/System.Printing/System.Printing.vcxproj +++ b/src/Microsoft.DotNet.Wpf/src/System.Printing/System.Printing.vcxproj @@ -161,7 +161,7 @@ - + <_defineReferences>@(_defineReference->'%(Define)=<%(Identity)>') diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/AccessibilitySwitches.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/AccessibilitySwitches.cs index fc79753bb75..904363455d8 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/AccessibilitySwitches.cs +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/AccessibilitySwitches.cs @@ -147,6 +147,29 @@ public static bool ItemsControlDoesNotSupportAutomation #endregion + #region UseLegacyAutomationPeerDisconnect + + internal const string UseLegacyAutomationPeerDisconnectSwitchName = "Switch.System.Windows.Automation.Peers.UseLegacyAutomationPeerDisconnect"; + private static int _UseLegacyAutomationPeerDisconnect; + + /// + /// Switch to opt-out of the automation peer disconnect behavior. + /// When true, compatibility mode is enabled: removed automation peers are NOT + /// disconnected from UIA, preserving the legacy element lifetime semantics. + /// When false (default), removed automation peers are disconnected via + /// UiaDisconnectProvider, allowing CCWs and associated managed objects to be GC'd. + /// + public static bool UseLegacyAutomationPeerDisconnect + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(UseLegacyAutomationPeerDisconnectSwitchName, ref _UseLegacyAutomationPeerDisconnect); + } + } + + #endregion + #endregion #region Switch Functions @@ -167,6 +190,7 @@ internal static void SetSwitchDefaults(string platformIdentifier, int targetFram LocalAppContext.DefineSwitchDefault(UseLegacyAccessibilityFeatures3SwitchName, false); LocalAppContext.DefineSwitchDefault(UseLegacyToolTipDisplaySwitchName, false); LocalAppContext.DefineSwitchDefault(ItemsControlDoesNotSupportAutomationSwitchName, false); + LocalAppContext.DefineSwitchDefault(UseLegacyAutomationPeerDisconnectSwitchName, false); } /// @@ -218,6 +242,10 @@ internal static void VerifyDependencies(Dispatcher dispatcher) { DispatchOnError(dispatcher, String.Format(SR.AccessibilitySwitchDependencyNotSatisfied, ItemsControlDoesNotSupportAutomationSwitchName, UseLegacyAccessibilityFeatures3SwitchName, 3)); } + if (!UseLegacyAutomationPeerDisconnect && UseNetFx472CompatibleAccessibilityFeatures) + { + DispatchOnError(dispatcher, String.Format(SR.AccessibilitySwitchDependencyNotSatisfied, UseLegacyAutomationPeerDisconnectSwitchName, UseLegacyAccessibilityFeatures3SwitchName, 3)); + } } diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/effects/effectlist.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/effects/effectlist.cpp index 4ded9028ff9..dbf5945d138 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/effects/effectlist.cpp +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/effects/effectlist.cpp @@ -21,6 +21,7 @@ **************************************************************************/ #include "precomp.hpp" +#include "..\shared\WpfGfxSwitches.h" MtDefine(CEffectList, MILRender, "CEffectList"); @@ -320,16 +321,47 @@ CEffectList::GetParameters( API_ENTRY_NOFPU(IMILEffectList::GetParameters); HRESULT hr = S_OK; - UINT uiSize = m_rgParamBlock[idxEffect].cbParamSize; - if (idxEffect >= (UINT)m_rgParamBlock.GetCount() || - size < uiSize || - pData == NULL) + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) { - IFC(E_INVALIDARG); + if (idxEffect >= (UINT)m_rgParamBlock.GetCount() || + pData == NULL) + { + IFC(E_INVALIDARG); + } + + UINT uiSize = m_rgParamBlock[idxEffect].cbParamSize; + if (size < uiSize) + { + IFC(E_INVALIDARG); + } + + UINT cbParamOffset = m_rgParamBlock[idxEffect].cbParamOffset; + UINT cbDataBlockSize = m_rgDataBlock.GetCount(); + UINT cbEndOffset; + + // Validate that offset + size does not exceed data block bounds + if (FAILED(UIntAdd(cbParamOffset, uiSize, &cbEndOffset)) || + cbEndOffset > cbDataBlockSize) + { + IFC(E_INVALIDARG); + } + + void* pParamData = m_rgDataBlock.GetDataBuffer() + cbParamOffset; + GpMemcpy(pData, pParamData, uiSize); } + else + { + UINT uiSize = m_rgParamBlock[idxEffect].cbParamSize; + if (idxEffect >= (UINT)m_rgParamBlock.GetCount() || + size < uiSize || + pData == NULL) + { + IFC(E_INVALIDARG); + } - void* pParamData = m_rgDataBlock.GetDataBuffer() + m_rgParamBlock[idxEffect].cbParamOffset; - GpMemcpy(pData, pParamData, uiSize); + void* pParamData = m_rgDataBlock.GetDataBuffer() + m_rgParamBlock[idxEffect].cbParamOffset; + GpMemcpy(pData, pParamData, uiSize); + } Cleanup: API_CHECK(hr); diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/scanop/soconvert.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/scanop/soconvert.cpp index 67235c49dc3..8129b289e1b 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/scanop/soconvert.cpp +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/scanop/soconvert.cpp @@ -40,6 +40,7 @@ // #include "precomp.hpp" +#include "..\shared\WpfGfxSwitches.h" //+----------------------------------------------------------------------------- // @@ -84,8 +85,17 @@ Convert_1_32bppARGB( UINT n, bits; - ARGB c0 = ppal->Entries[0]; - ARGB c1 = ppal->Entries[1]; + ARGB c0 = 0, c1 = 0; + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + c0 = ppal->Count > 0 ? ppal->Entries[0] : 0; + c1 = ppal->Count > 1 ? ppal->Entries[1] : 0; + } + else + { + c0 = ppal->Entries[0]; + c1 = ppal->Entries[1]; + } // NOTE: We choose code size over speed here @@ -149,6 +159,7 @@ Convert_4_32bppARGB( Assert(ppal); const ARGB* colors = ppal->Entries; + UINT paletteCount = ppal->Count; UINT n = uiCount >> 1; // Handle whole bytes @@ -160,8 +171,20 @@ Convert_4_32bppARGB( Assert((bits >> 4) < ppal->Count); Assert((bits & 0xf) < ppal->Count); - pDest[0] = colors[bits >> 4]; - pDest[1] = colors[bits & 0xf]; + UINT hiNibble = bits >> 4; + UINT loNibble = bits & 0xf; + + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + // Clamp indices to valid palette range to prevent OOB read + pDest[0] = hiNibble < paletteCount ? colors[hiNibble] : 0; + pDest[1] = loNibble < paletteCount ? colors[loNibble] : 0; + } + else + { + pDest[0] = colors[hiNibble]; + pDest[1] = colors[loNibble]; + } pDest += 2; } @@ -169,7 +192,17 @@ Convert_4_32bppARGB( // Handle the last odd nibble, if any if (uiCount & 1) - *pDest = colors[*pSrc >> 4]; + { + UINT lastNibble = *pSrc >> 4; + if(!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + *pDest = lastNibble < paletteCount ? colors[lastNibble] : 0; + } + else + { + *pDest = colors[lastNibble]; + } + } } @@ -186,6 +219,7 @@ Convert_2_32bppARGB( const ColorPalette *ppal = DYNCAST(OSDPalette, pSOP->m_posd)->m_pPalette; Assert(ppal); + UINT paletteCount = ppal->Count; const ARGB* colors = ppal->Entries; @@ -205,7 +239,14 @@ Convert_2_32bppARGB( Assert(i < ppal->Count); - * pDest++ = colors[i]; + if(!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + *pDest++ = i < paletteCount ? colors[i] : 0; + } + else + { + *pDest++ = colors[i]; + } c --; } @@ -226,19 +267,29 @@ Convert_8_32bppARGB( const ColorPalette *ppal = DYNCAST(OSDPalette, pSOP->m_posd)->m_pPalette; Assert(ppal); + UINT paletteCount = ppal->Count; const ARGB* colors = ppal->Entries; while (uiCount--) { + BYTE index = *pSrc++; #if DBG - if (*pSrc >= ppal->Count) + if (index >= paletteCount) { TraceTag((tagMILWarning, "Palette missing entries on conversion from 8bpp to 32bppARGB")); } #endif - *pDest++ = colors[*pSrc++]; + + if(!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + *pDest++ = index < paletteCount ? colors[index] : 0; + } + else + { + *pDest++ = colors[index]; + } } } diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.cpp new file mode 100644 index 00000000000..189817c241f --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.cpp @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include "WpfGfxSwitches.h" + +// Static storage for WpfGfxSwitches +bool WpfGfxSwitches::g_fWpfGfxBoundsCheckProtectionDisabled = false; + +void WINAPI +WpfGfx_SetDisableBoundsCheckProtection(BOOL fDisable) +{ + WpfGfxSwitches::SetWpfGfxBoundsCheckProtectionDisabled(!!fDisable); +} diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.h b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.h new file mode 100644 index 00000000000..c041446bf67 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/WpfGfxSwitches.h @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +/// +/// Switch for WpfGfx security fixes, set from managed CoreAppContextSwitches +/// via P/Invoke at startup. +/// +class WpfGfxSwitches +{ +public: + static bool IsWpfGfxBoundsCheckProtectionDisabled() + { + return g_fWpfGfxBoundsCheckProtectionDisabled; + } + + static void SetWpfGfxBoundsCheckProtectionDisabled(bool disabled) + { + g_fWpfGfxBoundsCheckProtectionDisabled = disabled; + } + +private: + static bool g_fWpfGfxBoundsCheckProtectionDisabled; +}; diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/dynarray.h b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/dynarray.h index c65ae22fa26..927e9cef07e 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/dynarray.h +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/dynarray.h @@ -89,16 +89,30 @@ template class DynArray : public DynArray __ecount(this->Count) T &First() const { __pfx_assert(Count > 0, "Buffer overflow accessing empty DynArray"); - Assert(Count > 0); + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + FreAssert(Count > 0); + } + else + { + Assert(Count > 0); + } return GetDataBuffer()[0]; } __ecount(1) T &Last() const { __pfx_assert(Count > 0, "Buffer overflow accessing empty DynArray"); - Assert(Count > 0); + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + FreAssert(Count > 0); + } + else + { + Assert(Count > 0); + } #pragma prefast (push) -#pragma prefast (disable: 37001 37002 37003, "This operation will not overflow becasuse of the Assert above.") +#pragma prefast (disable: 37001 37002 37003, "This operation will not overflow because of the Assert/FreAssert above.") return GetDataBuffer()[Count-1]; #pragma prefast (pop) } diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.h b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.h index 00a0e0808cc..ce6a9b86dcc 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.h +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.h @@ -29,6 +29,7 @@ #include "refcountbase.h" #include "arithmetic.h" #include "dynarrayimpl.h" +#include "WpfGfxSwitches.h" #include "dynarray.h" #include "heap.h" #include "resourcecache.h" diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.vcxproj b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.vcxproj index d20cf37c3ad..8d2cb7bcb1c 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.vcxproj +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/common/shared/shared.vcxproj @@ -71,6 +71,7 @@ + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/engine.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/engine.cpp index ba3244c453f..d8882a0fef0 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/engine.cpp +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/engine.cpp @@ -303,6 +303,3 @@ CCommonRegistryData::InitializeDWMKeysFromRegistry() } #endif - - - diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/gradienttexture.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/gradienttexture.cpp index b16b6d203d2..75ca633d4f3 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/gradienttexture.cpp +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/common/gradienttexture.cpp @@ -1176,7 +1176,7 @@ CGradientTextureGenerator::SetFirstStop( Assert(uStopCount <= MAX_GRADIENTSTOP_COUNT); UINT uCurrentIndex; - + // // This method handles all possible cominations to determine the gradient stop at 0.0 // @@ -1450,7 +1450,7 @@ CGradientTextureGenerator::SetLastStop( // This method requires that pStopBuffer contain at least two gradient stops Assert(uStopCount >= 2); Assert(uStopCount <= MAX_GRADIENTSTOP_COUNT); - + // // See the comment in SetFirstStop for the URL containing the Spec Case #'s // This method handles the remaining cominations of stops to determine the diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/dll/wpfgfx.def b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/dll/wpfgfx.def index 518ecd99426..fe56105c301 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/dll/wpfgfx.def +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/dll/wpfgfx.def @@ -138,4 +138,5 @@ EXPORTS RenderOptions_ForceSoftwareRenderingModeForProcess RenderOptions_IsSoftwareRenderingForcedForProcess RenderOptions_EnableHardwareAccelerationInRdp + WpfGfx_SetDisableBoundsCheckProtection diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/d3dglyphbank.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/d3dglyphbank.cpp index fb7b1fdb0ba..29355c75192 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/d3dglyphbank.cpp +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/d3dglyphbank.cpp @@ -343,9 +343,21 @@ HRESULT CD3DGlyphBank::RectFillAlpha( // pDst00 points to the texel in destination that corresponds // to point (x,y) = (0,0) in source array - const BYTE *pSrc00 = pSrcData - - srcPitch*fullDataRect.top - - fullDataRect.left; + // Use 64-bit arithmetic to avoid integer overflow when srcPitch * fullDataRect.top + // exceeds INT32 range (possible with large ClearType glyphs where srcPitch = width*3). + const BYTE *pSrc00; + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + pSrc00 = pSrcData + - (INT64)srcPitch*fullDataRect.top + - fullDataRect.left; + } + else + { + pSrc00 = pSrcData + - srcPitch*fullDataRect.top + - fullDataRect.left; + } // pSrc00 points to (x,y) = (0,0) in given data array int y; @@ -365,7 +377,15 @@ HRESULT CD3DGlyphBank::RectFillAlpha( for (; y < ymax; y++) { BYTE* pDstRow = pDst00 + lockedRect.Pitch*y; - const BYTE* pSrcRow = pSrc00 + srcPitch*y; + const BYTE* pSrcRow; + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + pSrcRow = pSrc00 + (INT64)srcPitch*y; + } + else + { + pSrcRow = pSrc00 + srcPitch*y; + } memset(pDstRow + srcRect.left, 0, xmin - srcRect.left); memcpy(pDstRow + xmin, pSrcRow + xmin, xmax - xmin); diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/hwbitmapcolorsource.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/hwbitmapcolorsource.cpp index 73785e9e942..8d77ba689b2 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/hwbitmapcolorsource.cpp +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/hw/hwbitmapcolorsource.cpp @@ -3716,7 +3716,14 @@ CHwBitmapColorSource::PushTheSourceBitsToVideoMemory( rcMilTextureLock.Y = 0; rcMilTextureLock.Width = static_cast(m_d3dsdRequired.Width); rcMilTextureLock.Height = static_cast(m_d3dsdRequired.Height); - cbLockedBufferSize = GetRequiredBufferSize(m_fmtTexture, d3dlrBitmapCopyDestination.Pitch, &rcMilTextureLock); + if(!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + IFC(HrGetRequiredBufferSize(m_fmtTexture, d3dlrBitmapCopyDestination.Pitch, &rcMilTextureLock, &cbLockedBufferSize)); + } + else + { + cbLockedBufferSize = GetRequiredBufferSize(m_fmtTexture, d3dlrBitmapCopyDestination.Pitch, &rcMilTextureLock); + } fLockedSurface = true; } @@ -3774,16 +3781,49 @@ CHwBitmapColorSource::PushTheSourceBitsToVideoMemory( rcDirty.left, rcDirty.top, rcDirty.right - rcDirty.left, rcDirty.bottom - rcDirty.top }; - BYTE *pvDestPixels = reinterpret_cast(d3dlrBitmapCopyDestination.pBits) - + uPixelSize * static_cast(ptDest.x) - + d3dlrBitmapCopyDestination.Pitch * ptDest.y + - // Offset according to border. - uBorderSize * (uPixelSize + d3dlrBitmapCopyDestination.Pitch); + BYTE *pvDestPixels; + UINT cbRemainingBufferSize; + + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + // Compute destination offset with overflow-safe arithmetic. + UINT uDestOffsetX; + UINT uDestOffsetY; + UINT uDestOffset; + UINT uBorderOffset; + + IFC(UIntMult(uPixelSize, static_cast(ptDest.x), &uDestOffsetX)); + IFC(UIntMult(static_cast(d3dlrBitmapCopyDestination.Pitch), static_cast(ptDest.y), &uDestOffsetY)); + IFC(UIntAdd(uDestOffsetX, uDestOffsetY, &uDestOffset)); + + // Border offset: uBorderSize * (uPixelSize + Pitch) + IFC(UIntAdd(uPixelSize, static_cast(d3dlrBitmapCopyDestination.Pitch), &uBorderOffset)); + IFC(UIntMult(uBorderSize, uBorderOffset, &uBorderOffset)); + IFC(UIntAdd(uDestOffset, uBorderOffset, &uDestOffset)); + + // Verify the offset doesn't exceed the locked buffer + if (uDestOffset >= cbLockedBufferSize) + { + IFC(WGXERR_INTERNALERROR); + } + + pvDestPixels = reinterpret_cast(d3dlrBitmapCopyDestination.pBits) + + uDestOffset; + cbRemainingBufferSize = cbLockedBufferSize - uDestOffset; + } + else + { + pvDestPixels = reinterpret_cast(d3dlrBitmapCopyDestination.pBits) + + uPixelSize * static_cast(ptDest.x) + + d3dlrBitmapCopyDestination.Pitch * ptDest.y + + uBorderSize * (uPixelSize + d3dlrBitmapCopyDestination.Pitch); + cbRemainingBufferSize = cbLockedBufferSize; + } IFC(pIBitmapSource->CopyPixels( &rcCopy, d3dlrBitmapCopyDestination.Pitch, - cbLockedBufferSize, + cbRemainingBufferSize, pvDestPixels )); } @@ -4451,7 +4491,8 @@ DbgTintDirtyRectangle( // Function: SelfCopyPixels // // Synopsis: Copy source rectangle to new location (non-overlapping) -// in image. Does not check memory! +// in image. Validates all offsets against buffer size using +// overflow-safe arithmetic before copying. // //----------------------------------------------------------------------------- void @@ -4468,20 +4509,52 @@ SelfCopyPixels( __inout_bcount(cbBufferSize) BYTE *pvPixels // Pointer to start of output ) { - #pragma prefast(suppress: 22013, "Offset calculations may not overflow") - UINT offReadEnd = cbStep * rc.right + cbStride * (rc.bottom-1); - UINT offWriteEnd = cbStep * (x+rc.Width()) + cbStride * (y+rc.Height()-1); - - if (cbBufferSize < offReadEnd) - { - RIP("Buffer size too small for source rectangle"); - } - else if (cbBufferSize < offWriteEnd) - { - RIP("Buffer size too small for destination rectangle"); - } - else + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) { + // Compute the end offsets for both source and destination using + // overflow-safe arithmetic. If any multiplication or addition + // overflows, the bounds check will correctly reject the operation. + UINT offReadEnd = 0; + UINT offWriteEnd = 0; + UINT temp1, temp2; + + bool fOverflow = false; + + // offReadEnd = cbStep * rc.right + cbStride * (rc.bottom - 1) + if (rc.bottom == 0 || + FAILED(UIntMult(cbStep, rc.right, &temp1)) || + FAILED(UIntMult(cbStride, rc.bottom - 1, &temp2)) || + FAILED(UIntAdd(temp1, temp2, &offReadEnd))) + { + fOverflow = true; + } + + // offWriteEnd = cbStep * (x + rc.Width()) + cbStride * (y + rc.Height() - 1) + if (!fOverflow) + { + UINT destRight, destBottom; + if (FAILED(UIntAdd(x, rc.Width(), &destRight)) || + FAILED(UIntMult(cbStep, destRight, &temp1)) || + FAILED(UIntAdd(y, rc.Height(), &destBottom)) || + destBottom == 0 || + FAILED(UIntMult(cbStride, destBottom - 1, &temp2)) || + FAILED(UIntAdd(temp1, temp2, &offWriteEnd))) + { + fOverflow = true; + } + } + + if (fOverflow || cbBufferSize < offReadEnd) + { + RIP("Buffer size too small for source rectangle"); + return; + } + else if (cbBufferSize < offWriteEnd) + { + RIP("Buffer size too small for destination rectangle"); + return; + } + for (UINT i = rc.left; i < rc.right; ++i) { for (UINT j = rc.top; j < rc.bottom; ++j) @@ -4495,6 +4568,36 @@ SelfCopyPixels( } } } + else + { + #pragma prefast(suppress: 22013, "Offset calculations may not overflow") + UINT offReadEnd = cbStep * rc.right + cbStride * (rc.bottom-1); + UINT offWriteEnd = cbStep * (x+rc.Width()) + cbStride * (y+rc.Height()-1); + + if (cbBufferSize < offReadEnd) + { + RIP("Buffer size too small for source rectangle"); + } + else if (cbBufferSize < offWriteEnd) + { + RIP("Buffer size too small for destination rectangle"); + } + else + { + for (UINT i = rc.left; i < rc.right; ++i) + { + for (UINT j = rc.top; j < rc.bottom; ++j) + { + BYTE *pvSrc = pvPixels + j * cbStride + i * cbStep; + BYTE *pvDst = pvPixels + ((j-rc.top)+y) * cbStride + ((i-rc.left)+x) * cbStep; + Assert(pvDst + cbStep <= pvPixels + cbBufferSize); + Assert(pvSrc + cbStep <= pvPixels + cbBufferSize); + + RtlCopyMemory(pvDst, pvSrc, cbStep); + } + } + } + } return; } diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/resources/glyphrunslave.cpp b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/resources/glyphrunslave.cpp index 7c81f299d53..8dabb56c491 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/resources/glyphrunslave.cpp +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/core/resources/glyphrunslave.cpp @@ -1700,7 +1700,22 @@ CGlyphRunRealization::EnsureValidAlphaMap(__in const EnhancedContrastTable *pECT CMilRectL CTBbox(clearTypeAlphaMapBoundingBox); CMilRectL UnionBBox(BLBbox); UnionBBox.Union(CTBbox); - UINT32 textureSize = UnionBBox.Width() * UnionBBox.Height(); + + UINT32 textureSize; + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + UINT64 textureSize64 = (UINT64)UnionBBox.Width() * UnionBBox.Height(); + if (textureSize64 > UINT32_MAX) + { + IFC(WGXERR_BADNUMBER); + } + textureSize = (UINT32)textureSize64; + } + else + { + textureSize = UnionBBox.Width() * UnionBBox.Height(); + } + BYTE *pCombinedAlphaMap = (BYTE*)WPFAlloc(ProcessHeap, Mt(GlyphBitmapClearType), textureSize @@ -1866,14 +1881,25 @@ CGlyphRunRealization::RealizeAlphaBoundsAndTextures( // UINT32 width = boundingBox.right - boundingBox.left; UINT32 height = boundingBox.bottom - boundingBox.top; - UINT32 textureStride = width; + UINT32 textureStrideU32 = width; if (textureType == DWRITE_TEXTURE_CLEARTYPE_3x1) { - // ClearType bitmaps (DWRITE_TEXTURE_CLEARTYPE_3x1) contain 3 bytes per pixel, - // Aliased bitmaps only contain 1. - textureStride *= 3; + textureStrideU32 *= 3; + } + UINT32 textureSize = 0; + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + UINT64 textureSize64 = (UINT64)textureStrideU32 * height; + if (textureSize64 > UINT32_MAX) + { + IFC(WGXERR_BADNUMBER); + } + textureSize = (UINT32)textureSize64; + } + else + { + textureSize = textureStrideU32 * height; } - UINT32 textureSize = textureStride * height; pAlphaValues = (BYTE *)WPFAlloc(ProcessHeap, (textureType == DWRITE_TEXTURE_CLEARTYPE_3x1 ? Mt(GlyphBitmapClearType) : Mt(GlyphBitmapBiLevel)), @@ -1902,7 +1928,7 @@ CGlyphRunRealization::RealizeAlphaBoundsAndTextures( // pECT may be NULL if the contrast enhancement value is 0. if (pECT) { - pECT->RenormalizeAndApplyContrast(pAlphaValues, boundingBox.right - boundingBox.left, boundingBox.bottom - boundingBox.top, textureStride, textureSize); + pECT->RenormalizeAndApplyContrast(pAlphaValues, boundingBox.right - boundingBox.left, boundingBox.bottom - boundingBox.top, textureStrideU32, textureSize); } } else @@ -1910,10 +1936,27 @@ CGlyphRunRealization::RealizeAlphaBoundsAndTextures( // Future Consideration: probably shouldn't do this texture expansion. Need to write a different // shader and shrink the texture to benefit perf. Aliased text is relatively rare however, so it's // not worth the investment at this point. - BYTE *pNewAlphaValues = (BYTE *)WPFAlloc(ProcessHeap, - Mt(GlyphBitmapBiLevel), - textureSize * 3); - TraceTagText((tagError, "CGlyphRunRealization::RealizeAlphaBoundsAndTextures, allocated bytes: %d", textureSize * 3)); + BYTE *pNewAlphaValues; + if (!WpfGfxSwitches::IsWpfGfxBoundsCheckProtectionDisabled()) + { + UINT64 expandedSize64 = (UINT64)textureSize * 3; + if (expandedSize64 > UINT32_MAX) + { + IFC(WGXERR_BADNUMBER); + } + UINT32 expandedSize = (UINT32)expandedSize64; + pNewAlphaValues = (BYTE *)WPFAlloc(ProcessHeap, + Mt(GlyphBitmapBiLevel), + expandedSize); + TraceTagText((tagError, "CGlyphRunRealization::RealizeAlphaBoundsAndTextures, allocated bytes: %d", expandedSize)); + } + else + { + pNewAlphaValues = (BYTE *)WPFAlloc(ProcessHeap, + Mt(GlyphBitmapBiLevel), + textureSize * 3); + TraceTagText((tagError, "CGlyphRunRealization::RealizeAlphaBoundsAndTextures, allocated bytes: %d", textureSize * 3)); + } for (UINT i = 0; i < textureSize; i++) { diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/WindowsBase.Tests/System/Windows/Interop/ComponentDispatcherTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/WindowsBase.Tests/System/Windows/Interop/ComponentDispatcherTests.cs index f1ad9ced078..052ae45cd39 100644 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/WindowsBase.Tests/System/Windows/Interop/ComponentDispatcherTests.cs +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/WindowsBase.Tests/System/Windows/Interop/ComponentDispatcherTests.cs @@ -262,6 +262,10 @@ public void PopModal_InvokeNoPush_Success() // Push again. ComponentDispatcher.PushModal(); Assert.True(ComponentDispatcher.IsThreadModal); + + // Clean up to avoid leaking modal state to other tests. + ComponentDispatcher.PopModal(); + ComponentDispatcher.PopModal(); } [Fact]