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.

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

mercurial