From e7f07eb6ff1eb437ebe83493ec7f35b9b23e426c Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Wed, 11 Nov 2026 16:03:14 +0100 Subject: [PATCH 1/3] ref: Narrow Throwable catches to the exceptions they guard Replace catch (Throwable) with the types the guarded code can throw, so SDK bugs and fatal errors are no longer swallowed: RejectedExecutionException around executor submit and schedule, IOException and SecurityException around file I/O, and the specific parse exceptions elsewhere. Drop the try where nothing in it can throw. Several tests only passed because these catches hid broken mocks: executor mocks that returned Unit from submit, mock Contexts without assets, a Runtime.exec that returned null. Make those mocks behave like the real objects. Refs JAVA-552 Co-Authored-By: Claude Opus 5.5 --- .../core/AndroidContinuousProfiler.java | 2 +- .../core/AndroidLoggerBatchProcessor.java | 3 +- .../core/AndroidMetricsBatchProcessor.java | 3 +- .../sentry/android/core/AndroidProfiler.java | 4 +- .../sentry/android/core/AnrIntegration.java | 3 +- .../sentry/android/core/AnrV2Integration.java | 5 +- .../AppComponentsBreadcrumbsIntegration.java | 3 +- .../ApplicationExitInfoEventProcessor.java | 6 +- .../core/DefaultAndroidEventProcessor.java | 68 ++++++--------- .../sentry/android/core/DeviceInfoUtil.java | 62 ++++--------- .../core/EnvelopeFileObserverIntegration.java | 3 +- .../core/FeedbackShakeIntegration.java | 3 +- .../android/core/InternalSentrySdk.java | 3 +- .../sentry/android/core/LifecycleWatcher.java | 3 +- .../android/core/NativeEventCollector.java | 2 +- .../core/PerfettoContinuousProfiler.java | 2 +- .../core/SendCachedEnvelopeIntegration.java | 13 ++- .../SystemEventsBreadcrumbsIntegration.java | 2 +- .../android/core/TombstoneIntegration.java | 3 +- .../core/anr/AnrProfileRotationHelper.java | 4 +- .../core/anr/AnrProfilingIntegration.java | 3 +- .../core/cache/AndroidEnvelopeCache.java | 27 +++--- .../internal/modules/AssetsModulesLoader.java | 3 +- .../util/AndroidConnectionStatusProvider.java | 3 +- .../core/internal/util/RootChecker.java | 2 +- .../core/AndroidLoggerBatchProcessorTest.kt | 3 +- .../core/AndroidMetricsBatchProcessorTest.kt | 3 +- .../android/core/ContextUtilsTestHelper.kt | 27 ++++-- .../core/internal/util/RootCheckerTest.kt | 6 +- .../sentry/android/ndk/NdkScopeObserver.java | 20 ++--- .../io/sentry/android/replay/ReplayCache.kt | 6 +- .../replay/capture/BufferCaptureStrategy.kt | 2 +- .../sentry/android/replay/util/Executors.kt | 3 +- .../replay/util/ReplayExecutorService.kt | 3 +- .../android/replay/ReplayIntegrationTest.kt | 17 +++- .../apollo3/SentryApollo3HttpInterceptor.kt | 5 +- .../apollo4/SentryApollo4HttpInterceptor.kt | 5 +- .../profiling/JavaContinuousProfiler.java | 2 +- .../java/io/sentry/jdbc/DatabaseUtils.java | 21 ++--- .../OpenTelemetryAttributesExtractor.java | 5 +- .../otlp/OpenTelemetryOtlpPropagator.java | 3 +- sentry/src/main/java/io/sentry/Baggage.java | 86 +++++++++---------- .../main/java/io/sentry/EnvelopeSender.java | 2 +- .../src/main/java/io/sentry/FilterString.java | 3 +- .../main/java/io/sentry/MonitorSchedule.java | 2 +- ...achedEnvelopeFireAndForgetIntegration.java | 4 - sentry/src/main/java/io/sentry/Sentry.java | 11 +-- .../io/sentry/SentryCrashLastRunState.java | 2 +- .../main/java/io/sentry/SentryOptions.java | 2 +- .../src/main/java/io/sentry/SentryTracer.java | 5 +- .../java/io/sentry/cache/EnvelopeCache.java | 6 +- .../sentry/cache/PersistingScopeObserver.java | 3 +- .../config/FilesystemPropertiesLoader.java | 3 +- .../modules/ManifestModulesLoader.java | 3 +- .../java/io/sentry/util/CheckInUtils.java | 8 +- .../main/java/io/sentry/util/Platform.java | 4 +- .../main/java/io/sentry/util/SpanUtils.java | 10 +-- .../main/java/io/sentry/util/StringUtils.java | 2 - .../java/io/sentry/util/TracingUtils.java | 9 +- .../java/io/sentry/cache/EnvelopeCacheTest.kt | 3 +- 60 files changed, 257 insertions(+), 277 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java index 23a72b131fc..7cedd3ad141 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java @@ -383,7 +383,7 @@ private void sendChunks(final @NotNull IScopes scopes, final @NotNull SentryOpti scopes.captureProfileChunk(payload); } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to send profile chunks.", e); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLoggerBatchProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLoggerBatchProcessor.java index b81666e2f38..6dd05c76de1 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLoggerBatchProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLoggerBatchProcessor.java @@ -4,6 +4,7 @@ import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.logger.LoggerBatchProcessor; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -37,7 +38,7 @@ public void run() { flush(LoggerBatchProcessor.FLUSH_AFTER_MS); } }); - } catch (Throwable t) { + } catch (RejectedExecutionException t) { options.getLogger().log(SentryLevel.ERROR, t, "Failed to submit log flush in onBackground()"); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidMetricsBatchProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidMetricsBatchProcessor.java index d92c4369139..2cba40bb863 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidMetricsBatchProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidMetricsBatchProcessor.java @@ -4,6 +4,7 @@ import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.metrics.MetricsBatchProcessor; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -37,7 +38,7 @@ public void run() { flush(MetricsBatchProcessor.FLUSH_AFTER_MS); } }); - } catch (Throwable t) { + } catch (RejectedExecutionException t) { options .getLogger() .log(SentryLevel.ERROR, t, "Failed to submit metrics flush in onBackground()"); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java index 8710c5d637f..e6b559a0d8c 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java @@ -214,7 +214,7 @@ public void onFrameMetricCollected( isRunning = true; return new ProfileStartData( profileStartNanos, profileStartCpuMillis, profileStartTimestamp); - } catch (Throwable e) { + } catch (RuntimeException e) { endAndCollect(false, null); logger.log(SentryLevel.ERROR, "Unable to start a profile: ", e); isRunning = false; @@ -237,7 +237,7 @@ public void onFrameMetricCollected( // wrapped, so this should never happen (except for tests, where this is the only method // that throws) Debug.stopMethodTracing(); - } catch (Throwable e) { + } catch (RuntimeException e) { logger.log(SentryLevel.ERROR, "Error while stopping profiling: ", e); } finally { isRunning = false; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java index 275914e3fe2..389f050a044 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java @@ -20,6 +20,7 @@ import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -75,7 +76,7 @@ private void register( } } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log(SentryLevel.DEBUG, "Failed to start AnrIntegration on executor thread.", e); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java index c80ce982b95..88642d408c3 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java @@ -39,6 +39,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -87,7 +88,7 @@ public void register(@NotNull IScopes scopes, @NotNull SentryOptions options) { .submit( new ApplicationExitInfoHistoryDispatcher( context, scopes, this.options, dateProvider, new AnrV2Policy(this.options))); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to start ANR processor.", e); } options.getLogger().log(SentryLevel.DEBUG, "AnrV2Integration installed."); @@ -203,7 +204,7 @@ public void markReported(final long timestamp) { return new ParseResult(ParseResult.Type.NO_DUMP); } dump = NativeEventUtils.readBytes(trace); - } catch (Throwable e) { + } catch (IOException e) { options.getLogger().log(SentryLevel.WARNING, "Failed to read ANR thread dump", e); return new ParseResult(ParseResult.Type.NO_DUMP); } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java index e98c0afb2db..a2ca81faa9a 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java @@ -20,6 +20,7 @@ import java.io.Closeable; import java.io.IOException; import java.util.Locale; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -173,7 +174,7 @@ private void executeInBackground(final @NotNull Runnable runnable) { if (options != null) { try { options.getExecutorService().submit(runnable); - } catch (Throwable t) { + } catch (RejectedExecutionException t) { options .getLogger() .log(SentryLevel.ERROR, t, "Failed to submit app components breadcrumb task"); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java index 79e671b4f49..2b624c8982a 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java @@ -234,7 +234,7 @@ private boolean sampleReplay( event.getEventId()); return false; } - } catch (Throwable e) { + } catch (NumberFormatException e) { options.getLogger().log(SentryLevel.ERROR, "Error parsing replay sample rate.", e); return false; } @@ -467,7 +467,7 @@ private void setAppVersionAndBuild(final @NotNull SentryBaseEvent event) { app.setAppVersion(versionName); app.setAppBuild(versionCode); event.getContexts().setApp(app); - } catch (Throwable e) { + } catch (IndexOutOfBoundsException e) { options .getLogger() .log(SentryLevel.WARNING, "Failed to parse release from scope cache: %s", release); @@ -698,7 +698,7 @@ private void mergeUser(final @NotNull SentryBaseEvent event) { private @Nullable String getDeviceId() { try { return Installation.id(context); - } catch (Throwable e) { + } catch (RuntimeException e) { options.getLogger().log(SentryLevel.ERROR, "Error getting installationId.", e); } return null; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index b6fb245c11d..c2139d9dcbe 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -232,59 +232,39 @@ private void mergeOS(final @NotNull SentryBaseEvent event) { } private void setDevice(final @NotNull SentryLogEvent event) { - try { - event.setAttribute( - "device.brand", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); - event.setAttribute( - "device.model", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); - event.setAttribute( - "device.family", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); - } + event.setAttribute( + "device.brand", new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); + event.setAttribute( + "device.model", new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); + event.setAttribute( + "device.family", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); } private void setOs(final @NotNull SentryLogEvent event) { - try { - event.setAttribute( - "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); - event.setAttribute( - "os.version", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve os system", e); - } + event.setAttribute( + "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); + event.setAttribute( + "os.version", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); } private void setDevice(final @NotNull SentryMetricsEvent event) { - try { - event.setAttribute( - "device.brand", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); - event.setAttribute( - "device.model", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); - event.setAttribute( - "device.family", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); - } + event.setAttribute( + "device.brand", new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); + event.setAttribute( + "device.model", new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); + event.setAttribute( + "device.family", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); } private void setOs(final @NotNull SentryMetricsEvent event) { - try { - event.setAttribute( - "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); - event.setAttribute( - "os.version", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve os system", e); - } + event.setAttribute( + "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); + event.setAttribute( + "os.version", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); } // Data to be applied to events that was created in the running process diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java index 3cc0b3c67f5..f0889d12f0e 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java @@ -369,16 +369,10 @@ private Device.DeviceOrientation getOrientation() { * * @return the total amount of internal storage, in bytes */ - @Nullable - private Long getTotalInternalStorage(final @NotNull StatFs stat) { - try { - long blockSize = stat.getBlockSizeLong(); - long totalBlocks = stat.getBlockCountLong(); - return totalBlocks * blockSize; - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting total internal storage amount.", e); - return null; - } + private long getTotalInternalStorage(final @NotNull StatFs stat) { + long blockSize = stat.getBlockSizeLong(); + long totalBlocks = stat.getBlockCountLong(); + return totalBlocks * blockSize; } /** @@ -386,18 +380,10 @@ private Long getTotalInternalStorage(final @NotNull StatFs stat) { * * @return the unused amount of internal storage, in bytes */ - @Nullable - private Long getUnusedInternalStorage(final @NotNull StatFs stat) { - try { - long blockSize = stat.getBlockSizeLong(); - long availableBlocks = stat.getAvailableBlocksLong(); - return availableBlocks * blockSize; - } catch (Throwable e) { - options - .getLogger() - .log(SentryLevel.ERROR, "Error getting unused internal storage amount.", e); - return null; - } + private long getUnusedInternalStorage(final @NotNull StatFs stat) { + long blockSize = stat.getBlockSizeLong(); + long availableBlocks = stat.getAvailableBlocksLong(); + return availableBlocks * blockSize; } @Nullable @@ -449,16 +435,10 @@ private File getExternalStorageDep(final @Nullable File internalStorage) { * @return the total amount of external storage, in bytes, or null if no external storage is * mounted */ - @Nullable - private Long getTotalExternalStorage(final @NotNull StatFs stat) { - try { - final long blockSize = stat.getBlockSizeLong(); - final long totalBlocks = stat.getBlockCountLong(); - return totalBlocks * blockSize; - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting total external storage amount.", e); - return null; - } + private long getTotalExternalStorage(final @NotNull StatFs stat) { + final long blockSize = stat.getBlockSizeLong(); + final long totalBlocks = stat.getBlockCountLong(); + return totalBlocks * blockSize; } /** @@ -467,25 +447,17 @@ private Long getTotalExternalStorage(final @NotNull StatFs stat) { * @return the unused amount of external storage, in bytes, or null if no external storage is * mounted */ - @Nullable - private Long getUnusedExternalStorage(final @NotNull StatFs stat) { - try { - final long blockSize = stat.getBlockSizeLong(); - final long availableBlocks = stat.getAvailableBlocksLong(); - return availableBlocks * blockSize; - } catch (Throwable e) { - options - .getLogger() - .log(SentryLevel.ERROR, "Error getting unused external storage amount.", e); - return null; - } + private long getUnusedExternalStorage(final @NotNull StatFs stat) { + final long blockSize = stat.getBlockSizeLong(); + final long availableBlocks = stat.getAvailableBlocksLong(); + return availableBlocks * blockSize; } @Nullable private String getDeviceId() { try { return Installation.id(context); - } catch (Throwable e) { + } catch (RuntimeException e) { options.getLogger().log(SentryLevel.ERROR, "Error getting installationId.", e); } return null; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java index ab95ae32daa..b5c254a88c1 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java @@ -14,6 +14,7 @@ import io.sentry.util.Objects; import java.io.Closeable; import java.io.File; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -56,7 +57,7 @@ public final void register(final @NotNull IScopes scopes, final @NotNull SentryO } } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { logger.log( SentryLevel.DEBUG, "Failed to start EnvelopeFileObserverIntegration on executor thread.", diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/FeedbackShakeIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/FeedbackShakeIntegration.java index 4405cd19309..b2a47afda2c 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/FeedbackShakeIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/FeedbackShakeIntegration.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -97,7 +98,7 @@ public synchronized void enableOnShake() { options .getExecutorService() .submit(() -> shakeDetector.init(application, options.getLogger())); - } catch (Throwable t) { + } catch (RejectedExecutionException t) { options .getLogger() .log(SentryLevel.WARNING, "Failed to submit shake detector initialization.", t); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java index 4ad11399d02..fb4fef1383e 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java @@ -41,6 +41,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicReference; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -419,7 +420,7 @@ private static void deleteCurrentSessionFile( () -> { deleteCurrentSessionFile(options); }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log(WARNING, "Submission of deletion of the current session file rejected.", e); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java b/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java index f0078bc353e..98e66d247ce 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java @@ -11,6 +11,7 @@ import io.sentry.util.AutoClosableReentrantLock; import java.util.Date; import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.jetbrains.annotations.NotNull; @@ -131,7 +132,7 @@ private void scheduleEndSession() { .getOptions() .getTimerExecutorService() .schedule(endSession, sessionEnd.remaining(TimeUnit.MILLISECONDS)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { scopes .getOptions() .getLogger() diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/NativeEventCollector.java b/sentry-android-core/src/main/java/io/sentry/android/core/NativeEventCollector.java index 69dfa9c16be..df6d843cae2 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/NativeEventCollector.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/NativeEventCollector.java @@ -223,7 +223,7 @@ public boolean deleteNativeEventFile(final @NotNull NativeEventData nativeEventD file.getAbsolutePath()); return false; } - } catch (Throwable e) { + } catch (SecurityException e) { options .getLogger() .log( diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/PerfettoContinuousProfiler.java b/sentry-android-core/src/main/java/io/sentry/android/core/PerfettoContinuousProfiler.java index 15ae88f22c8..002ad4200de 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/PerfettoContinuousProfiler.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/PerfettoContinuousProfiler.java @@ -552,7 +552,7 @@ private void sendChunk( } else { executorServiceSupplier.evaluate().submit(task); } - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to send profile chunk.", e); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java index 8eea2d71047..22ff7dc92b9 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java @@ -16,6 +16,7 @@ import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; @@ -157,6 +158,14 @@ private void sendCachedEnvelopes( options .getLogger() .log(SentryLevel.DEBUG, "Synchronous send timed out, continuing in the background."); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + options + .getLogger() + .log( + SentryLevel.DEBUG, "Synchronous send interrupted, continuing in the background."); + } catch (ExecutionException e) { + options.getLogger().log(SentryLevel.ERROR, "Failed trying to send cached events.", e); } } options.getLogger().log(SentryLevel.DEBUG, "SendCachedEnvelopeIntegration installed."); @@ -167,10 +176,6 @@ private void sendCachedEnvelopes( SentryLevel.ERROR, "Failed to call the executor. Cached events will not be sent. Did you call Sentry.close()?", e); - } catch (Throwable e) { - options - .getLogger() - .log(SentryLevel.ERROR, "Failed to call the executor. Cached events will not be sent", e); } } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java index 3f45a9a9fb8..15ec2321be5 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java @@ -187,7 +187,7 @@ private void registerReceiver( } } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log( diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java index 43de4034ec5..215af07dad3 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java @@ -44,6 +44,7 @@ import java.time.Instant; import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -98,7 +99,7 @@ public void register(@NotNull IScopes scopes, @NotNull SentryOptions options) { this.options, dateProvider, new TombstonePolicy(this.options, this.context))); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to start tombstone processor.", e); } options.getLogger().log(SentryLevel.DEBUG, "TombstoneIntegration installed."); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileRotationHelper.java b/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileRotationHelper.java index 761309f1670..75b4b776dff 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileRotationHelper.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileRotationHelper.java @@ -37,13 +37,13 @@ private static void performRotationIfNeeded(final @NotNull File cacheDir) { try { oldFile.delete(); - } catch (Throwable e) { + } catch (SecurityException e) { // ignored } try { currentFile.renameTo(oldFile); - } catch (Throwable e) { + } catch (SecurityException e) { // ignored } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java index 1a8552c51a8..80c25ec3305 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java @@ -22,6 +22,7 @@ import java.io.Closeable; import java.io.File; import java.io.IOException; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -143,7 +144,7 @@ public void close() throws IOException { logger.log(SentryLevel.WARNING, "Failed to close AnrProfileManager"); } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { logger.log(SentryLevel.WARNING, "Failed to submit AnrProfileManager close"); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/cache/AndroidEnvelopeCache.java b/sentry-android-core/src/main/java/io/sentry/android/core/cache/AndroidEnvelopeCache.java index 13148097289..966ded83beb 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/cache/AndroidEnvelopeCache.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/cache/AndroidEnvelopeCache.java @@ -23,6 +23,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; import java.util.List; @@ -120,7 +121,7 @@ private void writeStartupCrashMarkerFile() { final File crashMarkerFile = new File(outboxDir, STARTUP_CRASH_MARKER_FILE); try { crashMarkerFile.createNewFile(); - } catch (Throwable e) { + } catch (IOException e) { options.getLogger().log(ERROR, "Error writing the startup crash marker file to the disk", e); } } @@ -148,7 +149,7 @@ public static boolean hasStartupCrashMarker(final @NotNull SentryOptions options } } return exists; - } catch (Throwable e) { + } catch (SecurityException e) { options .getLogger() .log(ERROR, "Error reading/deleting the startup crash marker file on the disk", e); @@ -171,17 +172,15 @@ public static boolean hasStartupCrashMarker(final @NotNull SentryOptions options // we wrapped into try-catch already //noinspection ConstantConditions return (content == null || content.equals("null")) ? null : Long.parseLong(content.trim()); - } catch (Throwable e) { - if (e instanceof FileNotFoundException) { - options - .getLogger() - .log( - DEBUG, - "Last " + markerLabel + " marker does not exist. %s.", - lastMarker.getAbsolutePath()); - } else { - options.getLogger().log(ERROR, "Error reading last " + markerLabel + " marker", e); - } + } catch (FileNotFoundException e) { + options + .getLogger() + .log( + DEBUG, + "Last " + markerLabel + " marker does not exist. %s.", + lastMarker.getAbsolutePath()); + } catch (IOException | NumberFormatException e) { + options.getLogger().log(ERROR, "Error reading last " + markerLabel + " marker", e); } return null; } @@ -205,7 +204,7 @@ private static void writeLastReportedMarker( try (final OutputStream outputStream = new FileOutputStream(anrMarker)) { outputStream.write(String.valueOf(timestamp).getBytes(UTF_8)); outputStream.flush(); - } catch (Throwable e) { + } catch (IOException e) { options .getLogger() .log(ERROR, "Error writing the " + markerCategory + " marker to the disk", e); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/modules/AssetsModulesLoader.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/modules/AssetsModulesLoader.java index 1aa8a89f8fc..e8b0361c863 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/modules/AssetsModulesLoader.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/modules/AssetsModulesLoader.java @@ -10,6 +10,7 @@ import java.io.InputStream; import java.util.Map; import java.util.TreeMap; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -30,7 +31,7 @@ public AssetsModulesLoader(final @NotNull Context context, final @NotNull Sentry () -> { getOrLoadModules(); }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, "AssetsModulesLoader submit failed", e); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java index a5ff05e27d5..0b2f28a4cf5 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java @@ -24,6 +24,7 @@ import io.sentry.util.AutoClosableReentrantLock; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.jetbrains.annotations.ApiStatus; @@ -788,7 +789,7 @@ public static List getChildCallbacks() { private void submitSafe(@NotNull Runnable r) { try { options.getExecutorService().submit(r); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log(SentryLevel.ERROR, "AndroidConnectionStatusProvider submit failed", e); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/RootChecker.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/RootChecker.java index 2823f278a7d..8576469e719 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/RootChecker.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/RootChecker.java @@ -169,7 +169,7 @@ private boolean checkRootC() { } } catch (IOException e) { logger.log(SentryLevel.DEBUG, "SU isn't found on this Device."); - } catch (Throwable e) { + } catch (SecurityException e) { logger.log(SentryLevel.DEBUG, "Error when trying to check if SU exists.", e); } finally { if (p != null) { diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidLoggerBatchProcessorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidLoggerBatchProcessorTest.kt index d9f9b1e3edd..66ff1bd776f 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidLoggerBatchProcessorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidLoggerBatchProcessorTest.kt @@ -10,6 +10,7 @@ import io.sentry.SentryOptions import io.sentry.protocol.SentryId import io.sentry.test.ImmediateExecutorService import io.sentry.test.getProperty +import java.util.concurrent.RejectedExecutionException import java.util.concurrent.atomic.AtomicBoolean import kotlin.test.AfterTest import kotlin.test.BeforeTest @@ -96,7 +97,7 @@ class AndroidLoggerBatchProcessorTest { fun `onBackground handles executor exception gracefully`() { val sut = fixture.getSut { options -> val rejectingExecutor = mock() - whenever(rejectingExecutor.submit(any())).thenThrow(RuntimeException("Rejected")) + whenever(rejectingExecutor.submit(any())).thenThrow(RejectedExecutionException("Rejected")) options.executorService = rejectingExecutor } sut.add(SentryLogEvent(SentryId(), 1.0, "test", SentryLogLevel.INFO)) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidMetricsBatchProcessorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidMetricsBatchProcessorTest.kt index 7648a2b3bab..9e7c20843c1 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidMetricsBatchProcessorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidMetricsBatchProcessorTest.kt @@ -9,6 +9,7 @@ import io.sentry.SentryOptions import io.sentry.protocol.SentryId import io.sentry.test.ImmediateExecutorService import io.sentry.test.getProperty +import java.util.concurrent.RejectedExecutionException import java.util.concurrent.atomic.AtomicBoolean import kotlin.test.AfterTest import kotlin.test.BeforeTest @@ -95,7 +96,7 @@ class AndroidMetricsBatchProcessorTest { fun `onBackground handles executor exception gracefully`() { val sut = fixture.getSut { options -> val rejectingExecutor = mock() - whenever(rejectingExecutor.submit(any())).thenThrow(RuntimeException("Rejected")) + whenever(rejectingExecutor.submit(any())).thenThrow(RejectedExecutionException("Rejected")) options.executorService = rejectingExecutor } sut.add(SentryMetricsEvent(SentryId(), 1.0, "test", "counter", 3.0)) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsTestHelper.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsTestHelper.kt index cd09d280d1a..89943fb2325 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsTestHelper.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsTestHelper.kt @@ -27,22 +27,31 @@ object ContextUtilsTestHelper { ) .thenReturn(mockApplicationInfo) - if (assets == null) { - val mockAssets = mock() - whenever(mockAssets.open(any())).thenThrow(FileNotFoundException()) - whenever(mockContext.assets).thenReturn(mockAssets) - } else { - whenever(mockContext.assets).thenReturn(assets) - } + val contextAssets = assets ?: assetsWithoutModulesFile() + whenever(mockContext.assets).thenReturn(contextAssets) mockApplicationInfo.metaData = metaData return mockContext } fun createMockContext(hasAppContext: Boolean = true): Context { + // A real Context always has assets. Without sentry-external-modules.txt, open() throws. + val assets = assetsWithoutModulesFile() val mockApp = mock() - whenever(mockApp.applicationContext) - .thenReturn(if (hasAppContext) mock() else null) + whenever(mockApp.assets).thenReturn(assets) + if (hasAppContext) { + val application = mock() + whenever(application.assets).thenReturn(assets) + whenever(mockApp.applicationContext).thenReturn(application) + } else { + whenever(mockApp.applicationContext).thenReturn(null) + } return mockApp } + + private fun assetsWithoutModulesFile(): AssetManager { + val mockAssets = mock() + whenever(mockAssets.open(any())).thenThrow(FileNotFoundException()) + return mockAssets + } } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/RootCheckerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/RootCheckerTest.kt index 71368b80ae9..bf99317f1fd 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/RootCheckerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/RootCheckerTest.kt @@ -14,6 +14,7 @@ import kotlin.test.Test import kotlin.test.assertFalse import kotlin.test.assertTrue import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.verify @@ -25,7 +26,10 @@ class RootCheckerTest { val logger = mock() val buildInfoProvider = mock() val packageManager = mock() - val runtime = mock() + // by default, `which su` finds nothing, like on a device without su + private val whichSuNotFound = + mock { on { inputStream } doReturn ByteArrayInputStream(ByteArray(0)) } + val runtime = mock { on { exec(any>()) } doReturn whichSuNotFound } fun getSut( tags: String? = "abc", diff --git a/sentry-android-ndk/src/main/java/io/sentry/android/ndk/NdkScopeObserver.java b/sentry-android-ndk/src/main/java/io/sentry/android/ndk/NdkScopeObserver.java index c35a294c828..f4e6bee54cb 100644 --- a/sentry-android-ndk/src/main/java/io/sentry/android/ndk/NdkScopeObserver.java +++ b/sentry-android-ndk/src/main/java/io/sentry/android/ndk/NdkScopeObserver.java @@ -49,7 +49,7 @@ public void setUser(final @Nullable User user) { user.getId(), user.getEmail(), user.getIpAddress(), user.getUsername()); } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setUser has an error."); } } @@ -96,7 +96,7 @@ public void addBreadcrumb(final @NotNull Breadcrumb crumb) { timestamp, data); }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync addBreadcrumb has an error."); } } @@ -105,7 +105,7 @@ public void addBreadcrumb(final @NotNull Breadcrumb crumb) { public void setTag(final @NotNull String key, final @NotNull String value) { try { options.getExecutorService().submit(() -> nativeScope.setTag(key, value)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setTag(%s) has an error.", key); } } @@ -114,7 +114,7 @@ public void setTag(final @NotNull String key, final @NotNull String value) { public void removeTag(final @NotNull String key) { try { options.getExecutorService().submit(() -> nativeScope.removeTag(key)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync removeTag(%s) has an error.", key); } } @@ -123,7 +123,7 @@ public void removeTag(final @NotNull String key) { public void setExtra(final @NotNull String key, final @NotNull String value) { try { options.getExecutorService().submit(() -> nativeScope.setExtra(key, value)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setExtra(%s) has an error.", key); } } @@ -132,7 +132,7 @@ public void setExtra(final @NotNull String key, final @NotNull String value) { public void removeExtra(final @NotNull String key) { try { options.getExecutorService().submit(() -> nativeScope.removeExtra(key)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log(SentryLevel.ERROR, e, "Scope sync removeExtra(%s) has an error.", key); @@ -152,7 +152,7 @@ public void setTrace(@Nullable SpanContext spanContext, @NotNull IScope scope) { () -> nativeScope.setTrace( spanContext.getTraceId().toString(), spanContext.getSpanId().toString())); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setTrace failed."); } } @@ -163,7 +163,7 @@ public void addAttachment(final @NotNull Attachment attachment) { if (pathname != null) { try { options.getExecutorService().submit(() -> nativeScope.addAttachment(pathname)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync addAttachment has an error."); } return; @@ -174,7 +174,7 @@ public void addAttachment(final @NotNull Attachment attachment) { final String filename = attachment.getFilename(); try { options.getExecutorService().submit(() -> nativeScope.addAttachmentBytes(bytes, filename)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync addAttachment has an error."); } return; @@ -189,7 +189,7 @@ public void addAttachment(final @NotNull Attachment attachment) { public void clearAttachments() { try { options.getExecutorService().submit(() -> nativeScope.clearAttachments()); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync clearAttachments has an error."); } } diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/ReplayCache.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/ReplayCache.kt index 64aec8a077c..5d802388f6d 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/ReplayCache.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/ReplayCache.kt @@ -246,7 +246,7 @@ public class ReplayCache(private val options: SentryOptions, private val replayI if (!file.delete()) { options.logger.log(ERROR, "Failed to delete replay frame: %s", file.absolutePath) } - } catch (e: Throwable) { + } catch (e: SecurityException) { options.logger.log(ERROR, e, "Failed to delete replay frame: %s", file.absolutePath) } } @@ -397,13 +397,13 @@ public class ReplayCache(private val options: SentryOptions, private val replayI val segmentTimestamp = try { DateUtils.getDateTime(lastSegment[SEGMENT_KEY_TIMESTAMP].orEmpty()) - } catch (e: Throwable) { + } catch (_: IllegalArgumentException) { null } val replayType = try { ReplayType.valueOf(lastSegment[SEGMENT_KEY_REPLAY_TYPE].orEmpty()) - } catch (e: Throwable) { + } catch (_: IllegalArgumentException) { null } if ( diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/BufferCaptureStrategy.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/BufferCaptureStrategy.kt index 071acc19cae..37985e6cc80 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/BufferCaptureStrategy.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/BufferCaptureStrategy.kt @@ -213,7 +213,7 @@ constructor( if (!file.delete()) { options.logger.log(ERROR, "Failed to delete replay segment: %s", file.absolutePath) } - } catch (e: Throwable) { + } catch (e: SecurityException) { options.logger.log(ERROR, e, "Failed to delete replay segment: %s", file.absolutePath) } } diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Executors.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Executors.kt index a5dddc3bd4d..9b94d9198c4 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Executors.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Executors.kt @@ -4,6 +4,7 @@ import io.sentry.ISentryExecutorService import io.sentry.SentryLevel.ERROR import io.sentry.SentryOptions import java.util.concurrent.Future +import java.util.concurrent.RejectedExecutionException internal fun ISentryExecutorService.submitSafely( options: SentryOptions, @@ -18,7 +19,7 @@ internal fun ISentryExecutorService.submitSafely( options.logger.log(ERROR, "Failed to execute task $taskName", e) } } - } catch (e: Throwable) { + } catch (e: RejectedExecutionException) { options.logger.log(ERROR, "Failed to submit task $taskName to executor", e) null } diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/ReplayExecutorService.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/ReplayExecutorService.kt index 5ba334f8029..292d44b1e20 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/ReplayExecutorService.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/ReplayExecutorService.kt @@ -3,6 +3,7 @@ package io.sentry.android.replay.util import io.sentry.SentryLevel.ERROR import io.sentry.SentryOptions import java.util.concurrent.Future +import java.util.concurrent.RejectedExecutionException import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit.MILLISECONDS @@ -42,7 +43,7 @@ internal class ReplayExecutorService( ) } } - } catch (e: Throwable) { + } catch (e: RejectedExecutionException) { options.logger.log( ERROR, "Failed to submit task ${if (task is ReplayRunnable) task.taskName else ""} to executor", diff --git a/sentry-android-replay/src/test/java/io/sentry/android/replay/ReplayIntegrationTest.kt b/sentry-android-replay/src/test/java/io/sentry/android/replay/ReplayIntegrationTest.kt index 70e8426d124..a013ca6e2bc 100644 --- a/sentry-android-replay/src/test/java/io/sentry/android/replay/ReplayIntegrationTest.kt +++ b/sentry-android-replay/src/test/java/io/sentry/android/replay/ReplayIntegrationTest.kt @@ -105,7 +105,12 @@ class ReplayIntegrationTest { mock { on { breadcrumbConverter }.thenReturn(DefaultReplayBreadcrumbConverter()) } ) executorService = mock { - doAnswer { (it.arguments[0] as Runnable).run() }.whenever(mock).submit(any()) + doAnswer { + (it.arguments[0] as Runnable).run() + null + } + .whenever(mock) + .submit(any()) } } val scope = Scope(options) @@ -1272,7 +1277,10 @@ class ReplayIntegrationTest { // hold back the startup work, like a busy executor does val deferredTasks = mutableListOf() fixture.options.executorService = mock { - doAnswer { deferredTasks += it.arguments[0] as Runnable } + doAnswer { + deferredTasks += it.arguments[0] as Runnable + null + } .whenever(mock) .submit(any()) } @@ -1326,7 +1334,10 @@ class ReplayIntegrationTest { fixture.options.addScopeObserver(PersistingScopeObserver(fixture.options)) val deferredTasks = mutableListOf() fixture.options.executorService = mock { - doAnswer { deferredTasks += it.arguments[0] as Runnable } + doAnswer { + deferredTasks += it.arguments[0] as Runnable + null + } .whenever(mock) .submit(any()) } diff --git a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt index 400643cef4a..2473266f2a5 100644 --- a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt +++ b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt @@ -39,6 +39,7 @@ import io.sentry.util.SpanUtils import io.sentry.util.TracingUtils import io.sentry.util.UrlUtils import io.sentry.vendor.Base64 +import java.io.IOException import kotlin.coroutines.cancellation.CancellationException import okio.Buffer import org.jetbrains.annotations.ApiStatus @@ -192,7 +193,7 @@ constructor( return getHeader(headerName, request.headers)?.let { try { String(Base64.decode(it, Base64.NO_WRAP)) - } catch (e: Throwable) { + } catch (e: IllegalArgumentException) { scopes.options.logger.log( SentryLevel.ERROR, "Error decoding internal apolloHeader $headerName", @@ -381,7 +382,7 @@ constructor( val body = try { response.body?.peek()?.readUtf8() ?: "" - } catch (e: Throwable) { + } catch (e: IOException) { scopes.options.logger.log(SentryLevel.ERROR, "Error reading the response body.", e) // bail out because the response body has the most important information return diff --git a/sentry-apollo-4/src/main/java/io/sentry/apollo4/SentryApollo4HttpInterceptor.kt b/sentry-apollo-4/src/main/java/io/sentry/apollo4/SentryApollo4HttpInterceptor.kt index 539bdb25b21..d2b7959cf48 100644 --- a/sentry-apollo-4/src/main/java/io/sentry/apollo4/SentryApollo4HttpInterceptor.kt +++ b/sentry-apollo-4/src/main/java/io/sentry/apollo4/SentryApollo4HttpInterceptor.kt @@ -37,6 +37,7 @@ import io.sentry.util.SpanUtils import io.sentry.util.TracingUtils import io.sentry.util.UrlUtils import io.sentry.vendor.Base64 +import java.io.IOException import java.util.Locale import kotlin.coroutines.cancellation.CancellationException import okio.Buffer @@ -191,7 +192,7 @@ constructor( return getHeader(headerName, request.headers)?.let { try { String(Base64.decode(it, Base64.NO_WRAP)) - } catch (e: Throwable) { + } catch (e: IllegalArgumentException) { scopes.options.logger.log( SentryLevel.ERROR, "Error decoding internal apolloHeader $headerName", @@ -380,7 +381,7 @@ constructor( val body = try { response.body?.peek()?.readUtf8() ?: "" - } catch (e: Throwable) { + } catch (e: IOException) { scopes.options.logger.log(SentryLevel.ERROR, "Error reading the response body.", e) // bail out because the response body has the most important information return diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java index ced363d4a58..36ecf351818 100644 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java +++ b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java @@ -417,7 +417,7 @@ private void sendChunks(final @NotNull IScopes scopes, final @NotNull SentryOpti scopes.captureProfileChunk(payload); } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to send profile chunks.", e); } } diff --git a/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java b/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java index 4c442d4ae09..f4b1612d159 100644 --- a/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java +++ b/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java @@ -4,6 +4,7 @@ import com.p6spy.engine.common.StatementInformation; import io.sentry.util.StringUtils; import java.net.URI; +import java.net.URISyntaxException; import java.util.Locale; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -46,7 +47,7 @@ public static DatabaseDetails parse(final @Nullable String databaseConnectionUrl final @NotNull String dbSystem = urlParts[0]; return parseDbSystemSpecific(dbSystem, urlParts, rawUrl); } - } catch (Throwable t) { + } catch (IndexOutOfBoundsException t) { // ignore } @@ -80,17 +81,11 @@ public static DatabaseDetails parse(final @Nullable String databaseConnectionUrl return parseAsUri(dbSystem, urlString); } if ("sqlserver".equalsIgnoreCase(dbSystem)) { - try { - String dbProperty = ";databasename="; - final int index = urlString.indexOf(dbProperty); - if (index >= 0) { - final @NotNull String dbNameAndMaybeMore = - urlString.substring(index + dbProperty.length()); - return new DatabaseDetails( - dbSystem, StringUtils.substringBefore(dbNameAndMaybeMore, ";")); - } - } catch (Throwable t) { - // ignore + String dbProperty = ";databasename="; + final int index = urlString.indexOf(dbProperty); + if (index >= 0) { + final @NotNull String dbNameAndMaybeMore = urlString.substring(index + dbProperty.length()); + return new DatabaseDetails(dbSystem, StringUtils.substringBefore(dbNameAndMaybeMore, ";")); } } if ("oracle".equalsIgnoreCase(dbSystem)) { @@ -132,7 +127,7 @@ public static DatabaseDetails parse(final @Nullable String databaseConnectionUrl String path = StringUtils.removePrefix(url.getPath(), "/"); String pathWithoutProperties = StringUtils.substringBefore(path, ";"); return new DatabaseDetails(dbSystem, pathWithoutProperties); - } catch (Throwable t) { + } catch (URISyntaxException t) { // ignore } return new DatabaseDetails(dbSystem, null); diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OpenTelemetryAttributesExtractor.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OpenTelemetryAttributesExtractor.java index cf0fb06c11a..592d582349d 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OpenTelemetryAttributesExtractor.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OpenTelemetryAttributesExtractor.java @@ -13,6 +13,7 @@ import io.sentry.util.HttpUtils; import io.sentry.util.StringUtils; import io.sentry.util.UrlUtils; +import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.List; @@ -94,7 +95,7 @@ private static Map collectHeaders( toString( CookieUtils.filterOutSecurityCookiesFromHeader( headerValues, headerName, null))); - } catch (Throwable t) { + } catch (ClassCastException t) { options .getLogger() .log(SentryLevel.WARNING, "Expected a List as header", t); @@ -143,7 +144,7 @@ private static Map collectHeaders( } else { return new URL(scheme, serverAddress, serverPort.intValue(), pathToUse).toString(); } - } catch (Throwable t) { + } catch (MalformedURLException t) { options .getLogger() .log(SentryLevel.WARNING, "Unable to combine URL span attributes into one.", t); diff --git a/sentry-opentelemetry/sentry-opentelemetry-otlp/src/main/java/io/sentry/opentelemetry/otlp/OpenTelemetryOtlpPropagator.java b/sentry-opentelemetry/sentry-opentelemetry-otlp/src/main/java/io/sentry/opentelemetry/otlp/OpenTelemetryOtlpPropagator.java index 4cdf1b0ed09..e11fce13e76 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-otlp/src/main/java/io/sentry/opentelemetry/otlp/OpenTelemetryOtlpPropagator.java +++ b/sentry-opentelemetry/sentry-opentelemetry-otlp/src/main/java/io/sentry/opentelemetry/otlp/OpenTelemetryOtlpPropagator.java @@ -25,6 +25,7 @@ import io.sentry.exception.InvalidSentryTraceHeaderException; import io.sentry.util.PropagationTargetsUtils; import io.sentry.util.TracingUtils; +import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.Collection; @@ -123,7 +124,7 @@ private boolean shouldInjectTracingHeaders(final @NotNull Span otelSpan) { } else { return new URL(scheme, serverAddress, serverPort.intValue(), pathToUse).toString(); } - } catch (Throwable t) { + } catch (MalformedURLException t) { options .getLogger() .log(SentryLevel.WARNING, "Unable to combine URL span attributes into one.", t); diff --git a/sentry/src/main/java/io/sentry/Baggage.java b/sentry/src/main/java/io/sentry/Baggage.java index e4777bd063e..af94ede98ae 100644 --- a/sentry/src/main/java/io/sentry/Baggage.java +++ b/sentry/src/main/java/io/sentry/Baggage.java @@ -112,53 +112,49 @@ public static Baggage fromHeader( @Nullable Double sampleRand = null; if (headerValue != null) { - try { - // see https://errorprone.info/bugpattern/StringSplitter for why limit is passed - final String[] keyValueStrings = headerValue.split(",", -1); - for (final String keyValueString : keyValueStrings) { - if (keyValueString.trim().startsWith(SENTRY_BAGGAGE_PREFIX)) { - try { - // As per spec (https://www.w3.org/TR/baggage/#value) - // a value may contain "=" signs, thus we split by the first occurrence - final int separatorIndex = keyValueString.indexOf("="); - final String key = keyValueString.substring(0, separatorIndex).trim(); - final String keyDecoded = decode(key); - final String value = keyValueString.substring(separatorIndex + 1).trim(); - final String valueDecoded = decode(value); - - if (DSCKeys.SAMPLE_RATE.equals(keyDecoded)) { - sampleRate = toDouble(valueDecoded); - } else if (DSCKeys.SAMPLE_RAND.equals(keyDecoded)) { - sampleRand = toDouble(valueDecoded); - } else { - keyValues.put(keyDecoded, valueDecoded); - } - // Without ignoring SAMPLE_RAND here, we'd be freezing baggage that we're transporting - // via OTel span attributes. - // This is done when a transaction is created via Sentry API. - // In that case Baggage is created before the OTel span is created and we put it on - // the span attributes. - // It does however only contain the sample random value as its only value. - // The OTel code then uses it to create a propagation context from it and ends up - // freezing it, - // preventing outgoing requests (to other systems or Sentry) from adding info to - // baggage and only then freeze it. - if (!DSCKeys.SAMPLE_RAND.equalsIgnoreCase(key)) { - shouldFreeze = true; - } - } catch (Throwable e) { - logger.log( - SentryLevel.ERROR, - e, - "Unable to decode baggage key value pair %s", - keyValueString); + // see https://errorprone.info/bugpattern/StringSplitter for why limit is passed + final String[] keyValueStrings = headerValue.split(",", -1); + for (final String keyValueString : keyValueStrings) { + if (keyValueString.trim().startsWith(SENTRY_BAGGAGE_PREFIX)) { + try { + // As per spec (https://www.w3.org/TR/baggage/#value) + // a value may contain "=" signs, thus we split by the first occurrence + final int separatorIndex = keyValueString.indexOf("="); + final String key = keyValueString.substring(0, separatorIndex).trim(); + final String keyDecoded = decode(key); + final String value = keyValueString.substring(separatorIndex + 1).trim(); + final String valueDecoded = decode(value); + + if (DSCKeys.SAMPLE_RATE.equals(keyDecoded)) { + sampleRate = toDouble(valueDecoded); + } else if (DSCKeys.SAMPLE_RAND.equals(keyDecoded)) { + sampleRand = toDouble(valueDecoded); + } else { + keyValues.put(keyDecoded, valueDecoded); + } + // Without ignoring SAMPLE_RAND here, we'd be freezing baggage that we're transporting + // via OTel span attributes. + // This is done when a transaction is created via Sentry API. + // In that case Baggage is created before the OTel span is created and we put it on + // the span attributes. + // It does however only contain the sample random value as its only value. + // The OTel code then uses it to create a propagation context from it and ends up + // freezing it, + // preventing outgoing requests (to other systems or Sentry) from adding info to + // baggage and only then freeze it. + if (!DSCKeys.SAMPLE_RAND.equalsIgnoreCase(key)) { + shouldFreeze = true; } - } else if (includeThirdPartyValues) { - thirdPartyKeyValueStrings.add(keyValueString.trim()); + } catch (UnsupportedEncodingException + | IllegalArgumentException + | IndexOutOfBoundsException e) { + // e.g. an entry without "=", or an invalid percent-encoding + logger.log( + SentryLevel.ERROR, e, "Unable to decode baggage key value pair %s", keyValueString); } + } else if (includeThirdPartyValues) { + thirdPartyKeyValueStrings.add(keyValueString.trim()); } - } catch (Throwable e) { - logger.log(SentryLevel.ERROR, e, "Unable to decode baggage header %s", headerValue); } } final String thirdPartyHeader = @@ -315,7 +311,7 @@ public String getThirdPartyHeader() { sb.append(encodedKeyValue); separator = ","; } - } catch (Throwable e) { + } catch (UnsupportedEncodingException e) { logger.log( SentryLevel.ERROR, e, diff --git a/sentry/src/main/java/io/sentry/EnvelopeSender.java b/sentry/src/main/java/io/sentry/EnvelopeSender.java index 9f630fc2602..06bcaf88e64 100644 --- a/sentry/src/main/java/io/sentry/EnvelopeSender.java +++ b/sentry/src/main/java/io/sentry/EnvelopeSender.java @@ -128,7 +128,7 @@ private void safeDelete(final @NotNull File file, final @NotNull String errorMes file.getAbsolutePath(), errorMessageSuffix); } - } catch (Throwable e) { + } catch (SecurityException e) { logger.log( SentryLevel.ERROR, e, diff --git a/sentry/src/main/java/io/sentry/FilterString.java b/sentry/src/main/java/io/sentry/FilterString.java index 3fd146aa4eb..9d49ebcd0e5 100644 --- a/sentry/src/main/java/io/sentry/FilterString.java +++ b/sentry/src/main/java/io/sentry/FilterString.java @@ -2,6 +2,7 @@ import java.util.Objects; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,7 +15,7 @@ public FilterString(@NotNull String filterString) { @Nullable Pattern pattern = null; try { pattern = Pattern.compile(filterString); - } catch (Throwable t) { + } catch (PatternSyntaxException t) { Sentry.getCurrentScopes() .getOptions() .getLogger() diff --git a/sentry/src/main/java/io/sentry/MonitorSchedule.java b/sentry/src/main/java/io/sentry/MonitorSchedule.java index 438e0399632..a065dfc15ea 100644 --- a/sentry/src/main/java/io/sentry/MonitorSchedule.java +++ b/sentry/src/main/java/io/sentry/MonitorSchedule.java @@ -100,7 +100,7 @@ public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger if (MonitorScheduleType.INTERVAL.apiName().equalsIgnoreCase(type)) { try { writer.name(JsonKeys.VALUE).value(Integer.valueOf(value)); - } catch (Throwable t) { + } catch (NumberFormatException t) { logger.log(SentryLevel.ERROR, "Unable to serialize monitor schedule value: %s", value); } } else { diff --git a/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java b/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java index b08e140392c..3ba7ab6503a 100644 --- a/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java +++ b/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java @@ -173,10 +173,6 @@ private void sendCachedEnvelopes( SentryLevel.ERROR, "Failed to call the executor. Cached events will not be sent. Did you call Sentry.close()?", e); - } catch (Throwable e) { - options - .getLogger() - .log(SentryLevel.ERROR, "Failed to call the executor. Cached events will not be sent", e); } } } diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index 932569177b4..4cc64060e26 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -32,6 +32,7 @@ import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; @@ -490,7 +491,7 @@ private static void handleAppStartProfilingConfig( options.getSerializer().serialize(appStartProfilingOptions, writer); } } - } catch (Throwable e) { + } catch (IOException e) { options .getLogger() .log( @@ -498,7 +499,7 @@ private static void handleAppStartProfilingConfig( } } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log( @@ -523,7 +524,7 @@ private static void movePreviousSession(final @NotNull SentryOptions options) { // enqueue a task to move previous unfinished session to its own file try { options.getExecutorService().submit(new MovePreviousSession(options)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to move previous session.", e); } } @@ -536,7 +537,7 @@ private static void finalizePreviousSession( // to modify the previous session have done their work, even if they do that async. try { options.getExecutorService().submit(new PreviousSessionFinalizer(options, scopes)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to finalize previous session.", e); } } @@ -579,7 +580,7 @@ private static void notifyOptionsObservers(final @NotNull SentryOptions options) } } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to notify options observers.", e); } } diff --git a/sentry/src/main/java/io/sentry/SentryCrashLastRunState.java b/sentry/src/main/java/io/sentry/SentryCrashLastRunState.java index dc5b334df25..d086e5b3027 100644 --- a/sentry/src/main/java/io/sentry/SentryCrashLastRunState.java +++ b/sentry/src/main/java/io/sentry/SentryCrashLastRunState.java @@ -53,7 +53,7 @@ public static SentryCrashLastRunState getInstance() { nativeMarker.delete(); } } - } catch (Throwable e) { + } catch (SecurityException e) { // ignore // TODO: Take ILogger via ctor and log here } diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 71dd4588e33..0885eb44e4a 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -2519,7 +2519,7 @@ public void setOrgId(final @Nullable String orgId) { try { final @Nullable String dsnOrgId = retrieveParsedDsn().getOrgId(); return dsnOrgId; - } catch (Throwable e) { + } catch (IllegalArgumentException e) { return null; } } diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index ad130ac55a9..06b2822025f 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -15,6 +15,7 @@ import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.jetbrains.annotations.ApiStatus; @@ -122,7 +123,7 @@ public void scheduleFinish() { .getOptions() .getTimerExecutorService() .schedule(this::onIdleTimeoutReached, idleTimeout); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { scopes .getOptions() .getLogger() @@ -314,7 +315,7 @@ private void scheduleDeadlineTimeout() { .getOptions() .getTimerExecutorService() .schedule(this::onDeadlineTimeoutReached, deadlineTimeOut); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { scopes .getOptions() .getLogger() diff --git a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java index d3f473cfbc9..9a7d3385a6e 100644 --- a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java +++ b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java @@ -285,7 +285,7 @@ private void writeCrashMarkerFile() { final String timestamp = DateUtils.getTimestamp(DateUtils.getCurrentDateTime()); outputStream.write(timestamp.getBytes(UTF_8)); outputStream.flush(); - } catch (Throwable e) { + } catch (IOException e) { options.getLogger().log(ERROR, "Error writing the crash marker file to the disk", e); } } @@ -376,7 +376,7 @@ private boolean writeSessionToDisk(final @NotNull File file, final @NotNull Sess .log(DEBUG, "Overwriting session to offline storage: %s", session.getSessionId()); serializer.getValue().serialize(session, writer); - } catch (Throwable e) { + } catch (IOException e) { options .getLogger() .log(ERROR, e, "Error writing Session to offline storage: %s", session.getSessionId()); @@ -529,7 +529,7 @@ public void movePreviousSession( if (!renamed) { options.getLogger().log(WARNING, "Unable to move current session to previous session."); } - } catch (Throwable e) { + } catch (SecurityException e) { options .getLogger() .log(SentryLevel.ERROR, "Error moving current session to previous session.", e); diff --git a/sentry/src/main/java/io/sentry/cache/PersistingScopeObserver.java b/sentry/src/main/java/io/sentry/cache/PersistingScopeObserver.java index 756f36f65da..a4b1269390b 100644 --- a/sentry/src/main/java/io/sentry/cache/PersistingScopeObserver.java +++ b/sentry/src/main/java/io/sentry/cache/PersistingScopeObserver.java @@ -35,6 +35,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -246,7 +247,7 @@ private void requestFlush() { // no later mutation would ever be able to queue a flush again hasPendingFlush.set(false); } - } catch (Throwable e) { + } catch (RejectedExecutionException e) { hasPendingFlush.set(false); options.getLogger().log(ERROR, "Scope persistence flush could not be submitted", e); } diff --git a/sentry/src/main/java/io/sentry/config/FilesystemPropertiesLoader.java b/sentry/src/main/java/io/sentry/config/FilesystemPropertiesLoader.java index c896091f006..a87ebc4bc33 100644 --- a/sentry/src/main/java/io/sentry/config/FilesystemPropertiesLoader.java +++ b/sentry/src/main/java/io/sentry/config/FilesystemPropertiesLoader.java @@ -5,6 +5,7 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; import java.io.InputStream; import java.util.Properties; import org.jetbrains.annotations.NotNull; @@ -50,7 +51,7 @@ public FilesystemPropertiesLoader( "Failed to load Sentry configuration since it is not readable: %s", filePath); } - } catch (Throwable e) { + } catch (IOException | IllegalArgumentException e) { logger.log( SentryLevel.ERROR, e, "Failed to load Sentry configuration from file: %s", filePath); return null; diff --git a/sentry/src/main/java/io/sentry/internal/modules/ManifestModulesLoader.java b/sentry/src/main/java/io/sentry/internal/modules/ManifestModulesLoader.java index fc1c313ec43..d4889147293 100644 --- a/sentry/src/main/java/io/sentry/internal/modules/ManifestModulesLoader.java +++ b/sentry/src/main/java/io/sentry/internal/modules/ManifestModulesLoader.java @@ -4,6 +4,7 @@ import io.sentry.ILogger; import io.sentry.SentryLevel; +import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; @@ -57,7 +58,7 @@ protected Map loadModules() { modules.add(module); } } - } catch (Throwable e) { + } catch (IOException e) { logger.log(SentryLevel.ERROR, "Unable to detect modules via manifest files.", e); } diff --git a/sentry/src/main/java/io/sentry/util/CheckInUtils.java b/sentry/src/main/java/io/sentry/util/CheckInUtils.java index 7dd4bd486ba..e5beedefc22 100644 --- a/sentry/src/main/java/io/sentry/util/CheckInUtils.java +++ b/sentry/src/main/java/io/sentry/util/CheckInUtils.java @@ -130,12 +130,8 @@ public static boolean isIgnored( } for (final FilterString ignoredSlug : ignoredSlugs) { - try { - if (ignoredSlug.matches(slug)) { - return true; - } - } catch (Throwable t) { - // ignore invalid regex + if (ignoredSlug.matches(slug)) { + return true; } } diff --git a/sentry/src/main/java/io/sentry/util/Platform.java b/sentry/src/main/java/io/sentry/util/Platform.java index bad0f214db3..a46e816311c 100644 --- a/sentry/src/main/java/io/sentry/util/Platform.java +++ b/sentry/src/main/java/io/sentry/util/Platform.java @@ -15,7 +15,7 @@ public final class Platform { // All system properties on Android: // https://developer.android.com/reference/java/lang/System#getProperties() isAndroid = "The Android Project".equals(System.getProperty("java.vendor")); - } catch (Throwable e) { + } catch (SecurityException e) { isAndroid = false; } @@ -31,7 +31,7 @@ public final class Platform { } else { isJavaNinePlus = false; } - } catch (Throwable e) { + } catch (SecurityException | NumberFormatException e) { isJavaNinePlus = false; } } diff --git a/sentry/src/main/java/io/sentry/util/SpanUtils.java b/sentry/src/main/java/io/sentry/util/SpanUtils.java index d1002a3cc97..3ed4e4d5f04 100644 --- a/sentry/src/main/java/io/sentry/util/SpanUtils.java +++ b/sentry/src/main/java/io/sentry/util/SpanUtils.java @@ -78,13 +78,9 @@ public static boolean isIgnored( } for (final FilterString ignoredOrigin : ignoredOrigins) { - try { - if (ignoredOrigin.matches(origin)) { - ignoredSpanDecisionsCache.put(origin, true); - return true; - } - } catch (Throwable t) { - // ignore invalid regex + if (ignoredOrigin.matches(origin)) { + ignoredSpanDecisionsCache.put(origin, true); + return true; } } diff --git a/sentry/src/main/java/io/sentry/util/StringUtils.java b/sentry/src/main/java/io/sentry/util/StringUtils.java index 02d7d4636a4..edae53197a9 100644 --- a/sentry/src/main/java/io/sentry/util/StringUtils.java +++ b/sentry/src/main/java/io/sentry/util/StringUtils.java @@ -150,8 +150,6 @@ private StringUtils() {} // For specifying wrong message digest algorithms catch (NoSuchAlgorithmException e) { logger.log(SentryLevel.INFO, "SHA-1 isn't available to calculate the hash.", e); - } catch (Throwable e) { - logger.log(SentryLevel.INFO, "string: %s could not calculate its hash", e, str); } return null; } diff --git a/sentry/src/main/java/io/sentry/util/TracingUtils.java b/sentry/src/main/java/io/sentry/util/TracingUtils.java index 8a1aa0ac660..e4f1254d430 100644 --- a/sentry/src/main/java/io/sentry/util/TracingUtils.java +++ b/sentry/src/main/java/io/sentry/util/TracingUtils.java @@ -187,13 +187,8 @@ public static boolean isIgnored( } for (final FilterString ignoredTransaction : ignoredTransactions) { - - try { - if (ignoredTransaction.matches(transactionName)) { - return true; - } - } catch (Throwable t) { - // ignore invalid regex + if (ignoredTransaction.matches(transactionName)) { + return true; } } diff --git a/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt b/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt index 0cc2c968195..591b89e4959 100644 --- a/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt +++ b/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt @@ -24,6 +24,7 @@ import io.sentry.hints.SessionStartHint import io.sentry.protocol.SentryId import io.sentry.util.HintUtils import java.io.File +import java.io.IOException import java.io.Writer import java.nio.file.Files import java.nio.file.Path @@ -335,7 +336,7 @@ class EnvelopeCacheTest { val delayedStart = createSession(sessionId = sid) val serializer = mock() whenever(serializer.serialize(same(liveSession), any())) - .thenThrow(RuntimeException("forced ex")) + .thenThrow(IOException("forced ex")) whenever(serializer.deserialize(any(), eq(Session::class.java))).thenReturn(delayedStart) val cache = fixture.getSUT { options -> options.setSerializer(serializer) } From 0cde4a506fadf5c89ad7467f2a0b452002adcf0a Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Wed, 11 Nov 2026 16:04:18 +0100 Subject: [PATCH 2/3] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3d0cec6fc1..3ba00f4a517 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,6 +115,7 @@ ### Internal - Measure the 30 second performance-collection budget on a monotonic ticker, so that a device time change no longer ends collection early or extends it past the budget ([#6101](https://github.com/getsentry/sentry-java/pull/6101)) +- Narrow `catch (Throwable)` to the exceptions the guarded code throws, so SDK bugs and fatal errors are no longer swallowed ([#6564](https://github.com/getsentry/sentry-java/pull/6564)) ## 8.63.0 From 93c9699376405a52696a66d7979b68fd72a8e941 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Wed, 11 Nov 2026 16:15:19 +0100 Subject: [PATCH 3/3] ref: Move the catches that guard nothing to their own PR Their removal is in no/java-552-remove-unneeded-throwable-catches, so this branch only narrows. Refs JAVA-552 Co-Authored-By: Claude Opus 5.5 --- .../core/DefaultAndroidEventProcessor.java | 68 ++++++++++----- .../sentry/android/core/DeviceInfoUtil.java | 60 +++++++++---- .../java/io/sentry/jdbc/DatabaseUtils.java | 16 ++-- sentry/src/main/java/io/sentry/Baggage.java | 87 ++++++++++--------- ...achedEnvelopeFireAndForgetIntegration.java | 4 + .../java/io/sentry/util/CheckInUtils.java | 8 +- .../main/java/io/sentry/util/SpanUtils.java | 10 ++- .../main/java/io/sentry/util/StringUtils.java | 2 + .../java/io/sentry/util/TracingUtils.java | 9 +- 9 files changed, 172 insertions(+), 92 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index c2139d9dcbe..b6fb245c11d 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -232,39 +232,59 @@ private void mergeOS(final @NotNull SentryBaseEvent event) { } private void setDevice(final @NotNull SentryLogEvent event) { - event.setAttribute( - "device.brand", new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); - event.setAttribute( - "device.model", new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); - event.setAttribute( - "device.family", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); + try { + event.setAttribute( + "device.brand", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); + event.setAttribute( + "device.model", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); + event.setAttribute( + "device.family", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); + } } private void setOs(final @NotNull SentryLogEvent event) { - event.setAttribute( - "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); - event.setAttribute( - "os.version", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); + try { + event.setAttribute( + "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); + event.setAttribute( + "os.version", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve os system", e); + } } private void setDevice(final @NotNull SentryMetricsEvent event) { - event.setAttribute( - "device.brand", new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); - event.setAttribute( - "device.model", new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); - event.setAttribute( - "device.family", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); + try { + event.setAttribute( + "device.brand", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); + event.setAttribute( + "device.model", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); + event.setAttribute( + "device.family", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); + } } private void setOs(final @NotNull SentryMetricsEvent event) { - event.setAttribute( - "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); - event.setAttribute( - "os.version", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); + try { + event.setAttribute( + "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); + event.setAttribute( + "os.version", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve os system", e); + } } // Data to be applied to events that was created in the running process diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java index f0889d12f0e..146566a754d 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java @@ -369,10 +369,16 @@ private Device.DeviceOrientation getOrientation() { * * @return the total amount of internal storage, in bytes */ - private long getTotalInternalStorage(final @NotNull StatFs stat) { - long blockSize = stat.getBlockSizeLong(); - long totalBlocks = stat.getBlockCountLong(); - return totalBlocks * blockSize; + @Nullable + private Long getTotalInternalStorage(final @NotNull StatFs stat) { + try { + long blockSize = stat.getBlockSizeLong(); + long totalBlocks = stat.getBlockCountLong(); + return totalBlocks * blockSize; + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Error getting total internal storage amount.", e); + return null; + } } /** @@ -380,10 +386,18 @@ private long getTotalInternalStorage(final @NotNull StatFs stat) { * * @return the unused amount of internal storage, in bytes */ - private long getUnusedInternalStorage(final @NotNull StatFs stat) { - long blockSize = stat.getBlockSizeLong(); - long availableBlocks = stat.getAvailableBlocksLong(); - return availableBlocks * blockSize; + @Nullable + private Long getUnusedInternalStorage(final @NotNull StatFs stat) { + try { + long blockSize = stat.getBlockSizeLong(); + long availableBlocks = stat.getAvailableBlocksLong(); + return availableBlocks * blockSize; + } catch (Throwable e) { + options + .getLogger() + .log(SentryLevel.ERROR, "Error getting unused internal storage amount.", e); + return null; + } } @Nullable @@ -435,10 +449,16 @@ private File getExternalStorageDep(final @Nullable File internalStorage) { * @return the total amount of external storage, in bytes, or null if no external storage is * mounted */ - private long getTotalExternalStorage(final @NotNull StatFs stat) { - final long blockSize = stat.getBlockSizeLong(); - final long totalBlocks = stat.getBlockCountLong(); - return totalBlocks * blockSize; + @Nullable + private Long getTotalExternalStorage(final @NotNull StatFs stat) { + try { + final long blockSize = stat.getBlockSizeLong(); + final long totalBlocks = stat.getBlockCountLong(); + return totalBlocks * blockSize; + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Error getting total external storage amount.", e); + return null; + } } /** @@ -447,10 +467,18 @@ private long getTotalExternalStorage(final @NotNull StatFs stat) { * @return the unused amount of external storage, in bytes, or null if no external storage is * mounted */ - private long getUnusedExternalStorage(final @NotNull StatFs stat) { - final long blockSize = stat.getBlockSizeLong(); - final long availableBlocks = stat.getAvailableBlocksLong(); - return availableBlocks * blockSize; + @Nullable + private Long getUnusedExternalStorage(final @NotNull StatFs stat) { + try { + final long blockSize = stat.getBlockSizeLong(); + final long availableBlocks = stat.getAvailableBlocksLong(); + return availableBlocks * blockSize; + } catch (Throwable e) { + options + .getLogger() + .log(SentryLevel.ERROR, "Error getting unused external storage amount.", e); + return null; + } } @Nullable diff --git a/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java b/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java index f4b1612d159..f45781c352d 100644 --- a/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java +++ b/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java @@ -81,11 +81,17 @@ public static DatabaseDetails parse(final @Nullable String databaseConnectionUrl return parseAsUri(dbSystem, urlString); } if ("sqlserver".equalsIgnoreCase(dbSystem)) { - String dbProperty = ";databasename="; - final int index = urlString.indexOf(dbProperty); - if (index >= 0) { - final @NotNull String dbNameAndMaybeMore = urlString.substring(index + dbProperty.length()); - return new DatabaseDetails(dbSystem, StringUtils.substringBefore(dbNameAndMaybeMore, ";")); + try { + String dbProperty = ";databasename="; + final int index = urlString.indexOf(dbProperty); + if (index >= 0) { + final @NotNull String dbNameAndMaybeMore = + urlString.substring(index + dbProperty.length()); + return new DatabaseDetails( + dbSystem, StringUtils.substringBefore(dbNameAndMaybeMore, ";")); + } + } catch (Throwable t) { + // ignore } } if ("oracle".equalsIgnoreCase(dbSystem)) { diff --git a/sentry/src/main/java/io/sentry/Baggage.java b/sentry/src/main/java/io/sentry/Baggage.java index af94ede98ae..c8d8a0118ae 100644 --- a/sentry/src/main/java/io/sentry/Baggage.java +++ b/sentry/src/main/java/io/sentry/Baggage.java @@ -112,49 +112,56 @@ public static Baggage fromHeader( @Nullable Double sampleRand = null; if (headerValue != null) { - // see https://errorprone.info/bugpattern/StringSplitter for why limit is passed - final String[] keyValueStrings = headerValue.split(",", -1); - for (final String keyValueString : keyValueStrings) { - if (keyValueString.trim().startsWith(SENTRY_BAGGAGE_PREFIX)) { - try { - // As per spec (https://www.w3.org/TR/baggage/#value) - // a value may contain "=" signs, thus we split by the first occurrence - final int separatorIndex = keyValueString.indexOf("="); - final String key = keyValueString.substring(0, separatorIndex).trim(); - final String keyDecoded = decode(key); - final String value = keyValueString.substring(separatorIndex + 1).trim(); - final String valueDecoded = decode(value); - - if (DSCKeys.SAMPLE_RATE.equals(keyDecoded)) { - sampleRate = toDouble(valueDecoded); - } else if (DSCKeys.SAMPLE_RAND.equals(keyDecoded)) { - sampleRand = toDouble(valueDecoded); - } else { - keyValues.put(keyDecoded, valueDecoded); - } - // Without ignoring SAMPLE_RAND here, we'd be freezing baggage that we're transporting - // via OTel span attributes. - // This is done when a transaction is created via Sentry API. - // In that case Baggage is created before the OTel span is created and we put it on - // the span attributes. - // It does however only contain the sample random value as its only value. - // The OTel code then uses it to create a propagation context from it and ends up - // freezing it, - // preventing outgoing requests (to other systems or Sentry) from adding info to - // baggage and only then freeze it. - if (!DSCKeys.SAMPLE_RAND.equalsIgnoreCase(key)) { - shouldFreeze = true; + try { + // see https://errorprone.info/bugpattern/StringSplitter for why limit is passed + final String[] keyValueStrings = headerValue.split(",", -1); + for (final String keyValueString : keyValueStrings) { + if (keyValueString.trim().startsWith(SENTRY_BAGGAGE_PREFIX)) { + try { + // As per spec (https://www.w3.org/TR/baggage/#value) + // a value may contain "=" signs, thus we split by the first occurrence + final int separatorIndex = keyValueString.indexOf("="); + final String key = keyValueString.substring(0, separatorIndex).trim(); + final String keyDecoded = decode(key); + final String value = keyValueString.substring(separatorIndex + 1).trim(); + final String valueDecoded = decode(value); + + if (DSCKeys.SAMPLE_RATE.equals(keyDecoded)) { + sampleRate = toDouble(valueDecoded); + } else if (DSCKeys.SAMPLE_RAND.equals(keyDecoded)) { + sampleRand = toDouble(valueDecoded); + } else { + keyValues.put(keyDecoded, valueDecoded); + } + // Without ignoring SAMPLE_RAND here, we'd be freezing baggage that we're transporting + // via OTel span attributes. + // This is done when a transaction is created via Sentry API. + // In that case Baggage is created before the OTel span is created and we put it on + // the span attributes. + // It does however only contain the sample random value as its only value. + // The OTel code then uses it to create a propagation context from it and ends up + // freezing it, + // preventing outgoing requests (to other systems or Sentry) from adding info to + // baggage and only then freeze it. + if (!DSCKeys.SAMPLE_RAND.equalsIgnoreCase(key)) { + shouldFreeze = true; + } + } catch (UnsupportedEncodingException + | IllegalArgumentException + | IndexOutOfBoundsException e) { + // e.g. an entry without "=", or an invalid percent-encoding + logger.log( + SentryLevel.ERROR, + e, + "Unable to decode baggage key value pair %s", + keyValueString); } - } catch (UnsupportedEncodingException - | IllegalArgumentException - | IndexOutOfBoundsException e) { - // e.g. an entry without "=", or an invalid percent-encoding - logger.log( - SentryLevel.ERROR, e, "Unable to decode baggage key value pair %s", keyValueString); + } else if (includeThirdPartyValues) { + thirdPartyKeyValueStrings.add(keyValueString.trim()); } - } else if (includeThirdPartyValues) { - thirdPartyKeyValueStrings.add(keyValueString.trim()); } + } catch (Throwable e) { + logger.log(SentryLevel.ERROR, e, "Unable to decode baggage header %s", headerValue); } } final String thirdPartyHeader = diff --git a/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java b/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java index 3ba7ab6503a..b08e140392c 100644 --- a/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java +++ b/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java @@ -173,6 +173,10 @@ private void sendCachedEnvelopes( SentryLevel.ERROR, "Failed to call the executor. Cached events will not be sent. Did you call Sentry.close()?", e); + } catch (Throwable e) { + options + .getLogger() + .log(SentryLevel.ERROR, "Failed to call the executor. Cached events will not be sent", e); } } } diff --git a/sentry/src/main/java/io/sentry/util/CheckInUtils.java b/sentry/src/main/java/io/sentry/util/CheckInUtils.java index e5beedefc22..7dd4bd486ba 100644 --- a/sentry/src/main/java/io/sentry/util/CheckInUtils.java +++ b/sentry/src/main/java/io/sentry/util/CheckInUtils.java @@ -130,8 +130,12 @@ public static boolean isIgnored( } for (final FilterString ignoredSlug : ignoredSlugs) { - if (ignoredSlug.matches(slug)) { - return true; + try { + if (ignoredSlug.matches(slug)) { + return true; + } + } catch (Throwable t) { + // ignore invalid regex } } diff --git a/sentry/src/main/java/io/sentry/util/SpanUtils.java b/sentry/src/main/java/io/sentry/util/SpanUtils.java index 3ed4e4d5f04..d1002a3cc97 100644 --- a/sentry/src/main/java/io/sentry/util/SpanUtils.java +++ b/sentry/src/main/java/io/sentry/util/SpanUtils.java @@ -78,9 +78,13 @@ public static boolean isIgnored( } for (final FilterString ignoredOrigin : ignoredOrigins) { - if (ignoredOrigin.matches(origin)) { - ignoredSpanDecisionsCache.put(origin, true); - return true; + try { + if (ignoredOrigin.matches(origin)) { + ignoredSpanDecisionsCache.put(origin, true); + return true; + } + } catch (Throwable t) { + // ignore invalid regex } } diff --git a/sentry/src/main/java/io/sentry/util/StringUtils.java b/sentry/src/main/java/io/sentry/util/StringUtils.java index edae53197a9..02d7d4636a4 100644 --- a/sentry/src/main/java/io/sentry/util/StringUtils.java +++ b/sentry/src/main/java/io/sentry/util/StringUtils.java @@ -150,6 +150,8 @@ private StringUtils() {} // For specifying wrong message digest algorithms catch (NoSuchAlgorithmException e) { logger.log(SentryLevel.INFO, "SHA-1 isn't available to calculate the hash.", e); + } catch (Throwable e) { + logger.log(SentryLevel.INFO, "string: %s could not calculate its hash", e, str); } return null; } diff --git a/sentry/src/main/java/io/sentry/util/TracingUtils.java b/sentry/src/main/java/io/sentry/util/TracingUtils.java index e4f1254d430..8a1aa0ac660 100644 --- a/sentry/src/main/java/io/sentry/util/TracingUtils.java +++ b/sentry/src/main/java/io/sentry/util/TracingUtils.java @@ -187,8 +187,13 @@ public static boolean isIgnored( } for (final FilterString ignoredTransaction : ignoredTransactions) { - if (ignoredTransaction.matches(transactionName)) { - return true; + + try { + if (ignoredTransaction.matches(transactionName)) { + return true; + } + } catch (Throwable t) { + // ignore invalid regex } }