Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d08aaca
Publish: develop bdc4a54 to release
github-actions[bot] Nov 9, 2026
2d7992e
Publish: develop 6a189ed to release
github-actions[bot] Nov 9, 2026
9cd95b9
Publish: develop 85d41b8 to release
github-actions[bot] Nov 9, 2026
5e45d5c
Publish: develop bd78ac4 to release
github-actions[bot] Nov 9, 2026
2cf8ecf
Publish: develop 114c4c2 to release
github-actions[bot] Nov 9, 2026
32a8eaf
Publish: develop a1b6326 to release
github-actions[bot] Nov 9, 2026
d4a0c91
Publish: develop e4eb0cb to release
github-actions[bot] Nov 9, 2026
57a4a80
Publish: develop 5526572 to release
github-actions[bot] Nov 9, 2026
afba09d
Publish: develop 25e4d5f to release
github-actions[bot] Nov 9, 2026
9e780b5
Publish: develop de06c4a to release
github-actions[bot] Nov 9, 2026
2db10bb
Publish: develop 5b2abea to release
github-actions[bot] Nov 9, 2026
c375d55
Publish: develop 89082e9 to release
github-actions[bot] Nov 9, 2026
6ed6270
Publish: develop 95d03ce to release
github-actions[bot] Nov 9, 2026
94d2933
Publish: develop 513cb2b to release
github-actions[bot] Nov 9, 2026
772cae5
Publish: develop 2accf71 to release
github-actions[bot] Nov 9, 2026
bafdea5
Publish: develop ed28982 to release
github-actions[bot] Nov 9, 2026
683a4d2
Publish: develop 29afff0 to release
github-actions[bot] Nov 9, 2026
b18b6ca
Publish: develop fd0146a to release
github-actions[bot] Nov 9, 2026
47cf18e
Publish: develop 6723f90 to release
github-actions[bot] Nov 9, 2026
d4280aa
Publish: develop 2b28c97 to release
github-actions[bot] Nov 9, 2026
518c24d
Publish: develop 87dffd9 to release
github-actions[bot] Nov 9, 2026
76f97cf
Publish: develop ee81d92 to release
github-actions[bot] Nov 9, 2026
93668dc
Publish: develop 7af17d7 to release
github-actions[bot] Nov 9, 2026
94c6537
Publish: develop 1422917 to release
github-actions[bot] Nov 10, 2026
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
7 changes: 7 additions & 0 deletions rivet/installer/windows/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ Copy-Item (Join-Path $installer "setup-ui\assets\logo.ico") (Join-Path $stage "r
Copy-Item (Join-Path $repository "LICENSE") (Join-Path $stage "LICENSE")
Copy-Item (Join-Path $rivet "runtime\windows\fonts\OFL-*.txt") $stage

# A binary built for the feature tests starts browsers with sync and sign-in off. It never ships.
. (Join-Path $installer "test-flags.ps1")
$tainted = @(Get-TestFlagBinaries @(Get-ChildItem $stage -Recurse -File | Where-Object { $_.Extension -in '.exe', '.dll' } | ForEach-Object FullName))
if ($tainted.Count -gt 0) {
throw "built with the feature tests' browser switches, which turn sync and sign-in off: $($tainted -join ', '). Build again without them."
}

# Authenticode: with RIVET_CODE_SIGN_CERT (a certificate thumbprint in the build account's store),
# every program file, the package and setup.exe are signed, so Windows can tell a changed file.
# RIVET_TIMESTAMP_URL is the RFC 3161 timestamp service of the certificate's issuer. The timestamp
Expand Down
12 changes: 12 additions & 0 deletions rivet/installer/windows/test-flags.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# The feature tests build Rivet with browser switches that turn sync and sign-in off. A package made
# from such a build would start a person's browser without sync, so build.ps1 refuses it. These are
# the switches only that test build adds; the browser start a person gets never carries them.
$script:TestOnlySwitches = @('--disable-sync', 'msImplicitSignin,msEdgeSignIn,CalculateNativeWinOcclusion')

# The files among `$Files` that carry a test-only browser switch.
function Get-TestFlagBinaries([string[]]$Files) {
foreach ($file in $Files) {
$text = [Text.Encoding]::ASCII.GetString([IO.File]::ReadAllBytes($file))
if (@($script:TestOnlySwitches | Where-Object { $text.Contains($_) }).Count -gt 0) { $file }
}
}
8 changes: 7 additions & 1 deletion rivet/platform/windows/src/bin/chrome-builds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,12 @@ fn port(
let wanted = row_port::wanted_names(&named);
drop(old);
let mut new = std::collections::HashMap::<String, Vec<u32>>::new();
// `views::View::ConvertPointToScreen` is found by its own name, for a prior row without it.
let mut screen_origin = Vec::new();
symbols::publics(new_pdb, &mut |address, name| {
if row_port::is_screen_origin_name(name) {
screen_origin.push(address);
}
let name = row_port::stable_name(name);
if wanted.contains(name) {
new.entry(name.to_owned()).or_default().push(address);
Expand All @@ -178,7 +183,7 @@ fn port(
},
)
.collect();
let (row, mut report) = row_port::port_row(
let (mut row, mut report) = row_port::port_row(
&prior,
&named,
&NewBuild {
Expand All @@ -188,6 +193,7 @@ fn port(
private: &private,
},
);
row_port::seed_screen_origin(&mut row, &screen_origin, &pe, &mut report);
report.review.extend(row_port::hand_only_review(&prior));
let text = |value: &dyn erased::Json| value.pretty();
std::fs::write(row_path, text(&row)).map_err(|error| error.to_string())?;
Expand Down
95 changes: 95 additions & 0 deletions rivet/platform/windows/src/row_port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ pub struct PortReport {
pub derived: Vec<String>,
/// Values that are not addresses and have no recipe, so they were carried over.
pub carried: Vec<String>,
/// Optional parts the new build could not supply. The runtime does without them.
pub left_out: Vec<String>,
}

fn is_address(value: u64) -> bool {
Expand Down Expand Up @@ -1348,6 +1350,61 @@ fn check_frame_slot(frame: &mut Value, pe: &PeFile, report: &mut PortReport) {
}
}

/// The start of the public name of `views::View::ConvertPointToScreen(const View*, gfx::Point*)`:
/// a static function returning nothing. The other overload returns the point and is named `SA?AV`.
pub const SCREEN_ORIGIN_NAME: &str = "?ConvertPointToScreen@View@views@@SAX";

/// How many bytes of that function's start the runtime compares before it ever calls it.
const SCREEN_ORIGIN_BYTES: usize = 12;

/// Whether a public name is the one `screen_origin` is found by.
pub fn is_screen_origin_name(name: &str) -> bool {
stable_name(name).starts_with(SCREEN_ORIGIN_NAME)
}

/// The first whole instructions of a function, at least `SCREEN_ORIGIN_BYTES` long.
fn function_start(pe: &PeFile, address: u32) -> Option<Vec<u8>> {
if !pe.is_code(address) {
return None;
}
let window = pe.read(address, 32)?;
let (ends, _) = x64::boundaries(window, SCREEN_ORIGIN_BYTES);
let end = *ends.iter().find(|end| **end >= SCREEN_ORIGIN_BYTES)?;
Some(window[..end].to_vec())
}

/// Adds `screen_origin`, `[address, first bytes]` of `views::View::ConvertPointToScreen`, to a row
/// whose prior row had none, by the function's public name in the new build. A prior row that had
/// it was ported with every other address. A build with no single place for the name goes without
/// it, and the runtime keeps placing bubbles from the window's monitor, so the row is not stopped.
pub fn seed_screen_origin(row: &mut Value, places: &[u32], pe: &PeFile, report: &mut PortReport) {
if row["build"]["screen_origin"].is_array() {
return;
}
let mut places = places.to_vec();
places.sort_unstable();
places.dedup();
let found = match places.as_slice() {
[only] => function_start(pe, *only).map(|bytes| (*only, bytes)),
_ => None,
};
match found {
Some((address, bytes)) => {
row["build"]["screen_origin"] =
json!([write_address(u64::from(address)), hex_text(&bytes)]);
report.derived.push(format!(
"build.screen_origin: {SCREEN_ORIGIN_NAME} at {address:#x}"
));
}
None => {
row["build"]["screen_origin"] = Value::Null;
report.left_out.push(format!(
"build.screen_origin: no single readable function named {SCREEN_ORIGIN_NAME}: {places:x?}"
));
}
}
}

/// The review items for the parts of the prior row that only a person writes today. A row made
/// without them opens Rivet's frame with those features off, so it goes to a person instead of
/// the table. The runtime names them in the prior row's `hand_only` list.
Expand Down Expand Up @@ -1489,6 +1546,44 @@ mod tests {
.collect()
}

#[test]
fn nfr3_screen_origin_is_found_by_its_public_name_in_the_new_build() {
// push rsi; push rdi; sub rsp, 0x28; mov rsi, rdx; mov rdi, rcx; call.
let start = hex("56574883ec284889d64889cfe800000000").unwrap();
let bytes = module(&[(0x101400, start.as_slice())]);
let pe = PeFile::parse(&bytes).unwrap();
let mut row = prior();
let mut report = PortReport::default();
seed_screen_origin(&mut row, &[0x101400, 0x101400], &pe, &mut report);
assert_eq!(
row["build"]["screen_origin"],
json!(["0x101400", "56574883ec284889d64889cf"])
);
assert!(report.review.is_empty() && report.left_out.is_empty());
// A row that already has it keeps the place the port gave it.
seed_screen_origin(&mut row, &[0x101500], &pe, &mut report);
assert_eq!(row["build"]["screen_origin"][0], "0x101400");
// No name, or two places for it, leaves the part out without stopping the row.
for places in [&[][..], &[0x101400, 0x101500][..]] {
let mut row = prior();
let mut report = PortReport::default();
seed_screen_origin(&mut row, places, &pe, &mut report);
assert!(row["build"]["screen_origin"].is_null());
assert_eq!(report.left_out.len(), 1);
assert!(report.review.is_empty());
}
// Only the in-place overload, which returns nothing, is the one.
assert!(is_screen_origin_name(
"?ConvertPointToScreen@View@views@@SAXPEBV12@PEAVPoint@gfx@@@Z"
));
assert!(!is_screen_origin_name(
"?ConvertPointToScreen@View@views@@SA?AVPoint@gfx@@PEBV12@AEBV34@@Z"
));
assert!(!is_screen_origin_name(
"?ConvertRectToScreen@View@views@@SAXPEBV12@PEAVRect@gfx@@@Z"
));
}

#[test]
fn nfr3_a_new_row_takes_addresses_by_name_and_bytes_from_the_new_module() {
let code = new_code();
Expand Down
1 change: 1 addition & 0 deletions rivet/platform/windows/src/row_watch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ pub const FEATURES: &[&str] = &[
"split-grid-3",
"split-grid-4",
"bar-layout",
"bar-folded",
"mini-pop-out",
"mini-move",
"mini-return",
Expand Down
Loading