Skip to content

Commit 884faeb

Browse files
fix(sourcemaps): Avoid associating only sourcemap with all minified sources
Remove the branch from `guess_sourcemap_reference` which handles the case of there only being one sourcemap. If there are multiple minified souces, they would all (erroneously) end up associated with the same single sourcemap. Also, since code for uploading bundles was relying on this branch (specifically when unpacking bundles), refactor so that we use the sourcemap which is passed to the command directly, rather thna "guessing" it. Fixes #2438 Fixes #2503
1 parent c30b264 commit 884faeb

File tree

6 files changed

+134
-152
lines changed

6 files changed

+134
-152
lines changed

src/commands/react_native/gradle.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::config::Config;
1212
use crate::constants::DEFAULT_MAX_WAIT;
1313
use crate::utils::args::{validate_distribution, ArgExt};
1414
use crate::utils::file_search::ReleaseFileSearch;
15-
use crate::utils::file_upload::UploadContext;
15+
use crate::utils::file_upload::{SourceFile, UploadContext};
1616
use crate::utils::sourcemaps::SourceMapProcessor;
1717

1818
pub fn make_command(command: Command) -> Command {
@@ -92,16 +92,16 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
9292
&bundle_url,
9393
ReleaseFileSearch::collect_file(bundle_path.clone())?,
9494
);
95-
processor.add(
96-
&sourcemap_url,
97-
ReleaseFileSearch::collect_file(sourcemap_path)?,
98-
);
95+
96+
let sourcemap_match = ReleaseFileSearch::collect_file(sourcemap_path.clone())?;
9997

10098
if let Ok(ram_bundle) = RamBundle::parse_unbundle_from_path(&bundle_path) {
10199
debug!("File RAM bundle found, extracting its contents...");
102-
processor.unpack_ram_bundle(&ram_bundle, &bundle_url)?;
100+
let sourcemap_source = SourceFile::from_release_file_match(&sourcemap_url, sourcemap_match);
101+
processor.unpack_ram_bundle(&ram_bundle, &bundle_url, &sourcemap_source)?;
103102
} else {
104103
debug!("Non-file bundle found");
104+
processor.add(&sourcemap_url, sourcemap_match);
105105
}
106106

107107
processor.rewrite(&[base.to_str().unwrap()])?;

src/commands/sourcemaps/upload.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::config::Config;
1313
use crate::constants::DEFAULT_MAX_WAIT;
1414
use crate::utils::args::validate_distribution;
1515
use crate::utils::file_search::ReleaseFileSearch;
16-
use crate::utils::file_upload::UploadContext;
16+
use crate::utils::file_upload::{SourceFile, UploadContext};
1717
use crate::utils::fs::path_as_url;
1818
use crate::utils::sourcemaps::SourceMapProcessor;
1919

@@ -303,21 +303,23 @@ fn process_sources_from_bundle(
303303
&bundle_url,
304304
ReleaseFileSearch::collect_file(bundle_path.clone())?,
305305
);
306-
processor.add(
307-
&sourcemap_url,
308-
ReleaseFileSearch::collect_file(sourcemap_path)?,
309-
);
306+
let sourcemap_match = ReleaseFileSearch::collect_file(sourcemap_path)?;
310307

311308
if let Ok(ram_bundle) = sourcemap::ram_bundle::RamBundle::parse_unbundle_from_path(&bundle_path)
312309
{
313310
debug!("File RAM bundle found, extracting its contents...");
314311
// For file ("unbundle") RAM bundles we need to explicitly unpack it, otherwise we cannot detect it
315312
// reliably inside "processor.rewrite()"
316-
processor.unpack_ram_bundle(&ram_bundle, &bundle_url)?;
313+
314+
let sourcemap_source = SourceFile::from_release_file_match(&sourcemap_url, sourcemap_match);
315+
processor.unpack_ram_bundle(&ram_bundle, &bundle_url, &sourcemap_source)?;
317316
} else if sourcemap::ram_bundle::RamBundle::parse_indexed_from_path(&bundle_path).is_ok() {
318317
debug!("Indexed RAM bundle found");
318+
let sourcemap_source = SourceFile::from_release_file_match(&sourcemap_url, sourcemap_match);
319+
processor.unpack_indexed_ram_bundles(&sourcemap_source)?;
319320
} else {
320321
warn!("Regular bundle found");
322+
processor.add(&sourcemap_url, sourcemap_match);
321323
}
322324

323325
let mut prefixes = get_prefixes_from_args(matches);

