From 9b9489c4b6e31e2cabf5ba70c8285f1d3c11a97e Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 19 Jun 2020 21:56:58 +0100 Subject: [PATCH] Catch IllegalReferenceCountException Closes gh-22594 --- .../core/codec/AbstractSingleValueEncoder.java | 5 +++-- .../core/io/buffer/DataBufferUtils.java | 18 +++++++++++++++--- .../http/codec/EncoderHttpMessageWriter.java | 5 +++-- .../multipart/MultipartHttpMessageWriter.java | 3 ++- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/codec/AbstractSingleValueEncoder.java b/spring-core/src/main/java/org/springframework/core/codec/AbstractSingleValueEncoder.java index 3a45507b03de..cdaba36bcc37 100644 --- a/spring-core/src/main/java/org/springframework/core/codec/AbstractSingleValueEncoder.java +++ b/spring-core/src/main/java/org/springframework/core/codec/AbstractSingleValueEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.springframework.core.ResolvableType; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.PooledDataBuffer; import org.springframework.lang.Nullable; import org.springframework.util.MimeType; @@ -51,7 +52,7 @@ public final Flux encode(Publisher inputStream, DataBuf return Flux.from(inputStream) .take(1) .concatMap(value -> encode(value, bufferFactory, elementType, mimeType, hints)) - .doOnDiscard(PooledDataBuffer.class, PooledDataBuffer::release); + .doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release); } /** diff --git a/spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java b/spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java index 6db32e406127..eb2927677cf2 100644 --- a/spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java +++ b/spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,6 +39,9 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import io.netty.util.IllegalReferenceCountException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.reactivestreams.Publisher; import org.reactivestreams.Subscription; import reactor.core.publisher.BaseSubscriber; @@ -60,6 +63,8 @@ */ public abstract class DataBufferUtils { + private final static Log logger = LogFactory.getLog(DataBufferUtils.class); + private static final Consumer RELEASE_CONSUMER = DataBufferUtils::release; @@ -494,7 +499,15 @@ public static boolean release(@Nullable DataBuffer dataBuffer) { if (dataBuffer instanceof PooledDataBuffer) { PooledDataBuffer pooledDataBuffer = (PooledDataBuffer) dataBuffer; if (pooledDataBuffer.isAllocated()) { - return pooledDataBuffer.release(); + try { + return pooledDataBuffer.release(); + } + catch (IllegalReferenceCountException ex) { + if (logger.isDebugEnabled()) { + logger.debug("RefCount already at 0", ex); + } + return false; + } } } return false; @@ -523,7 +536,6 @@ public static Consumer releaseConsumer() { * @return a buffer that is composed from the {@code dataBuffers} argument * @since 5.0.3 */ - @SuppressWarnings("unchecked") public static Mono join(Publisher dataBuffers) { return join(dataBuffers, -1); } diff --git a/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java index a5ed28274175..5a63145b4be9 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java @@ -29,6 +29,7 @@ import org.springframework.core.codec.Encoder; import org.springframework.core.codec.Hints; import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.PooledDataBuffer; import org.springframework.http.HttpLogging; import org.springframework.http.MediaType; @@ -126,13 +127,13 @@ public Mono write(Publisher inputStream, ResolvableType eleme .flatMap(buffer -> { message.getHeaders().setContentLength(buffer.readableByteCount()); return message.writeWith(Mono.just(buffer) - .doOnDiscard(PooledDataBuffer.class, PooledDataBuffer::release)); + .doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release)); }); } if (isStreamingMediaType(contentType)) { return message.writeAndFlushWith(body.map(buffer -> - Mono.just(buffer).doOnDiscard(PooledDataBuffer.class, PooledDataBuffer::release))); + Mono.just(buffer).doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release))); } return message.writeWith(body); diff --git a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java index 350d693cd318..1db1356751f3 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java @@ -40,6 +40,7 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.PooledDataBuffer; import org.springframework.core.log.LogFormatUtils; import org.springframework.http.HttpEntity; @@ -247,7 +248,7 @@ private Mono writeMultipart(MultiValueMap map, Flux body = Flux.fromIterable(map.entrySet()) .concatMap(entry -> encodePartValues(boundary, entry.getKey(), entry.getValue(), bufferFactory)) .concatWith(generateLastLine(boundary, bufferFactory)) - .doOnDiscard(PooledDataBuffer.class, PooledDataBuffer::release); + .doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release); return outputMessage.writeWith(body); }