diff --git a/crates/symbolicator-proguard/src/interface.rs b/crates/symbolicator-proguard/src/interface.rs index 28945dfa9..d51e292fb 100644 --- a/crates/symbolicator-proguard/src/interface.rs +++ b/crates/symbolicator-proguard/src/interface.rs @@ -165,8 +165,6 @@ pub enum ProguardErrorKind { Missing, /// The file is invalid according to [`is_valid`](proguard::ProguardMapping::is_valid). Invalid, - /// The file doesn't contain line mapping information. - NoLineInfo, } impl fmt::Display for ProguardErrorKind { @@ -174,9 +172,6 @@ impl fmt::Display for ProguardErrorKind { match self { ProguardErrorKind::Missing => write!(f, "The proguard mapping file is missing."), ProguardErrorKind::Invalid => write!(f, "The proguard mapping file is invalid."), - ProguardErrorKind::NoLineInfo => { - write!(f, "The proguard mapping file does not contain line info.") - } } } } diff --git a/crates/symbolicator-proguard/src/service.rs b/crates/symbolicator-proguard/src/service.rs index 5fc4bbe01..d820352c9 100644 --- a/crates/symbolicator-proguard/src/service.rs +++ b/crates/symbolicator-proguard/src/service.rs @@ -176,10 +176,6 @@ impl CacheItemRequest for FetchProguard { Err(CacheError::Malformed( "The file is not a valid ProGuard file".into(), )) - } else if !mapping.has_line_info() { - Err(CacheError::Malformed( - "The ProGuard file doesn't contain any line mappings".into(), - )) } else { let cache_temp_file = tempfile_in_parent(temp_file)?; let mut writer = BufWriter::new(cache_temp_file); diff --git a/crates/symbolicator-proguard/src/symbolication.rs b/crates/symbolicator-proguard/src/symbolication.rs index 20bbeaef9..e0a8bbd18 100644 --- a/crates/symbolicator-proguard/src/symbolication.rs +++ b/crates/symbolicator-proguard/src/symbolication.rs @@ -78,13 +78,7 @@ impl ProguardService { tracing::error!(%debug_id, "Error reading Proguard file: {e}"); } let kind = match e { - CacheError::Malformed(msg) => match msg.as_str() { - "The file is not a valid ProGuard file" => ProguardErrorKind::Invalid, - "The ProGuard file doesn't contain any line mappings" => { - ProguardErrorKind::NoLineInfo - } - _ => unreachable!(), - }, + CacheError::Malformed(_) => ProguardErrorKind::Invalid, _ => ProguardErrorKind::Missing, }; errors.push(ProguardError { diff --git a/crates/symbolicator-proguard/tests/integration/proguard.rs b/crates/symbolicator-proguard/tests/integration/proguard.rs index b57f137f9..61eac04f5 100644 --- a/crates/symbolicator-proguard/tests/integration/proguard.rs +++ b/crates/symbolicator-proguard/tests/integration/proguard.rs @@ -545,3 +545,61 @@ async fn test_rewrite_frames() { let response_npe = symbolication.symbolicate_jvm(request_npe).await; assert_snapshot!(response_npe); } + +#[tokio::test] +async fn test_no_line_info_mapping() { + symbolicator_test::setup(); + let (symbolication, _cache_dir) = setup_service(|_| ()); + let (_srv, source) = proguard_server("no_line_info", |_url, _query| { + json!([{ + "id":"proguard.txt", + "uuid":"246fb328-fc4e-406a-87ff-fc35f6149d8f", + "debugId":"246fb328-fc4e-406a-87ff-fc35f6149d8f", + "codeId":null, + "cpuName":"any", + "objectName":"proguard-mapping", + "symbolType":"proguard", + "headers": { + "Content-Type":"text/x-proguard+plain" + }, + "size":1000, + "sha1":"0000000000000000000000000000000000000000", + "dateCreated":"2024-02-14T10:49:38.770116Z", + "data":{ + "features":["mapping"] + } + }]) + }); + + let source = SourceConfig::Sentry(Arc::new(source)); + + // Mapping file has no line number ranges — only class/method name mappings. + // Previously rejected with "doesn't contain any line mappings". + let frames = r#"[{ + "function": "kc", + "module": "yy.xv", + "lineno": 42, + "index": 0 + }, { + "function": "kV", + "module": "yy.Fv", + "lineno": 123, + "index": 1 + }, { + "function": "VF", + "module": "yy.zX", + "index": 2 + }]"#; + + let request = make_jvm_request( + source, + r#"{"type": "RuntimeException", "module": "java.lang"}"#, + frames, + r#"[{"uuid": "246fb328-fc4e-406a-87ff-fc35f6149d8f", "type": "proguard"}]"#, + None, + ); + + let response = symbolication.symbolicate_jvm(request).await; + + assert_snapshot!(response); +} diff --git a/crates/symbolicator-proguard/tests/integration/snapshots/integration__proguard__no_line_info_mapping.snap b/crates/symbolicator-proguard/tests/integration/snapshots/integration__proguard__no_line_info_mapping.snap new file mode 100644 index 000000000..1c70dd2d5 --- /dev/null +++ b/crates/symbolicator-proguard/tests/integration/snapshots/integration__proguard__no_line_info_mapping.snap @@ -0,0 +1,32 @@ +--- +source: crates/symbolicator-proguard/tests/integration/proguard.rs +expression: response +--- +exceptions: + - type: RuntimeException + module: java.lang +stacktraces: + - exception: + type: RuntimeException + module: java.lang + frames: + - function: checkMessageInitialized + filename: AbstractParser.java + module: com.google.protobuf.AbstractParser + abs_path: AbstractParser.java + lineno: 42 + index: 0 + - function: ensureIsMutable + filename: AbstractProtobufList.java + module: com.google.protobuf.AbstractProtobufList + abs_path: AbstractProtobufList.java + lineno: 123 + index: 1 + - function: coroutineBoundary + filename: ArtificialStackFrames.java + module: _COROUTINE.ArtificialStackFrames + abs_path: ArtificialStackFrames.java + lineno: 0 + index: 2 +classes: {} +errors: [] diff --git a/tests/fixtures/proguard/no_line_info/proguard.txt b/tests/fixtures/proguard/no_line_info/proguard.txt new file mode 100644 index 000000000..ea52ebb22 --- /dev/null +++ b/tests/fixtures/proguard/no_line_info/proguard.txt @@ -0,0 +1,81 @@ +# {'id':'com.android.tools.r8.mapping','version':'1.0'} +_COROUTINE.ArtificialStackFrames -> yy.zX: + android.content.Context appContext -> Xc + java.lang.Object contentProviderStarted -> kc + java.lang.String guardsInvoked -> zc + boolean _COROUTINE.ArtificialStackFrames.isSupported() -> GV + java.lang.StackTraceElement _COROUTINE.ArtificialStackFrames.coroutineBoundary() -> VF + java.lang.StackTraceElement _COROUTINE.ArtificialStackFrames.coroutineCreation() -> XF +_COROUTINE.CoroutineDebuggingKt -> yy.Lr: + java.lang.StackTraceElement _COROUTINE.CoroutineDebuggingKt.access$artificialFrame(java.lang.Throwable,java.lang.String) -> kc +_COROUTINE._BOUNDARY -> yy.lX: + int _COROUTINE._BOUNDARY.decodeVarint64(long,byte[],int,com.google.protobuf.ArrayDecoders$Registers) -> uG +_COROUTINE._CREATION -> yy.QG: +com.google.common.util.concurrent.ListenableFuture -> yy.Pv: +com.google.protobuf.AbstractMessageLite -> yy.Hv: +com.google.protobuf.AbstractMessageLite$Builder -> yy.Ov: +com.google.protobuf.AbstractMessageLite$Builder$LimitedInputStream -> yy.pv: + int limit -> Xc + int $stable -> kc + com.google.protobuf.InvalidProtocolBufferException com.google.protobuf.AbstractMessageLite$Builder$LimitedInputStream.parseFailure() -> xc +com.google.protobuf.AbstractMessageLite$InternalOneOfEnum -> yy.ov: +com.google.protobuf.AbstractParser -> yy.xv: + com.google.protobuf.ExtensionRegistryLite EMPTY_REGISTRY -> Xc + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(byte[],com.google.protobuf.ExtensionRegistryLite) -> BAc + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(com.google.protobuf.CodedInputStream) -> DAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(java.io.InputStream,com.google.protobuf.ExtensionRegistryLite) -> DW + java.lang.Object com.google.protobuf.AbstractParser.parseDelimitedFrom(java.io.InputStream) -> GAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(java.io.InputStream) -> GW + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parsePartialFrom(byte[]) -> HW + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parsePartialFrom(byte[],int,int) -> IW + java.lang.Object com.google.protobuf.AbstractParser.parsePartialFrom(byte[],com.google.protobuf.ExtensionRegistryLite) -> JAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(byte[]) -> JW + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(byte[],int,int) -> KAc + java.lang.Object com.google.protobuf.AbstractParser.parsePartialFrom(byte[]) -> OAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(com.google.protobuf.ByteString,com.google.protobuf.ExtensionRegistryLite) -> OW + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(com.google.protobuf.CodedInputStream,com.google.protobuf.ExtensionRegistryLite) -> PW + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(java.io.InputStream,com.google.protobuf.ExtensionRegistryLite) -> RAc + java.lang.Object com.google.protobuf.AbstractParser.parsePartialFrom(java.io.InputStream) -> SAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parsePartialFrom(byte[],int,int,com.google.protobuf.ExtensionRegistryLite) -> TW + java.lang.Object com.google.protobuf.AbstractParser.parsePartialFrom(java.io.InputStream,com.google.protobuf.ExtensionRegistryLite) -> UAc + java.lang.Object com.google.protobuf.AbstractParser.parseDelimitedFrom(java.io.InputStream,com.google.protobuf.ExtensionRegistryLite) -> VAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parsePartialDelimitedFrom(java.io.InputStream) -> VW + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(java.nio.ByteBuffer) -> XAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parsePartialFrom(java.io.InputStream) -> XW + com.google.protobuf.UninitializedMessageException com.google.protobuf.AbstractParser.newUninitializedMessageException(com.google.protobuf.MessageLite) -> Xc + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(byte[],int,int,com.google.protobuf.ExtensionRegistryLite) -> YAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(java.nio.ByteBuffer) -> YW + java.lang.Object com.google.protobuf.AbstractParser.parsePartialDelimitedFrom(java.io.InputStream) -> ZAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(java.nio.ByteBuffer,com.google.protobuf.ExtensionRegistryLite) -> ZW + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseDelimitedFrom(java.io.InputStream) -> aq + java.lang.Object com.google.protobuf.AbstractParser.parsePartialFrom(com.google.protobuf.ByteString) -> bAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(byte[],com.google.protobuf.ExtensionRegistryLite) -> dW + java.lang.Object com.google.protobuf.AbstractParser.parsePartialFrom(com.google.protobuf.CodedInputStream) -> eAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parsePartialFrom(com.google.protobuf.CodedInputStream) -> eW + java.lang.Object com.google.protobuf.AbstractParser.parsePartialFrom(com.google.protobuf.ByteString,com.google.protobuf.ExtensionRegistryLite) -> gAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parsePartialFrom(com.google.protobuf.ByteString) -> gW + java.lang.Object com.google.protobuf.AbstractParser.parsePartialDelimitedFrom(java.io.InputStream,com.google.protobuf.ExtensionRegistryLite) -> hAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(com.google.protobuf.CodedInputStream) -> hW + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parsePartialFrom(byte[],com.google.protobuf.ExtensionRegistryLite) -> iW + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(byte[],int,int,com.google.protobuf.ExtensionRegistryLite) -> jW + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(com.google.protobuf.CodedInputStream,com.google.protobuf.ExtensionRegistryLite) -> kAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.checkMessageInitialized(com.google.protobuf.MessageLite) -> kc + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(com.google.protobuf.ByteString,com.google.protobuf.ExtensionRegistryLite) -> lAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parsePartialFrom(java.io.InputStream,com.google.protobuf.ExtensionRegistryLite) -> lW + java.lang.Object com.google.protobuf.AbstractParser.parsePartialFrom(byte[],int,int) -> oAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parsePartialFrom(com.google.protobuf.ByteString,com.google.protobuf.ExtensionRegistryLite) -> oW + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(com.google.protobuf.ByteString) -> pW + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(java.io.InputStream) -> rAc + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(byte[]) -> sAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseFrom(byte[],int,int) -> tW + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(java.nio.ByteBuffer,com.google.protobuf.ExtensionRegistryLite) -> vAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parseDelimitedFrom(java.io.InputStream,com.google.protobuf.ExtensionRegistryLite) -> vW + java.lang.Object com.google.protobuf.AbstractParser.parsePartialFrom(byte[],int,int,com.google.protobuf.ExtensionRegistryLite) -> wAc + java.lang.Object com.google.protobuf.AbstractParser.parseFrom(com.google.protobuf.ByteString) -> zAc + com.google.protobuf.MessageLite com.google.protobuf.AbstractParser.parsePartialDelimitedFrom(java.io.InputStream,com.google.protobuf.ExtensionRegistryLite) -> zW +com.google.protobuf.AbstractProtobufList -> yy.Fv: + boolean isMutable -> Xc + int DEFAULT_CAPACITY -> kc + boolean com.google.protobuf.AbstractProtobufList.isModifiable() -> Zf + void com.google.protobuf.AbstractProtobufList.makeImmutable() -> bf + void com.google.protobuf.AbstractProtobufList.ensureIsMutable() -> kV