Bug 1176698 - Use fallible allocator for attribute values in the HTML parser. r=wchen.
authorHenri Sivonen <hsivonen@hsivonen.fi>
Tue, 25 Aug 2015 18:05:46 +0300
changeset 287774 470bee720c97d1901570cfb8fbb4eedfddcd21a8
parent 287773 c283d026937dc773be935ed668b2bd15b241d52a
child 287775 4c795bc737c80b59658173b0a558b8b717205ed1
push id4743
push usermartin.thomson@gmail.com
push dateTue, 25 Aug 2015 20:50:01 +0000
reviewerswchen
bugs1176698
milestone43.0a1
Bug 1176698 - Use fallible allocator for attribute values in the HTML parser. r=wchen.
parser/html/javasrc/MetaScanner.java
parser/html/javasrc/Portability.java
parser/html/javasrc/Tokenizer.java
parser/html/javasrc/TreeBuilder.java
parser/html/nsHtml5MetaScanner.cpp
parser/html/nsHtml5MetaScanner.h
parser/html/nsHtml5Portability.cpp
parser/html/nsHtml5Portability.h
parser/html/nsHtml5StreamParser.cpp
parser/html/nsHtml5Tokenizer.cpp
parser/html/nsHtml5Tokenizer.h
parser/html/nsHtml5TreeBuilder.cpp
parser/html/nsHtml5TreeBuilder.h
parser/html/nsHtml5TreeBuilderCppSupplement.h
parser/html/nsHtml5TreeBuilderHSupplement.h
--- a/parser/html/javasrc/MetaScanner.java
+++ b/parser/html/javasrc/MetaScanner.java
@@ -1,11 +1,11 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
- * Copyright (c) 2008-2010 Mozilla Foundation
+ * Copyright (c) 2008-2015 Mozilla Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a 
  * copy of this software and associated documentation files (the "Software"), 
  * to deal in the Software without restriction, including without limitation 
  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
  * and/or sell copies of the Software, and to permit persons to whom the 
  * Software is furnished to do so, subject to the following conditions:
  *
