From c28b308ecb77a2d82008dd94a0498a3de00384e0 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Mon, 19 Sep 2022 14:59:37 +0800 Subject: [PATCH] partly import changes from tenfourfox: - #651: M1767365+backbugs M1757604 M1497246 M1771774 M1776658 M1761981 M1773717 (bc6daa0ae) --- dom/bindings/ToJSValue.h | 2 +- dom/canvas/CanvasRenderingContext2D.cpp | 30 ++++--- dom/indexedDB/KeyPath.cpp | 2 +- dom/jsurl/nsJSProtocolHandler.cpp | 2 +- gfx/2d/BaseRect.h | 57 +++++++++++++ js/xpconnect/src/XPCConvert.cpp | 2 +- js/xpconnect/src/XPCVariant.cpp | 2 +- modules/libjar/moz.build | 4 + modules/libjar/nsJARChannel.cpp | 103 +++++++++++++++--------- modules/libjar/nsJARChannel.h | 3 + modules/libpref/init/all.js | 3 + xpcom/glue/nsTArray.h | 2 + 12 files changed, 159 insertions(+), 53 deletions(-) diff --git a/dom/bindings/ToJSValue.h b/dom/bindings/ToJSValue.h index d2e91366b..f47fba312 100644 --- a/dom/bindings/ToJSValue.h +++ b/dom/bindings/ToJSValue.h @@ -117,7 +117,7 @@ ToJSValue(JSContext* aCx, // Make sure we're called in a compartment MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); - aValue.setNumber(aArgument); + aValue.set(JS_NumberValue(aArgument)); return true; } diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index e0b8e9ef1..9033abaf0 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -5219,6 +5219,16 @@ CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx, return imageData.forget(); } +static IntRect ClipImageDataTransfer(IntRect& aSrc, const IntPoint& aDestOffset, + const IntSize& aDestBounds) { + IntRect dest = aSrc; + dest.SafeMoveBy(aDestOffset); + dest = IntRect(IntPoint(0, 0), aDestBounds).SafeIntersect(dest); + + aSrc = aSrc.SafeIntersect(dest - aDestOffset); + return aSrc + aDestOffset; +} + nsresult CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx, int32_t aX, @@ -5256,8 +5266,9 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx, } IntRect srcRect(0, 0, mWidth, mHeight); - IntRect destRect(aX, aY, aWidth, aHeight); - IntRect srcReadRect = srcRect.Intersect(destRect); + IntRect dstWriteRect(0, 0, aWidth, aHeight); + IntRect srcReadRect = ClipImageDataTransfer(dstWriteRect, IntPoint(aX, aY), + IntSize(mWidth, mHeight)); RefPtr readback; DataSourceSurface::MappedSurface rawData; if (!srcReadRect.IsEmpty()) { @@ -5270,9 +5281,6 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx, } } - IntRect dstWriteRect = srcReadRect; - dstWriteRect.MoveBy(-aX, -aY); - uint8_t* src; uint32_t srcStride; @@ -5457,10 +5465,10 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w dirtyRect = imageDataRect; } - dirtyRect.MoveBy(IntPoint(x, y)); - dirtyRect = IntRect(0, 0, mWidth, mHeight).Intersect(dirtyRect); - - if (dirtyRect.Width() <= 0 || dirtyRect.Height() <= 0) { + IntRect srcRect = dirtyRect; + dirtyRect = ClipImageDataTransfer(srcRect, IntPoint(x, y), + IntSize(mWidth, mHeight)); + if (dirtyRect.IsEmpty()) { return NS_OK; } @@ -5482,8 +5490,8 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w return NS_ERROR_FAILURE; } - uint32_t copyX = dirtyRect.x - x; - uint32_t copyY = dirtyRect.y - y; + uint32_t copyX = dirtyRect.x; + uint32_t copyY = dirtyRect.y; //uint8_t *src = aArray->Data(); uint8_t *dst = imgsurf->Data(); uint8_t* srcLine = aArray->Data() + copyY * (w * 4) + copyX * 4; diff --git a/dom/indexedDB/KeyPath.cpp b/dom/indexedDB/KeyPath.cpp index dc8d10668..99ea9b160 100644 --- a/dom/indexedDB/KeyPath.cpp +++ b/dom/indexedDB/KeyPath.cpp @@ -107,7 +107,7 @@ GetJSValFromKeyPathString(JSContext* aCx, // step 4 substep 1: check for .length on a String value. if (currentVal.isString() && !tokenizer.hasMoreTokens() && token.EqualsLiteral("length") && aOptions == DoNotCreateProperties) { - aKeyJSVal->setNumber(double(JS_GetStringLength(currentVal.toString()))); + aKeyJSVal->setNumber(uint32_t(JS_GetStringLength(currentVal.toString()))); break; } diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp index b1b295e2b..86ef33cd6 100644 --- a/dom/jsurl/nsJSProtocolHandler.cpp +++ b/dom/jsurl/nsJSProtocolHandler.cpp @@ -201,7 +201,7 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel, // Sandboxed document check: javascript: URI's are disabled // in a sandboxed document unless 'allow-scripts' was specified. nsIDocument* doc = aOriginalInnerWindow->GetExtantDoc(); - if (doc && doc->HasScriptsBlockedBySandbox()) { + if (doc && !doc->IsScriptEnabled()) { return NS_ERROR_DOM_RETVAL_UNDEFINED; } diff --git a/gfx/2d/BaseRect.h b/gfx/2d/BaseRect.h index b802df5e3..481213e3d 100644 --- a/gfx/2d/BaseRect.h +++ b/gfx/2d/BaseRect.h @@ -118,12 +118,36 @@ struct BaseRect { } return result; } + // Gives the same results as Intersect() but handles integer overflow + // better. This comes at a tiny cost in performance. + // e.g. {INT_MIN, 0, 0, 20} Intersect { 5000, 0, 500, 20 } gives: + // {5000, 0, 0, 0} + MOZ_WARN_UNUSED_RESULT Sub SafeIntersect(const Sub& aRect) const { + Sub result; + result.x = std::max(x, aRect.x); + result.y = std::max(y, aRect.y); + T right = std::min(x + width, aRect.x + aRect.width); + T bottom = std::min(y + height, aRect.y + aRect.height); + // See bug 1457110, this function expects to -only- size to 0,0 if the + // width/height is explicitly negative. + if (right < result.x || bottom < result.y) { + result.width = 0; + result.height = 0; + } else { + result.width = right - result.x; + result.height = bottom - result.y; + } + return result; + } // Sets *this to be the rectangle containing the intersection of the points // (including edges) of *this and aRect. If there are no points in that // intersection, sets *this to be an empty rectangle with x/y set to the std::max // of the x/y of *this and aRect. // // 'this' can be the same object as either aRect1 or aRect2 + // Note: bug 1457110 changed this due to a regression from bug 1387399, + // but we never used that code, and it was subsequently backed out. We have + // SafeIntersect only so we can implement bug 1767365. bool IntersectRect(const Sub& aRect1, const Sub& aRect2) { *static_cast(this) = aRect1.Intersect(aRect2); @@ -209,6 +233,39 @@ struct BaseRect { void SizeTo(T aWidth, T aHeight) { width = aWidth; height = aHeight; } void SizeTo(const SizeT& aSize) { width = aSize.width; height = aSize.height; } + // Variant of MoveBy that ensures that even after translation by a point that + // the rectangle coordinates will still fit within numeric limits. The origin + // and size will be clipped within numeric limits to ensure this. + void SafeMoveByX(T aDx) { + T x2 = XMost(); + if (aDx >= T(0)) { + T limit = std::numeric_limits::max(); + x = limit - aDx < x ? limit : x + aDx; + width = (limit - aDx < x2 ? limit : x2 + aDx) - x; + } else { + T limit = std::numeric_limits::min(); + x = limit - aDx > x ? limit : x + aDx; + width = (limit - aDx > x2 ? limit : x2 + aDx) - x; + } + } + void SafeMoveByY(T aDy) { + T y2 = YMost(); + if (aDy >= T(0)) { + T limit = std::numeric_limits::max(); + y = limit - aDy < y ? limit : y + aDy; + height = (limit - aDy < y2 ? limit : y2 + aDy) - y; + } else { + T limit = std::numeric_limits::min(); + y = limit - aDy > y ? limit : y + aDy; + height = (limit - aDy > y2 ? limit : y2 + aDy) - y; + } + } + void SafeMoveBy(T aDx, T aDy) { + SafeMoveByX(aDx); + SafeMoveByY(aDy); + } + void SafeMoveBy(const Point& aPoint) { SafeMoveBy(aPoint.x, aPoint.y); } + void Inflate(T aD) { Inflate(aD, aD); } void Inflate(T aDx, T aDy) { diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index a4c07ab57..753a10a5d 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -134,7 +134,7 @@ XPCConvert::NativeData2JS(MutableHandleValue d, const void* s, d.setNumber(*static_cast(s)); return true; case nsXPTType::T_DOUBLE: - d.setNumber(*static_cast(s)); + d.set(JS_NumberValue(*static_cast(s))); return true; case nsXPTType::T_BOOL : d.setBoolean(*static_cast(s)); diff --git a/js/xpconnect/src/XPCVariant.cpp b/js/xpconnect/src/XPCVariant.cpp index d37d0eb01..0fea6bc10 100644 --- a/js/xpconnect/src/XPCVariant.cpp +++ b/js/xpconnect/src/XPCVariant.cpp @@ -425,7 +425,7 @@ XPCVariant::VariantDataToJS(nsIVariant* variant, double d; if (NS_FAILED(variant->GetAsDouble(&d))) return false; - pJSVal.setNumber(d); + pJSVal.set(JS_NumberValue(d)); return true; } case nsIDataType::VTYPE_BOOL: diff --git a/modules/libjar/moz.build b/modules/libjar/moz.build index c4f86a484..097c9b3c8 100644 --- a/modules/libjar/moz.build +++ b/modules/libjar/moz.build @@ -48,5 +48,9 @@ include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' +LOCAL_INCLUDES += [ + '/netwerk/base', +] + if CONFIG['GNU_CXX']: CXXFLAGS += ['-Wshadow'] diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index c9ec701da..dee2863d7 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -28,6 +28,7 @@ #include "nsINetworkInterceptController.h" #include "InterceptedJARChannel.h" #include "nsInputStreamPump.h" +#include "nsStandardURL.h" using namespace mozilla; using namespace mozilla::net; @@ -83,6 +84,24 @@ public: fullJarURI->GetAsciiSpec(mJarDirSpec); NS_ASSERTION(NS_SUCCEEDED(rv), "this shouldn't fail"); } + /* implement bug 1771774 without NS_MutateURI: use asciispec above */ + if (ENTRY_IS_DIRECTORY(mJarEntry) && fullJarURI) { + RefPtr cleanuri = new nsStandardURL(); + + if (NS_SUCCEEDED(cleanuri->Init( + nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, + mJarDirSpec, nullptr, nullptr))) { + cleanuri->SetQuery(NS_LITERAL_CSTRING("")); + cleanuri->SetRef(NS_LITERAL_CSTRING("")); +#ifdef DEBUG + nsresult rv = +#endif + cleanuri->GetAsciiSpec(mJarDirSpec); + NS_ASSERTION(NS_SUCCEEDED(rv), "this shouldn't fail either"); + } else { + MOZ_CRASH("failed to clean jar URI"); + } + } } int64_t GetContentLength() @@ -695,48 +714,50 @@ nsJARChannel::GetSecurityInfo(nsISupports **aSecurityInfo) return NS_OK; } +nsresult +nsJARChannel::SetContentTypeGuess() { + // + // generate content type and set it + // + const char *ext = nullptr, *fileName = mJarEntry.get(); + int32_t len = mJarEntry.Length(); + + // check if we're displaying a directory + // mJarEntry will be empty if we're trying to display + // the topmost directory in a zip, e.g. jar:foo.zip!/ + if (ENTRY_IS_DIRECTORY(mJarEntry)) { + mContentType.AssignLiteral(APPLICATION_HTTP_INDEX_FORMAT); + } else { + // not a directory, take a guess by its extension + for (int32_t i = len-1; i >= 0; i--) { + if (fileName[i] == '.') { + ext = &fileName[i + 1]; + break; + } + } + if (ext) { + nsIMIMEService *mimeServ = gJarHandler->MimeService(); + if (mimeServ) + mimeServ->GetTypeFromExtension(nsDependentCString(ext), mContentType); + } + if (mContentType.IsEmpty()) + mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE); + } + + return NS_OK; +} + NS_IMETHODIMP -nsJARChannel::GetContentType(nsACString &result) +nsJARChannel::GetContentType(nsACString &aResult) { // If the Jar file has not been open yet, // We return application/x-unknown-content-type - if (!mOpened) { - result.Assign(UNKNOWN_CONTENT_TYPE); + if (!mOpened || mContentType.IsEmpty()) { + aResult.Assign(UNKNOWN_CONTENT_TYPE); return NS_OK; } - if (mContentType.IsEmpty()) { - - // - // generate content type and set it - // - const char *ext = nullptr, *fileName = mJarEntry.get(); - int32_t len = mJarEntry.Length(); - - // check if we're displaying a directory - // mJarEntry will be empty if we're trying to display - // the topmost directory in a zip, e.g. jar:foo.zip!/ - if (ENTRY_IS_DIRECTORY(mJarEntry)) { - mContentType.AssignLiteral(APPLICATION_HTTP_INDEX_FORMAT); - } - else { - // not a directory, take a guess by its extension - for (int32_t i = len-1; i >= 0; i--) { - if (fileName[i] == '.') { - ext = &fileName[i + 1]; - break; - } - } - if (ext) { - nsIMIMEService *mimeServ = gJarHandler->MimeService(); - if (mimeServ) - mimeServ->GetTypeFromExtension(nsDependentCString(ext), mContentType); - } - if (mContentType.IsEmpty()) - mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE); - } - } - result = mContentType; + aResult = mContentType; return NS_OK; } @@ -847,7 +868,7 @@ nsJARChannel::Open(nsIInputStream **stream) return rv; input.forget(stream); - mOpened = true; + SetOpened(); // local files are always considered safe mIsUnsafe = false; return NS_OK; @@ -934,6 +955,14 @@ nsJARChannel::OverrideWithSynthesizedResponse(nsIInputStream* aSynthesizedInput, NS_ENSURE_SUCCESS_VOID(rv); } +void +nsJARChannel::SetOpened() { + MOZ_ASSERT(!mOpened, "Opening channel twice?"); + mOpened = true; + // Compute the content type now. + NS_ASSERTION(NS_SUCCEEDED(SetContentTypeGuess()), "content type guess failure"); +} + NS_IMETHODIMP nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx) { @@ -1068,7 +1097,7 @@ nsJARChannel::FinishAsyncOpen() if (mLoadGroup) mLoadGroup->AddRequest(this, nullptr); - mOpened = true; + SetOpened(); } //----------------------------------------------------------------------------- diff --git a/modules/libjar/nsJARChannel.h b/modules/libjar/nsJARChannel.h index 8c5d6f6ab..ce2e312d4 100644 --- a/modules/libjar/nsJARChannel.h +++ b/modules/libjar/nsJARChannel.h @@ -82,6 +82,9 @@ private: bool BypassServiceWorker() const; + nsresult SetContentTypeGuess(); + void SetOpened(); + // Returns true if this channel should intercept the network request and // prepare for a possible synthesized response instead. bool ShouldIntercept(); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 63fa4c221..834b15e3a 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1232,7 +1232,10 @@ pref("network.protocol-handler.external.iehistory", false); pref("network.protocol-handler.external.ierss", false); pref("network.protocol-handler.external.mk", false); pref("network.protocol-handler.external.ms-help", false); +pref("network.protocol-handler.external.ms-msdt", false); pref("network.protocol-handler.external.res", false); +pref("network.protocol-handler.external.search", false); +pref("network.protocol-handler.external.search-ms", false); pref("network.protocol-handler.external.shell", false); pref("network.protocol-handler.external.vnd.ms.radio", false); #ifdef XP_MACOSX diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index ad80cab8d..e0704581a 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -1278,6 +1278,8 @@ protected: elem_type* ReplaceElementsAt(index_type aStart, size_type aCount, const Item* aArray, size_type aArrayLen) { + MOZ_RELEASE_ASSERT(!(aStart > Length())); + MOZ_RELEASE_ASSERT(!(aCount > (Length() - aStart))); // Adjust memory allocation up-front to catch errors. if (!ActualAlloc::Successful(this->template EnsureCapacity( Length() + aArrayLen - aCount, sizeof(elem_type)))) {