Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,15 @@ jobs:
run: cargo run -p windows-platform-probes --bin probe-ioring --locked
- name: probe magnitudes (completion port)
run: cargo run -p windows-platform-probes --bin probe-completion-port --locked
# Both halves of the long-path pair, deliberately. Either alone says
# nothing: the finding is the *difference* between two executables that
# differ only in whether `build.rs` embedded the `longPathAware` manifest,
# so a run that reported one of them would be reporting a number with no
# baseline to read it against.
- name: probe magnitudes (long path, manifest-aware)
run: cargo run -p windows-platform-probes --bin probe-long-path-aware --locked
- name: probe magnitudes (long path, manifest-unaware)
run: cargo run -p windows-platform-probes --bin probe-long-path-unaware --locked

# The NUMA questions the 2026-08-30 design session could not answer, run
# against whatever machine the runner fleet supplies.
Expand Down
3 changes: 2 additions & 1 deletion CHECKLIST-mutation-survivors.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ to the engineer, not to whoever picks up this checklist.
tracked as `SH-13.4` on the branch that ships the topology and queue crates.
The sink has since landed here
([crates/windows-platform-probes/src/report.rs](crates/windows-platform-probes/src/report.rs))
and all eight probes in this repository route through it, so what remains of
and every probe in this repository routes through it -- stated without a count,
because the count moves as stages land -- so what remains of
`SH-13.4` is the six branch-only probes, and it stays named rather than linked
because that branch checklist is still not in this repository. The crate's own
durable work now has a home to link:
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/windows-platform-probes/CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ piece of work rather than a correction to that one.

- [ ] **M1.1** -- Decide how a formatted line reaches the sink, because that choice is what makes the
rest mechanical. Every renderer today writes through `let _ = writeln!(out, ...)` against a
`String`'s `fmt::Write` -- roughly 156 sites across the eight probes -- so the sink must accept
`String`'s `fmt::Write` -- upwards of 160 sites across the probes -- so the sink must accept
*formatted* output, not just `&str`, or every site grows a `format!` and an allocation per line.
The options differ in what they cost callers, and the choice is the engineer's:
(a) give `Report` a method taking `fmt::Arguments` plus a `report_line!` macro, so a call site stays
Expand All @@ -41,7 +41,7 @@ piece of work rather than a correction to that one.
(c) leave the renderers writing to a `String` and flush it to the sink at each line boundary, which
streams without touching the call sites but keeps two buffers.

- [ ] **M1.2** -- Convert the eight renderers to write into the sink as they measure, and simplify
- [ ] **M1.2** -- Convert every renderer to write into the sink as it measures, and simplify
`emit_report` accordingly: once lines leave as they are produced, catching the unwind is no longer
what makes partial output work, and the `catch_unwind`/`resume_unwind` pair should be removed rather
than left as machinery that no longer earns its place. Keep `Captured` working -- it is what every
Expand Down
28 changes: 28 additions & 0 deletions crates/windows-platform-probes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ path = "src/bin/ioring.rs"
name = "probe-pool-growth"
path = "src/bin/pool_growth.rs"

# These two are the same code, and that is the measurement: they differ only in
# whether `build.rs` embeds the `longPathAware` manifest, which is not a runtime
# switch and so cannot be a flag on one binary.
[[bin]]
name = "probe-long-path-aware"
path = "src/bin/long_path_aware.rs"

[[bin]]
name = "probe-long-path-unaware"
path = "src/bin/long_path_unaware.rs"

[dependencies]
# **Every workspace dependency below is path-only, with no `version`**, because
# this crate is never distributed at all -- not to a registry, and not as a
Expand All @@ -68,6 +79,19 @@ windows-threadpool-sys = { path = "../windows-threadpool-sys" }
# somewhere and compared against something it does not describe. That banner is
# `windows-placement-probe`'s to render, not a second copy here.
windows-placement-probe = { path = "../windows-placement-probe" }
# The long-path probe measures a length against `MAX_PATH`, and `MAX_PATH` counts
# UTF-16 code units. `OsStr::len` counts Rust's platform encoding -- WTF-8 here --
# so the two disagree the moment a non-ASCII character appears in `%TEMP%`, which
# would put an attempt on the wrong side of the ceiling the probe exists to
# characterize. This crate holds a string in the encoding Windows uses, so its
# `len` is the number under test rather than a conversion of one.
#
# That is the whole of what it is used for here: a code-unit count, at every site
# where a length is compared against a Windows limit.
# `encode_wide().count()` would give the same number, and the choice of this crate
# over that is a vocabulary one -- the workspace's own WTF-16 type naming the
# quantity rather than an ad-hoc count that happens to agree.
wtf-string = { path = "../wtf-string" }

