fix(compile): temporarily fallback to reading resource data from file on windows (#29024)

Temp hacky fix for https://github.com/denoland/deno/issues/28982
This commit is contained in:
David Sherret 2025-04-23 22:08:15 -04:00 committed by GitHub
parent 74425ddb0b
commit 3d16eb8ff3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 136 additions and 5 deletions

View file

@ -3,7 +3,11 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::OsString;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::io::ErrorKind;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
@ -58,11 +62,7 @@ pub struct StandaloneData {
pub fn extract_standalone(
cli_args: Cow<Vec<OsString>>,
) -> Result<StandaloneData, AnyError> {
let Some(data) = libsui::find_section("d3n0l4nd")
.context("Failed reading standalone binary section.")?
else {
bail!("Could not find standalone binary section.")
};
let data = find_section()?;
let root_path = {
let maybe_current_exe = std::env::current_exe().ok();
@ -117,6 +117,118 @@ pub fn extract_standalone(
})
}
fn find_section() -> Result<&'static [u8], AnyError> {
if std::env::var_os("DENO_INTERNAL_RT_USE_FILE_FALLBACK").is_some() {
return read_from_file_fallback();
}
match libsui::find_section("d3n0l4nd")
.context("Failed reading standalone binary section.")
{
Ok(Some(data)) => Ok(data),
Ok(None) => bail!("Could not find standalone binary section."),
Err(err) => {
if cfg!(windows) {
if let Ok(data) = read_from_file_fallback() {
return Ok(data);
}
}
Err(err)
}
}
}
/// This is a temporary hacky fallback until we can find
/// a fix for https://github.com/denoland/deno/issues/28982
fn read_from_file_fallback() -> Result<&'static [u8], AnyError> {
// search for DENOLAND in utf16
const MARKER: &[u8] = &[
0x44, 0x00, 0x33, 0x00, 0x4E, 0x00, 0x30, 0x00, 0x4C, 0x00, 0x34, 0x00,
0x4E, 0x00, 0x44, 0x00,
];
const ASCII_SENTINEL: &[u8] = b"d3n0l4nd";
let file_path = std::env::current_exe()?;
const BUF_CAP: usize = 64 * 1024;
let file = File::open(file_path)?;
let mut r = BufReader::with_capacity(BUF_CAP, file);
fn scan<R: Read>(
reader: &mut BufReader<R>,
needle: &[u8],
) -> std::io::Result<Option<Vec<u8>>> {
let mut overlap = Vec::<u8>::with_capacity(needle.len().saturating_sub(1));
let mut out = None;
loop {
let chunk = reader.fill_buf()?;
if chunk.is_empty() {
return Ok(out);
}
// search in overlap+chunk
let mut search_space = overlap.clone();
search_space.extend_from_slice(chunk);
if let Some(pos) =
search_space.windows(needle.len()).position(|w| w == needle)
{
// How far into `chunk` does the match **end**?
let bytes_before_chunk = overlap.len();
let match_end_in_chunk = pos + needle.len() - bytes_before_chunk;
// Consume up to the end of the needle
reader.consume(match_end_in_chunk);
// Everything *after* the match that is already in memory
let tail_in_mem = &search_space[pos..]; // begins with the needle
out = Some(tail_in_mem.to_vec());
break;
}
// Prepare next overlap (needle.len()-1 bytes)
overlap.clear();
let keep = needle.len().saturating_sub(1);
if search_space.len() >= keep {
overlap.extend_from_slice(&search_space[search_space.len() - keep..]);
} else {
overlap.extend_from_slice(&search_space);
}
let chunk_len = chunk.len(); // prevent multiple borrow
reader.consume(chunk_len);
}
Ok(out)
}
// skip up to and including MARKER
if scan(&mut r, MARKER)?.is_none() {
bail!("Failed to find.");
}
// collect from ASCII_SENTINEL onward
let mut result = scan(&mut r, ASCII_SENTINEL)?.ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"ASCII sentinel not found",
)
})?;
r.read_to_end(&mut result)?;
if let Some(last_pos) = result
.windows(ASCII_SENTINEL.len())
.rposition(|w| w == ASCII_SENTINEL)
{
result.truncate(last_pos + ASCII_SENTINEL.len());
} else {
bail!("Failed to find.");
}
Ok(Box::leak(result.into_boxed_slice()))
}
pub struct DeserializedDataSection {
pub metadata: Metadata,
pub npm_snapshot: Option<ValidSerializedNpmResolutionSnapshot>,

View file

@ -267,6 +267,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
// Phase 2 of the 'min sized' deno compile RFC talks
// about adding this as a flag.
if let Some(path) = get_dev_binary_path() {
log::debug!("Resolved denort: {}", path.to_string_lossy());
return std::fs::read(&path).with_context(|| {
format!("Could not find denort at '{}'", path.to_string_lossy())
});
@ -286,6 +287,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
let download_directory = self.deno_dir.dl_folder_path();
let binary_path = download_directory.join(&binary_path_suffix);
log::debug!("Resolved denort: {}", binary_path.display());
let read_file = |path: &Path| -> Result<Vec<u8>, AnyError> {
std::fs::read(path).with_context(|| format!("Reading {}", path.display()))

View file

@ -0,0 +1,16 @@
{
"envs": {
"DENO_INTERNAL_RT_USE_FILE_FALLBACK": "1"
},
"tempDir": true,
"steps": [{
"if": "windows",
"args": "compile --output bin main.ts",
"output": "[WILDCARD]"
}, {
"if": "windows",
"commandName": "./bin",
"args": [],
"output": "HI\n"
}]
}

View file

@ -0,0 +1 @@
console.log("HI");