layout/style/ErrorReporter.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /* diagnostic reporting for CSS style sheet parser */
     8 #include "mozilla/css/ErrorReporter.h"
     9 #include "mozilla/css/Loader.h"
    10 #include "mozilla/Preferences.h"
    11 #include "mozilla/Services.h"
    12 #include "nsCSSScanner.h"
    13 #include "nsCSSStyleSheet.h"
    14 #include "nsIConsoleService.h"
    15 #include "nsIDocument.h"
    16 #include "nsIFactory.h"
    17 #include "nsIScriptError.h"
    18 #include "nsIStringBundle.h"
    19 #include "nsServiceManagerUtils.h"
    20 #include "nsStyleUtil.h"
    21 #include "nsThreadUtils.h"
    23 #ifdef CSS_REPORT_PARSE_ERRORS
    25 using mozilla::Preferences;
    26 namespace services = mozilla::services;
    28 namespace {
    29 class ShortTermURISpecCache : public nsRunnable {
    30 public:
    31   ShortTermURISpecCache() : mPending(false) {}
    33   nsString const& GetSpec(nsIURI* aURI) {
    34     if (mURI != aURI) {
    35       mURI = aURI;
    37       nsAutoCString cSpec;
    38       mURI->GetSpec(cSpec);
    39       CopyUTF8toUTF16(cSpec, mSpec);
    40     }
    41     return mSpec;
    42   }
    44   bool IsInUse() const { return mURI != nullptr; }
    45   bool IsPending() const { return mPending; }
    46   void SetPending() { mPending = true; }
    48   // When invoked as a runnable, zap the cache.
    49   NS_IMETHOD Run() {
    50     mURI = nullptr;
    51     mSpec.Truncate();
    52     mPending = false;
    53     return NS_OK;
    54   }
    56 private:
    57   nsCOMPtr<nsIURI> mURI;
    58   nsString mSpec;
    59   bool mPending;
    60 };
    61 }
    63 static bool sReportErrors;
    64 static nsIConsoleService *sConsoleService;
    65 static nsIFactory *sScriptErrorFactory;
    66 static nsIStringBundle *sStringBundle;
    67 static ShortTermURISpecCache *sSpecCache;
    69 #define CSS_ERRORS_PREF "layout.css.report_errors"
    71 static bool
    72 InitGlobals()
    73 {
    74   NS_ABORT_IF_FALSE(!sConsoleService && !sScriptErrorFactory && !sStringBundle,
    75                     "should not have been called");
    77   if (NS_FAILED(Preferences::AddBoolVarCache(&sReportErrors, CSS_ERRORS_PREF,
    78                                              true))) {
    79     return false;
    80   }
    82   nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    83   if (!cs) {
    84     return false;
    85   }
    87   nsCOMPtr<nsIFactory> sf = do_GetClassObject(NS_SCRIPTERROR_CONTRACTID);
    88   if (!sf) {
    89     return false;
    90   }
    92   nsCOMPtr<nsIStringBundleService> sbs = services::GetStringBundleService();
    93   if (!sbs) {
    94     return false;
    95   }
    97   nsCOMPtr<nsIStringBundle> sb;
    98   nsresult rv = sbs->CreateBundle("chrome://global/locale/css.properties",
    99                                   getter_AddRefs(sb));
   100   if (NS_FAILED(rv) || !sb) {
   101     return false;
   102   }
   104   cs.forget(&sConsoleService);
   105   sf.forget(&sScriptErrorFactory);
   106   sb.forget(&sStringBundle);
   108   return true;
   109 }
   111 static inline bool
   112 ShouldReportErrors()
   113 {
   114   if (!sConsoleService) {
   115     if (!InitGlobals()) {
   116       return false;
   117     }
   118   }
   119   return sReportErrors;
   120 }
   122 namespace mozilla {
   123 namespace css {
   125 /* static */ void
   126 ErrorReporter::ReleaseGlobals()
   127 {
   128   NS_IF_RELEASE(sConsoleService);
   129   NS_IF_RELEASE(sScriptErrorFactory);
   130   NS_IF_RELEASE(sStringBundle);
   131   NS_IF_RELEASE(sSpecCache);
   132 }
   134 ErrorReporter::ErrorReporter(const nsCSSScanner& aScanner,
   135                              const nsCSSStyleSheet* aSheet,
   136                              const Loader* aLoader,
   137                              nsIURI* aURI)
   138   : mScanner(&aScanner), mSheet(aSheet), mLoader(aLoader), mURI(aURI),
   139     mInnerWindowID(0), mErrorLineNumber(0), mPrevErrorLineNumber(0),
   140     mErrorColNumber(0)
   141 {
   142 }
   144 ErrorReporter::~ErrorReporter()
   145 {
   146   // Schedule deferred cleanup for cached data. We want to strike a
   147   // balance between performance and memory usage, so we only allow
   148   // short-term caching.
   149   if (sSpecCache && sSpecCache->IsInUse() && !sSpecCache->IsPending()) {
   150     if (NS_FAILED(NS_DispatchToCurrentThread(sSpecCache))) {
   151       // Peform the "deferred" cleanup immediately if the dispatch fails.
   152       sSpecCache->Run();
   153     } else {
   154       sSpecCache->SetPending();
   155     }
   156   }
   157 }
   159 void
   160 ErrorReporter::OutputError()
   161 {
   162   if (mError.IsEmpty()) {
   163     return;
   164   }
   165   if (!ShouldReportErrors()) {
   166     ClearError();
   167     return;
   168   }
   170   if (mInnerWindowID == 0 && (mSheet || mLoader)) {
   171     if (mSheet) {
   172       mInnerWindowID = mSheet->FindOwningWindowInnerID();
   173     }
   174     if (mInnerWindowID == 0 && mLoader) {
   175       nsIDocument* doc = mLoader->GetDocument();
   176       if (doc) {
   177         mInnerWindowID = doc->InnerWindowID();
   178       }
   179     }
   180     // don't attempt this again, even if we failed
   181     mSheet = nullptr;
   182     mLoader = nullptr;
   183   }
   185   if (mFileName.IsEmpty()) {
   186     if (mURI) {
   187       if (!sSpecCache) {
   188         sSpecCache = new ShortTermURISpecCache;
   189         NS_ADDREF(sSpecCache);
   190       }
   191       mFileName = sSpecCache->GetSpec(mURI);
   192       mURI = nullptr;
   193     } else {
   194       mFileName.AssignLiteral("from DOM");
   195     }
   196   }
   198   nsresult rv;
   199   nsCOMPtr<nsIScriptError> errorObject =
   200     do_CreateInstance(sScriptErrorFactory, &rv);
   202   if (NS_SUCCEEDED(rv)) {
   203     rv = errorObject->InitWithWindowID(mError,
   204                                        mFileName,
   205                                        mErrorLine,
   206                                        mErrorLineNumber,
   207                                        mErrorColNumber,
   208                                        nsIScriptError::warningFlag,
   209                                        "CSS Parser",
   210                                        mInnerWindowID);
   211     if (NS_SUCCEEDED(rv)) {
   212       sConsoleService->LogMessage(errorObject);
   213     }
   214   }
   216   ClearError();
   217 }
   219 void
   220 ErrorReporter::OutputError(uint32_t aLineNumber, uint32_t aLineOffset)
   221 {
   222   mErrorLineNumber = aLineNumber;
   223   mErrorColNumber = aLineOffset;
   224   OutputError();
   225 }
   227 void
   228 ErrorReporter::ClearError()
   229 {
   230   mError.Truncate();
   231 }
   233 void
   234 ErrorReporter::AddToError(const nsString &aErrorText)
   235 {
   236   if (!ShouldReportErrors()) return;
   238   if (mError.IsEmpty()) {
   239     mError = aErrorText;
   240     mErrorLineNumber = mScanner->GetLineNumber();
   241     mErrorColNumber = mScanner->GetColumnNumber();
   242     // Retrieve the error line once per line, and reuse the same nsString
   243     // for all errors on that line.  That causes the text of the line to
   244     // be shared among all the nsIScriptError objects.
   245     if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
   246       mErrorLine = mScanner->GetCurrentLine();
   247       mPrevErrorLineNumber = mErrorLineNumber;
   248     }
   249   } else {
   250     mError.AppendLiteral("  ");
   251     mError.Append(aErrorText);
   252   }
   253 }
   255 void
   256 ErrorReporter::ReportUnexpected(const char *aMessage)
   257 {
   258   if (!ShouldReportErrors()) return;
   260   nsAutoString str;
   261   sStringBundle->GetStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
   262                                    getter_Copies(str));
   263   AddToError(str);
   264 }
   266 void
   267 ErrorReporter::ReportUnexpected(const char *aMessage,
   268                                 const nsString &aParam)
   269 {
   270   if (!ShouldReportErrors()) return;
   272   nsAutoString qparam;
   273   nsStyleUtil::AppendEscapedCSSIdent(aParam, qparam);
   274   const char16_t *params[1] = { qparam.get() };
   276   nsAutoString str;
   277   sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
   278                                       params, ArrayLength(params),
   279                                       getter_Copies(str));
   280   AddToError(str);
   281 }
   283 void
   284 ErrorReporter::ReportUnexpected(const char *aMessage,
   285                                 const nsCSSToken &aToken)
   286 {
   287   if (!ShouldReportErrors()) return;
   289   nsAutoString tokenString;
   290   aToken.AppendToString(tokenString);
   291   const char16_t *params[1] = { tokenString.get() };
   293   nsAutoString str;
   294   sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
   295                                       params, ArrayLength(params),
   296                                       getter_Copies(str));
   297   AddToError(str);
   298 }
   300 void
   301 ErrorReporter::ReportUnexpected(const char *aMessage,
   302                                 const nsCSSToken &aToken,
   303                                 char16_t aChar)
   304 {
   305   if (!ShouldReportErrors()) return;
   307   nsAutoString tokenString;
   308   aToken.AppendToString(tokenString);
   309   const char16_t charStr[2] = { aChar, 0 };
   310   const char16_t *params[2] = { tokenString.get(), charStr };
   312   nsAutoString str;
   313   sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
   314                                       params, ArrayLength(params),
   315                                       getter_Copies(str));
   316   AddToError(str);
   317 }
   319 void
   320 ErrorReporter::ReportUnexpectedEOF(const char *aMessage)
   321 {
   322   if (!ShouldReportErrors()) return;
   324   nsAutoString innerStr;
   325   sStringBundle->GetStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
   326                                    getter_Copies(innerStr));
   327   const char16_t *params[1] = { innerStr.get() };
   329   nsAutoString str;
   330   sStringBundle->FormatStringFromName(MOZ_UTF16("PEUnexpEOF2"),
   331                                       params, ArrayLength(params),
   332                                       getter_Copies(str));
   333   AddToError(str);
   334 }
   336 void
   337 ErrorReporter::ReportUnexpectedEOF(char16_t aExpected)
   338 {
   339   if (!ShouldReportErrors()) return;
   341   const char16_t expectedStr[] = {
   342     char16_t('\''), aExpected, char16_t('\''), char16_t(0)
   343   };
   344   const char16_t *params[1] = { expectedStr };
   346   nsAutoString str;
   347   sStringBundle->FormatStringFromName(MOZ_UTF16("PEUnexpEOF2"),
   348                                       params, ArrayLength(params),
   349                                       getter_Copies(str));
   350   AddToError(str);
   351 }
   353 } // namespace css
   354 } // namespace mozilla
   356 #endif

mercurial