src/utils/file_upload.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Searches, processes and uploads release files.
22
use std::collections::{BTreeMap, HashMap};
3+
use std::ffi::OsStr;
34
use std::fmt::{self, Display};
45
use std::io::BufWriter;
56
use std::path::PathBuf;
@@ -16,6 +17,7 @@ use rayon::ThreadPoolBuilder;
1617
use sentry::types::DebugId;
1718
use sha1_smol::Digest;
1819
use symbolic::common::ByteView;
20+
use symbolic::debuginfo::js;
1921
use symbolic::debuginfo::sourcebundle::{
2022
SourceBundleErrorKind, SourceBundleWriter, SourceFileInfo, SourceFileType,
2123
};
@@ -29,6 +31,8 @@ use crate::utils::chunks::{upload_chunks, Chunk, ASSEMBLE_POLL_INTERVAL};
2931
use crate::utils::fs::{get_sha1_checksum, get_sha1_checksums, TempFile};
3032
use crate::utils::progress::{ProgressBar, ProgressBarMode, ProgressStyle};
3133

34+
use super::file_search::ReleaseFileMatch;
35+
3236
/// Fallback concurrency for release file uploads.
3337
static DEFAULT_CONCURRENCY: usize = 4;
3438

@@ -239,6 +243,68 @@ pub struct SourceFile {
239243
}
240244

241245
impl SourceFile {
246+
pub fn from_release_file_match(url: &str, mut file: ReleaseFileMatch) -> SourceFile {
247+
let (ty, debug_id) = if sourcemap::is_sourcemap_slice(&file.contents) {
248+
(
249+
SourceFileType::SourceMap,
250+
std::str::from_utf8(&file.contents)
251+
.ok()
252+
.and_then(js::discover_sourcemap_embedded_debug_id),
253+
)
254+
} else if file
255+
.path
256+
.file_name()
257+
.and_then(OsStr::to_str)
258+
.map(|x| x.ends_with("bundle"))
259+
.unwrap_or(false)
260+
&& sourcemap::ram_bundle::is_ram_bundle_slice(&file.contents)
261+
{
262+
(SourceFileType::IndexedRamBundle, None)
263+
} else if is_hermes_bytecode(&file.contents) {
264+
// This is actually a big hack:
265+
// For the react-native Hermes case, we skip uploading the bytecode bundle,
266+
// and rather flag it as an empty "minified source". That way, it
267+
// will get a SourceMap reference, and the server side processor
268+
// should deal with it accordingly.
269+
file.contents.clear();
270+
(SourceFileType::MinifiedSource, None)
271+
} else {
272+
// Here, we use MinifiedSource for historical reasons. We used to guess whether
273+
// a JS file was a minified file or a source file, and we would treat these files
274+
// differently when uploading or injecting them. However, the desired behavior is
275+
// and has always been to treat all JS files the same, since users should be
276+
// responsible for providing the file paths for only files they would like to have
277+
// uploaded or injected. The minified file guessing furthermore was not reliable,
278+
// since minification is not a necessary step in the JS build process.
279+
//
280+
// We use MinifiedSource here rather than Source because we want to treat all JS
281+
// files the way we used to treat minified files only. To use Source, we would need
282+
// to analyze all possible code paths that check this value, and update those as
283+
// well. To keep the change minimal, we use MinifiedSource here.
284+
(
285+
SourceFileType::MinifiedSource,
286+
std::str::from_utf8(&file.contents)
287+
.ok()
288+
.and_then(js::discover_debug_id),
289+
)
290+
};
291+
292+
let mut source_file = SourceFile {
293+
url: url.into(),
294+
path: file.path,
295+
contents: file.contents.into(),
296+
ty,
297+
headers: BTreeMap::new(),
298+
messages: vec![],
299+
already_uploaded: false,
300+
};
301+
302+
if let Some(debug_id) = debug_id {
303+
source_file.set_debug_id(debug_id.to_string());
304+
}
305+
source_file
306+
}
307+
242308
/// Calculates and returns the SHA1 checksum of the file.
243309
pub fn checksum(&self) -> Result<Digest> {
244310
get_sha1_checksum(&**self.contents)
@@ -753,6 +819,13 @@ fn print_upload_context_details(context: &UploadContext) {
753819
);
754820
}
755821

822+
fn is_hermes_bytecode(slice: &[u8]) -> bool {
823+
// The hermes bytecode format magic is defined here:
824+
// https://github.com/facebook/hermes/blob/5243222ef1d92b7393d00599fc5cff01d189a88a/include/hermes/BCGen/HBC/BytecodeFileFormat.h#L24-L25
825+
const HERMES_MAGIC: [u8; 8] = [0xC6, 0x1F, 0xBC, 0x03, 0xC1, 0x03, 0x19, 0x1F];
826+
slice.starts_with(&HERMES_MAGIC)
827+
}
828+
756829
#[cfg(test)]
757830
mod tests {
758831
use sha1_smol::Sha1;

0 commit comments

Comments
 (0)