Bug 393832 - svg circle with infinite radius causes hang r=jwatt a=ss
authorRobert Longson <longsonr@gmail.com>
Wed, 29 Jul 2009 14:33:58 -0400
changeset 26163 131947ecddd4dcd13c07f6b97429a5d2e51b330c
parent 26162 ead6f7b539e139639ae4a1512a86cd49d24c2b82
child 26164 89d25217b0b2a259beb82ef7c03caeae4add1f3d
push id1834
push userjdrew@mozilla.com
push dateWed, 29 Jul 2009 18:35:07 +0000
reviewersjwatt, ss
bugs393832
milestone1.9.1.2pre
Bug 393832 - svg circle with infinite radius causes hang r=jwatt a=ss
content/svg/content/src/nsSVGAngle.cpp
content/svg/content/src/nsSVGDataParser.cpp
content/svg/content/src/nsSVGElement.cpp
content/svg/content/src/nsSVGLength.cpp
content/svg/content/src/nsSVGLength2.cpp
content/svg/content/src/nsSVGNumber.cpp
content/svg/content/src/nsSVGNumber2.cpp
content/svg/content/src/nsSVGNumberList.cpp
content/svg/content/src/nsSVGPointList.cpp
content/svg/content/src/nsSVGRect.cpp
content/svg/content/src/nsSVGStopElement.cpp
--- a/content/svg/content/src/nsSVGAngle.cpp
+++ b/content/svg/content/src/nsSVGAngle.cpp
@@ -204,17 +204,17 @@ GetValueFromString(const nsAString &aVal
   NS_ConvertUTF16toUTF8 value(aValueAsString);
   const char *str = value.get();
 
   if (NS_IsAsciiWhitespace(*str))
     return NS_ERROR_FAILURE;
   
   char *rest;
   *aValue = float(PR_strtod(str, &rest));
-  if (rest != str) {
+  if (rest != str && NS_FloatIsFinite(*aValue)) {
     *aUnitType = GetUnitTypeForString(rest);
     if (IsValidUnitType(*aUnitType)) {
       return NS_OK;
     }
   }
   
   return NS_ERROR_FAILURE;
 }
--- a/content/svg/content/src/nsSVGDataParser.cpp
+++ b/content/svg/content/src/nsSVGDataParser.cpp
@@ -44,16 +44,17 @@
   *
   *   A subclass should implement a Match method which gets invoked from the
   *   Parse method.  The Parse method can be overridden, as required.
   *
   */
 
 
 #include "nsSVGDataParser.h"
+#include "nsContentUtils.h"
 #include "prdtoa.h"
 #include "nsSVGUtils.h"
 #include <stdlib.h>
 #include <math.h>
 
 //----------------------------------------------------------------------
 // public interface
 
@@ -146,20 +147,22 @@ nsresult nsSVGDataParser::MatchNonNegati
   nsresult rv = MatchFloatingPointConst();
 
   if (NS_FAILED(rv)) {
     RewindTo(pos);
     ENSURE_MATCHED(MatchIntegerConst());
   }
 
   char* end;
-  *aX = (float) PR_strtod(pos, &end);
-  NS_ASSERTION(end == mTokenPos, "number parse error");
+  *aX = float(PR_strtod(pos, &end));
+  if (pos != end && NS_FloatIsFinite(*aX)) {
+    return NS_OK;
+  }
   
-  return NS_OK;
+  return NS_ERROR_FAILURE;
 }
 
 PRBool nsSVGDataParser::IsTokenNonNegativeNumberStarter()
 {
   return (mTokenType == DIGIT || mTokenType == POINT);
 }
 
 //----------------------------------------------------------------------
