Bug 1340577 - Add release-grade assertions to various XPCOM string API implementations to avoid input causing an overflow. r=froydnj
authorHonza Bambas <honzab.moz@firemni.cz>
Tue, 21 Feb 2017 11:38:00 -0500
changeset 373919 3e552501cd1fc10a5c5e41fdc87c8161453cf8f0
parent 373918 f4eae24795b9ae702254e576a1f2c5d8d72c7a60
child 373920 185d93157773808aade7b37af798ee25b2b12f9f
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1340577
milestone54.0a1
Bug 1340577 - Add release-grade assertions to various XPCOM string API implementations to avoid input causing an overflow. r=froydnj
xpcom/glue/nsStringAPI.cpp
xpcom/glue/nsStringAPI.h
xpcom/string/nsTDependentString.cpp
xpcom/string/nsTDependentString.h
xpcom/string/nsTDependentSubstring.cpp
xpcom/string/nsTDependentSubstring.h
xpcom/string/nsTSubstring.cpp
xpcom/string/nsTSubstring.h
--- a/xpcom/glue/nsStringAPI.cpp
+++ b/xpcom/glue/nsStringAPI.cpp
@@ -1301,8 +1301,40 @@ ParseString(const nsACString& aSource, c
     start = ++delimiter;
     if (start == end) {
       break;
     }
   }
 
   return true;
 }
+
+const nsDependentSubstring
+Substring(const char16_t* aStart, const char16_t* aEnd)
+{
+  MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!");
+  MOZ_ASSERT(uint32_t(aEnd - aStart) == uintptr_t(aEnd - aStart),
+             "string too long");
+  return nsDependentSubstring(aStart, uint32_t(aEnd - aStart));
+}
+
+const nsDependentSubstring
+StringTail(const nsAString& aStr, uint32_t aCount)
+{
+  MOZ_RELEASE_ASSERT(aStr.Length() >= aCount, "Overflow!");
+  return nsDependentSubstring(aStr, aStr.Length() - aCount, aCount);
+}
+
+const nsDependentCSubstring
+Substring(const char* aStart, const char* aEnd)
+{
+  MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!");
+  MOZ_ASSERT(uint32_t(aEnd - aStart) == uintptr_t(aEnd - aStart),
+             "string too long");
+  return nsDependentCSubstring(aStart, uint32_t(aEnd - aStart));
+}
+
+inline const nsDependentCSubstring
+StringTail(const nsACString& aStr, uint32_t aCount)
+{
+  MOZ_RELEASE_ASSERT(aStr.Length() >= aCount, "Overflow!");
+  return nsDependentCSubstring(aStr, aStr.Length() - aCount, aCount);
+}
--- a/xpcom/glue/nsStringAPI.h
+++ b/xpcom/glue/nsStringAPI.h
@@ -1435,80 +1435,64 @@ Substring(const nsAString& aStr, uint32_
 }
 
 inline const nsDependentSubstring
 Substring(const nsAString& aStr, uint32_t aStartPos, uint32_t aLength)
 {
   return nsDependentSubstring(aStr, aStartPos, aLength);
 }
 
-inline const nsDependentSubstring
-Substring(const char16_t* aStart, const char16_t* aEnd)
-{
-  MOZ_ASSERT(uint32_t(aEnd - aStart) == uintptr_t(aEnd - aStart),
-             "string too long");
-  return nsDependentSubstring(aStart, uint32_t(aEnd - aStart));
-}
+const nsDependentSubstring
+Substring(const char16_t* aStart, const char16_t* aEnd);
 
 inline const nsDependentSubstring
 Substring(const char16_t* aStart, uint32_t aLength)
 {
   return nsDependentSubstring(aStart, aLength);
 }
 
 inline const nsDependentSubstring
 StringHead(const nsAString& aStr, uint32_t aCount)
 {
   return nsDependentSubstring(aStr, 0, aCount);
 }
 
