Skip to content

Commit d69a082

Browse files
authored
fix: Don't use Java serialization for cluster metrics (#32748)
* it was possibly used for BigDecimal and BigInteger * might result in serialization errors during rolling update, but that should heal as soon as the rollout is completed
1 parent 0bbe6d5 commit d69a082

File tree

3 files changed

+50
-23
lines changed

3 files changed

+50
-23
lines changed

akka-cluster-metrics/src/main/scala/akka/cluster/metrics/Metric.scala

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,13 +260,15 @@ private[metrics] trait MetricNumericConverter {
260260
* May involve rounding or truncation.
261261
*/
262262
def convertNumber(from: Any): Either[Long, Double] = from match {
263-
case n: Int => Left(n)
264-
case n: Long => Left(n)
265-
case n: Double => Right(n)
266-
case n: Float => Right(n)
267-
case n: BigInt => Left(n.longValue)
268-
case n: BigDecimal => Right(n.doubleValue)
269-
case x => throw new IllegalArgumentException(s"Not a number [$x]")
263+
case n: Int => Left(n)
264+
case n: Long => Left(n)
265+
case n: Double => Right(n)
266+
case n: Float => Right(n)
267+
case n: BigInt => Left(n.longValue)
268+
case n: java.math.BigInteger => Left(n.longValue)
269+
case n: BigDecimal => Right(n.doubleValue)
270+
case n: java.math.BigDecimal => Right(n.doubleValue)
271+
case x => throw new IllegalArgumentException(s"Not a number [$x]")
270272
}
271273

272274
}

akka-cluster-metrics/src/main/scala/akka/cluster/metrics/protobuf/MessageSerializer.scala

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import akka.serialization.{ BaseSerializer, SerializationExtension, SerializerWi
2222
import akka.util.ClassLoaderObjectInputStream
2323
import scala.jdk.CollectionConverters._
2424

25+
import akka.serialization.DisabledJavaSerializer
26+
2527
/**
2628
* Protobuf serializer for [[akka.cluster.metrics.ClusterMetricsMessage]] types.
2729
*/
@@ -186,23 +188,35 @@ class MessageSerializer(val system: ExtendedActorSystem) extends SerializerWithS
186188
cm.NodeMetrics.EWMA.newBuilder().setValue(x.value).setAlpha(x.alpha)
187189
}
188190

189-
def numberToProto(number: Number): cm.NodeMetrics.Number.Builder = {
191+
@tailrec def numberToProto(number: Number): cm.NodeMetrics.Number.Builder = {
190192
import cm.NodeMetrics.Number
191193
import cm.NodeMetrics.NumberType
192194
number match {
193195
case n: jl.Double => Number.newBuilder().setType(NumberType.Double).setValue64(jl.Double.doubleToLongBits(n))
194196
case n: jl.Long => Number.newBuilder().setType(NumberType.Long).setValue64(n)
195197
case n: jl.Float => Number.newBuilder().setType(NumberType.Float).setValue32(jl.Float.floatToIntBits(n))
196198
case n: jl.Integer => Number.newBuilder().setType(NumberType.Integer).setValue32(n)
199+
case n: java.math.BigInteger =>
200+
numberToProto(n.longValue) // this truncation is anyway in MetricNumericConverter
201+
case n: BigInt => numberToProto(n.toLong) // this truncation is anyway in MetricNumericConverter
202+
case n: java.math.BigDecimal =>
203+
numberToProto(n.doubleValue) // this rounding is anyway in MetricNumericConverter
204+
case n: BigDecimal => numberToProto(n.toDouble) // this rounding is anyway in MetricNumericConverter
197205
case _ =>
198-
val bos = new ByteArrayOutputStream
199-
val out = new ObjectOutputStream(bos)
200-
out.writeObject(number)
201-
out.close()
202-
Number
203-
.newBuilder()
204-
.setType(NumberType.Serialized)
205-
.setSerialized(ByteStringUtils.toProtoByteStringUnsafe(bos.toByteArray))
206+
if (system.settings.AllowJavaSerialization) {
207+
val bos = new ByteArrayOutputStream
208+
val out = new ObjectOutputStream(bos)
209+
out.writeObject(number)
210+
out.close()
211+
Number
212+
.newBuilder()
213+
.setType(NumberType.Serialized)
214+
.setSerialized(ByteStringUtils.toProtoByteStringUnsafe(bos.toByteArray))
215+
} else {
216+
// this is the default, and it shouldn't happen since all number types should be covered above
217+
throw throw new DisabledJavaSerializer.JavaSerializationException(
218+
s"Unsupported number [${number.getClass.getName}], when Java serialization is disabled")
219+
}
206220
}
207221
}
208222

@@ -253,12 +267,18 @@ class MessageSerializer(val system: ExtendedActorSystem) extends SerializerWithS
253267
case NumberType.Float_VALUE => jl.Float.intBitsToFloat(number.getValue32)
254268
case NumberType.Integer_VALUE => number.getValue32
255269
case NumberType.Serialized_VALUE =>
256-
val in = new ClassLoaderObjectInputStream(
257-
system.dynamicAccess.classLoader,
258-
new ByteArrayInputStream(number.getSerialized.toByteArray))
259-
val obj = in.readObject
260-
in.close()
261-
obj.asInstanceOf[jl.Number]
270+
if (system.settings.AllowJavaSerialization) {
271+
val in = new ClassLoaderObjectInputStream(
272+
system.dynamicAccess.classLoader,
273+
new ByteArrayInputStream(number.getSerialized.toByteArray))
274+
val obj = in.readObject
275+
in.close()
276+
obj.asInstanceOf[jl.Number]
277+
} else {
278+
// this is the default, and it shouldn't happen since all number types should be covered above
279+
throw throw new DisabledJavaSerializer.JavaSerializationException(
280+
s"Unsupported number [${number.getClass.getName}], when Java serialization is disabled")
281+
}
262282
}
263283
}
264284

akka-cluster-metrics/src/test/scala/akka/cluster/metrics/protobuf/MessageSerializerSpec.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package akka.cluster.metrics.protobuf
66

7+
import java.math.BigInteger
8+
79
import akka.actor.{ Address, ExtendedActorSystem }
810
import akka.cluster.MemberStatus
911
import akka.cluster.TestMember
@@ -52,7 +54,10 @@ class MessageSerializerSpec extends AkkaSpec("""
5254
Metric("bar2", Float.MaxValue, None),
5355
Metric("bar3", Int.MaxValue, None),
5456
Metric("bar4", Long.MaxValue, None),
55-
Metric("bar5", BigInt(Long.MaxValue), None)))))
57+
Metric("bar5", BigInt(Long.MaxValue), None),
58+
Metric("bar6", new BigInteger(s"${Long.MaxValue}"), None),
59+
Metric("bar7", BigDecimal.exact(s"${Long.MaxValue}.0"), None),
60+
Metric("bar8", new java.math.BigDecimal(s"${Long.MaxValue}.0"), None)))))
5661

5762
checkSerialization(MetricsGossipEnvelope(a1.address, metricsGossip, true))
5863

0 commit comments

Comments
 (0)