[dependencies.windows-sys]
version = "0.61.2"
Expand All @@ -76,6 +100,10 @@ features = [
"Win32_Foundation",
"Win32_Security",
"Win32_Storage_FileSystem",
# SetCurrentDirectoryW, for the long-path probe: the current directory is
# half of what a relative path resolves against, so the probe has to place
# it deliberately rather than inherit whatever launched it.
"Win32_System_Environment",
"Win32_System_Diagnostics_Debug",
"Win32_System_IO",
"Win32_System_Pipes",
Expand Down
69 changes: 69 additions & 0 deletions crates/windows-platform-probes/DESIGN-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,3 +498,72 @@ that introduced the sink.
The ordering was deliberate. The sink had to exist before the probes could be
peeled off their originating branch in reviewable stages, and a design that
streams is a different design, not a later revision of this one.

## The long-path probe: a pair of binaries, and a second declined hardening

<a id="d-long-path"></a>

The `longPathAware` opt-in has two halves and neither is a runtime switch: a
machine-wide registry value, and a per-executable manifest. Nothing a process can
read off itself tells it whether the manifest half applies, so the question
"does the opt-in lift `MAX_PATH` for a relative path?" cannot be answered by one
binary with a flag. It is answered by two binaries that differ *only* in the
manifest, and the finding is the difference between their reports.

`build.rs` embeds the manifest with `rustc-link-arg-bin` naming
`probe-long-path-aware` specifically, never `rustc-link-arg-bins`: the plural
form would opt every binary in the crate into long paths and silently change what
all the others measure. The aware binary does not assert its own manifest either;
it reads a `cargo::rustc-cfg` the build script emits from the same guarded block
that does the embedding, so the label and the linker cannot disagree. Before that,
a non-MSVC target skipped the block and produced two binaries with no manifest
between them, one of which still reported `manifest longPathAware : yes` -- the
one failure this probe cannot make loudly, because the whole finding is the
difference between the pair.

### `measure` moves the process's current directory, and that is the point

<a id="d-long-path-cwd"></a>

A relative path resolves against the current directory, so half of what is under
test is *where the process is*. The probe therefore sets the current directory
deliberately rather than inheriting whatever launched it, restores it in a `Drop`
guard, and removes the tree it built.

This is the same tension the error-mode probe records in
[The concurrency hardening is knowingly declined](#the-concurrency-hardening-is-knowingly-declined):
a probe may change process-wide state, a component may not. As there, **the
concurrency hardening is knowingly declined.** `measure` is not safe to call
concurrently, and its rustdoc says so. Giving each call a unique root would not
fix it, because the current directory is per-process rather than per-call: two
concurrent runs would still fight over the one thing being measured. The
serialization lives in the tests, which take a mutex, and the binaries are
single-threaded and call `measure` once.

The declined alternative is worth naming so it is not re-proposed: threading the
directory through as an explicit parameter and never calling
`SetCurrentDirectoryW` would make the function safe, and would also stop it
measuring the thing it exists to measure -- a *relative* path's resolution, which
is defined against the process's current directory and nothing else.

### The ceiling is applied to the path as written

<a id="d-long-path-literal"></a>

`MAX_PATH` is compared against the literal path handed to the call, before `..`
is collapsed. That matters here because the `..` shape's literal is five units
longer than its canonical form, so the two readings disagree in a five-unit band
-- and the probe classifies every row on that number.

Measured rather than assumed, using this crate's own un-manifested binary with
the deep level forced to 21: plain resolved to 258 and **opened**, `..` resolved
to 263 and was **refused**, against a content ceiling of 259. Had the collapse
come first, both would have been 258 and both would have opened.

The obvious shortcut does not settle this and should not be used. Reaching for
`cmd.exe` measures `cmd`'s manifest, not the un-opted-in case: on the development
host -- Windows 11 build 26200, `cmd.exe` 10.0.26100.1 -- `cmd` carries
`longPathAware` in its own manifest beside `dpiAware`, so a long path that opens
there says nothing about the ceiling. That is a fact about that binary on that
build rather than about `cmd` for all time, which is exactly why the probe rests
on a binary this workspace builds and manifests itself.
50 changes: 50 additions & 0 deletions crates/windows-platform-probes/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Mike Grier.

//! Embeds `longPathAware` into **one** binary, so the long-path opt-in can be
//! measured rather than read about.
//!
//! The opt-in has two halves and neither is a runtime switch: a machine-wide
//! registry value, and a per-executable manifest. The manifest half is what
//! this adds, and it is added to `probe-long-path-aware` **alone** --
//! `probe-long-path-unaware` is the same code without it, because a comparison
//! needs both sides and the un-opted-in case is what most consumers of this
//! workspace actually have.
//!
//! `rustc-link-arg-bin` rather than `rustc-link-arg-bins`: the latter would
//! opt every probe in this crate into long paths, silently changing what all
//! the others measure -- stated without a count on purpose, so it stays true as
//! probes are added.

fn main() {
// Declared unconditionally, because the cfg's *absence* is as meaningful as
// its presence and an undeclared name would warn under `unexpected_cfgs`.
println!("cargo::rustc-check-cfg=cfg(long_path_manifest_embedded)");

// Only the MSVC linker understands these, and this crate is Windows-only
// anyway; guarding keeps a cross-compile from failing on a flag its linker
// has never heard of.
if std::env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc") {
let manifest =
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("long-path-aware.manifest");
println!("cargo::rerun-if-changed=long-path-aware.manifest");
println!("cargo::rustc-link-arg-bin=probe-long-path-aware=/MANIFEST:EMBED");
println!(
"cargo::rustc-link-arg-bin=probe-long-path-aware=/MANIFESTINPUT:{}",
manifest.display()
);
Comment thread
MikeGrier marked this conversation as resolved.

// The aware binary reads this rather than claiming the opt-in outright,
// so its report cannot say `manifest longPathAware : yes` for an
// executable this script did not manifest.
//
// That mattered: with the claim hardcoded, a non-MSVC target skipped the
// block above and produced two binaries with *no* manifest between them,
// one of which still announced it had one. Both halves then measured the
// un-opted-in case and a reader comparing them would conclude the opt-in
// does not work -- a wrong answer, silently, in the one place this probe
// cannot fail loudly instead, because the whole finding is the difference
// between the two. Emitting the flag from the same branch that does the
// embedding is what keeps the label and the linker in step.
println!("cargo::rustc-cfg=long_path_manifest_embedded");
}
}
9 changes: 9 additions & 0 deletions crates/windows-platform-probes/long-path-aware.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="probe-long-path-aware" version="1.0.0.0"/>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</windowsSettings>
</application>
</assembly>
32 changes: 32 additions & 0 deletions crates/windows-platform-probes/src/bin/long_path_aware.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) Mike Grier.

