diff --git a/changelog.d/8239-windows-static-literal-identity.md b/changelog.d/8239-windows-static-literal-identity.md new file mode 100644 index 0000000000..1024f19ef2 --- /dev/null +++ b/changelog.d/8239-windows-static-literal-identity.md @@ -0,0 +1,16 @@ +`windows-build` is green again, restoring the whole `test.yml` run that +`release-packages`' `await-tests` requires before it will cut a tag. + +Two tests from #8177 failed on Windows and only there, asserting that a bound +method's closure captures the `'static` method-name literal by comparing +pointers. Both failing pairs differed by the same constant offset (0x161F90) — +two copies of the same read-only data, not a heap pointer. ELF +(`SHF_MERGE|SHF_STRINGS`) and Mach-O (`__TEXT,__cstring`) merge identical +read-only strings, so the copy the closure captures and the copy the lookup +returns land at one address; MSVC does not pool identical literals across +codegen units, so they stay distinct. Both are `'static`. + +The address comparison is now gated on a linker that merges. The property the +test exists for — the captured name must not be the movable key string's +interior — is asserted unconditionally, as are the captured length and bytes, so +Windows keeps the coverage and loses only the proxy it cannot evaluate. diff --git a/crates/perry-runtime/src/gc/tests/handle_bound_method_name.rs b/crates/perry-runtime/src/gc/tests/handle_bound_method_name.rs index e2684883c0..7330644102 100644 --- a/crates/perry-runtime/src/gc/tests/handle_bound_method_name.rs +++ b/crates/perry-runtime/src/gc/tests/handle_bound_method_name.rs @@ -84,6 +84,20 @@ unsafe fn assert_names_the_literal( what: &str, ) { let (name_ptr, name_len) = captured_name(bound); + // Pointer identity is only assertable where the linker merges identical + // read-only strings. ELF (`SHF_MERGE|SHF_STRINGS`) and Mach-O + // (`__TEXT,__cstring`) do; MSVC does not pool identical literals across + // codegen units, so the copy the closure captures and the copy the lookup + // returns can be two distinct `&'static [u8]` at different addresses. + // Measured on the Windows runner: both failing pairs differed by the SAME + // constant offset (0x161F90), i.e. two whole copies of the same read-only + // data, not a heap pointer. + // + // Both are `'static`, which is the property this test exists for: the name + // must not be the MOVABLE key string's interior. That invariant is asserted + // unconditionally below, together with the length and the bytes, so Windows + // keeps real coverage — it just cannot use address equality as the proxy. + #[cfg(not(windows))] assert_eq!( name_ptr, expected.as_ptr(),