-inline const nsDependentSubstring
-StringTail(const nsAString& aStr, uint32_t aCount)
-{
-  return nsDependentSubstring(aStr, aStr.Length() - aCount, aCount);
-}
+const nsDependentSubstring
+StringTail(const nsAString& aStr, uint32_t aCount);
 
 // char
 inline const nsDependentCSubstring
 Substring(const nsACString& aStr, uint32_t aStartPos)
 {
   return nsDependentCSubstring(aStr, aStartPos);
 }
 
 inline const nsDependentCSubstring
 Substring(const nsACString& aStr, uint32_t aStartPos, uint32_t aLength)
 {
   return nsDependentCSubstring(aStr, aStartPos, aLength);
 }
 
-inline const nsDependentCSubstring
-Substring(const char* aStart, const char* aEnd)
-{
-  MOZ_ASSERT(uint32_t(aEnd - aStart) == uintptr_t(aEnd - aStart),
-             "string too long");
-  return nsDependentCSubstring(aStart, uint32_t(aEnd - aStart));
-}
+const nsDependentCSubstring
+Substring(const char* aStart, const char* aEnd);
 
 inline const nsDependentCSubstring
 Substring(const char* aStart, uint32_t aLength)
 {
   return nsDependentCSubstring(aStart, aLength);
 }
 
 inline const nsDependentCSubstring
 StringHead(const nsACString& aStr, uint32_t aCount)
 {
   return nsDependentCSubstring(aStr, 0, aCount);
 }
 
-inline const nsDependentCSubstring
-StringTail(const nsACString& aStr, uint32_t aCount)
-{
-  return nsDependentCSubstring(aStr, aStr.Length() - aCount, aCount);
-}
+const nsDependentCSubstring
+StringTail(const nsACString& aStr, uint32_t aCount);
 
 
 inline bool
 StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring,
                  nsAString::ComparatorFunc aComparator = nsAString::DefaultComparator)
 {
   return aSubstring.Length() <= aSource.Length() &&
     StringHead(aSource, aSubstring.Length()).Equals(aSubstring, aComparator);
--- a/xpcom/string/nsTDependentString.cpp
+++ b/xpcom/string/nsTDependentString.cpp
@@ -1,14 +1,23 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+nsTDependentString_CharT::nsTDependentString_CharT(const char_type* aStart,
+                                                   const char_type* aEnd)
+  : string_type(const_cast<char_type*>(aStart),
+                uint32_t(aEnd - aStart), F_TERMINATED)
+{
+  MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!");
+  AssertValidDependentString();
+}
+
 void
 nsTDependentString_CharT::Rebind(const string_type& str, uint32_t startPos)
 {
   MOZ_ASSERT(str.Flags() & F_TERMINATED, "Unterminated flat string");
 
   // If we currently own a buffer, release it.
   Finalize();
 
@@ -18,8 +27,15 @@ nsTDependentString_CharT::Rebind(const s
     startPos = strLength;
   }
 
   mData = const_cast<char_type*>(static_cast<const char_type*>(str.Data())) + startPos;
   mLength = strLength - startPos;
 
   SetDataFlags(str.Flags() & (F_TERMINATED | F_LITERAL));
 }
+
+void
+nsTDependentString_CharT::Rebind(const char_type* aStart, const char_type* aEnd)
+{
+  MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!");
+  Rebind(aStart, uint32_t(aEnd - aStart));
+}
--- a/xpcom/string/nsTDependentString.h
+++ b/xpcom/string/nsTDependentString.h
@@ -23,22 +23,17 @@ public:
   typedef nsTDependentString_CharT self_type;
 
 public:
 
   /**
    * constructors
    */
 
-  nsTDependentString_CharT(const char_type* aStart, const char_type* aEnd)
-    : string_type(const_cast<char_type*>(aStart),
-                  uint32_t(aEnd - aStart), F_TERMINATED)
-  {
-    AssertValidDependentString();
-  }
+  nsTDependentString_CharT(const char_type* aStart, const char_type* aEnd);
 
   nsTDependentString_CharT(const char_type* aData, uint32_t aLength)
     : string_type(const_cast<char_type*>(aData), aLength, F_TERMINATED)
   {
     AssertValidDependentString();
   }
 
 #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
@@ -87,20 +82,16 @@ public:
    */
 
   using nsTString_CharT::Rebind;
   void Rebind(const char_type* aData)
   {
     Rebind(aData, uint32_t(char_traits::length(aData)));
   }
 
-  void Rebind(const char_type* aStart, const char_type* aEnd)
-  {
-    Rebind(aStart, uint32_t(aEnd - aStart));
-  }
-
+  void Rebind(const char_type* aStart, const char_type* aEnd);
   void Rebind(const string_type&, uint32_t aStartPos);
 
 private:
 
   // NOT USED
   nsTDependentString_CharT(const substring_tuple_type&) = delete;
 };
