Skip to content

ADD: native FTP listing, fuzzing, budgets and soak; FIX: dialogs on screen, screen reader names, a multi-volume RAR crash - #93

Merged
CodingDiego merged 2 commits into
masterfrom
FIX/windows-fit-icons-scale-and-accessibility
Nov 14, 2026
Merged

CodingDiego merged 2 commits into
masterfrom
FIX/windows-fit-icons-scale-and-accessibility

Conversation

@CodingDiego

Copy link
Copy Markdown
Owner

Two commits, kept apart by a rebase merge. Changes are under Unreleased in the changelog; the crate version stays 1.0.0-rc.2.

Commit 1: native FTP listing, fuzz targets, UI-thread timing, budgets, a one-hour soak

  • FTP (Compatibility: FTP verified or dropped #36). An ftp:// folder is listed by rexplorer itself. The shell's FTP folder only enumerates on a single-threaded apartment, so the listing runs on one, and everything it made there is released there before the list reaches the window (ShellFolder::park and rebind). The embedded Explorer view the handoff recommended was tried first: the server log showed no connection at all. connect::redact keeps the password out of titles, the address box, recents, the session file and error texts.
  • Fuzzing (Testing: Fuzzing #57). All seven targets link and run on MSVC; the workflow fails a target that never reports its runs, and fails when no target is listed.
  • UI-thread timing (Performance: UI-thread budget tooling #49). Every dispatched message is timed; a debug build logs each one over 50 ms with its message, window class and operation.
  • Budgets (Performance: Budgets in CI #48). scripts\budgets.ps1 gains reload churn and slowest-UI-message budgets; CI runs them on every PR.
  • Soak (Reliability: Soak test #29). The release soak is one hour, with a floor on the rounds done.
  • scripts\ftp-check.ps1 and scripts\ftp-server.py: twelve live checks against a local read-only FTP server.

Commit 2: display and accessibility fixes, review fixes, one crash

  • Text size and scale (Accessibility: Text scaling #24, Compatibility: Display scaling and multi-monitor #33). Folder options, Connect and the archive password prompt stay inside the work area and scroll when their content is larger (fit.rs). The palette shows the rows the screen has room for. Small list icons follow the window's scale after it changes. Tooltips follow the text size.
  • Screen readers and keyboard (Accessibility: UI Automation for every custom control #21, Accessibility: Full keyboard reach #22, Accessibility: High contrast #23). Folder options' check boxes and radio buttons are real buttons with a role and a state; its combo and edits have names. Toolbar menu buttons report collapsed. The palette's box has a name and recents read by name. A focused, unselected row shows an outline in every theme. About names the contrast theme. The README's keys table covers the tree, the palette and the dialogs.
  • Strings (Localization: Externalized strings #37). Two archive errors were English in every language; they come from the string table now.
  • Crash, with a vendored dependency. A multi-volume .rar could crash rexplorer now and then while it was listed or extracted. At each change of volume unrar-ng 0.7.7 copies 2048 characters from the pointer libunrar passes, which is a std::wstring only as long as the next volume's name; when the read leaves mapped memory the process dies in memcpy (stack from a traced test run: archive::list > RARProcessFileW > MergeArchive > DllVolNotify > Internal::callback > U16CString::from_ptr_truncate). 0.7.7 is the newest release, so the crate is built from vendor/unrar-ng through [patch.crates-io]: the published src/ with that one read changed to stop at the NUL (diff -r against the registry copy shows only that hunk; VENDORED.md has the details). The whole core test binary died with an access violation in 3 of 47 runs before and in 0 of 60 after. The fuzz workspace has the same patch.
  • Two reviews by a second reviewer (reports kept out of the repo): the test FTP server refuses every path outside its root and exits by itself; redact ends the authority where the shell does (/, ?, #), handles IPv6 hosts, backslash passwords and several addresses in one text; an error from the FTP worker carries only its code across threads; a message that began a loop of its own is timed up to that loop.

How it was tested

On the final tree, on a quiet machine (Windows 11, toolchain 1.99.1):

  • cargo build --release --locked --all-targets with -D warnings; cargo test --release --locked three times (app 278, core 257, data_ops 11, all green); cargo clippy --workspace --all-targets --locked -- -D warnings clean.
  • scripts\smoke.ps1 -Hosted: 32 PASS, 8 SKIP, 0 FAIL, with the new fit check (Folder options did not fit at 225 % and its OK button was reached by scrolling; Connect and the palette fit).
  • scripts\ftp-check.ps1: 12 of 12, six runs in a row.
  • scripts\budgets.ps1 with the CI values: start 334 ms, 100,000-file list 305 ms, idle CPU 0.0 %, churn 0.1 reloads/s, slowest UI-thread message 59 ms.
  • The whole core test binary 60 times after the RAR fix: no access violation in memcpy (3 in 47 runs before).
  • Display and accessibility, earlier the same day on this branch: a probe at a forced Text size of 225 % (Folder options, Connect and the palette inside the work area, OK reachable by scrolling) and an MSAA probe (check boxes and radio buttons with role and state, the combo named, menu buttons collapsed, the palette box named, a ::{GUID} recent shown by its name).
  • Two reviews of the diff by a second reviewer, security included, and a re-check of each fix.

Not done

  • No real Windows setting was changed for this PR: Text size 225 % was forced through REXPLORER_TEXT_SCALE, and the scale change by a unit test of the icon scaling. A re-test under the real settings, with Narrator, and under a contrast theme (the new check boxes there) is still to run.
  • On a screen where both dialogs fit at 225 %, the smoke fit check does not exercise scrolling; its line says which case ran.
  • Left from the reviews as notes: the palette resolves each recent place on the UI thread when it opens; Folder options paints a content-sized bitmap on every erase; a raw FTP password that is all digits up to a /, or one in ftp:user:pw@host without slashes, is shown.
  • FTP is read and copy-out only as tested; uploads, renames and deletes on a server were not tested.
  • One of those 60 runs died somewhere else: an access violation inside Windows' DUI70.dll while the menu, tree and undo tests (the ones that show shell UI) ran. It is the only such event in this machine's log for 30 days and is not traced yet.
  • Smoke look and sidebar-shell fail now and then on a loaded machine (a sidebar row not there within 5 s). The master build fails the same way under the same load, and both pass 24 of 24 on a quiet machine.

Issues

Related to #36, #49, #48, #84, #37, #22, #23 (each gets its verdict and is closed by hand after the merge), #57 and #29 (they wait for a green hosted "Fuzz and soak" run), #21, #24, #33 (a live re-test is left).

…hurn budgets, a one-hour soak

FTP: the shell's FTP folder lists nothing from the loader's multi-threaded
apartment, and the embedded Explorer view the tab fell back to showed a
blank page without ever contacting the server. An ftp:// load now runs on
a single-threaded apartment of its own, sorts there, releases its COM
objects there (ShellFolder::park) and hands the UI thread only item IDs,
which it binds again (rebind). A refused login or a silent server shows an
error naming the place. scripts\ftp-check.ps1 proves listing, a subfolder,
Up, a refused login, a copy out and password hygiene against
scripts\ftp-server.py.

Password redaction looks for the scheme anywhere in the text (after
blanks, quotes or invisible characters, inside an error message, with one
slash or two of either kind) and ends the password at the last @ of the
authority, so an @ in a folder name can never change the host of an
address that is shown, saved or opened again. The error text is redacted
too.

Fuzzing: the seven targets link and run on Windows MSVC with
--sanitizer none (fuzz/src/lib.rs supplies the coverage section bounds and
makes a panic leave its input); libfuzzer-sys is pinned.

Performance: every dispatched message and accelerator is timed; a debug
build logs each one over 50 ms with its message, window class and
operation, and every build keeps the slowest in a window property. A
message that ran a modal loop (a window move, a menu, a dialog, a drag) is
left out. budgets.ps1 checks churn reloads and the slowest UI-thread
message; CI passes -ChurnPerSec 1 -UiMs 1000.

Soak: the release soak is one hour with a floor on the operation count,
and the weekly workflow runs that hour.
…n readers, stop a multi-volume RAR crash

Display and accessibility bugs found by the live tests of 2026-11-13, the
fixes for the review of the previous commit, and one crash.

Display (#24, #33):
- Folder options, Connect and the archive password prompt stay inside the
  work area and scroll when their content is larger (new fit.rs).
- The palette shows only the rows the screen has room for.
- Small list icons follow the window's scale after it changes.
- Tooltips follow the text size; a Home tile is never wider than its pane.
- REXPLORER_TEXT_SCALE stands in for the Windows text size in tests; the
  smoke test has a fit check at 225 %.

Accessibility (#21, #22, #23):
- Folder options' check boxes and radio buttons are real buttons with a role
  and a state; its combo and edits have names.
- Toolbar menu buttons report collapsed; the palette box has a name and
  recents read by name, not by ::{GUID}; preview caption lines have places.
- A focused, unselected row shows an outline in every theme.
- About names the contrast theme.

Review of the FTP and tooling commit:
- The test FTP server refuses every path outside its root, does not reuse
  its address and exits by itself after ten minutes; the check kills its
  whole process tree, and its refused-login step uses another user name
  (with the same user the shell may answer from the connection it holds).
- redact finds the password by the authority's last @, in every address of
  a text, with IPv6 hosts and backslash passwords.
- An error from the FTP worker carries only its code across threads.
- A message that began a loop of its own is timed up to that loop.
- The soak workflow fails when no fuzz target is listed.

Crash: at each volume change of a multi-volume .rar, unrar-ng 0.7.7 copied
2048 characters from a string only as long as the next volume's name, and
now and then that read left mapped memory (stack: archive::list >
RARProcessFileW > MergeArchive > DllVolNotify > Internal::callback >
U16CString::from_ptr_truncate). The crate is built from vendor/unrar-ng
with that read fixed (it reads to the NUL). Whole core test binary: an
access violation in 3 of 47 runs before, 0 of 60 after.

Second review (of this commit): the redacted address ends its authority at
? and # as the shell does and reads each address once; the FTP check's
cleanup cannot throw; parts of a wheel notch add up in the scrolled dialogs.

Strings (#37): two archive errors come from the string table. Keys (#22):
the README covers the tree, the palette and the dialogs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request rust Pull requests that update rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant