Log a backtrace on panic

This commit is contained in:
marc-signal
2026-03-31 12:12:40 -04:00
committed by GitHub
parent 1bca413376
commit 400a021c2b
7 changed files with 94 additions and 4 deletions

View File

@@ -6,3 +6,5 @@ v0.91.0
- Add `UserBasedAuthorization.UnrestrictedUnauthenticatedAccess` / `unrestrictedUnauthenticatedAccess` / `'unrestricted'` for `UnauthKeysService.getPreKeys` (and for 1:1 sealed sender messages in the future).
- Log more details on gRPC failure
- Log backtraces on panic

View File

@@ -17,7 +17,8 @@ public class AndroidJUnitRunner extends androidx.test.runner.AndroidJUnitRunner
super.onCreate(bundle);
// Make sure libsignal logs get caught correctly.
SignalProtocolLoggerProvider.setProvider(new AndroidSignalProtocolLogger());
SignalProtocolLoggerProvider.setProvider(
new TestLoggerDecorator(new AndroidSignalProtocolLogger()));
SignalProtocolLoggerProvider.initializeLogging(SignalProtocolLogger.VERBOSE);
// Propagate any "environment variables" the test might need into System properties.

View File

@@ -42,12 +42,13 @@ sourceSets {
dependencies {
testImplementation 'junit:junit:4.13'
testImplementation 'org.jetbrains.kotlin:kotlin-test:2.1.0'
}
test {
jvmArgs '-Xcheck:jni'
testLogging {
events 'passed','skipped','failed'
events 'passed', 'skipped', 'failed'
showStandardStreams = true
showExceptions = true
exceptionFormat = 'full'

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.signal.libsignal
import org.junit.Assert
import org.junit.ClassRule
import org.junit.Test
import org.junit.function.ThrowingRunnable
import org.signal.libsignal.internal.NativeTesting
import org.signal.libsignal.util.TestLogger
import org.signal.libsignal.util.TestLoggerDecorator
import kotlin.test.assertContains
import kotlin.test.assertEquals
class PanicLogTest {
companion object {
@ClassRule
@JvmField
val logger = TestLogger()
}
@Test
public fun testPanicsLog() {
TestLoggerDecorator.logs.set(mutableListOf())
try {
Assert.assertThrows(
AssertionError::class.java,
ThrowingRunnable {
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
NativeTesting.TESTING_PanicOnBorrowSync("123" as Object)
},
)
val logs = TestLoggerDecorator.logs.get()!!
assertEquals(1, logs.size)
assertContains(logs[0].message, "panicked at")
} finally {
TestLoggerDecorator.logs.set(null)
}
}
}

View File

@@ -27,7 +27,7 @@ public class TestLogger extends ExternalResource {
}
SignalProtocolLoggerProvider.initializeLogging(SignalProtocolLogger.VERBOSE);
SignalProtocolLoggerProvider.setProvider(new StderrLogger());
SignalProtocolLoggerProvider.setProvider(new TestLoggerDecorator(new StderrLogger()));
}
@Override

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.signal.libsignal.util
import org.signal.libsignal.protocol.logging.SignalProtocolLogger
public class TestLoggerDecorator(
private val inner: SignalProtocolLogger,
) : SignalProtocolLogger {
public data class LogRecord(
val priority: Int,
val tag: String,
val message: String,
)
companion object {
public val logs = ThreadLocal<MutableList<LogRecord>>()
}
override fun log(
priority: Int,
tag: String?,
message: String?,
) {
logs.get()?.add(LogRecord(priority, tag!!, message!!))
inner.log(priority, tag, message)
}
}

View File

@@ -30,7 +30,9 @@ pub fn log_enabled_in_apps(metadata: &log::Metadata) -> bool {
// Other libsignal crates:
b'a' => check("attest"),
b'd' => check("device_transfer"),
b'p' => check("poksho"),
// target == "panic" isn't a libsignal crate, it's the log_panics crate
// In log_panics, they manually override the log target to be "panic" rather than log_panics
b'p' => check("poksho") || target == "panic",
b'u' => check("usernames"),
b'z' => check("zkgroup") || check("zkcredential"),
@@ -49,6 +51,16 @@ mod tests {
use super::*;
#[test]
fn test_panic() {
assert!(log_enabled_in_apps(
&log::Metadata::builder()
.target("panic")
.level(log::Level::Error)
.build()
));
}
#[test_matrix([
"libsignal_foo",
"signal_foo",