@@ -157,29 +157,34 @@ public abstract class MetaScanner {
     private @Auto char[] strBuf;
     
     private String content;
     
     private String charset;
     
     private int httpEquivState;
     
-    public MetaScanner() {
+    // CPPONLY: private TreeBuilder treeBuilder;
+
+    public MetaScanner(
+        // CPPONLY: TreeBuilder tb
+    ) {
         this.readable = null;
         this.metaState = NO;
         this.contentIndex = Integer.MAX_VALUE;
         this.charsetIndex = Integer.MAX_VALUE;
         this.httpEquivIndex = Integer.MAX_VALUE;
         this.contentTypeIndex = Integer.MAX_VALUE;
         this.stateSave = DATA;
         this.strBufLen = 0;
         this.strBuf = new char[36];
         this.content = null;
         this.charset = null;
         this.httpEquivState = HTTP_EQUIV_NOT_SEEN;
+        // CPPONLY: this.treeBuilder = tb;
     }
     
     @SuppressWarnings("unused") private void destructor() {
         Portability.releaseString(content);
         Portability.releaseString(charset);
     }
 
     // [NOCPP[
@@ -785,21 +790,25 @@ public abstract class MetaScanner {
      * @return <code>true</code> if successful
      * @throws SAXException
      */
     private void handleAttributeValue() throws SAXException {
         if (metaState != A) {
             return;
         }
         if (contentIndex == CONTENT.length && content == null) {
-            content = Portability.newStringFromBuffer(strBuf, 0, strBufLen);
+            content = Portability.newStringFromBuffer(strBuf, 0, strBufLen
+                 // CPPONLY: , treeBuilder
+            );
             return;
         }
         if (charsetIndex == CHARSET.length && charset == null) {
-            charset = Portability.newStringFromBuffer(strBuf, 0, strBufLen);            
+            charset = Portability.newStringFromBuffer(strBuf, 0, strBufLen
+                 // CPPONLY: , treeBuilder
+            );
             return;
         }
         if (httpEquivIndex == HTTP_EQUIV.length
                 && httpEquivState == HTTP_EQUIV_NOT_SEEN) {
             httpEquivState = (contentTypeIndex == CONTENT_TYPE.length) ? HTTP_EQUIV_CONTENT_TYPE
                     : HTTP_EQUIV_OTHER;
             return;
         }
@@ -815,17 +824,19 @@ public abstract class MetaScanner {
         return stop;
     }
     
     private boolean handleTagInner() throws SAXException {
         if (charset != null && tryCharset(charset)) {
                 return true;
         }
         if (content != null && httpEquivState == HTTP_EQUIV_CONTENT_TYPE) {
-            String extract = TreeBuilder.extractCharsetFromContent(content);
+            String extract = TreeBuilder.extractCharsetFromContent(content
+                // CPPONLY: , treeBuilder
+            );
             if (extract == null) {
                 return false;
             }
             boolean success = tryCharset(extract);
             Portability.releaseString(extract);
             return success;
         }
         return false;
--- a/parser/html/javasrc/Portability.java
+++ b/parser/html/javasrc/Portability.java
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2008-2009 Mozilla Foundation
+ * Copyright (c) 2008-2015 Mozilla Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a 
  * copy of this software and associated documentation files (the "Software"), 
  * to deal in the Software without restriction, including without limitation 
  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
  * and/or sell copies of the Software, and to permit persons to whom the 
  * Software is furnished to do so, subject to the following conditions:
  *
@@ -34,17 +34,19 @@ public final class Portability {
     /**
      * Allocates a new local name object. In C++, the refcount must be set up in such a way that 
      * calling <code>releaseLocal</code> on the return value balances the refcount set by this method.
      */
     public static @Local String newLocalNameFromBuffer(@NoLength char[] buf, int offset, int length, Interner interner) {
         return new String(buf, offset, length).intern();
     }
 
-    public static String newStringFromBuffer(@NoLength char[] buf, int offset, int length) {
+    public static String newStringFromBuffer(@NoLength char[] buf, int offset, int length
+        // CPPONLY: , TreeBuilder treeBuilder
+    ) {
         return new String(buf, offset, length);
     }
 
     public static String newEmptyString() {
         return "";
     }
 
     public static String newStringFromLiteral(@Literal String literal) {
--- a/parser/html/javasrc/Tokenizer.java
+++ b/parser/html/javasrc/Tokenizer.java
@@ -1,11 +1,11 @@
 /*
  * Copyright (c) 2005-2007 Henri Sivonen
- * Copyright (c) 2007-2013 Mozilla Foundation
+ * Copyright (c) 2007-2015 Mozilla Foundation
  * Portions of comments Copyright 2004-2010 Apple Computer, Inc., Mozilla 
  * Foundation, and Opera Software ASA.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a 
  * copy of this software and associated documentation files (the "Software"), 
  * to deal in the Software without restriction, including without limitation 
  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
  * and/or sell copies of the Software, and to permit persons to whom the 
@@ -850,17 +850,19 @@ public class Tokenizer implements Locato
      * The buffer as a String. Currently only used for error reporting.
      * 
      * <p>
      * C++ memory note: The return value must be released.
      * 
      * @return the buffer as a string
      */
     protected String strBufToString() {
-        return Portability.newStringFromBuffer(strBuf, 0, strBufLen);
+        return Portability.newStringFromBuffer(strBuf, 0, strBufLen
+            // CPPONLY: , tokenHandler
+        );
     }
 
     /**
      * Returns the buffer as a local name. The return value is released in
      * emitDoctypeToken().
      * 
      * @return the buffer as local name
      */
--- a/parser/html/javasrc/TreeBuilder.java
+++ b/parser/html/javasrc/TreeBuilder.java
@@ -1,11 +1,11 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
- * Copyright (c) 2007-2011 Mozilla Foundation
+ * Copyright (c) 2007-2015 Mozilla Foundation
  * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
  * Foundation, and Opera Software ASA.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  * and/or sell copies of the Software, and to permit persons to whom the
@@ -3179,17 +3179,19 @@ public abstract class TreeBuilder<T> imp
      *
      * <p>
      * C++ memory note: The return value must be released.
      *
      * @return
      * @throws SAXException
      * @throws StopSniffingException
      */
-    public static String extractCharsetFromContent(String attributeValue) {
+    public static String extractCharsetFromContent(String attributeValue
+        // CPPONLY: , TreeBuilder tb
+    ) {
         // This is a bit ugly. Converting the string to char array in order to
         // make the portability layer smaller.
         int charsetState = CHARSET_INITIAL;
         int start = -1;
         int end = -1;
         @Auto char[] buffer = Portability.newCharArrayFromString(attributeValue);
 
         charsetloop: for (int i = 0; i < buffer.length; i++) {
@@ -3331,17 +3333,19 @@ public abstract class TreeBuilder<T> imp
             }
         }
         String charset = null;
         if (start != -1) {
             if (end == -1) {
                 end = buffer.length;
             }
             charset = Portability.newStringFromBuffer(buffer, start, end
-                    - start);
+                    - start
+                // CPPONLY: , tb
+            );
         }
         return charset;
     }
 
     private void checkMetaCharset(HtmlAttributes attributes)
             throws SAXException {
         String charset = attributes.getValue(AttributeName.CHARSET);
         if (charset != null) {
@@ -3353,17 +3357,19 @@ public abstract class TreeBuilder<T> imp
         }
         if (!Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
                 "content-type",
                 attributes.getValue(AttributeName.HTTP_EQUIV))) {
             return;
         }
         String content = attributes.getValue(AttributeName.CONTENT);
         if (content != null) {
-            String extract = TreeBuilder.extractCharsetFromContent(content);
+            String extract = TreeBuilder.extractCharsetFromContent(content
+                // CPPONLY: , this
+            );
             // remember not to return early without releasing the string
             if (extract != null) {
                 if (tokenizer.internalEncodingDeclaration(extract)) {
                     requestSuspension();
                 }
             }
             Portability.releaseString(extract);
         }
--- a/parser/html/nsHtml5MetaScanner.cpp
+++ b/parser/html/nsHtml5MetaScanner.cpp
@@ -1,11 +1,11 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
- * Copyright (c) 2008-2010 Mozilla Foundation
+ * Copyright (c) 2008-2015 Mozilla Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a 
  * copy of this software and associated documentation files (the "Software"), 
  * to deal in the Software without restriction, including without limitation 
  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
  * and/or sell copies of the Software, and to permit persons to whom the 
  * Software is furnished to do so, subject to the following conditions:
  *
@@ -59,29 +59,30 @@ static char16_t const CHARSET_DATA[] = {
 staticJArray<char16_t,int32_t> nsHtml5MetaScanner::CHARSET = { CHARSET_DATA, MOZ_ARRAY_LENGTH(CHARSET_DATA) };
 static char16_t const CONTENT_DATA[] = { 'o', 'n', 't', 'e', 'n', 't' };
 staticJArray<char16_t,int32_t> nsHtml5MetaScanner::CONTENT = { CONTENT_DATA, MOZ_ARRAY_LENGTH(CONTENT_DATA) };
 static char16_t const HTTP_EQUIV_DATA[] = { 't', 't', 'p', '-', 'e', 'q', 'u', 'i', 'v' };
 staticJArray<char16_t,int32_t> nsHtml5MetaScanner::HTTP_EQUIV = { HTTP_EQUIV_DATA, MOZ_ARRAY_LENGTH(HTTP_EQUIV_DATA) };
 static char16_t const CONTENT_TYPE_DATA[] = { 'c', 'o', 'n', 't', 'e', 'n', 't', '-', 't', 'y', 'p', 'e' };
 staticJArray<char16_t,int32_t> nsHtml5MetaScanner::CONTENT_TYPE = { CONTENT_TYPE_DATA, MOZ_ARRAY_LENGTH(CONTENT_TYPE_DATA) };
 
-nsHtml5MetaScanner::nsHtml5MetaScanner()
+nsHtml5MetaScanner::nsHtml5MetaScanner(nsHtml5TreeBuilder* tb)
   : readable(nullptr),
     metaState(NS_HTML5META_SCANNER_NO),
     contentIndex(INT32_MAX),
     charsetIndex(INT32_MAX),
     httpEquivIndex(INT32_MAX),
     contentTypeIndex(INT32_MAX),
     stateSave(NS_HTML5META_SCANNER_DATA),
     strBufLen(0),
     strBuf(jArray<char16_t,int32_t>::newJArray(36)),
     content(nullptr),
     charset(nullptr),
-    httpEquivState(NS_HTML5META_SCANNER_HTTP_EQUIV_NOT_SEEN)
+    httpEquivState(NS_HTML5META_SCANNER_HTTP_EQUIV_NOT_SEEN),
+    treeBuilder(tb)
 {
   MOZ_COUNT_CTOR(nsHtml5MetaScanner);
 }
 
 
 nsHtml5MetaScanner::~nsHtml5MetaScanner()
 {
   MOZ_COUNT_DTOR(nsHtml5MetaScanner);
@@ -748,21 +749,21 @@ nsHtml5MetaScanner::addToBuffer(int32_t 
 
 void 
 nsHtml5MetaScanner::handleAttributeValue()
 {
   if (metaState != NS_HTML5META_SCANNER_A) {
     return;
   }
   if (contentIndex == CONTENT.length && !content) {
-    content = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen);
+    content = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, treeBuilder);
     return;
   }
   if (charsetIndex == CHARSET.length && !charset) {
-    charset = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen);
+    charset = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, treeBuilder);
     return;
   }
   if (httpEquivIndex == HTTP_EQUIV.length && httpEquivState == NS_HTML5META_SCANNER_HTTP_EQUIV_NOT_SEEN) {
     httpEquivState = (contentTypeIndex == CONTENT_TYPE.length) ? NS_HTML5META_SCANNER_HTTP_EQUIV_CONTENT_TYPE : NS_HTML5META_SCANNER_HTTP_EQUIV_OTHER;
     return;
   }
 }
 
@@ -780,17 +781,17 @@ nsHtml5MetaScanner::handleTag()
 
 bool 
 nsHtml5MetaScanner::handleTagInner()
 {
   if (!!charset && tryCharset(charset)) {
     return true;
   }
   if (!!content && httpEquivState == NS_HTML5META_SCANNER_HTTP_EQUIV_CONTENT_TYPE) {
-    nsString* extract = nsHtml5TreeBuilder::extractCharsetFromContent(content);
+    nsString* extract = nsHtml5TreeBuilder::extractCharsetFromContent(content, treeBuilder);
     if (!extract) {
       return false;
     }
     bool success = tryCharset(extract);
     nsHtml5Portability::releaseString(extract);
     return success;
   }
   return false;
--- a/parser/html/nsHtml5MetaScanner.h
+++ b/parser/html/nsHtml5MetaScanner.h
@@ -1,11 +1,11 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
- * Copyright (c) 2008-2010 Mozilla Foundation
+ * Copyright (c) 2008-2015 Mozilla Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a 
  * copy of this software and associated documentation files (the "Software"), 
  * to deal in the Software without restriction, including without limitation 
  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
  * and/or sell copies of the Software, and to permit persons to whom the 
  * Software is furnished to do so, subject to the following conditions:
  *
@@ -74,18 +74,19 @@ class nsHtml5MetaScanner
   protected:
     int32_t stateSave;
   private:
     int32_t strBufLen;
     autoJArray<char16_t,int32_t> strBuf;
     nsString* content;
     nsString* charset;
     int32_t httpEquivState;
+    nsHtml5TreeBuilder* treeBuilder;
   public:
-    nsHtml5MetaScanner();
+    explicit nsHtml5MetaScanner(nsHtml5TreeBuilder* tb);
     ~nsHtml5MetaScanner();
   protected:
     void stateLoop(int32_t state);
   private:
     void handleCharInAttributeValue(int32_t c);
     inline int32_t toAsciiLowerCase(int32_t c)
     {
       if (c >= 'A' && c <= 'Z') {
--- a/parser/html/nsHtml5Portability.cpp
+++ b/parser/html/nsHtml5Portability.cpp
@@ -1,29 +1,36 @@
 /* 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 "nsIAtom.h"
 #include "nsString.h"
 #include "jArray.h"
 #include "nsHtml5Portability.h"
+#include "nsHtml5TreeBuilder.h"
 
 nsIAtom*
 nsHtml5Portability::newLocalNameFromBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5AtomTable* interner)
 {
   NS_ASSERTION(!offset, "The offset should always be zero here.");
   NS_ASSERTION(interner, "Didn't get an atom service.");
   return interner->GetAtom(nsDependentSubstring(buf, buf + length));
 }
 
 nsString*
-nsHtml5Portability::newStringFromBuffer(char16_t* buf, int32_t offset, int32_t length)
+nsHtml5Portability::newStringFromBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5TreeBuilder* treeBuilder)
 {
-  return new nsString(buf + offset, length);
+  nsString* str = new nsString();
+  bool succeeded = str->Append(buf + offset, length, mozilla::fallible);
+  if (!succeeded) {
+    str->Assign(char16_t(0xFFFD));
+    treeBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
+  }
+  return str;
 }
 
 nsString*
 nsHtml5Portability::newEmptyString()
 {
   return new nsString();
 }
 
--- a/parser/html/nsHtml5Portability.h
+++ b/parser/html/nsHtml5Portability.h
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2008-2009 Mozilla Foundation
+ * Copyright (c) 2008-2015 Mozilla Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a 
  * copy of this software and associated documentation files (the "Software"), 
  * to deal in the Software without restriction, including without limitation 
  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
  * and/or sell copies of the Software, and to permit persons to whom the 
  * Software is furnished to do so, subject to the following conditions:
  *
@@ -54,17 +54,17 @@ class nsHtml5HtmlAttributes;
 class nsHtml5UTF16Buffer;
 class nsHtml5StateSnapshot;
 
 
 class nsHtml5Portability
 {
   public:
     static nsIAtom* newLocalNameFromBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5AtomTable* interner);
-    static nsString* newStringFromBuffer(char16_t* buf, int32_t offset, int32_t length);
+    static nsString* newStringFromBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5TreeBuilder* treeBuilder);
     static nsString* newEmptyString();
     static nsString* newStringFromLiteral(const char* literal);
     static nsString* newStringFromString(nsString* string);
     static jArray<char16_t,int32_t> newCharArrayFromLocal(nsIAtom* local);
     static jArray<char16_t,int32_t> newCharArrayFromString(nsString* string);
     static nsIAtom* newLocalFromLocal(nsIAtom* local, nsHtml5AtomTable* interner);
     static void releaseString(nsString* str);
     static bool localEqualsBuffer(nsIAtom* local, char16_t* buf, int32_t offset, int32_t length);
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -703,28 +703,34 @@ nsHtml5StreamParser::SniffStreamBytes(co
     mTreeBuilder->SetDocumentCharset(mCharset, mCharsetSource);
     return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment,
       aCount, aWriteCount);
   }
 
   if (!mMetaScanner && (mMode == NORMAL ||
                         mMode == VIEW_SOURCE_HTML ||
                         mMode == LOAD_AS_DATA)) {
-    mMetaScanner = new nsHtml5MetaScanner();
+    mMetaScanner = new nsHtml5MetaScanner(mTreeBuilder);
   }
   
   if (mSniffingLength + aCount >= NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE) {
     // this is the last buffer
     uint32_t countToSniffingLimit =
         NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE - mSniffingLength;
     if (mMode == NORMAL || mMode == VIEW_SOURCE_HTML || mMode == LOAD_AS_DATA) {
       nsHtml5ByteReadable readable(aFromSegment, aFromSegment +
           countToSniffingLimit);
       nsAutoCString encoding;
       mMetaScanner->sniff(&readable, encoding);
+      // Due to the way nsHtml5Portability reports OOM, ask the tree buider
+      nsresult rv;
+      if (NS_FAILED((rv = mTreeBuilder->IsBroken()))) {
+        MarkAsBroken(rv);
+        return rv;
+      }
       if (!encoding.IsEmpty()) {
         // meta scan successful; honor overrides unless meta is XSS-dangerous
         if ((mCharsetSource == kCharsetFromParentForced ||
              mCharsetSource == kCharsetFromUserForced) &&
             EncodingUtils::IsAsciiCompatible(encoding)) {
           // Honor override
           return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
             aFromSegment, aCount, aWriteCount);
@@ -747,16 +753,22 @@ nsHtml5StreamParser::SniffStreamBytes(co
         countToSniffingLimit);
   }
 
   // not the last buffer
   if (mMode == NORMAL || mMode == VIEW_SOURCE_HTML || mMode == LOAD_AS_DATA) {
     nsHtml5ByteReadable readable(aFromSegment, aFromSegment + aCount);
     nsAutoCString encoding;
     mMetaScanner->sniff(&readable, encoding);
+    // Due to the way nsHtml5Portability reports OOM, ask the tree buider
+    nsresult rv;
+    if (NS_FAILED((rv = mTreeBuilder->IsBroken()))) {
+      MarkAsBroken(rv);
+      return rv;
+    }
     if (!encoding.IsEmpty()) {
       // meta scan successful; honor overrides unless meta is XSS-dangerous
       if ((mCharsetSource == kCharsetFromParentForced ||
            mCharsetSource == kCharsetFromUserForced) &&
           EncodingUtils::IsAsciiCompatible(encoding)) {
         // Honor override
         return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment,
             aCount, aWriteCount);
--- a/parser/html/nsHtml5Tokenizer.cpp
+++ b/parser/html/nsHtml5Tokenizer.cpp
@@ -1,11 +1,11 @@
 /*
  * Copyright (c) 2005-2007 Henri Sivonen
- * Copyright (c) 2007-2013 Mozilla Foundation
+ * Copyright (c) 2007-2015 Mozilla Foundation
  * Portions of comments Copyright 2004-2010 Apple Computer, Inc., Mozilla 
  * Foundation, and Opera Software ASA.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a 
  * copy of this software and associated documentation files (the "Software"), 
  * to deal in the Software without restriction, including without limitation 
  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
  * and/or sell copies of the Software, and to permit persons to whom the 
@@ -224,17 +224,17 @@ void
 nsHtml5Tokenizer::appendStrBuf(char16_t c)
 {
   strBuf[strBufLen++] = c;
 }
 
 nsString* 
 nsHtml5Tokenizer::strBufToString()
 {
-  return nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen);
+  return nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, tokenHandler);
 }
 
 void 
 nsHtml5Tokenizer::strBufToDoctypeName()
 {
   doctypeName = nsHtml5Portability::newLocalNameFromBuffer(strBuf, 0, strBufLen, interner);
 }
 
--- a/parser/html/nsHtml5Tokenizer.h
+++ b/parser/html/nsHtml5Tokenizer.h
@@ -1,11 +1,11 @@
 /*
  * Copyright (c) 2005-2007 Henri Sivonen
- * Copyright (c) 2007-2013 Mozilla Foundation
+ * Copyright (c) 2007-2015 Mozilla Foundation
  * Portions of comments Copyright 2004-2010 Apple Computer, Inc., Mozilla 
  * Foundation, and Opera Software ASA.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a 
  * copy of this software and associated documentation files (the "Software"), 
  * to deal in the Software without restriction, including without limitation 
  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
  * and/or sell copies of the Software, and to permit persons to whom the 
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -1,11 +1,11 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
- * Copyright (c) 2007-2011 Mozilla Foundation
+ * Copyright (c) 2007-2015 Mozilla Foundation
  * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
  * Foundation, and Opera Software ASA.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  * and/or sell copies of the Software, and to permit persons to whom the
@@ -1986,17 +1986,17 @@ nsHtml5TreeBuilder::isTemplateModeStackE
 bool 
 nsHtml5TreeBuilder::isSpecialParentInForeign(nsHtml5StackNode* stackNode)
 {
   int32_t ns = stackNode->ns;
   return (kNameSpaceID_XHTML == ns) || (stackNode->isHtmlIntegrationPoint()) || ((kNameSpaceID_MathML == ns) && (stackNode->getGroup() == NS_HTML5TREE_BUILDER_MI_MO_MN_MS_MTEXT));
 }
 
 nsString* 
-nsHtml5TreeBuilder::extractCharsetFromContent(nsString* attributeValue)
+nsHtml5TreeBuilder::extractCharsetFromContent(nsString* attributeValue, nsHtml5TreeBuilder* tb)
 {
   int32_t charsetState = NS_HTML5TREE_BUILDER_CHARSET_INITIAL;
   int32_t start = -1;
   int32_t end = -1;
   autoJArray<char16_t,int32_t> buffer = nsHtml5Portability::newCharArrayFromString(attributeValue);
   for (int32_t i = 0; i < buffer.length; i++) {
     char16_t c = buffer[i];
     switch(charsetState) {
@@ -2175,17 +2175,17 @@ nsHtml5TreeBuilder::extractCharsetFromCo
     }
   }
   charsetloop_end: ;
   nsString* charset = nullptr;
   if (start != -1) {
     if (end == -1) {
       end = buffer.length;
     }
-    charset = nsHtml5Portability::newStringFromBuffer(buffer, start, end - start);
+    charset = nsHtml5Portability::newStringFromBuffer(buffer, start, end - start, tb);
   }
   return charset;
 }
 
 void 
 nsHtml5TreeBuilder::checkMetaCharset(nsHtml5HtmlAttributes* attributes)
 {
   nsString* charset = attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
@@ -2196,17 +2196,17 @@ nsHtml5TreeBuilder::checkMetaCharset(nsH
     }
     return;
   }
   if (!nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("content-type", attributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
     return;
   }
   nsString* content = attributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
   if (content) {
-    nsString* extract = nsHtml5TreeBuilder::extractCharsetFromContent(content);
+    nsString* extract = nsHtml5TreeBuilder::extractCharsetFromContent(content, this);
     if (extract) {
       if (tokenizer->internalEncodingDeclaration(extract)) {
         requestSuspension();
       }
     }
     nsHtml5Portability::releaseString(extract);
   }
 }
--- a/parser/html/nsHtml5TreeBuilder.h
+++ b/parser/html/nsHtml5TreeBuilder.h
@@ -1,11 +1,11 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
- * Copyright (c) 2007-2011 Mozilla Foundation
+ * Copyright (c) 2007-2015 Mozilla Foundation
  * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
  * Foundation, and Opera Software ASA.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  * and/or sell copies of the Software, and to permit persons to whom the
@@ -114,17 +114,17 @@ class nsHtml5TreeBuilder : public nsAHtm
     void startTagTitleInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes);
     void startTagGenericRawText(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes);
     void startTagScriptInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes);
     void startTagTemplateInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes);
     bool isTemplateContents();
     bool isTemplateModeStackEmpty();
     bool isSpecialParentInForeign(nsHtml5StackNode* stackNode);
   public:
-    static nsString* extractCharsetFromContent(nsString* attributeValue);
+    static nsString* extractCharsetFromContent(nsString* attributeValue, nsHtml5TreeBuilder* tb);
   private:
     void checkMetaCharset(nsHtml5HtmlAttributes* attributes);
   public:
     void endTag(nsHtml5ElementName* elementName);
   private:
     void endTagTemplateInHead();
     int32_t findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
     int32_t findLast(nsIAtom* name);
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -1143,16 +1143,27 @@ nsHtml5TreeBuilder::MarkAsBroken(nsresul
     return;
   }
   mBroken = aRv;
   mOpQueue.Clear(); // Previous ops don't matter anymore
   mOpQueue.AppendElement()->Init(aRv);
 }
 
 void
+nsHtml5TreeBuilder::MarkAsBrokenFromPortability(nsresult aRv)
+{
+  if (mBuilder) {
+    MarkAsBrokenAndRequestSuspension(aRv);
+    return;
+  }
+  mBroken = aRv;
+  requestSuspension();
+}
+
+void
 nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle)
 {
   MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
   startTag(nsHtml5ElementName::ELT_TITLE,
            nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
            false);
 
   // XUL will add the "Source of: " prefix.
--- a/parser/html/nsHtml5TreeBuilderHSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderHSupplement.h
@@ -66,16 +66,18 @@
     }
 
     void MarkAsBrokenAndRequestSuspension(nsresult aRv)
     {
       mBuilder->MarkAsBroken(aRv);
       requestSuspension();
     }
 
+    void MarkAsBrokenFromPortability(nsresult aRv);
+
   public:
 
     explicit nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder);
 
     nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
                        nsHtml5TreeOpStage* aStage);
 
     ~nsHtml5TreeBuilder();