Fix parsing decimal values used with integral numbers. Fixes #9090
authorMarek Safar <marek.safar@gmail.com>
Tue, 19 Mar 2013 11:25:24 +0000 (12:25 +0100)
committerMarek Safar <marek.safar@gmail.com>
Tue, 19 Mar 2013 11:27:06 +0000 (12:27 +0100)
mcs/class/corlib/System/Int32.cs
mcs/class/corlib/System/Int64.cs
mcs/class/corlib/System/UInt32.cs
mcs/class/corlib/System/UInt64.cs
mcs/class/corlib/Test/System/Int32Test.cs
mcs/class/corlib/Test/System/Int64Test.cs
mcs/class/corlib/Test/System/UInt32Test.cs
mcs/class/corlib/Test/System/UInt64Test.cs

index b65e3b106964eae061f23d359a90f40f4fe516c4..b78c0a5b14ec32b54a26167defe075bf8f6734db 100644 (file)
@@ -461,10 +461,9 @@ namespace System {
 
                        int number = 0;
                        int nDigits = 0;
-                       bool decimalPointFound = false;
+                       int decimalPointPos = -1;
                        int digitValue;
                        char hexDigit;
-                       int exponent = 0;
                                
                        // Number stuff
                        do {
@@ -474,18 +473,20 @@ namespace System {
                                            (FindOther (ref pos, s, nfi.NumberGroupSeparator)
                                                || FindOther (ref pos, s, nfi.CurrencyGroupSeparator)))
                                            continue;
-                                       else
-                                       if (!decimalPointFound && AllowDecimalPoint &&
+
+                                       if (AllowDecimalPoint && decimalPointPos < 0 &&
                                            (FindOther (ref pos, s, nfi.NumberDecimalSeparator)
                                                || FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
-                                           decimalPointFound = true;
+                                               decimalPointPos = nDigits;
                                            continue;
                                        }
 
                                        break;
                                }
+
+                               nDigits++;
+
                                if (AllowHexSpecifier) {
-                                       nDigits++;
                                        hexDigit = s [pos++];
                                        if (Char.IsDigit (hexDigit))
                                                digitValue = (int) (hexDigit - '0');
@@ -503,34 +504,18 @@ namespace System {
                                        } else {
                                                number = (int)checked (unumber * 16u + (uint)digitValue);
                                        }
+
+                                       continue;
                                }
-                               else if (decimalPointFound) {
-                                       nDigits++;
-                                       // Allows decimal point as long as it's only 
-                                       // followed by zeroes.
-                                       if (s [pos++] != '0') {
-                                               if (!tryParse)
-                                                       exc = new OverflowException ("Value too large or too " +
-                                                                       "small.");
-                                               return false;
-                                       }
-                               }
-                               else {
-                                       nDigits++;
-
-                                       try {
-                                               // Calculations done as negative
-                                               // (abs (MinValue) > abs (MaxValue))
-                                               number = checked (
-                                                       number * 10 - 
-                                                       (int) (s [pos++] - '0')
-                                                       );
-                                       } catch (OverflowException) {
-                                               if (!tryParse)
-                                                       exc = new OverflowException ("Value too large or too " +
-                                                                       "small.");
-                                               return false;
-                                       }
+
+                               try {
+                                       // Calculations done as negative
+                                       // (abs (MinValue) > abs (MaxValue))
+                                       number = checked (number * 10 - (int) (s [pos++] - '0'));
+                               } catch (OverflowException) {
+                                       if (!tryParse)
+                                               exc = new OverflowException ("Value too large or too small.");
+                                       return false;
                                }
                        } while (pos < s.Length);
 
@@ -541,6 +526,7 @@ namespace System {
                                return false;
                        }
 
+                       int exponent = 0;
                        if (AllowExponent)
                                if (FindExponent (ref pos, s, ref exponent, tryParse, ref exc) && exc != null)
                                        return false;
@@ -599,11 +585,28 @@ namespace System {
                                        number = checked (-number);
                        }
 
-                       // result *= 10^exponent
-                       if (exponent > 0) {
+                       if (decimalPointPos >= 0)
+                               exponent = exponent - nDigits + decimalPointPos;
+                       
+                       if (exponent < 0) {
+                               //
+                               // Any non-zero values after decimal point are not allowed
+                               //
+                               int remainder;
+                               number = Math.DivRem (number, (int) Math.Pow (10, -exponent), out remainder);
+                               if (remainder != 0) {
+                                       if (!tryParse)
+                                               exc = new OverflowException ("Value too large or too small.");
+                                       return false;
+                               }
+                       } else if (exponent > 0) {
+                               //
+                               // result *= 10^exponent
+                               //
                                // Reduce the risk of throwing an overflow exc
+                               //
                                double res = checked (Math.Pow (10, exponent) * number);
-                               if (res < Int32.MinValue || res > Int32.MaxValue) {
+                               if (res < MinValue || res > MaxValue) {
                                        if (!tryParse)
                                                exc = new OverflowException ("Value too large or too small.");
                                        return false;
index b96cfdb7f8a3625db7aaeecacb459e176f08c753..09538f8ea6e59eca30c9301f37bdd7552e96d617 100644 (file)
@@ -293,10 +293,9 @@ namespace System {
                        
                        long number = 0;
                        int nDigits = 0;
-                       bool decimalPointFound = false;
+                       int decimalPointPos = -1;
                        int digitValue;
                        char hexDigit;
-                       int exponent = 0;
                                
                        // Number stuff
                        do {
@@ -306,18 +305,20 @@ namespace System {
                                            (Int32.FindOther (ref pos, s, nfi.NumberGroupSeparator)
                                                || Int32.FindOther (ref pos, s, nfi.CurrencyGroupSeparator)))
                                            continue;
-                                       else
-                                       if (!decimalPointFound && AllowDecimalPoint &&
+
+                                       if (AllowDecimalPoint && decimalPointPos < 0 &&
                                            (Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)
                                                || Int32.FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
-                                           decimalPointFound = true;
+                                           decimalPointPos = nDigits;
                                            continue;
                                        }
 
                                        break;
                                }
+
+                               nDigits++;
+
                                if (AllowHexSpecifier) {
-                                       nDigits++;
                                        hexDigit = s [pos++];
                                        if (Char.IsDigit (hexDigit))
                                                digitValue = (int) (hexDigit - '0');
@@ -336,35 +337,19 @@ namespace System {
                                                        exc = e;
                                                return false;
                                        }
-                               }
-                               else if (decimalPointFound) {
-                                       nDigits++;
-                                       // Allows decimal point as long as it's only 
-                                       // followed by zeroes.
-                                       if (s [pos++] != '0') {
-                                               if (!tryParse)
-                                                       exc = new OverflowException ("Value too large or too " +
-                                                                       "small.");
-                                               return false;
-                                       }
-                               }
-                               else {
-                                       nDigits++;
 
-                                       try {
-                                               // Calculations done as negative
-                                               // (abs (MinValue) > abs (MaxValue))
-                                               number = checked (
-                                                       number * 10 - 
-                                                       (long) (s [pos++] - '0')
-                                                       );
-                                       } catch (OverflowException) {
-                                               if (!tryParse)
-                                                       exc = new OverflowException ("Value too large or too " +
-                                                                       "small.");
-                                               return false;
-                                       }
+                                       continue;
                                }
+
+                               try {
+                                       // Calculations done as negative
+                                       // (abs (MinValue) > abs (MaxValue))
+                                       number = checked (number * 10 - (long) (s [pos++] - '0'));
+                               } catch (OverflowException) {
+                                       if (!tryParse)
+                                               exc = new OverflowException ("Value too large or too small.");
+                                       return false;
+                               }                               
                        } while (pos < s.Length);
 
                        // Post number stuff
@@ -374,6 +359,7 @@ namespace System {
                                return false;
                        }
 
+                       int exponent = 0;
                        if (AllowExponent)
                                if (Int32.FindExponent (ref pos, s, ref exponent, tryParse, ref exc) && exc != null)
                                        return false;
@@ -431,17 +417,34 @@ namespace System {
                                }
                        }
 
-                       // result *= 10^exponent
-                       if (exponent > 0) {
+                       if (decimalPointPos >= 0)
+                               exponent = exponent - nDigits + decimalPointPos;
+                       
+                       if (exponent < 0) {
+                               //
+                               // Any non-zero values after decimal point are not allowed
+                               //
+                               long remainder;
+                               number = Math.DivRem (number, (long) Math.Pow (10, -exponent), out remainder);
+                               if (remainder != 0) {
+                                       if (!tryParse)
+                                               exc = new OverflowException ("Value too large or too small.");
+                                       return false;
+                               }
+                       } else if (exponent > 0) {
+                               //
+                               // result *= 10^exponent
+                               //
                                // Reduce the risk of throwing an overflow exc
+                               //
                                double res = checked (Math.Pow (10, exponent) * number);
-                               if (res < Int32.MinValue || res > Int32.MaxValue) {
+                               if (res < MinValue || res > MaxValue) {
                                        if (!tryParse)
                                                exc = new OverflowException ("Value too large or too small.");
                                        return false;
                                }
 
-                               number = (long) res;
+                               number = (long)res;
                        }
 
                        result = number;
index 819970e7568bd022de145bd34f5a6681938966be..f78ee9dbab20297f91be7f9e9db1cd9425a01742 100644 (file)
@@ -271,10 +271,9 @@ namespace System
 
                        uint number = 0;
                        int nDigits = 0;
-                       bool decimalPointFound = false;
+                       int decimalPointPos = -1;
                        uint digitValue;
                        char hexDigit;
-                       int exponent = 0;
 
                        // Number stuff
                        // Just the same as Int32, but this one adds instead of substract
@@ -285,18 +284,20 @@ namespace System
                                            (Int32.FindOther (ref pos, s, nfi.NumberGroupSeparator)
                                                || Int32.FindOther (ref pos, s, nfi.CurrencyGroupSeparator)))
                                                continue;
-                                       else
-                                               if (!decimalPointFound && AllowDecimalPoint &&
+                                       
+                                       if (AllowDecimalPoint && decimalPointPos < 0 &&
                                            (Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)
                                                || Int32.FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
-                                                       decimalPointFound = true;
+                                                       decimalPointPos = nDigits;
                                                        continue;
                                                }
 
                                        break;
                                }
+
+                               nDigits++;
+
                                if (AllowHexSpecifier) {
-                                       nDigits++;
                                        hexDigit = s [pos++];
                                        if (Char.IsDigit (hexDigit))
                                                digitValue = (uint) (hexDigit - '0');
@@ -313,28 +314,16 @@ namespace System
                                                number = (uint) l;
                                        } else
                                                number = checked (number * 16 + digitValue);
+
+                                       continue;
                                }
-                               else if (decimalPointFound) {
-                                       nDigits++;
-                                       // Allows decimal point as long as it's only 
-                                       // followed by zeroes.
-                                       if (s [pos++] != '0') {
-                                               if (!tryParse)
-                                                       exc = new OverflowException (Locale.GetText ("Value too large or too small."));
-                                               return false;
-                                       }
-                               }
-                               else {
-                                       nDigits++;
 
-                                       try {
-                                               number = checked (number * 10 + (uint) (s [pos++] - '0'));
-                                       }
-                                       catch (OverflowException) {
-                                               if (!tryParse)
-                                                       exc = new OverflowException (Locale.GetText ("Value too large or too small."));
-                                               return false;
-                                       }
+                               try {
+                                       number = checked (number * 10 + (uint) (s [pos++] - '0'));
+                               } catch (OverflowException) {
+                                       if (!tryParse)
+                                               exc = new OverflowException (Locale.GetText ("Value too large or too small."));
+                                       return false;
                                }
                        } while (pos < s.Length);
 
@@ -345,6 +334,7 @@ namespace System
                                return false;
                        }
 
+                       int exponent = 0;
                        if (AllowExponent)
                                if (Int32.FindExponent (ref pos, s, ref exponent, tryParse, ref exc) && exc != null)
                                        return false;
@@ -400,21 +390,37 @@ namespace System
                                return false;
                        }
 
-                       // result *= 10^exponent
-                       if (exponent > 0) {
+                       if (decimalPointPos >= 0)
+                               exponent = exponent - nDigits + decimalPointPos;
+                       
+                       if (exponent < 0) {
+                               //
+                               // Any non-zero values after decimal point are not allowed
+                               //
+                               long remainder;
+                               number = (uint) Math.DivRem (number, (int) Math.Pow (10, -exponent), out remainder);
+                               if (remainder != 0) {
+                                       if (!tryParse)
+                                               exc = new OverflowException ("Value too large or too small.");
+                                       return false;
+                               }
+                       } else if (exponent > 0) {
+                               //
+                               // result *= 10^exponent
+                               //
                                // Reduce the risk of throwing an overflow exc
+                               //
                                double res = checked (Math.Pow (10, exponent) * number);
-                               if (res < Int32.MinValue || res > Int32.MaxValue) {
+                               if (res < MinValue || res > MaxValue) {
                                        if (!tryParse)
                                                exc = new OverflowException ("Value too large or too small.");
                                        return false;
                                }
 
-                               number = (uint) res;
+                               number = (uint)res;
                        }
 
                        result = number;
-
                        return true;
                }
 
index 922e763e0a681de5135eaf98269bb3b0af27a12f..1ac283149a609796ad3c88d0bbe9b4eb2ec9c3a4 100644 (file)
@@ -294,10 +294,9 @@ namespace System
 
                        ulong number = 0;
                        int nDigits = 0;
-                       bool decimalPointFound = false;
+                       int decimalPointPos = -1;
                        ulong digitValue;
                        char hexDigit;
-                       int exponent = 0;
 
                        // Number stuff
                        // Just the same as Int32, but this one adds instead of substract
@@ -308,18 +307,20 @@ namespace System
                                            (Int32.FindOther (ref pos, s, nfi.NumberGroupSeparator)
                                                || Int32.FindOther (ref pos, s, nfi.CurrencyGroupSeparator)))
                                                continue;
-                                       else
-                                               if (!decimalPointFound && AllowDecimalPoint && 
+                                       
+                                       if (AllowDecimalPoint && decimalPointPos < 0 &&
                                            (Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)
                                                || Int32.FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
-                                                       decimalPointFound = true;
+                                                       decimalPointPos = nDigits;
                                                        continue;
                                                }
 
                                        break;
                                }
+
+                               nDigits++;
+
                                if (AllowHexSpecifier) {
-                                       nDigits++;
                                        hexDigit = s [pos++];
                                        if (Char.IsDigit (hexDigit))
                                                digitValue = (ulong) (hexDigit - '0');
@@ -338,28 +339,16 @@ namespace System
                                                        return false;
                                        } else
                                                number = checked (number * 16 + digitValue);
+
+                                       continue;
                                }
-                               else if (decimalPointFound) {
-                                       nDigits++;
-                                       // Allows decimal point as long as it's only 
-                                       // followed by zeroes.
-                                       if (s [pos++] != '0') {
-                                               if (!tryParse)
-                                                       exc = new OverflowException (Locale.GetText ("Value too large or too small."));
-                                               return false;
-                                       }
-                               }
-                               else {
-                                       nDigits++;
 
-                                       try {
-                                               number = checked (number * 10 + (ulong) (s [pos++] - '0'));
-                                       }
-                                       catch (OverflowException) {
-                                               if (!tryParse)
-                                                       exc = new OverflowException (Locale.GetText ("Value too large or too small."));
-                                               return false;
-                                       }
+                               try {
+                                       number = checked (number * 10 + (ulong) (s [pos++] - '0'));
+                               } catch (OverflowException) {
+                                       if (!tryParse)
+                                               exc = new OverflowException (Locale.GetText ("Value too large or too small."));
+                                       return false;
                                }
                        } while (pos < s.Length);
 
@@ -370,6 +359,7 @@ namespace System
                                return false;
                        }
 
+                       int exponent = 0;
                        if (AllowExponent)
                                if (Int32.FindExponent (ref pos, s, ref exponent, tryParse, ref exc) && exc != null)
                                        return false;
@@ -425,17 +415,34 @@ namespace System
                                return false;
                        }
 
-                       // result *= 10^exponent
-                       if (exponent > 0) {
+                       if (decimalPointPos >= 0)
+                               exponent = exponent - nDigits + decimalPointPos;
+                       
+                       if (exponent < 0) {
+                               //
+                               // Any non-zero values after decimal point are not allowed
+                               //
+                               long remainder;
+                               number = (ulong) Math.DivRem ((long) number, (long) Math.Pow (10, -exponent), out remainder);
+                               if (remainder != 0) {
+                                       if (!tryParse)
+                                               exc = new OverflowException ("Value too large or too small.");
+                                       return false;
+                               }
+                       } else if (exponent > 0) {
+                               //
+                               // result *= 10^exponent
+                               //
                                // Reduce the risk of throwing an overflow exc
+                               //
                                double res = checked (Math.Pow (10, exponent) * number);
-                               if (res < Int32.MinValue || res > Int32.MaxValue) {
+                               if (res < MinValue || res > MaxValue) {
                                        if (!tryParse)
                                                exc = new OverflowException ("Value too large or too small.");
                                        return false;
                                }
 
-                               number = (ulong) res;
+                               number = (ulong)res;
                        }
 
                        result = number;
index 60c756a903431d66a9a99774520b7b700833cad2..128cc19790df3809993d52f43a8308e197ea9124 100644 (file)
@@ -274,6 +274,10 @@ public class Int32Test
                Assert.AreEqual (2000000, Int32.Parse ("2E6", NumberStyles.AllowExponent), "A#4");
                Assert.AreEqual (200, Int32.Parse ("2E+2", NumberStyles.AllowExponent), "A#5");
                Assert.AreEqual (2, Int32.Parse ("2", NumberStyles.AllowExponent), "A#6");
+               Assert.AreEqual (21, Int32.Parse ("2.1E1", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#7");
+               Assert.AreEqual (520, Int32.Parse (".52E3", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#8");
+               Assert.AreEqual (32500000, Int32.Parse ("32.5E6", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#9");
+               Assert.AreEqual (890, Int32.Parse ("8.9000E2", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#10");
 
                try {
                        Int32.Parse ("2E");
@@ -323,6 +327,12 @@ public class Int32Test
                        Assert.Fail ("B#8");
                } catch (FormatException) {
                }
+
+               try {
+                       Int32.Parse ("2.09E1",  NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent);
+                       Assert.Fail ("B#9");
+               } catch (OverflowException) {
+               }               
        }
 
        [Test]
index b1b6b079b40e13beb8f68e50c98b76e32af8576e..6ad5e36ce4882974205e66d3965a86824265d52f 100644 (file)
@@ -330,6 +330,10 @@ public class Int64Test
                Assert.AreEqual (2000000, long.Parse ("2E6", NumberStyles.AllowExponent), "A#4");
                Assert.AreEqual (200, long.Parse ("2E+2", NumberStyles.AllowExponent), "A#5");
                Assert.AreEqual (2, long.Parse ("2", NumberStyles.AllowExponent), "A#6");
+               Assert.AreEqual (21, long.Parse ("2.1E1", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#7");
+               Assert.AreEqual (520, long.Parse (".52E3", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#8");
+               Assert.AreEqual (32500000, long.Parse ("32.5E6", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#9");
+               Assert.AreEqual (890, long.Parse ("8.9000E2", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#10");            
 
                try {
                        long.Parse ("2E");
@@ -379,6 +383,12 @@ public class Int64Test
                        Assert.Fail ("B#8");
                } catch (FormatException) {
                }
+
+               try {
+                       long.Parse ("2.09E1",  NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent);
+                       Assert.Fail ("B#9");
+               } catch (OverflowException) {
+               }
        }
 
        [Test]
index 24396d72484c3aaea7f35c6788e60daa206d71a3..20f5a299e36fdf12f742ee4c953dde0a8f9f90e6 100644 (file)
@@ -214,6 +214,10 @@ public class UInt32Test
                Assert.AreEqual (2000000, uint.Parse ("2E6", NumberStyles.AllowExponent), "A#4");
                Assert.AreEqual (200, uint.Parse ("2E+2", NumberStyles.AllowExponent), "A#5");
                Assert.AreEqual (2, uint.Parse ("2", NumberStyles.AllowExponent), "A#6");
+               Assert.AreEqual (21, uint.Parse ("2.1E1", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#7");
+               Assert.AreEqual (520, uint.Parse (".52E3", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#8");
+               Assert.AreEqual (32500000, uint.Parse ("32.5E6", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#9");
+               Assert.AreEqual (890, uint.Parse ("8.9000E2", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#10");            
 
                try {
                        uint.Parse ("2E");
@@ -263,6 +267,12 @@ public class UInt32Test
                        Assert.Fail ("B#8");
                } catch (FormatException) {
                }
+
+               try {
+                       uint.Parse ("2.09E1",  NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent);
+                       Assert.Fail ("B#9");
+               } catch (OverflowException) {
+               }
        }
 
        [Test]
index 335d216a4fc2b0b67666bf14c6188d79b154b352..3fbf591517be0614e35ca171d86b9f9f8a93d612 100644 (file)
@@ -203,6 +203,10 @@ public class UInt64Test
                Assert.AreEqual (2000000, ulong.Parse ("2E6", NumberStyles.AllowExponent), "A#4");
                Assert.AreEqual (200, ulong.Parse ("2E+2", NumberStyles.AllowExponent), "A#5");
                Assert.AreEqual (2, ulong.Parse ("2", NumberStyles.AllowExponent), "A#6");
+               Assert.AreEqual (21, ulong.Parse ("2.1E1", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#7");
+               Assert.AreEqual (520, ulong.Parse (".52E3", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#8");
+               Assert.AreEqual (32500000, ulong.Parse ("32.5E6", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#9");
+               Assert.AreEqual (890, ulong.Parse ("8.9000E2", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent), "A#10");           
 
                try {
                        ulong.Parse ("2E");
@@ -252,6 +256,12 @@ public class UInt64Test
                        Assert.Fail ("B#8");
                } catch (FormatException) {
                }
+
+               try {
+                       ulong.Parse ("2.09E1",  NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent);
+                       Assert.Fail ("B#9");
+               } catch (OverflowException) {
+               }
        }
 
        [Test]