--- a/xpcom/string/nsTDependentSubstring.cpp
+++ b/xpcom/string/nsTDependentSubstring.cpp
@@ -30,8 +30,50 @@ nsTDependentSubstring_CharT::Rebind(cons
 
   // If we currently own a buffer, release it.
   Finalize();
 
   mData = const_cast<char_type*>(static_cast<const char_type*>(data));
   mLength = length;
   SetDataFlags(F_NONE);
 }
+
+void
+nsTDependentSubstring_CharT::Rebind(const char_type* aStart, const char_type* aEnd)
+{
+  MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!");
+  Rebind(aStart, size_type(aEnd - aStart));
+}
+
+nsTDependentSubstring_CharT::nsTDependentSubstring_CharT(const char_type* aStart,
+                                                         const char_type* aEnd)
+  : substring_type(const_cast<char_type*>(aStart), uint32_t(aEnd - aStart),
+                   F_NONE)
+{
+  MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!");
+}
+
+#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
+nsTDependentSubstring_CharT::nsTDependentSubstring_CharT(char16ptr_t aStart,
+                                                         char16ptr_t aEnd)
+  : nsTDependentSubstring_CharT(static_cast<const char16_t*>(aStart),
+                                static_cast<const char16_t*>(aEnd))
+{
+  MOZ_RELEASE_ASSERT(static_cast<const char16_t*>(aStart) <=
+                     static_cast<const char16_t*>(aEnd),
+                     "Overflow!");
+}
+#endif
+
+nsTDependentSubstring_CharT::nsTDependentSubstring_CharT(const const_iterator& aStart,
+                                                         const const_iterator& aEnd)
+  : substring_type(const_cast<char_type*>(aStart.get()),
+                   uint32_t(aEnd.get() - aStart.get()), F_NONE)
+{
+  MOZ_RELEASE_ASSERT(aStart.get() <= aEnd.get(), "Overflow!");
+}
+
+const nsTDependentSubstring_CharT
+Substring(const CharT* aStart, const CharT* aEnd)
+{
+  MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!");
+  return nsTDependentSubstring_CharT(aStart, aEnd);
+}
--- a/xpcom/string/nsTDependentSubstring.h
+++ b/xpcom/string/nsTDependentSubstring.h
@@ -24,58 +24,43 @@ public:
 
 public:
 
   void Rebind(const substring_type&, uint32_t aStartPos,
               uint32_t aLength = size_type(-1));
 
   void Rebind(const char_type* aData, size_type aLength);
 
-  void Rebind(const char_type* aStart, const char_type* aEnd)
-  {
-    Rebind(aStart, size_type(aEnd - aStart));
-  }
+  void Rebind(const char_type* aStart, const char_type* aEnd);
 
   nsTDependentSubstring_CharT(const substring_type& aStr, uint32_t aStartPos,
                               uint32_t aLength = size_type(-1))
     : substring_type()
   {
     Rebind(aStr, aStartPos, aLength);
   }
 
   nsTDependentSubstring_CharT(const char_type* aData, size_type aLength)
     : substring_type(const_cast<char_type*>(aData), aLength, F_NONE)
   {
   }
 
-  nsTDependentSubstring_CharT(const char_type* aStart, const char_type* aEnd)
-    : substring_type(const_cast<char_type*>(aStart), uint32_t(aEnd - aStart),
-                     F_NONE)
-  {
-  }
+  nsTDependentSubstring_CharT(const char_type* aStart, const char_type* aEnd);
 
 #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
   nsTDependentSubstring_CharT(char16ptr_t aData, size_type aLength)
     : nsTDependentSubstring_CharT(static_cast<const char16_t*>(aData), aLength)
   {
   }
 
