Skip to content

Commit 451f2fe

Browse files
markushiadinauerromtsn
authored
Ensure Hints do not cause memory leaks (#2387)
Co-authored-by: Alexander Dinauer <[email protected]> Co-authored-by: Roman Zavarnitsyn <[email protected]>
1 parent b39d6a0 commit 451f2fe

File tree

5 files changed

+49
-4
lines changed

5 files changed

+49
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- Use `canonicalName` in Fragment Integration for better de-obfuscation ([#2379](https://github.com/getsentry/sentry-java/pull/2379))
1212
- Fix Timber and Fragment integrations auto-installation for obfuscated builds ([#2379](https://github.com/getsentry/sentry-java/pull/2379))
1313
- Don't attach screenshots to events from Hybrid SDKs ([#2360](https://github.com/getsentry/sentry-java/pull/2360))
14+
- Ensure Hints do not cause memory leaks ([#2387](https://github.com/getsentry/sentry-java/pull/2387))
1415

1516
### Dependencies
1617

sentry/api/sentry.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ public final class io/sentry/Hint {
249249
public fun <init> ()V
250250
public fun addAttachment (Lio/sentry/Attachment;)V
251251
public fun addAttachments (Ljava/util/List;)V
252+
public fun clear ()V
252253
public fun clearAttachments ()V
253254
public fun get (Ljava/lang/String;)Ljava/lang/Object;
254255
public fun getAs (Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;

sentry/src/main/java/io/sentry/Hint.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import java.util.ArrayList;
44
import java.util.HashMap;
5+
import java.util.Iterator;
56
import java.util.List;
67
import java.util.Map;
8+
import org.jetbrains.annotations.ApiStatus;
79
import org.jetbrains.annotations.NotNull;
810
import org.jetbrains.annotations.Nullable;
911

@@ -39,16 +41,17 @@ public final class Hint {
3941
return hint;
4042
}
4143

42-
public void set(@NotNull String name, @Nullable Object hint) {
44+
public synchronized void set(@NotNull String name, @Nullable Object hint) {
4345
internalStorage.put(name, hint);
4446
}
4547

46-
public @Nullable Object get(@NotNull String name) {
48+
public synchronized @Nullable Object get(@NotNull String name) {
4749
return internalStorage.get(name);
4850
}
4951

5052
@SuppressWarnings("unchecked")
51-
public <T extends Object> @Nullable T getAs(@NotNull String name, @NotNull Class<T> clazz) {
53+
public synchronized <T extends Object> @Nullable T getAs(
54+
@NotNull String name, @NotNull Class<T> clazz) {
5255
Object hintValue = internalStorage.get(name);
5356

5457
if (clazz.isInstance(hintValue)) {
@@ -60,7 +63,7 @@ public void set(@NotNull String name, @Nullable Object hint) {
6063
}
6164
}
6265

63-
public void remove(@NotNull String name) {
66+
public synchronized void remove(@NotNull String name) {
6467
internalStorage.remove(name);
6568
}
6669

@@ -89,6 +92,23 @@ public void clearAttachments() {
8992
attachments.clear();
9093
}
9194

95+
/**
96+
* Clears all attributes added via {@link #set(String, Object)} Note: SDK internal attributes are
97+
* being kept. This is useful to avoid leaking any objects (e.g. Android activities) being
98+
* referenced.
99+
*/
100+
@ApiStatus.Internal
101+
public synchronized void clear() {
102+
final Iterator<Map.Entry<String, Object>> iterator = internalStorage.entrySet().iterator();
103+
104+
while (iterator.hasNext()) {
105+
final Map.Entry<String, Object> entry = iterator.next();
106+
if (entry.getKey() == null || !entry.getKey().startsWith("sentry:")) {
107+
iterator.remove();
108+
}
109+
}
110+
}
111+
92112
public void setScreenshot(@Nullable Attachment screenshot) {
93113
this.screenshot = screenshot;
94114
}

sentry/src/main/java/io/sentry/SentryClient.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ private boolean shouldApplyScopeData(
178178
final SentryEnvelope envelope =
179179
buildEnvelope(event, attachments, session, traceContext, null);
180180

181+
hint.clear();
181182
if (envelope != null) {
182183
transport.send(envelope, hint);
183184
}
@@ -483,6 +484,7 @@ public void captureSession(final @NotNull Session session, final @Nullable Hint
483484
}
484485

485486
try {
487+
hint.clear();
486488
transport.send(envelope, hint);
487489
} catch (IOException e) {
488490
options.getLogger().log(SentryLevel.ERROR, "Failed to capture envelope.", e);
@@ -588,6 +590,7 @@ public void captureSession(final @NotNull Session session, final @Nullable Hint
588590
buildEnvelope(
589591
transaction, filterForTransaction(getAttachments(hint)), null, traceContext, null);
590592

593+
hint.clear();
591594
if (envelope != null) {
592595
transport.send(envelope, hint);
593596
} else {

sentry/src/test/java/io/sentry/hints/HintTest.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package io.sentry.hints
22

33
import io.sentry.Attachment
4+
import io.sentry.CachedEvent
45
import io.sentry.Hint
6+
import io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT
57
import kotlin.test.Test
68
import kotlin.test.assertEquals
79
import kotlin.test.assertNotNull
@@ -197,6 +199,24 @@ class HintTest {
197199
assertEquals(listOf(attachment3, attachment4), hint.attachments)
198200
}
199201

202+
@Test
203+
fun `calling clear does not remove internal sentry attrs, attachments or screenshots`() {
204+
val userAttribute = "app_label"
205+
206+
val hint = Hint()
207+
hint.set(SENTRY_TYPE_CHECK_HINT, CachedEvent())
208+
hint.set(userAttribute, "test label")
209+
hint.addAttachment(newAttachment("test attachment"))
210+
hint.screenshot = newAttachment("2")
211+
212+
hint.clear()
213+
214+
assertNotNull(hint.get(SENTRY_TYPE_CHECK_HINT))
215+
assertNull(hint.get(userAttribute))
216+
assertEquals(1, hint.attachments.size)
217+
assertNotNull(hint.screenshot)
218+
}
219+
200220
companion object {
201221
fun newAttachment(content: String) = Attachment(content.toByteArray(), "$content.txt")
202222
}

0 commit comments

Comments
 (0)