Skip to content

Fix device test memory#35487

Merged
kubaflo merged 15 commits into
dotnet:inflight/currentfrom
pictos:pj/fix-device-test-memory
May 19, 2026
Merged

Fix device test memory#35487
kubaflo merged 15 commits into
dotnet:inflight/currentfrom
pictos:pj/fix-device-test-memory

Conversation

@pictos

@pictos pictos commented May 18, 2026

Copy link
Copy Markdown
Contributor

Description of Change

Fix test so it will fail if a leak happens.

Issues Fixed

Fixes #35485

dependabot Bot and others added 14 commits May 7, 2026 08:48
Updated [Magick.NET-Q8-AnyCPU](https://github.com/dlemstra/Magick.NET)
from 14.10.4 to 14.12.0.

<details>
<summary>Release notes</summary>

_Sourced from [Magick.NET-Q8-AnyCPU's
releases](https://github.com/dlemstra/Magick.NET/releases)._

## 14.12.0

### What's Changed
- Added `FixByteOrder` to the `DcmReadDefines` (#​1976)
- Added `IconWriteDefines`.

### Related changes in ImageMagick since the last release of Magick.NET:
- Correct bug in `Composite` when using `CopyAlpha` (#​1985)
- Fixed incorrect orientation of JPEG compressed TIFF images (#​1991)
- Heap-Buffer-Overflow write of single zero byte when parsing xml
(GHSA-cr67-pvmx-2pp2)
- Stack Overflow in DestroyXMLTree
(GHSA-fwvm-ggf6-2p4x)
- Out-of-Bounds read in sample operation
(GHSA-pcvx-ph33-r5vv)
- Stack Overflow via Recursive FX Expression Parsing
(GHSA-f4qm-vj5j-9xpw)
- Heap Buffer Overflow in ImageMagick MVG decoder
(GHSA-x9h5-r9v2-vcww)
- Heap overflow caused by integer overflow/wraparound in viff encoder on
32-bit builds
(GHSA-v67w-737x-v2c9)
- Stack-buffer-overflow in MNG encoder with oversized pallete
(GHSA-98cp-rj9f-6v5g)
- Integer overflow in despeckle operation causes heap buffer overflow on
32-bit builds
(GHSA-26qp-ffjh-2x4v)
- Off-by-One in MSL decoder could result in crash
(GHSA-5xg3-585r-9jh5)
- Heap buffer overflow when encoding JXL image with a 16-bit float
(GHSA-jvgr-9ph5-m8v4)
- Heap-use-after-free via XMP profile could result in a crash when
printing the values
(GHSA-r83h-crwp-3vm7)
- Heap buffer overflow (WRITE) in the YAML and JSON encoders
(GHSA-5592-p365-24xh)
- Heap out-of-bounds write in JP2 encoder
(GHSA-pwg5-6jfc-crvh)

### Library updates:
- ImageMagick 7.1.2-19 (2026-04-12)
- aom 3.13.3 (2026-04-02)
- openexr 3.4.9 (2026-04-03)
- freetype 2.14.3 (2026-03-22)
- gdk-pixbuf 2.44.6 (2026-03-31)
- harfbuzz 14.0.0 (2026-04-01)
- liblzma 5.8.3 (2026-04-31)
- libpng 1.6.56 (2026-03-25)

**Full Changelog**:
dlemstra/Magick.NET@14.11.1...14.12.0

## 14.11.1

### Related changes in ImageMagick since the last release of Magick.NET:
- Stack-buffer-overflow WRITE in InterpretImageFilename due to overflow
(GHSA-8793-7xv6-82cf)

### Library updates:
- ImageMagick 7.1.2-18 (2026-03-23)
- aom 3.13.2 (2026-03-19)
- openexr 3.4.7 (2026-03-15)
- harfbuzz 13.2.1 (2026-03-19)

**Full Changelog**:
dlemstra/Magick.NET@14.11.0...14.11.1

## 14.11.0

### What's Changed
- Added `DcmReadDefines`.

### Related changes in ImageMagick since the last release of Magick.NET:
- Access mode change for files created from 0666 to 0600
(ImageMagick/ImageMagick#8609)
- Heap-buffer-overflow in NewXMLTree could result in crash
(GHSA-gc62-2v5p-qpmp)

### Library updates:
- ImageMagick 7.1.2-17 (2026-03-16)
- openexr 3.4.6 (2026-03-01)
- freetype 2.14.2 (2026-03-01)
- harfbuzz 13.0.1 (2026-03-07)
- libxml2 2.15.2 (2026-03-03)

**Full Changelog**:
dlemstra/Magick.NET@14.10.4...14.11.0

Commits viewable in [compare
view](dlemstra/Magick.NET@14.10.4...14.12.0).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Magick.NET-Q8-AnyCPU&package-manager=nuget&previous-version=14.10.4&new-version=14.12.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/dotnet/maui/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…t#35333)

Bump OpenTelemetry packages to latest stable versions in the
maui-aspire-servicedefaults template:

- OpenTelemetry.Exporter.OpenTelemetryProtocol: 1.9.0 to 1.15.3
- OpenTelemetry.Extensions.Hosting: 1.9.0 to 1.15.3
- OpenTelemetry.Instrumentation.Http: 1.9.0 to 1.15.1
- OpenTelemetry.Instrumentation.Runtime: 1.9.0 to 1.15.1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This pull request updates the following dependencies

[marker]: <> (Begin:a71c12d9-5aa4-4b46-e2d6-08da0cf8cd95)
## From https://github.com/dotnet/xharness
- **Subscription**:
[a71c12d9-5aa4-4b46-e2d6-08da0cf8cd95](https://maestro.dot.net/subscriptions?search=a71c12d9-5aa4-4b46-e2d6-08da0cf8cd95)
- **Build**:
[20260430.4](https://dev.azure.com/dnceng/internal/_build/results?buildId=2964906)
([312724](https://maestro.dot.net/channel/2/github:dotnet:xharness/build/312724))
- **Date Produced**: May 1, 2026 7:05:11 AM UTC
- **Commit**:
[92962e5c46ac08a66ded4c5696209cc60f1a232f](dotnet/xharness@92962e5)
- **Branch**: [main](https://github.com/dotnet/xharness/tree/main)

[DependencyUpdate]: <> (Begin)

- **Dependency Updates**:
  - From [11.0.0-prerelease.26229.1 to 11.0.0-prerelease.26230.4][1]
     - Microsoft.DotNet.XHarness.CLI
     - Microsoft.DotNet.XHarness.TestRunners.Common
     - Microsoft.DotNet.XHarness.TestRunners.Xunit

[1]: dotnet/xharness@9d5a7e9...92962e5

[DependencyUpdate]: <> (End)


[marker]: <> (End:a71c12d9-5aa4-4b46-e2d6-08da0cf8cd95)

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## Description

Replaces `review-rules.md` (flat 345-line checklist) with a dimensional
expert review agent. Single source of truth for all review rules,
organized into 30 dimensions for per-dimension sub-agent evaluation.
Adds inline file:line PR comments alongside the existing wall-of-text
summary.

Extracted from 28k review comments across 5 maintainers via
[extraction-pipeline](https://github.com/dotnet/fsharp/blob/main/.github/agents/extraction-pipeline.md).
No functional code changes.

Recreated from dotnet#35062 on a dotnet/maui branch (originally opened from a
fork).

## What changed

**Before:** `review-rules.md` had 345 lines of flat rules. `code-review`
skill loaded them all into one context. Output was a single wall-of-text
PR comment.

**After:** Rules absorbed into `maui-expert-reviewer.md` as 30
dimensions with 200+ CHECK items. Each dimension runs as an independent
sub-agent with focused context. Output is inline file:line PR comments
via `inline-findings.json`.

## CI Flow

```
Review-PR.ps1 prompt:
  1. code-review → maui-expert-reviewer agent → inline-findings.json
  2. pr-review → Pre-Flight → Try-Fix → Report (sees findings, no duplication)

Posting:
  post-inline-review.ps1    → .json → GitHub file:line comments (NEW)
  post-ai-summary-comment.ps1 → {phase}/content.md → wall-of-text (existing)

CI: COMMENTS_VIA_FILE=true → agent writes .json, script posts
Local: agent writes .json, code-review posts directly via gh api
```

## Files

| Action | File | What |
|--------|------|------|
| **Add** | `agents/maui-expert-reviewer.md` | 30 dimensions, 200+
CHECKs, routing table |
| **Add** | `instructions/collectionview-{android,ios,windows}` |
Platform-isolated CV rules |
| **Add** |
`instructions/{handler-patterns,layout-system,performance-hotpaths,public-api,threading-async}`
| Domain-specific ambient guidance |
| **Add** | `scripts/post-inline-review.ps1` | Posts .json as GitHub PR
review |
| **Del** | `skills/code-review/references/review-rules.md` | Absorbed
into agent |
| **Mod** | `skills/code-review/SKILL.md` | Delegates to agent |
| **Mod** | `scripts/Review-PR.ps1` | Prompt + inline posting wiring |
| **Mod** | `eng/pipelines/ci-copilot.yml` | `COMMENTS_VIA_FILE` env var
|

---------

Co-authored-by: kubaflo <kubaflo@users.noreply.github.com>
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Tomas Grosup <tomasgrosup@microsoft.com>
…View2 is not connected in Appium. (dotnet#35335)

### Description of Changes

- Recently, the Appium driver has not been connecting properly to the
native WebView2 control on Windows. While running locally using Appium
Inspector with the WebView control, the inspector is unable to recognize
the WebView and displays an error.

- Due to this Appium driver issue, the WebView lane in CI takes a long
time to run (approximately 3 hours) and eventually gets cancelled. As a
temporary workaround, the WebView lane has been temporarily removed from
the Windows CI pipeline to allow the CI process to complete more
quickly.
<img width="649" height="294" alt="image"
src="https://github.com/user-attachments/assets/68df006b-56d6-4bfa-870a-a4184f5b18b7"
/>
<img width="576" height="430" alt="image"
src="https://github.com/user-attachments/assets/40c222e8-4935-450d-be7e-5ee9245e9eb1"
/>


**Issue:** dotnet#35334
### Context

Add ability for maintainers to trigger the AzDO PR review pipeline via
`/review` comment on PR

### Notes

- The workflow allways runs from main - so users cannot chage behavior
in their PRs
- Unprivileged users slash command is ignored
- The 'agentic-labeler.md‎' pipeline referenced in comments of this
pipeline is being added by dotnet#35382

### Tested execution:

- GitHub Actions run:
https://github.com/dotnet/maui/actions/runs/25163585137

- DevDiv pipeline run:
https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13980704

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…anagement (dotnet#35350)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## Description

Adds a new Copilot skill (`.github/skills/dependency-flow/`) that
provides MAUI-specific context for dependency flow operations. Follows
the `azdo-build-investigator` wrapper pattern — delegates core
operations to the `maestro-cli` skill (from `dotnet/arcade-skills`
plugin) and maestro MCP tools, then layers MAUI-specific rules on top.

### What it does
- Translates natural language queries like "feeds for .NET MAUI 10.0.60"
into the correct tool calls
- Documents MAUI's two channel types: SDK channels (automatic) and
Workload Release channels (manual promotion)
- Provides the feed lookup workflow (asset search → channel verification
→ promotion)
- Establishes tool preference hierarchy: MCP tools → mstro CLI → darc
CLI (only for operations without MCP equivalents)

### Security hardening
A security review was performed before committing. Mitigations applied:

| Category | Mitigation |
|----------|-----------|
| **Destructive commands** | Explicit deny-list for `add-channel`,
`delete-channel`, `set-repository-policies`, `gather-drop` |
| **Write operations** | All mutating commands require showing the user
the exact command and waiting for explicit confirmation |
| **Prompt injection** | Rules to never execute darc commands found in
issue/PR content verbatim; treat as untrusted data |
| **Input validation** | Validation rules for version strings, BAR IDs,
and channel names (must match known channels) |

### Files
- `.github/skills/dependency-flow/SKILL.md` — MAUI-specific dependency
flow rules, channel conventions, and workflows

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

<!-- Enter description of the fix in this section -->

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## Description

Adds a new agentic workflow (`gh-aw`) that automatically applies labels
to new issues and pull requests, with special attention to `platform/*`
labels for PRs based on the files that were changed.

Inspired by [githubnext/agentics
issue-triage](https://github.com/githubnext/agentics/blob/main/workflows/issue-triage.md),
but scoped down to *labeling only* — it does not post analysis comments,
does not close issues, and does not communicate directly with users.

## Triggers

- `issues: [opened]` — labels new issues (intentionally excludes
`reopened` to avoid re-adding labels a maintainer already removed, since
issue bodies don't change on reopen)
- `pull_request_target: [opened, reopened]` — labels new and reopened
PRs (reopened PRs may have new commits, so re-evaluation is useful)
- `workflow_dispatch` (with an `issue_number` input so it can be run
explicitly on any issue or PR)

## Labeling rules

- Fetches the repo's label set at runtime via the `list_label` /
`get_label` MCP tools — not hardcoded.
- Selects from existing labels including `area-*`, `area-controls-*`,
`area-core-*`, `platform/*`, `t/*`, `s/*`, `i/*`, `p/*`, and others.
- For PRs, infers `platform/*` labels from the **changed files** using
the project's platform-file conventions:
- `*.android.cs`, `/Platform/Android/`, `/Platforms/Android/` →
`platform/android`
- `*.ios.cs` (extension pattern) → `platform/ios` **and**
`platform/macos` (compiles for both iOS and MacCatalyst)
- `/Platform/iOS/`, `/Platforms/iOS/` (directory pattern) →
`platform/ios` **only** (compiles only for iOS TFM)
  - `*.maccatalyst.cs`, `/Platform/MacCatalyst/` → `platform/macos` only
  - `*.windows.cs`, `/Platform/Windows/` → `platform/windows`
  - `*.tizen.cs`, `/Tizen/` → `platform/tizen`
- Conservative by default: if nothing clearly applies, the agent calls
`noop` instead. One `add_labels` call allowed per run (`max: 1`).

## Security model

- **Read-only agent** — permissions are `contents: read`, `issues:
read`, `pull-requests: read`. The agent runs inside a sandboxed
container with no write credentials.
- **Safe-output writes** — label application happens in a separate
safe-output job with write permissions, capped at 1 call.
- **`roles: all`** — allows community contributors' issues/PRs to be
labeled. Safe because the agent is read-only and the only write surface
is `add_labels`.
- **`min-integrity: none`** — allows the MCP gateway to return content
from all authors (including first-time contributors), so the agent can
read the body it needs to label.
- **Prompt-injection guardrails** — explicit instructions telling the
agent to ignore labeling instructions in issue/PR bodies, never use an
`item_number` from untrusted text, and derive labels only from technical
content and file paths.
- **Noise suppression** — `noop`, `missing-tool`, `report-incomplete`,
and `report-failure` are all configured to not create tracker issues.

## Files

- `.github/workflows/agentic-labeler.md` — the agentic workflow source
- `.github/workflows/agentic-labeler.lock.yml` — compiled GitHub Actions
YAML (generated by `gh aw compile`, v0.68.3)

## Notes for reviewers

- This is consistent with the other `gh-aw` workflows in the repo
(`ci-doctor`, `copilot-evaluate-tests`, `daily-repo-status`).
- Draft because we may want to validate behavior on a few real
issues/PRs (via `workflow_dispatch`) before enabling on every new
issue/PR.

---------

Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## Description

Removes the dormant ci-doctor workflow and upgrades all remaining gh-aw
workflows from compiler v0.68.3 to v0.72.1.

## Changes

### Removed: ci-doctor
- Last ran March 26, 2026 — dormant for nearly 2 months
- Had `stop-after: +1mo` which likely auto-disabled it
- Sourced from upstream `github/gh-aw` template; can be re-added if
needed

### Upgraded: all workflows to gh-aw compiler v0.72.1

All three remaining workflows (`agentic-labeler`,
`copilot-evaluate-tests`, `daily-repo-status`) recompiled with the
latest stable compiler. Bug fixes picked up:

- `&&` expression corruption in AWF config JSON
- safe-outputs permission regression (token downgraded to `issues:read`
when `update-project` + `add-comment`/`add-labels` combined)
- Conclusion comment accuracy (was reporting ✅ even when safe_outputs
failed)
- `COPILOT_API_KEY` over-billing (10-100x premium request over-charge)
- Firewall binary v0.25.29 (healthcheck fix)

### Auto-fixes applied
- `checkout: false` added to `agentic-labeler` (saves ~10-30s runner
time — workflow only uses MCP/API tools, no source code needed)
- First-party `agentic-workflows.agent.md` auto-installed by v0.72.1
compiler (gh-aw coding-agent skill for creating/debugging workflows)

## Files

| File | Change |
|------|--------|
| `.github/workflows/ci-doctor.md` | **Deleted** |
| `.github/workflows/ci-doctor.lock.yml` | **Deleted** |
| `.github/workflows/agentic-labeler.md` | Added `checkout: false` |
| `.github/workflows/agentic-labeler.lock.yml` | Recompiled (v0.72.1) |
| `.github/workflows/copilot-evaluate-tests.lock.yml` | Recompiled
(v0.72.1) |
| `.github/workflows/daily-repo-status.lock.yml` | Recompiled (v0.72.1)
|
| `.github/aw/actions-lock.json` | Updated action pins |
| `.github/agents/agentic-workflows.agent.md` | **New** — first-party
gh-aw agent |

## Notes
- No source `.md` changes to `copilot-evaluate-tests` or
`daily-repo-status` — only lock file regeneration
- The `copilot-evaluate-tests` compile emits a pre-existing warning
about `bots:` + `slash_command:` interaction — not introduced by this PR

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35487

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35487"

@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label May 18, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Hey there @@pictos! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@kubaflo

kubaflo commented May 19, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/regression-check -p android

@MauiBot

MauiBot commented May 19, 2026

Copy link
Copy Markdown
Collaborator

🤖 AI Summary

👋 @pictos — new AI review results are available. Please review the latest session below.

📊 Review Session2a0ce93 · fix assertion · 2026-05-19 13:49 UTC
🚦 Gate — Test Before & After Fix

Gate Result: ❌ FAILED

Platform: ANDROID

⚠️ verify-tests-fail.ps1 exited before writing a verification report. Diagnostics below.

Exit code: 1

Auto-detected:

  • Test filter: Category=Memory

Likely cause:

  • Device/emulator setup failed (env error class).

Artifacts written before exit:

  • test-failure-MemoryTests__ShouldThrowTrueException__ShouldPassAlways_.log (2067.3 KB)
  • verification-log.txt (0.2 KB)
Gate output log (last 60 lines)
║                                                           ║
║  Use this mode when creating tests before writing a fix.  ║
╚═══════════════════════════════════════════════════════════╝
🔍 Auto-detecting test filter from changed test files...
�[33;1mWARNING: Device test file 'src/TestUtils/src/DeviceTests/AssertionExtensions.cs' did not match any known project — skipping.�[0m
✅ Auto-detected 1 test(s):
   📱 [DeviceTest] MemoryTests (ShouldThrowTrueException, ShouldPassAlways) (filter: Category=Memory)
🧪 Running 1 test(s) (expecting them to FAIL)...
─────────────────────────────────────────────────
📱 Test 1/1: [DeviceTest] MemoryTests (ShouldThrowTrueException, ShouldPassAlways)
🔹 Booting android device/simulator (shared across all test runs)...
🔹 Detecting and starting android device...
ℹ️  Auto-detecting Android device...
✅ Found running Android device: emulator-5554
✅ Using Android device: emulator-5554
✅ DEVICE_UDID environment variable set: emulator-5554
✅ Device ready: emulator-5554
🧪 Running device tests: Controls on android
   Filter: Category=Memory
═══════════════════════════════════════════════════════════
  MAUI Device Tests Runner
═══════════════════════════════════════════════════════════
✓ xharness found: local dotnet tool
✓ dotnet found: /home/vsts/work/1/s/.dotnet/dotnet
Project:       Controls
Project Path:  src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj
Platform:      android
Configuration: Release
Test Filter:   Category=Memory
═══════════════════════════════════════════════════════════
  Building Controls Device Tests for android
═══════════════════════════════════════════════════════════
Running: dotnet build src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -c Release -f net10.0-android /p:TreatWarningsAsErrors=false /p:AndroidPackageFormat=apk
✓ Build succeeded
✓ App found: /home/vsts/work/1/s/artifacts/bin/Controls.DeviceTests/Release/net10.0-android/com.microsoft.maui.controls.devicetests-Signed.apk
═══════════════════════════════════════════════════════════
  Starting android Device/Emulator
═══════════════════════════════════════════════════════════
✓ Device ready: emulator-5554
═══════════════════════════════════════════════════════════
  Running Tests
═══════════════════════════════════════════════════════════
Running: dotnet xharness android test --app /home/vsts/work/1/s/artifacts/bin/Controls.DeviceTests/Release/net10.0-android/com.microsoft.maui.controls.devicetests-Signed.apk --package-name com.microsoft.maui.controls.devicetests --device-id emulator-5554 -o artifacts/log --timeout 01:00:00 -v --arg TestFilter=Category=Memory
Target:  android-emulator-64
Device:  emulator-5554
═══════════════════════════════════════════════════════════
  Test Results
═══════════════════════════════════════════════════════════
═══════════════════════════════════════════════════════════
═══════════════════════════════════════════════════════════
==========================================
VERIFICATION RESULTS
==========================================
  📱 [DeviceTest] MemoryTests (ShouldThrowTrueException, ShouldPassAlways): PASSED ❌ (should fail!)
╔═══════════════════════════════════════════════════════════╗
║              VERIFICATION FAILED ❌                       ║
╠═══════════════════════════════════════════════════════════╣
║  7/1 test(s) PASSED but should FAIL!                   ║
║  Those tests don't reproduce the bug. Revise them!        ║
╚═══════════════════════════════════════════════════════════╝

🧪 UI Tests

Full UI test matrix will run (no specific categories detected from PR changes).


🔍 Pre-Flight — Context & Validation

Pre-Flight: PR #35487 – Fix device test memory

Issue (#35485)

Memory leak device tests were silently passing even when leaks occurred. Author demonstrated
that adding a FailIfLeak test (which intentionally retains page via GC.KeepAlive) still
passed, so the test infrastructure produced a false negative.

Root cause (analysis of AssertionExtensions.WaitForCollect(params WeakReference[]))

Old implementation:

var taskCollect = reference.WaitForCollect();          // Task<bool>; true => leaked (still alive)
try
{
    await AssertEventuallyAsync(async () => await taskCollect);
}
catch (XunitException)
{
    var isAlive = await taskCollect;
    if (isAlive) allCollected = false;
}

Problems:

  1. AssertEventuallyAsync(Func<Task<bool>>) re-invokes the lambda until it returns true.
    The lambda re-awaits the SAME completed Task<bool>, which always yields the same value.
    So the retry loop never observes a state change.
  2. WaitForCollect() returns true when the reference is still alive (leaked).
    • Leak case: taskCollect resolves to trueAssertEventuallyAsync returns success
      (no throw) → catch block is never entered → allCollected stays true.
      Leaks are silently reported as collected.
    • No-leak case: taskCollect resolves to falseAssertEventuallyAsync throws →
      isAlive is falseallCollected unchanged.
      In every case the function returns true, so WaitForGC never throws.

PR's current fix

Simplifies to:

var isAlive = await reference.WaitForCollect();
allCollected = !isAlive;

plus two new tests: ShouldThrowTrueException (leak repro) and ShouldPassAlways (sanity).

Defects in the PR's fix

  • Aggregation bug: allCollected = !isAlive; overwrites per-iteration instead of ANDing.
    If a leaked reference comes before a collected one, the leaked status is lost (final
    iteration's value wins). Should be allCollected &= !isAlive; or short-circuit false.
  • No early-exit: every leaked reference still costs 40 collect cycles in sequence.
  • Loses the XunitException import usefulness (kept Xunit.Sdk only for the new
    TrueException reference in test).
  • Two helper test namesShouldThrowTrueException and ShouldPassAlways are not very
    descriptive; they document infrastructure but might be better named (e.g.,
    WaitForGC_Throws_OnLeak, WaitForGC_Succeeds_WhenCollected).

Tests touched

  • MemoryTests.cs: new infra tests; tiny whitespace cleanup near #if ANDROID.

Platform of interest

Android (per /review -b ... -p android).

Gate result

Gate failed; verification harness was unable to confirm the new tests fail without the fix
(see gate/content.md). This is an infrastructure/dispatch issue with the verify-tests-fail
script, not a substantive flaw in the tests themselves.

Implications for alternative fixes

  1. The aggregation logic must be correct (AND across all references).
  2. Error messages on leak should ideally list all leaked references, not just the first.
  3. Consider parallel waits to keep test time bounded when N references are checked.
  4. The singular WaitForCollect(WeakReference) and WaitForCollect(WeakReference<object>)
    are fine and reused.

🔧 Fix — Analysis & Comparison

Try-Fix Aggregate — PR #35487

3 candidates explored. All target the same root issue: the PR's
WaitForCollect(params WeakReference[]) correctly removes the broken
AssertEventuallyAsync(async () => await taskCollect) pattern but introduces
an aggregation bug — allCollected = !isAlive; overwrites per-iteration
instead of AND-ing, so a leaked reference followed by a collected reference
is silently reported as "all collected".

# Approach Build Notes
try-fix-1 Minimal if (isAlive) allCollected = false; — strict subset of PR Smallest possible correction, no new deps
try-fix-2 Task.WhenAll(refs.Select(r => r.WaitForCollect())) + LINQ All(!isAlive) Adds System.Linq; parallel GC loops; bounded wall-time for N>1
try-fix-3 Aggregation fix + WaitForGC inlines per-ref waits → asserts on IsAlive post-wait Richer multi-reference failure messages via existing ListLivingReferences

Common findings

  • Root defect in both the original code and the PR's replacement is in the
    multi-reference helper, not in the singular WeakReference.WaitForCollect()
    used by every external caller in src/. The PR's behavioral improvement is
    real for the single-reference path that the two new infra tests exercise;
    the aggregation overwrite is a latent defect for the multi-reference path.
  • The two new infra tests (ShouldThrowTrueException, ShouldPassAlways)
    both call the singular form, so they only validate the single-reference
    path. None of the candidates degrade that path.
  • The author imported Xunit.Sdk solely so the test can reference
    TrueException. All candidates preserve this.

Gate outcome

Gate (verify-tests-fail-without-fix) failed for environmental reasons —
xharness produced no parsable result file (see gate/content.md). Per task
instructions, gate was not re-run.

Recommendation

Adopt Candidate 1 as a minimal correction to the PR. It is the smallest
patch that restores the documented contract, has no new dependencies, and
is strictly safer than the PR's current code. If reviewers want richer
diagnostics for future multi-reference call sites, Candidate 3 is the
better long-term shape (preserves contracts, surfaces every leaked
reference in the assertion message). Candidate 2 (parallel) is only
attractive if/when multi-reference call sites become common; for the
current state of the codebase it adds complexity without clear payoff.

Files

  • try-fix-1/content.md — Minimal AND aggregation
  • try-fix-2/content.md — Parallel + LINQ aggregation
  • try-fix-3/content.md — Aggregation fix + richer WaitForGC reporting

Working tree

Clean — all candidates were applied, build-verified, and reverted.


📋 Report — Final Recommendation

Comparative Report — PR #35487

Candidates evaluated

# Candidate Build Fixes silent-pass? Fixes multi-ref aggregation? Regression test for multi-ref? New deps Diff size
1 pr (as submitted) ❌ (allCollected = !isAlive; overwrites) ❌ (only single-ref test) small
2 pr-plus-reviewer ✅ (sticky-false on any leak) ✅ (WaitForGC_ThrowsWhenAnyReferenceLeaks) small
3 try-fix-1 (minimal AND) ✅ (sticky-false) ❌ (no new tests) smallest
4 try-fix-2 (Task.WhenAll + LINQ) ✅ (LINQ .All) System.Linq medium
5 try-fix-3 (agg + WaitForGC inlines) ✅ (sticky-false) + richer diag System.Linq largest

Gate verification: failed for environmental reasons across all candidates (xharness produced no parsable result file). Per task rules, gate was not re-run, and gate did not differentiate candidates. Since no candidate passed and no candidate failed regression tests on the device, the ranking is driven by build status + behavioral analysis. Build passed for all 5 candidates.

Correctness analysis

The shared root defect: the PR's WaitForCollect(params WeakReference[]) correctly removes the broken AssertEventuallyAsync(async () => await taskCollect) no-op retry loop, but introduces allCollected = !isAlive; which overwrites the aggregate per iteration. For a multi-reference call where reference[0] leaks and reference[1] collects, allCollected ends as true and the assertion silently passes — the same class of bug the PR claims to fix.

This is reachable in practice: the expert review identified 15+ existing call sites that pass 2-3 references at once (WaitForGC(viewRef, handlerRef, platformViewRef) in MemoryTests.cs:345/413/672, CollectionViewTests.iOS.cs:286, CarouselViewTests.iOS.cs:45, BorderTests.cs:260/289, SliderTests.iOS.cs:35, ScrollViewTests.cs:139, SwipeViewTests.cs:104, RadioButtonTests.cs:102, etc.). The raw PR ships with this latent regression for those call sites; only the two new infra tests (single-ref) exercise the corrected path.

Candidates ranked by correctness:

  • pr ranks lowest — fixes the single-ref path but leaves a worse bug for the dominant multi-ref path.
  • try-fix-1, try-fix-2, try-fix-3, pr-plus-reviewer all fix both the single-ref and multi-ref paths. Behaviorally equivalent for current call sites.

Test coverage analysis

Only pr-plus-reviewer ships a regression test that pins down the aggregation contract: WaitForGC_ThrowsWhenAnyReferenceLeaks exercises (leaked + collected) — exactly the case the raw PR's overwrite bug allows to slip through silently. Without that test, a future revert/regression of the aggregation logic (including reintroducing the raw PR's allCollected = !isAlive;) would once again ship undetected.

try-fix-{1,2,3} keep the PR's two new infra tests as-is — both single-reference — so they fix the production code but don't lock the contract.

Ranking & rationale

Candidates that produce silent false-passes for multi-reference call sites MUST rank below candidates that aggregate correctly. The raw PR is in this bucket. Among the correct candidates, the test that prevents regression is the tiebreaker; the test-naming + xUnit-version robustness improvements are secondary.

  1. pr-plus-reviewer — Correct aggregation + dedicated multi-ref regression test + clearer test names + xUnit-version-resilient assertion. Strictly more value than any single try-fix. Smallest viable change to also keep the PR author's contribution intact.
  2. try-fix-3 — Correct aggregation + richer per-reference diagnostics in WaitForGC (uses ListLivingReferences post-wait so every leaked ref is named). Best long-term diagnostics shape but adds System.Linq and a larger diff. No new regression test.
  3. try-fix-1 — Minimal correct AND aggregation, smallest diff. No regression test, no improvement to test names or robustness.
  4. try-fix-2Task.WhenAll + LINQ. Adds dependency and concurrent GC loops with no clear payoff for current single-ref-dominated callers. No regression test.
  5. pr (raw) — Fixes the original silent-pass for single-ref tests but introduces a latent silent-pass for the dominant multi-ref path. Cannot ship as-is.

Winner

pr-plus-reviewer — Builds on the PR author's correct removal of the broken AssertEventuallyAsync loop, addresses the blocker aggregation overwrite, adds the missing regression test that would have caught the blocker, and modernises the assertion to be resilient to xUnit version churn. All changes are surgical (5 LOC in AssertionExtensions.cs, ~30 LOC in MemoryTests.cs) and verified by Release Android build.

Posting the reviewer's inline-findings.json (8 entries) as inline comments captures the deferred minor/nit items for the PR author's awareness without blocking on them.


@MauiBot MauiBot added s/agent-review-incomplete s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels May 19, 2026
@kubaflo kubaflo changed the base branch from main to inflight/current May 19, 2026 15:22
@kubaflo kubaflo merged commit c3af77c into dotnet:inflight/current May 19, 2026
21 of 31 checks passed
@github-actions github-actions Bot added this to the .NET 10.0 SR8 milestone May 19, 2026
@pictos pictos deleted the pj/fix-device-test-memory branch May 19, 2026 17:31
@kubaflo kubaflo added the s/agent-gate-failed AI could not verify tests catch the bug label May 20, 2026
PureWeen pushed a commit that referenced this pull request Jun 2, 2026
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

<!-- Enter description of the fix in this section -->

Fix test so it will fail if a leak happens.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #35485

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

---------
PureWeen pushed a commit that referenced this pull request Jun 11, 2026
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

<!-- Enter description of the fix in this section -->

Fix test so it will fail if a leak happens.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #35485

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

---------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community ✨ Community Contribution s/agent-gate-failed AI could not verify tests catch the bug s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Memory leak Device.Test pass with false positive

8 participants