Skip to content

Commit 3bfbbe8

Browse files
committed
Fix thread-safety issue in double-checked singleton instance creation.
1 parent 82e0d17 commit 3bfbbe8

4 files changed

Lines changed: 33 additions & 25 deletions

File tree

powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ private void setCorrelationIdFromNode(String correlationIdPath, JsonNode jsonNod
312312

313313
private byte[] bytesFromInputStreamSafely(final InputStream inputStream) throws IOException {
314314
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
315-
InputStreamReader reader = new InputStreamReader(inputStream, UTF_8)) {
316-
OutputStreamWriter writer = new OutputStreamWriter(out, UTF_8);
315+
InputStreamReader reader = new InputStreamReader(inputStream, UTF_8);
316+
OutputStreamWriter writer = new OutputStreamWriter(out, UTF_8)) {
317317
int n;
318318
char[] buffer = new char[4096];
319319
while (-1 != (n = reader.read(buffer))) {
@@ -326,7 +326,7 @@ private byte[] bytesFromInputStreamSafely(final InputStream inputStream) throws
326326

327327
private OutputStream prepareOutputStreamForLogging(Logging logging,
328328
Object[] proceedArgs) {
329-
if ((logging.logResponse() || POWERTOOLS_LOG_RESPONSE)) {
329+
if (logging.logResponse() || POWERTOOLS_LOG_RESPONSE) {
330330
OutputStream backupOutputStream = (OutputStream) proceedArgs[1];
331331
proceedArgs[1] = new ByteArrayOutputStream();
332332
return backupOutputStream;

powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManagerRegistry.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,16 @@
2020
import java.util.ArrayList;
2121
import java.util.List;
2222
import java.util.ServiceLoader;
23-
import java.util.concurrent.atomic.AtomicReference;
2423

2524
/**
2625
* Thread-safe singleton registry for LoggingManager instances.
2726
* Handles lazy loading and caching of the LoggingManager implementation.
2827
*/
2928
public final class LoggingManagerRegistry {
3029

31-
private static final AtomicReference<LoggingManager> instance = new AtomicReference<>();
30+
// Used with double-checked locking within getLoggingManger()
31+
@SuppressWarnings("java:S3077")
32+
private static volatile LoggingManager instance;
3233

3334
private LoggingManagerRegistry() {
3435
// Utility class
@@ -40,13 +41,13 @@ private LoggingManagerRegistry() {
4041
* @return the LoggingManager instance
4142
*/
4243
public static LoggingManager getLoggingManager() {
43-
LoggingManager manager = instance.get();
44+
LoggingManager manager = instance;
4445
if (manager == null) {
4546
synchronized (LoggingManagerRegistry.class) {
46-
manager = instance.get();
47+
manager = instance;
4748
if (manager == null) {
4849
manager = loadLoggingManager();
49-
instance.set(manager);
50+
instance = manager;
5051
}
5152
}
5253
}

powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/KeyBufferTest.java

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -248,16 +248,18 @@ void shouldBeThreadSafeForDifferentKeys() throws InterruptedException {
248248
});
249249
}
250250

251-
assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
252-
253-
// Verify each key has its events
254-
for (int i = 0; i < threadCount; i++) {
255-
String key = "key" + i;
256-
Deque<String> events = buffer.removeAll(key);
257-
assertThat(events).isNotNull().isNotEmpty();
251+
try {
252+
assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
253+
254+
// Verify each key has its events
255+
for (int i = 0; i < threadCount; i++) {
256+
String key = "key" + i;
257+
Deque<String> events = buffer.removeAll(key);
258+
assertThat(events).isNotNull().isNotEmpty();
259+
}
260+
} finally {
261+
executor.shutdown();
258262
}
259-
260-
executor.shutdown();
261263
}
262264

263265
@Test
@@ -281,12 +283,14 @@ void shouldBeThreadSafeForSameKey() throws InterruptedException {
281283
});
282284
}
283285

284-
assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
285-
286-
Deque<String> events = buffer.removeAll("sharedKey");
287-
assertThat(events).isNotNull().isNotEmpty();
286+
try {
287+
assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
288288

289-
executor.shutdown();
289+
Deque<String> events = buffer.removeAll("sharedKey");
290+
assertThat(events).isNotNull().isNotEmpty();
291+
} finally {
292+
executor.shutdown();
293+
}
290294
}
291295

292296
@Test

powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LoggingManagerRegistryTest.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,11 @@ void testGetLoggingManager_shouldBeThreadSafe() throws InterruptedException {
131131
}
132132

133133
// THEN
134-
latch.await(5, TimeUnit.SECONDS);
135-
executor.shutdown();
136-
assertThat(sharedInstance.get()).isNotNull();
134+
try {
135+
latch.await(5, TimeUnit.SECONDS);
136+
assertThat(sharedInstance.get()).isNotNull();
137+
} finally {
138+
executor.shutdown();
139+
}
137140
}
138141
}

0 commit comments

Comments
 (0)