Bug 1518440 - Use CheckedInt in JSON Quote function. r=jwalden, a=RyanVM
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 17 Jan 2019 18:24:49 +0000
changeset 509540 d850ab97f26b8824425de7d88a8603265de6e3ae
parent 509539 435e0e27532d79d15538cd8376ea0f6d706065ca
child 509541 9e5bf16f07c4103f751a6efbed31030716f93a82
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden, RyanVM
bugs1518440
milestone65.0
Bug 1518440 - Use CheckedInt in JSON Quote function. r=jwalden, a=RyanVM Differential Revision: https://phabricator.services.mozilla.com/D16534
js/src/builtin/JSON.cpp
--- a/js/src/builtin/JSON.cpp
+++ b/js/src/builtin/JSON.cpp
@@ -1,16 +1,17 @@
 /* -*- 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/. */
 
 #include "builtin/JSON.h"
 
+#include "mozilla/CheckedInt.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Range.h"
 #include "mozilla/ScopeExit.h"
 
 #include "jsnum.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
@@ -29,16 +30,17 @@
 
 #include "builtin/Array-inl.h"
 #include "builtin/Boolean-inl.h"
 #include "vm/JSAtom-inl.h"
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 
+using mozilla::CheckedInt;
 using mozilla::IsFinite;
 using mozilla::Maybe;
 using mozilla::RangedPtr;
 
 using JS::AutoStableStringChars;
 
 const Class js::JSONClass = {js_JSON_str,
                              JSCLASS_HAS_CACHED_PROTO(JSProto_JSON)};
@@ -133,23 +135,30 @@ static MOZ_ALWAYS_INLINE RangedPtr<DstCh
   }
 
   /* Steps 3-4. */
   *dstPtr++ = '"';
   return dstPtr;
 }
 
 template <typename SrcCharT, typename CharVectorT>
-static bool Quote(CharVectorT& sb, JSLinearString* str) {
+static bool Quote(JSContext* cx, CharVectorT& sb, JSLinearString* str) {
   // We resize the backing buffer to the maximum size we could possibly need,
   // write the escaped string into it, and shrink it back to the size we ended
   // up needing.
+
   size_t len = str->length();
+  CheckedInt<size_t> reservedLen = CheckedInt<size_t>(len) * 6 + 2;
+  if (MOZ_UNLIKELY(!reservedLen.isValid())) {
+    ReportAllocationOverflow(cx);
+    return false;
+  }
+
   size_t sbInitialLen = sb.length();
-  if (!sb.growByUninitialized(len * 6 + 2)) {
+  if (!sb.growByUninitialized(reservedLen.value())) {
     return false;
   }
 
   typedef typename CharVectorT::ElementType DstCharT;
 
   JS::AutoCheckCannotGC nogc;
   RangedPtr<const SrcCharT> srcBegin{str->chars<SrcCharT>(nogc), len};
   RangedPtr<DstCharT> dstBegin{sb.begin(), sb.begin(), sb.end()};
@@ -169,22 +178,22 @@ static bool Quote(JSContext* cx, StringB
   // Check if either has non-latin1 before calling ensure, so that the buffer's
   // hasEnsured flag is set if the converstion to twoByte was automatic.
   if (!sb.isUnderlyingBufferLatin1() || linear->hasTwoByteChars()) {
     if (!sb.ensureTwoByteChars()) {
       return false;
     }
   }
   if (linear->hasTwoByteChars()) {
-    return Quote<char16_t>(sb.rawTwoByteBuffer(), linear);
+    return Quote<char16_t>(cx, sb.rawTwoByteBuffer(), linear);
   }
 
   return sb.isUnderlyingBufferLatin1()
-             ? Quote<Latin1Char>(sb.latin1Chars(), linear)
-             : Quote<Latin1Char>(sb.rawTwoByteBuffer(), linear);
+             ? Quote<Latin1Char>(cx, sb.latin1Chars(), linear)
+             : Quote<Latin1Char>(cx, sb.rawTwoByteBuffer(), linear);
 }
 
 namespace {
 
 using ObjectVector = GCVector<JSObject*, 8>;
 
 class StringifyContext {
  public: