From 8aa09afd8b65db0a3ebfd4ea674c40e29382eec6 Mon Sep 17 00:00:00 2001 From: Naveed Khan Date: Fri, 26 Jun 2026 22:09:00 +0530 Subject: [PATCH] reject out-of-range long and float values in NumberConverter The Long branch had no bounds check and the Float branch checked only the upper bound, so out-of-range input was silently clamped to Long.MAX_VALUE or to -Infinity instead of throwing. Add the missing checks mirroring the byte/short/int branches. Ports the master fix (#404) to 1.X. --- .../beanutils/converters/NumberConverter.java | 12 +++++ .../converters/FloatConverterTest.java | 17 ++++++- .../converters/LongConverterTest.java | 50 +++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/beanutils/converters/NumberConverter.java b/src/main/java/org/apache/commons/beanutils/converters/NumberConverter.java index b9001fc69..eea88532f 100644 --- a/src/main/java/org/apache/commons/beanutils/converters/NumberConverter.java +++ b/src/main/java/org/apache/commons/beanutils/converters/NumberConverter.java @@ -481,6 +481,14 @@ private T toNumber(final Class sourceType, final Class targetType, fin // Long if (targetType.equals(Long.class)) { + if (value.doubleValue() > Long.MAX_VALUE) { + throw new ConversionException(toString(sourceType) + " value '" + value + + "' is too large for " + toString(targetType)); + } + if (value.doubleValue() < Long.MIN_VALUE) { + throw new ConversionException(toString(sourceType) + " value '" + value + + "' is too small " + toString(targetType)); + } return targetType.cast(Long.valueOf(value.longValue())); } @@ -490,6 +498,10 @@ private T toNumber(final Class sourceType, final Class targetType, fin throw new ConversionException(toString(sourceType) + " value '" + value + "' is too large for " + toString(targetType)); } + if (value.doubleValue() < -Float.MAX_VALUE) { + throw new ConversionException(toString(sourceType) + " value '" + value + + "' is too small " + toString(targetType)); + } return targetType.cast(Float.valueOf(value.floatValue())); } diff --git a/src/test/java/org/apache/commons/beanutils/converters/FloatConverterTest.java b/src/test/java/org/apache/commons/beanutils/converters/FloatConverterTest.java index 373cdc1af..b55fdb68c 100644 --- a/src/test/java/org/apache/commons/beanutils/converters/FloatConverterTest.java +++ b/src/test/java/org/apache/commons/beanutils/converters/FloatConverterTest.java @@ -67,12 +67,17 @@ public void testInvalidAmount() { final Converter converter = makeConverter(); final Class clazz = Float.class; - final Double max = Double.valueOf(Float.MAX_VALUE); - final Double tooBig = Double.valueOf(Double.MAX_VALUE); + final Double max = Double.valueOf(Float.MAX_VALUE); + final Double min = Double.valueOf(-Float.MAX_VALUE); + final Double tooBig = Double.valueOf(Double.MAX_VALUE); + final Double tooSmall = Double.valueOf(-Double.MAX_VALUE); // Maximum assertEquals("Maximum", Float.valueOf(Float.MAX_VALUE), converter.convert(clazz, max)); + // Minimum + assertEquals("Minimum", Float.valueOf(-Float.MAX_VALUE), converter.convert(clazz, min)); + // Too Large try { assertEquals("Too Big", null, converter.convert(clazz, tooBig)); @@ -80,6 +85,14 @@ public void testInvalidAmount() { } catch (final Exception e) { // expected result } + + // Too Small + try { + assertEquals("Too Small", null, converter.convert(clazz, tooSmall)); + fail("Less than minimum, expected ConversionException"); + } catch (final Exception e) { + // expected result + } } public void testSimpleConversion() throws Exception { diff --git a/src/test/java/org/apache/commons/beanutils/converters/LongConverterTest.java b/src/test/java/org/apache/commons/beanutils/converters/LongConverterTest.java index ddfbc85f7..99beeeac0 100644 --- a/src/test/java/org/apache/commons/beanutils/converters/LongConverterTest.java +++ b/src/test/java/org/apache/commons/beanutils/converters/LongConverterTest.java @@ -17,6 +17,9 @@ package org.apache.commons.beanutils.converters; +import java.math.BigInteger; +import java.util.Locale; + import org.apache.commons.beanutils.Converter; /** @@ -60,6 +63,53 @@ public void tearDown() throws Exception { converter = null; } + /** + * Test Invalid Amounts (too big/small) + */ + public void testInvalidAmount() { + final Converter converter = makeConverter(); + final Class clazz = Long.class; + + // Boundaries still convert + assertEquals("Minimum", Long.valueOf(Long.MIN_VALUE), converter.convert(clazz, Long.valueOf(Long.MIN_VALUE))); + assertEquals("Maximum", Long.valueOf(Long.MAX_VALUE), converter.convert(clazz, Long.valueOf(Long.MAX_VALUE))); + + // Out of range values must be rejected, not silently truncated/clamped + final BigInteger tooSmall = BigInteger.valueOf(Long.MIN_VALUE).multiply(BigInteger.TEN); + final BigInteger tooBig = BigInteger.valueOf(Long.MAX_VALUE).multiply(BigInteger.TEN); + + // Too Small + try { + converter.convert(clazz, tooSmall); + fail("Less than minimum, expected ConversionException"); + } catch (final Exception e) { + // expected result + } + + // Too Large + try { + converter.convert(clazz, tooBig); + fail("More than maximum, expected ConversionException"); + } catch (final Exception e) { + // expected result + } + } + + /** + * A locale-parsed String beyond long range comes back from DecimalFormat as a Double and must be + * rejected rather than clamped to Long.MAX_VALUE. + */ + public void testLocaleStringOutOfRange() { + final NumberConverter converter = makeConverter(); + converter.setLocale(Locale.US); + try { + converter.convert(Long.class, "99999999999999999999"); + fail("More than maximum, expected ConversionException"); + } catch (final Exception e) { + // expected result + } + } + public void testSimpleConversion() throws Exception { final String[] message= { "from String",