@@ -176,20 +179,22 @@ nsresult nsSVGDataParser::MatchNumber(fl
   nsresult rv = MatchFloatingPointConst();
 
   if (NS_FAILED(rv)) {
     RewindTo(pos2);
     ENSURE_MATCHED(MatchIntegerConst());
   }
 
   char* end;
-  *aX = (float) PR_strtod(pos, &end);
-  NS_ASSERTION(end == mTokenPos, "number parse error");
-               
-  return NS_OK;
+  *aX = float(PR_strtod(pos, &end));
+  if (pos != end && NS_FloatIsFinite(*aX)) {
+    return NS_OK;
+  }
+  
+  return NS_ERROR_FAILURE;
 }
 
 PRBool nsSVGDataParser::IsTokenNumberStarter()
 {
   return (mTokenType == DIGIT || mTokenType == POINT || mTokenType == SIGN);
 }
 
 
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -1465,31 +1465,31 @@ nsSVGElement::ParseNumberOptionalNumber(
 
   if (NS_IsAsciiWhitespace(*str))
     return NS_ERROR_FAILURE;
 
   char *rest;
   float x = float(PR_strtod(str, &rest));
   float y = x;
 
-  if (str == rest) {
+  if (str == rest || !NS_FloatIsFinite(x)) {
     //first value was illformed
     return NS_ERROR_FAILURE;
   }
   
   if (*rest != '\0') {
     while (NS_IsAsciiWhitespace(*rest)) {
       ++rest;
     }
     if (*rest == ',') {
       ++rest;
     }
 
     y = float(PR_strtod(rest, &rest));
-    if (*rest != '\0') {
+    if (*rest != '\0' || !NS_FloatIsFinite(y)) {
       //second value was illformed or there was trailing content
       return NS_ERROR_FAILURE;
     }
   }
 
   NumberAttributesInfo numberInfo = GetNumberInfo();
 
   numberInfo.mNumbers[aIndex1].SetBaseValue(x, this, PR_FALSE);
--- a/content/svg/content/src/nsSVGLength.cpp
+++ b/content/svg/content/src/nsSVGLength.cpp
@@ -140,17 +140,17 @@ NS_NewSVGLength(nsISVGLength** result,
   NS_ADDREF(pl);
   nsresult rv = pl->SetValueAsString(value);
   if (NS_FAILED(rv)) {
     NS_RELEASE(pl);
     return rv;
   }
   *result = pl;
   return NS_OK;
-}  
+}
 
 
 nsSVGLength::nsSVGLength(float value,
                          PRUint16 unit)
     : mValueInSpecifiedUnits(value),
       mSpecifiedUnitType(unit),
       mCtxType(0)
 {
@@ -391,33 +391,32 @@ nsSVGLength::GetValueAsString(nsAString 
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSVGLength::SetValueAsString(const nsAString & aValueAsString)
 {
   nsresult rv = NS_OK;
-  
+
   char *str = ToNewCString(aValueAsString);
 
   char* number = str;
   while (*number && isspace(*number))
     ++number;
 
   if (*number) {
     char *rest;
-    double value = PR_strtod(number, &rest);
+    float value = float(PR_strtod(number, &rest));
     if (rest!=number) {
       const char* unitStr = nsCRT::strtok(rest, "\x20\x9\xD\xA", &rest);
       PRUint16 unitType = SVG_LENGTHTYPE_UNKNOWN;
       if (!unitStr || *unitStr=='\0') {
         unitType = SVG_LENGTHTYPE_NUMBER;
-      }
-      else {
+      } else {
         nsCOMPtr<nsIAtom> unitAtom = do_GetAtom(unitStr);
         if (unitAtom == nsGkAtoms::px)
           unitType = SVG_LENGTHTYPE_PX;
         else if (unitAtom == nsGkAtoms::mm)
           unitType = SVG_LENGTHTYPE_MM;
         else if (unitAtom == nsGkAtoms::cm)
           unitType = SVG_LENGTHTYPE_CM;
         else if (unitAtom == nsGkAtoms::in)
@@ -428,35 +427,34 @@ nsSVGLength::SetValueAsString(const nsAS
           unitType = SVG_LENGTHTYPE_PC;
         else if (unitAtom == nsGkAtoms::em)
           unitType = SVG_LENGTHTYPE_EMS;
         else if (unitAtom == nsGkAtoms::ex)
           unitType = SVG_LENGTHTYPE_EXS;
         else if (unitAtom == nsGkAtoms::percentage)
           unitType = SVG_LENGTHTYPE_PERCENTAGE;
       }
-      if (IsValidUnitType(unitType)){
+      if (IsValidUnitType(unitType) && NS_FloatIsFinite(value)){
         WillModify();
-        mValueInSpecifiedUnits = (float)value;
+        mValueInSpecifiedUnits = value;
         mSpecifiedUnitType     = unitType;
         DidModify();
-      }
-      else { // parse error
+      } else { // parse error
         // not a valid unit type
         rv = NS_ERROR_FAILURE;
       }
     }
     else { // parse error
       // no number
       rv = NS_ERROR_FAILURE;
     }
   }
-  
+
   nsMemory::Free(str);
-    
+
   return rv;
 }
 
 /* void newValueSpecifiedUnits (in unsigned short unitType, in float valueInSpecifiedUnits); */
 NS_IMETHODIMP
 nsSVGLength::NewValueSpecifiedUnits(PRUint16 unitType, float valueInSpecifiedUnits)
 {
   NS_ENSURE_FINITE(valueInSpecifiedUnits, NS_ERROR_ILLEGAL_VALUE);
@@ -469,17 +467,17 @@ nsSVGLength::NewValueSpecifiedUnits(PRUi
   WillModify();
   if (observer_change)
     MaybeRemoveAsObserver();
   mValueInSpecifiedUnits = valueInSpecifiedUnits;
   mSpecifiedUnitType     = unitType;
   if (observer_change)
     MaybeAddAsObserver();
   DidModify();
-  
+
   return NS_OK;
 }
 
 /* void convertToSpecifiedUnits (in unsigned short unitType); */
 NS_IMETHODIMP
 nsSVGLength::ConvertToSpecifiedUnits(PRUint16 unitType)
 {
   if (!IsValidUnitType(unitType))
--- a/content/svg/content/src/nsSVGLength2.cpp
+++ b/content/svg/content/src/nsSVGLength2.cpp
@@ -156,17 +156,17 @@ GetValueFromString(const nsAString &aVal
   NS_ConvertUTF16toUTF8 value(aValueAsString);
   const char *str = value.get();
 
   if (NS_IsAsciiWhitespace(*str))
     return NS_ERROR_FAILURE;
   
   char *rest;
   *aValue = float(PR_strtod(str, &rest));
-  if (rest != str) {
+  if (rest != str && NS_FloatIsFinite(*aValue)) {
     *aUnitType = GetUnitTypeForString(rest);
     if (IsValidUnitType(*aUnitType)) {
       return NS_OK;
     }
   }
   
   return NS_ERROR_FAILURE;
 }
--- a/content/svg/content/src/nsSVGNumber.cpp
+++ b/content/svg/content/src/nsSVGNumber.cpp
@@ -115,43 +115,43 @@ nsSVGNumber::GetValueString(nsAString& a
 }
 
 NS_IMETHODIMP
 nsSVGNumber::SetValueString(const nsAString& aValue)
 {
   nsresult rv = NS_OK;
   WillModify();
   
-  char *str = ToNewCString(aValue);
+  NS_ConvertUTF16toUTF8 value(aValue);
+  const char *str = value.get();
 
   if (*str) {
     char *rest;
-    double value = PR_strtod(str, &rest);
-    if (rest && rest!=str) {
+    float val = float(PR_strtod(str, &rest));
+    if (rest && rest!=str && NS_FloatIsFinite(val)) {
       if (*rest=='%') {
-        rv = SetValue(float(value/100.0));
+        rv = SetValue(val / 100.0f);
         rest++;
       } else {
-        rv = SetValue(float(value));
+        rv = SetValue(val);
       }
       // skip trailing spaces
       while (*rest && isspace(*rest))
         ++rest;
 
       // check to see if there is trailing stuff...
       if (*rest != '\0') {
         rv = NS_ERROR_FAILURE;
         NS_ERROR("trailing data in number value");
       }
     } else {
       rv = NS_ERROR_FAILURE;
       // no number
     }
   }
-  nsMemory::Free(str);
   DidModify();
   return rv;
 }
 
 //----------------------------------------------------------------------
 
 //----------------------------------------------------------------------
 // nsIDOMSVGNumber methods:
--- a/content/svg/content/src/nsSVGNumber2.cpp
+++ b/content/svg/content/src/nsSVGNumber2.cpp
@@ -59,17 +59,17 @@ nsSVGNumber2::SetBaseValueString(const n
   NS_ConvertUTF16toUTF8 value(aValueAsString);
   const char *str = value.get();
 
   if (NS_IsAsciiWhitespace(*str))
     return NS_ERROR_FAILURE;
   
   char *rest;
   float val = float(PR_strtod(str, &rest));
-  if (rest == str || *rest != '\0') {
+  if (rest == str || *rest != '\0' || !NS_FloatIsFinite(val)) {
     return NS_ERROR_FAILURE;
   }
 
   mBaseVal = mAnimVal = val;
   return NS_OK;
 }
 
 void
--- a/content/svg/content/src/nsSVGNumberList.cpp
+++ b/content/svg/content/src/nsSVGNumberList.cpp
@@ -128,29 +128,28 @@ NS_INTERFACE_MAP_END
 NS_IMETHODIMP
 nsSVGNumberList::SetValueString(const nsAString& aValue)
 {
   WillModify();
   ReleaseNumbers();
 
   nsresult rv = NS_OK;
 
-  char* str;
-  str = ToNewCString(aValue);
+  char* str = ToNewCString(aValue);
 
   char* rest = str;
   char* token;
   const char* delimiters = ", \t\r\n";
 
   while ((token = nsCRT::strtok(rest, delimiters, &rest))) {
     char *left;
-    double value = PR_strtod(token, &left);
-    if (token!=left) {
+    float val = float(PR_strtod(token, &left));
+    if (token!=left && NS_FloatIsFinite(val)) {
       nsCOMPtr<nsIDOMSVGNumber> number;
-      NS_NewSVGNumber(getter_AddRefs(number), float(value));
+      NS_NewSVGNumber(getter_AddRefs(number), val);
       if (!number) {
         rv = NS_ERROR_FAILURE;
         break;
       }
       AppendElement(number);
     }
   }
   
--- a/content/svg/content/src/nsSVGPointList.cpp
+++ b/content/svg/content/src/nsSVGPointList.cpp
@@ -170,41 +170,40 @@ nsSVGPointList::SetValueString(const nsA
   const char* delimiters = ",\x20\x9\xD\xA";
   nsCOMArray<nsIDOMSVGPoint> points;
   
   while ( (token1 = nsCRT::strtok(rest, delimiters, &rest)) &&
           (token2 = nsCRT::strtok(rest, delimiters, &rest)) ) {
 
     char *end;
     
-    double x = PR_strtod(token1, &end);
-    if (*end != '\0') {
+    float x = float(PR_strtod(token1, &end));
+    if (*end != '\0' || !NS_FloatIsFinite(x)) {
       rv = NS_ERROR_FAILURE;
       break; // parse error
     }
-    double y = PR_strtod(token2, &end);
-    if (*end != '\0') {
+    float y = float(PR_strtod(token2, &end));
+    if (*end != '\0' || !NS_FloatIsFinite(y)) {
       rv = NS_ERROR_FAILURE;
       break; // parse error
     }
     
     nsCOMPtr<nsIDOMSVGPoint> point;
-    NS_NewSVGPoint(getter_AddRefs(point), (float)x, (float)y);
+    NS_NewSVGPoint(getter_AddRefs(point), x, y);
     if (!point) {
       rv = NS_ERROR_OUT_OF_MEMORY;
       break;
     }
     points.AppendObject(point);
   }
 
   if (token1 || NS_FAILED(rv)) {
     // there was a parse error or we ran out of memory
     rv = NS_ERROR_FAILURE;
-  }
-  else {
+  } else {
     WillModify();
     ReleasePoints();
     PRInt32 count = points.Count();
     for (PRInt32 i=0; i<count; ++i) {
       AppendElement(points.ObjectAt(i));
     }
     DidModify();
   }
--- a/content/svg/content/src/nsSVGRect.cpp
+++ b/content/svg/content/src/nsSVGRect.cpp
@@ -84,26 +84,26 @@ nsSVGRect::SetValueString(const nsAStrin
   nsresult rv = NS_OK;
 
   char* str = ToNewCString(aValue);
 
   char* rest = str;
   char* token;
   const char* delimiters = ",\x20\x9\xD\xA";
 
-  double vals[4];
-  int i;
-  for (i=0;i<4;++i) {
+  float vals[4];
+  PRUint32 i;
+  for (i = 0; i < 4; ++i) {
     if (!(token = nsCRT::strtok(rest, delimiters, &rest))) break; // parse error
 
     char *end;
-    vals[i] = PR_strtod(token, &end);
-    if (*end != '\0') break; // parse error
+    vals[i] = float(PR_strtod(token, &end));
+    if (*end != '\0' || !NS_FloatIsFinite(vals[i])) break; // parse error
   }
-  if (i!=4 || (nsCRT::strtok(rest, delimiters, &rest)!=0)) {
+  if (i!=4 || nsCRT::strtok(rest, delimiters, &rest)!=0) {
     // there was a parse error.
     rv = NS_ERROR_FAILURE;
   }
   else {
     WillModify();
     mX      = float(vals[0]);
     mY      = float(vals[1]);
     mWidth  = float(vals[2]);
--- a/content/svg/content/src/nsSVGStopElement.cpp
+++ b/content/svg/content/src/nsSVGStopElement.cpp
@@ -135,18 +135,18 @@ nsSVGStopElement::ParseAttribute(PRInt32
 								 nsAttrValue& aResult)
 {
   if (aNamespaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::offset) {
       NS_ConvertUTF16toUTF8 value(aValue);
       const char *str = value.get();
 
       char *rest;
-      float offset = static_cast<float>(PR_strtod(str, &rest));
-      if (str != rest) {
+      float offset = float(PR_strtod(str, &rest));
+      if (str != rest && NS_FloatIsFinite(offset)) {
         if (*rest == '%') {
           offset /= 100;
           ++rest;
         }
         if (*rest == '\0') {
           mOffset.SetBaseValue(offset, this, PR_FALSE);
           aResult.SetTo(aValue);
           return PR_TRUE;