-  nsTDependentSubstring_CharT(char16ptr_t aStart, char16ptr_t aEnd)
-    : nsTDependentSubstring_CharT(static_cast<const char16_t*>(aStart),
-                                  static_cast<const char16_t*>(aEnd))
-  {
-  }
+  nsTDependentSubstring_CharT(char16ptr_t aStart, char16ptr_t aEnd);
 #endif
 
   nsTDependentSubstring_CharT(const const_iterator& aStart,
-                              const const_iterator& aEnd)
-    : substring_type(const_cast<char_type*>(aStart.get()),
-                     uint32_t(aEnd.get() - aStart.get()), F_NONE)
-  {
-  }
+                              const const_iterator& aEnd);
 
   // Create a nsTDependentSubstring to be bound later
   nsTDependentSubstring_CharT()
     : substring_type()
   {
   }
 
   // auto-generated copy-constructor OK (XXX really?? what about base class copy-ctor?)
@@ -100,21 +85,18 @@ Substring(const nsReadingIterator<CharT>
 }
 
 inline const nsTDependentSubstring_CharT
 Substring(const CharT* aData, uint32_t aLength)
 {
   return nsTDependentSubstring_CharT(aData, aLength);
 }
 
-inline const nsTDependentSubstring_CharT
-Substring(const CharT* aStart, const CharT* aEnd)
-{
-  return nsTDependentSubstring_CharT(aStart, aEnd);
-}
+const nsTDependentSubstring_CharT
+Substring(const CharT* aStart, const CharT* aEnd);
 
 inline const nsTDependentSubstring_CharT
 StringHead(const nsTSubstring_CharT& aStr, uint32_t aCount)
 {
   return nsTDependentSubstring_CharT(aStr, 0, aCount);
 }
 
 inline const nsTDependentSubstring_CharT
--- a/xpcom/string/nsTSubstring.cpp
+++ b/xpcom/string/nsTSubstring.cpp
@@ -30,16 +30,30 @@ nsTSubstring_CharT::nsTSubstring_CharT(c
  */
 inline const nsTFixedString_CharT*
 AsFixedString(const nsTSubstring_CharT* aStr)
 {
   return static_cast<const nsTFixedString_CharT*>(aStr);
 }
 
 
+nsTSubstring_CharT::char_type
+nsTSubstring_CharT::First() const
+{
+  MOZ_RELEASE_ASSERT(mLength > 0, "|First()| called on an empty string");
+  return mData[0];
+}
+
+nsTSubstring_CharT::char_type
+nsTSubstring_CharT::Last() const
+{
+  MOZ_RELEASE_ASSERT(mLength > 0, "|Last()| called on an empty string");
+  return mData[mLength - 1];
+}
+
 /**
  * this function is called to prepare mData for writing.  the given capacity
  * indicates the required minimum storage size for mData, in sizeof(char_type)
  * increments.  this function returns true if the operation succeeds.  it also
  * returns the old data and old flags members if mData is newly allocated.
  * the old data must be released by the caller.
  */
 bool
--- a/xpcom/string/nsTSubstring.h
+++ b/xpcom/string/nsTSubstring.h
@@ -267,27 +267,19 @@ public:
     return mData[aIndex];
   }
 
   char_type operator[](index_type aIndex) const
   {
     return CharAt(aIndex);
   }
 
-  char_type First() const
-  {
-    NS_ASSERTION(mLength > 0, "|First()| called on an empty string");
-    return mData[0];
-  }
+  char_type First() const;
 
-  inline   char_type Last() const
-  {
-    NS_ASSERTION(mLength > 0, "|Last()| called on an empty string");
-    return mData[mLength - 1];
-  }
+  char_type Last() const;
 
   size_type NS_FASTCALL CountChar(char_type) const;
   int32_t NS_FASTCALL FindChar(char_type, index_type aOffset = 0) const;
 
   inline bool Contains(char_type aChar) const
   {
     return FindChar(aChar) != kNotFound;
   }