mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 786108 - Cache UTF-16 version of URI to prevent repeated conversions in the CSS scanner, and free the cache after a short time. r=bz
This commit is contained in:
parent
803b082135
commit
ed479625af
22
layout/style/crashtests/786108-1.html
Normal file
22
layout/style/crashtests/786108-1.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<body></body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
// Detect severe performance and memory issues when large amounts of errors
|
||||||
|
// are reported from CSS embedded in a file with a long data URI. Addressed
|
||||||
|
// by 786108; should finish quickly with that patch and run for a very long
|
||||||
|
// time otherwise.
|
||||||
|
|
||||||
|
var img = new Array;
|
||||||
|
img.push('<img src="data:image/svg+xml,');
|
||||||
|
img.push(encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300px" height="300px">'));
|
||||||
|
|
||||||
|
for (var i = 0 ; i < 10000 ; i++)
|
||||||
|
img.push(encodeURIComponent('<circle cx="0" cy="0" r="1" style="xxx-invalid-property: 0;"/>'));
|
||||||
|
|
||||||
|
img.push(encodeURIComponent('</svg>'));
|
||||||
|
img.push('">');
|
||||||
|
|
||||||
|
document.getElementsByTagName('body')[0].innerHTML = img.join('');
|
||||||
|
</script>
|
||||||
|
</html>
|
23
layout/style/crashtests/786108-2.html
Normal file
23
layout/style/crashtests/786108-2.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<body></body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
// Detect severe performance and memory issues when large amounts of errors
|
||||||
|
// are reported from CSS embedded in a file with a long data URI. Addressed
|
||||||
|
// by 786108; should finish quickly with that patch and run for a very long
|
||||||
|
// time otherwise. This version is designed for slow / memory constrained
|
||||||
|
// platforms like Android.
|
||||||
|
|
||||||
|
var img = new Array;
|
||||||
|
img.push('<img src="data:image/svg+xml,');
|
||||||
|
img.push(encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300px" height="300px">'));
|
||||||
|
|
||||||
|
for (var i = 0 ; i < 2500 ; i++)
|
||||||
|
img.push(encodeURIComponent('<circle cx="0" cy="0" r="1" style="xxx-invalid-property: 0;"/>'));
|
||||||
|
|
||||||
|
img.push(encodeURIComponent('</svg>'));
|
||||||
|
img.push('">');
|
||||||
|
|
||||||
|
document.getElementsByTagName('body')[0].innerHTML = img.join('');
|
||||||
|
</script>
|
||||||
|
</html>
|
@ -77,4 +77,6 @@ load 696188-1.html
|
|||||||
load 700116.html
|
load 700116.html
|
||||||
load 729126-1.html
|
load 729126-1.html
|
||||||
load 729126-2.html
|
load 729126-2.html
|
||||||
|
skip-if(Android||browserIsRemote) load 786108-1.html # Bug 795534
|
||||||
|
skip-if(browserIsRemote) load 786108-2.html # Bug 795534
|
||||||
load 788836.html
|
load 788836.html
|
||||||
|
@ -249,6 +249,29 @@ nsCSSToken::AppendToString(nsString& aBuffer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DeferredCleanupRunnable : public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeferredCleanupRunnable(nsCSSScanner* aToClean)
|
||||||
|
: mToClean(aToClean)
|
||||||
|
{}
|
||||||
|
|
||||||
|
NS_IMETHOD Run() {
|
||||||
|
if (mToClean) {
|
||||||
|
mToClean->PerformDeferredCleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Revoke() {
|
||||||
|
mToClean = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsCSSScanner* mToClean;
|
||||||
|
};
|
||||||
|
|
||||||
nsCSSScanner::nsCSSScanner()
|
nsCSSScanner::nsCSSScanner()
|
||||||
: mReadPointer(nullptr)
|
: mReadPointer(nullptr)
|
||||||
, mSVGMode(false)
|
, mSVGMode(false)
|
||||||
@ -271,13 +294,24 @@ nsCSSScanner::nsCSSScanner()
|
|||||||
nsCSSScanner::~nsCSSScanner()
|
nsCSSScanner::~nsCSSScanner()
|
||||||
{
|
{
|
||||||
MOZ_COUNT_DTOR(nsCSSScanner);
|
MOZ_COUNT_DTOR(nsCSSScanner);
|
||||||
Close();
|
Reset();
|
||||||
if (mLocalPushback != mPushback) {
|
if (mLocalPushback != mPushback) {
|
||||||
delete [] mPushback;
|
delete [] mPushback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CSS_REPORT_PARSE_ERRORS
|
#ifdef CSS_REPORT_PARSE_ERRORS
|
||||||
|
void
|
||||||
|
nsCSSScanner::PerformDeferredCleanup()
|
||||||
|
{
|
||||||
|
// Clean up all short term caches.
|
||||||
|
mCachedURI = nullptr;
|
||||||
|
mCachedFileName.Truncate();
|
||||||
|
|
||||||
|
// Release our DeferredCleanupRunnable.
|
||||||
|
mDeferredCleaner.Forget();
|
||||||
|
}
|
||||||
|
|
||||||
#define CSS_ERRORS_PREF "layout.css.report_errors"
|
#define CSS_ERRORS_PREF "layout.css.report_errors"
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -331,17 +365,13 @@ nsCSSScanner::Init(const nsAString& aBuffer,
|
|||||||
mCount = aBuffer.Length();
|
mCount = aBuffer.Length();
|
||||||
|
|
||||||
#ifdef CSS_REPORT_PARSE_ERRORS
|
#ifdef CSS_REPORT_PARSE_ERRORS
|
||||||
// If aURI is the same as mURI, no need to reget mFileName -- it
|
// If aURI is different from mCachedURI, invalidate the filename cache.
|
||||||
// shouldn't have changed.
|
if (aURI != mCachedURI) {
|
||||||
if (aURI != mURI) {
|
mCachedURI = aURI;
|
||||||
mURI = aURI;
|
mCachedFileName.Truncate();
|
||||||
if (aURI) {
|
|
||||||
aURI->GetSpec(mFileName);
|
|
||||||
} else {
|
|
||||||
mFileName.Adopt(NS_strdup("from DOM"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // CSS_REPORT_PARSE_ERRORS
|
#endif // CSS_REPORT_PARSE_ERRORS
|
||||||
|
|
||||||
mLineNumber = aLineNumber;
|
mLineNumber = aLineNumber;
|
||||||
|
|
||||||
// Reset variables that we use to keep track of our progress through the input
|
// Reset variables that we use to keep track of our progress through the input
|
||||||
@ -406,8 +436,19 @@ nsCSSScanner::OutputError()
|
|||||||
do_CreateInstance(gScriptErrorFactory, &rv);
|
do_CreateInstance(gScriptErrorFactory, &rv);
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
// Update the cached filename if needed.
|
||||||
|
if (mCachedFileName.IsEmpty()) {
|
||||||
|
if (mCachedURI) {
|
||||||
|
nsAutoCString cFileName;
|
||||||
|
mCachedURI->GetSpec(cFileName);
|
||||||
|
CopyUTF8toUTF16(cFileName, mCachedFileName);
|
||||||
|
} else {
|
||||||
|
mCachedFileName.AssignLiteral("from DOM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rv = errorObject->InitWithWindowID(mError,
|
rv = errorObject->InitWithWindowID(mError,
|
||||||
NS_ConvertUTF8toUTF16(mFileName),
|
mCachedFileName,
|
||||||
EmptyString(),
|
EmptyString(),
|
||||||
mErrorLineNumber,
|
mErrorLineNumber,
|
||||||
mErrorColNumber,
|
mErrorColNumber,
|
||||||
@ -554,19 +595,37 @@ nsCSSScanner::ReportUnexpectedTokenParams(nsCSSToken& tok,
|
|||||||
|
|
||||||
void
|
void
|
||||||
nsCSSScanner::Close()
|
nsCSSScanner::Close()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
// Schedule deferred cleanup for cached data. We want to strike a balance
|
||||||
|
// between performance and memory usage, so we only allow short-term caching.
|
||||||
|
#ifdef CSS_REPORT_PARSE_ERRORS
|
||||||
|
if (!mDeferredCleaner.IsPending()) {
|
||||||
|
mDeferredCleaner = new DeferredCleanupRunnable(this);
|
||||||
|
if (NS_FAILED(NS_DispatchToCurrentThread(mDeferredCleaner.get()))) {
|
||||||
|
// Peform the "deferred" cleanup immediately if the dispatch fails.
|
||||||
|
// This will also have the effect of clearing mDeferredCleaner.
|
||||||
|
nsCSSScanner::PerformDeferredCleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsCSSScanner::Reset()
|
||||||
{
|
{
|
||||||
mReadPointer = nullptr;
|
mReadPointer = nullptr;
|
||||||
|
|
||||||
// Clean things up so we don't hold on to memory if our parser gets recycled.
|
// Clean things up so we don't hold on to memory if our parser gets recycled.
|
||||||
#ifdef CSS_REPORT_PARSE_ERRORS
|
#ifdef CSS_REPORT_PARSE_ERRORS
|
||||||
mFileName.Truncate();
|
|
||||||
mURI = nullptr;
|
|
||||||
mError.Truncate();
|
mError.Truncate();
|
||||||
mInnerWindowID = 0;
|
mInnerWindowID = 0;
|
||||||
mWindowIDCached = false;
|
mWindowIDCached = false;
|
||||||
mSheet = nullptr;
|
mSheet = nullptr;
|
||||||
mLoader = nullptr;
|
mLoader = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mPushback != mLocalPushback) {
|
if (mPushback != mLocalPushback) {
|
||||||
delete [] mPushback;
|
delete [] mPushback;
|
||||||
mPushback = mLocalPushback;
|
mPushback = mLocalPushback;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
// for #ifdef CSS_REPORT_PARSE_ERRORS
|
// for #ifdef CSS_REPORT_PARSE_ERRORS
|
||||||
#include "nsXPIDLString.h"
|
#include "nsXPIDLString.h"
|
||||||
|
#include "nsThreadUtils.h"
|
||||||
class nsIURI;
|
class nsIURI;
|
||||||
|
|
||||||
// Token types
|
// Token types
|
||||||
@ -91,6 +92,8 @@ struct nsCSSToken {
|
|||||||
void AppendToString(nsString& aBuffer);
|
void AppendToString(nsString& aBuffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DeferredCleanupRunnable;
|
||||||
|
|
||||||
// CSS Scanner API. Used to tokenize an input stream using the CSS
|
// CSS Scanner API. Used to tokenize an input stream using the CSS
|
||||||
// forward compatible tokenization rules. This implementation is
|
// forward compatible tokenization rules. This implementation is
|
||||||
// private to this package and is only used internally by the css
|
// private to this package and is only used internally by the css
|
||||||
@ -120,6 +123,9 @@ class nsCSSScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CSS_REPORT_PARSE_ERRORS
|
#ifdef CSS_REPORT_PARSE_ERRORS
|
||||||
|
// Clean up any reclaimable cached resources.
|
||||||
|
void PerformDeferredCleanup();
|
||||||
|
|
||||||
void AddToError(const nsSubstring& aErrorText);
|
void AddToError(const nsSubstring& aErrorText);
|
||||||
void OutputError();
|
void OutputError();
|
||||||
void ClearError();
|
void ClearError();
|
||||||
@ -128,6 +134,8 @@ class nsCSSScanner {
|
|||||||
void ReportUnexpected(const char* aMessage);
|
void ReportUnexpected(const char* aMessage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void Reset();
|
||||||
|
|
||||||
void ReportUnexpectedParams(const char* aMessage,
|
void ReportUnexpectedParams(const char* aMessage,
|
||||||
const PRUnichar** aParams,
|
const PRUnichar** aParams,
|
||||||
uint32_t aParamsLength);
|
uint32_t aParamsLength);
|
||||||
@ -211,8 +219,9 @@ protected:
|
|||||||
uint32_t mRecordStartOffset;
|
uint32_t mRecordStartOffset;
|
||||||
|
|
||||||
#ifdef CSS_REPORT_PARSE_ERRORS
|
#ifdef CSS_REPORT_PARSE_ERRORS
|
||||||
nsXPIDLCString mFileName;
|
nsRevocableEventPtr<DeferredCleanupRunnable> mDeferredCleaner;
|
||||||
nsCOMPtr<nsIURI> mURI; // Cached so we know to not refetch mFileName
|
nsCOMPtr<nsIURI> mCachedURI; // Used to invalidate the cached filename.
|
||||||
|
nsString mCachedFileName;
|
||||||
uint32_t mErrorLineNumber, mColNumber, mErrorColNumber;
|
uint32_t mErrorLineNumber, mColNumber, mErrorColNumber;
|
||||||
nsFixedString mError;
|
nsFixedString mError;
|
||||||
PRUnichar mErrorBuf[200];
|
PRUnichar mErrorBuf[200];
|
||||||
|
Loading…
Reference in New Issue
Block a user