Commits

Anonymous committed ffcfdd7

WW-2307 Check for overflows and underflow when doing numeric conversion

git-svn-id: http://svn.opensymphony.com/svn/xwork/trunk@1879e221344d-f017-0410-9bd5-d282ab1896d7

  • Participants
  • Parent commits 8c6f1c2

Comments (0)

Files changed (2)

File src/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverter.java

     private ObjectTypeDeterminer objectTypeDeterminer;
     private XWorkConverter xworkConverter;
     private ObjectFactory objectFactory;
-    
+
     @Inject
     public void setObjectTypeDeterminer(ObjectTypeDeterminer det) {
         this.objectTypeDeterminer = det;
             } else if (toType == BigInteger.class) {
                 return new BigInteger((String) value);
             } else if (toType.isPrimitive()) {
-                return super.convertValue(context, value, toType);
+                Object convertedValue = super.convertValue(context, value, toType);
+                String stringValue = (String) value;
+                if (!isInRange((Number)convertedValue, stringValue,  toType))
+                        throw new XWorkException("Overflow or underflow casting: \"" + stringValue + "\" into class " + convertedValue.getClass().getName());
+
+                return convertedValue;
             } else {
                 String stringValue = (String) value;
                 if (!toType.isPrimitive() && (stringValue == null || stringValue.length() == 0)) {
                     throw new XWorkException("Unparseable number: \"" + stringValue + "\" at position "
                             + parsePos.getIndex());
                 } else {
+                    if (!isInRange(number, stringValue,  toType))
+                        throw new XWorkException("Overflow or underflow casting: \"" + stringValue + "\" into class " + number.getClass().getName());
+                    
                     value = super.convertValue(context, number, toType);
                 }
             }
         return super.convertValue(context, value, toType);
     }
 
+    protected boolean isInRange(Number value, String stringValue, Class toType) {
+        Number bigValue = null;
+        Number lowerBound = null;
+        Number upperBound = null;
+
+        try {
+            if (double.class == toType || Double.class == toType) {
+                bigValue = new BigDecimal(stringValue);
+                lowerBound = BigDecimal.valueOf(Double.MIN_VALUE);
+                upperBound = BigDecimal.valueOf(Double.MAX_VALUE);
+            } else if (float.class == toType || Float.class == toType) {
+                bigValue = new BigDecimal(stringValue);
+                lowerBound = BigDecimal.valueOf(Float.MIN_VALUE);
+                upperBound = BigDecimal.valueOf(Float.MAX_VALUE);
+            } else if (byte.class == toType || Byte.class == toType) {
+                bigValue = new BigInteger(stringValue);
+                lowerBound = BigInteger.valueOf(Byte.MIN_VALUE);
+                upperBound = BigInteger.valueOf(Byte.MAX_VALUE);
+            } else if (char.class == toType || Character.class == toType) {
+                bigValue = new BigInteger(stringValue);
+                lowerBound = BigInteger.valueOf(Character.MIN_VALUE);
+                upperBound = BigInteger.valueOf(Character.MAX_VALUE);
+            } else if (short.class == toType || Short.class == toType) {
+                bigValue = new BigInteger(stringValue);
+                lowerBound = BigInteger.valueOf(Short.MIN_VALUE);
+                upperBound = BigInteger.valueOf(Short.MAX_VALUE);
+            } else if (int.class == toType || Integer.class == toType) {
+                bigValue = new BigInteger(stringValue);
+                lowerBound = BigInteger.valueOf(Integer.MIN_VALUE);
+                upperBound = BigInteger.valueOf(Integer.MAX_VALUE);
+            } else if (long.class == toType || Long.class == toType) {
+                bigValue = new BigInteger(stringValue);
+                lowerBound = BigInteger.valueOf(Long.MIN_VALUE);
+                upperBound = BigInteger.valueOf(Long.MAX_VALUE);
+            }
+        } catch (NumberFormatException e) {
+            //shoult it fail here? BigInteger doesnt seem to be so nice parsing numbers as NumberFormat
+            return true;
+        }
+
+        return ((Comparable)bigValue).compareTo(lowerBound) >= 0 && ((Comparable)bigValue).compareTo(upperBound) <= 0;
+    }
+
     protected boolean isIntegerType(Class type) {
         if (double.class == type || float.class == type || Double.class == type || Float.class == type
                 || char.class == type || Character.class == type) {

File src/test/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java

         assertEquals(new BigInteger("123"), converter.convertValue(context, null, null, null, "123", BigInteger.class));
     }
 
+    public void testOverflows() {
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Double.MAX_VALUE + "1", double.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Double.MIN_VALUE + "1", double.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Double.MAX_VALUE + "1", Double.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Double.MIN_VALUE + "1", Double.class));
+
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Float.MAX_VALUE + "1", float.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Float.MIN_VALUE + "1", float.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Float.MAX_VALUE + "1", Float.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Float.MIN_VALUE + "1", Float.class));
+
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Integer.MAX_VALUE + "1", int.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Integer.MIN_VALUE + "1", int.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Integer.MAX_VALUE + "1", Integer.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Integer.MIN_VALUE + "1", Integer.class));
+
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Byte.MAX_VALUE + "1", byte.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Byte.MIN_VALUE + "1", byte.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Byte.MAX_VALUE + "1", Byte.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Byte.MIN_VALUE + "1", Byte.class));
+
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Short.MAX_VALUE + "1", short.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Short.MIN_VALUE + "1", short.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Short.MAX_VALUE + "1", Short.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Short.MIN_VALUE + "1", Short.class));
+
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Long.MAX_VALUE + "1", long.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Long.MIN_VALUE + "1", long.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Long.MAX_VALUE + "1", Long.class));
+        assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, Long.MIN_VALUE + "1", Long.class));
+    }
+
     public void testStringToInt() {
         assertEquals(new Integer(123), converter.convertValue(context, null, null, null, "123", int.class));
         context.put(ActionContext.LOCALE, Locale.US);