//! Measures the long-path opt-in **with** `longPathAware` in the manifest.
//!
//! **An experiment, not a component.** These probes measure platform behaviour
//! and are not for production use. See this crate's DESIGN-NOTES.md.
//!
//! Its twin, `probe-long-path-unaware`, is the same code without the manifest.
//! Run both: one row of results proves nothing, because the difference between
//! them is the whole measurement.

use windows_platform_probes::long_path_report;
use windows_platform_probes::report::emit_report;

fn main() {
// The probe's whole output policy, and it is one line: hand the renderer to
// the sink. Nothing here or below names a stream -- that is chosen once, in
// `report`, so retargeting a probe is not a rewrite.
//
// The manifest is this binary's whole difference from its twin, and it is a
// claim about the build rather than something measured at runtime: the two
// halves of the opt-in are a machine-wide registry value and a per-executable
// manifest, neither of which is a switch a process can read off itself.
//
// So the claim is *derived* from the flag `build.rs` sets in the same branch
// that embeds the manifest, never hardcoded. Hardcoding `true` here would let
// a target whose linker the script skips -- anything non-MSVC -- report
// `manifest longPathAware : yes` for an executable carrying no manifest,
// while both halves quietly measured the same un-opted-in case.
let manifest_aware = cfg!(long_path_manifest_embedded);
emit_report(|out| long_path_report::render(out, manifest_aware));
}
25 changes: 25 additions & 0 deletions crates/windows-platform-probes/src/bin/long_path_unaware.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Mike Grier.

//! Measures the long-path opt-in **without** `longPathAware` in the manifest.
//!
//! **An experiment, not a component.** These probes measure platform behaviour
//! and are not for production use. See this crate's DESIGN-NOTES.md.
//!
//! This is the case most consumers of this workspace actually have, which is
//! why it is measured rather than assumed: a library cannot add a manifest to
//! someone else's executable, so whatever this reports is what a caller who has
//! not opted in will meet.

use windows_platform_probes::long_path_report;
use windows_platform_probes::report::emit_report;

fn main() {
// The probe's whole output policy, and it is one line: hand the renderer to
// the sink. Nothing here or below names a stream -- that is chosen once, in
// `report`, so retargeting a probe is not a rewrite.
//
// `false` is this binary's whole difference from its twin: `build.rs`
// embeds the manifest into `probe-long-path-aware` alone, so this one is
// the same code compiled without the opt-in.
emit_report(|out| long_path_report::render(out, false));
}
3 changes: 3 additions & 0 deletions crates/windows-platform-probes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
//! | [`completion_port::measure`] | ignored | IOCP association, and `CreateThreadpoolIo`, foreclose `IoRing` use of a handle |
//! | [`cancel_io::cancel_against_idle_thread`] | binary only | `CancelSynchronousIo` is point-in-time against an idle thread |
//! | [`cancel_io::cancel_against_busy_thread`] | binary only | it can block indefinitely against a thread re-entering synchronous I/O |
//! | [`long_path::measure`] | binary only | whether the `longPathAware` manifest opt-in lifts `MAX_PATH` for a *relative* path -- binary only because the answer is the difference between two differently-manifested executables, which no single in-process test can observe |

#![cfg(windows)]
#![forbid(unsafe_op_in_unsafe_fn)]
Expand All @@ -115,6 +116,8 @@ pub mod device_map;
pub mod error_mode;
pub mod handle_state;
pub mod ioring;
pub mod long_path;
pub mod long_path_report;
pub mod pool_growth;
pub mod report;
pub mod worker_context;
Expand Down
Loading