Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h
Warning:line 1197, column 38
Dereference of null pointer (loaded from field 'mKeyHash')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nsGlobalWindowOuter.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -resource-dir /usr/lib/llvm-20/lib/clang/20 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/battery -I /var/lib/jenkins/workspace/firefox-scan-build/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/dom/media -I /var/lib/jenkins/workspace/firefox-scan-build/dom/network -I /var/lib/jenkins/workspace/firefox-scan-build/caps -I /var/lib/jenkins/workspace/firefox-scan-build/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/file -I /var/lib/jenkins/workspace/firefox-scan-build/dom/geolocation -I /var/lib/jenkins/workspace/firefox-scan-build/dom/html -I /var/lib/jenkins/workspace/firefox-scan-build/dom/ipc -I /var/lib/jenkins/workspace/firefox-scan-build/dom/storage -I /var/lib/jenkins/workspace/firefox-scan-build/dom/svg -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xml -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xslt/xpath -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xul -I /var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/src -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/2d -I /var/lib/jenkins/workspace/firefox-scan-build/image -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/loader -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/src -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/layout/base -I /var/lib/jenkins/workspace/firefox-scan-build/layout/forms -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/layout/style -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/base -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/url-classifier -I /var/lib/jenkins/workspace/firefox-scan-build/parser/htmlparser -I /var/lib/jenkins/workspace/firefox-scan-build/security/manager/ssl -I /var/lib/jenkins/workspace/firefox-scan-build/third_party/xsimd/include -I /var/lib/jenkins/workspace/firefox-scan-build/widget -I /var/lib/jenkins/workspace/firefox-scan-build/xpcom/build -I /var/lib/jenkins/workspace/firefox-scan-build/xpcom/ds -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/sctp/datachannel -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gtk-3.0/unix-print -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-20/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-01-20-090804-167946-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp

/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include "mozilla/Assertions.h"
8#include "mozilla/ScopeExit.h"
9#include "nsGlobalWindowOuter.h"
10#include "nsGlobalWindowInner.h"
11
12#include <algorithm>
13
14#include "mozilla/MemoryReporting.h"
15
16// Local Includes
17#include "Navigator.h"
18#include "nsContentSecurityManager.h"
19#include "nsGlobalWindowOuter.h"
20#include "nsScreen.h"
21#include "nsHistory.h"
22#include "nsDOMNavigationTiming.h"
23#include "nsIDOMStorageManager.h"
24#include "nsISecureBrowserUI.h"
25#include "nsIWebProgressListener.h"
26#include "mozilla/AntiTrackingUtils.h"
27#include "mozilla/Result.h"
28#include "mozilla/dom/AutoPrintEventDispatcher.h"
29#include "mozilla/dom/BindingUtils.h"
30#include "mozilla/dom/BrowserChild.h"
31#include "mozilla/dom/BrowsingContextBinding.h"
32#include "mozilla/dom/CanonicalBrowsingContext.h"
33#include "mozilla/dom/ContentChild.h"
34#include "mozilla/dom/ContentFrameMessageManager.h"
35#include "mozilla/dom/DocumentInlines.h"
36#include "mozilla/dom/EventTarget.h"
37#include "mozilla/dom/HTMLIFrameElement.h"
38#include "mozilla/dom/LocalStorage.h"
39#include "mozilla/dom/LSObject.h"
40#include "mozilla/dom/Storage.h"
41#include "mozilla/dom/MaybeCrossOriginObject.h"
42#include "mozilla/dom/Performance.h"
43#include "mozilla/dom/ProxyHandlerUtils.h"
44#include "mozilla/dom/StorageEvent.h"
45#include "mozilla/dom/StorageEventBinding.h"
46#include "mozilla/dom/StorageNotifierService.h"
47#include "mozilla/dom/StorageUtils.h"
48#include "mozilla/dom/Timeout.h"
49#include "mozilla/dom/TimeoutHandler.h"
50#include "mozilla/dom/TimeoutManager.h"
51#include "mozilla/dom/UserActivation.h"
52#include "mozilla/dom/WindowContext.h"
53#include "mozilla/dom/WindowFeatures.h" // WindowFeatures
54#include "mozilla/dom/WindowProxyHolder.h"
55#include "mozilla/IntegerPrintfMacros.h"
56#include "mozilla/StorageAccessAPIHelper.h"
57#include "nsBaseCommandController.h"
58#include "nsError.h"
59#include "nsICookieService.h"
60#include "nsISizeOfEventTarget.h"
61#include "nsDOMJSUtils.h"
62#include "nsArrayUtils.h"
63#include "nsIDocShellTreeOwner.h"
64#include "nsIInterfaceRequestorUtils.h"
65#include "nsIPermissionManager.h"
66#include "nsIScriptContext.h"
67#include "nsWindowMemoryReporter.h"
68#include "nsWindowSizes.h"
69#include "nsWindowWatcher.h"
70#include "WindowNamedPropertiesHandler.h"
71#include "nsFrameSelection.h"
72#include "nsNetUtil.h"
73#include "nsVariant.h"
74#include "nsPrintfCString.h"
75#include "mozilla/intl/LocaleService.h"
76#include "WindowDestroyedEvent.h"
77#include "nsDocShellLoadState.h"
78#include "mozilla/dom/WindowGlobalChild.h"
79
80// Helper Classes
81#include "nsJSUtils.h"
82#include "jsapi.h"
83#include "jsfriendapi.h"
84#include "js/CallAndConstruct.h" // JS::Call
85#include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
86#include "js/friend/WindowProxy.h" // js::IsWindowProxy, js::SetWindowProxy
87#include "js/PropertyAndElement.h" // JS_DefineObject, JS_GetProperty
88#include "js/PropertySpec.h"
89#include "js/RealmIterators.h"
90#include "js/Wrapper.h"
91#include "nsLayoutUtils.h"
92#include "nsReadableUtils.h"
93#include "nsJSEnvironment.h"
94#include "mozilla/dom/ScriptSettings.h"
95#include "mozilla/Preferences.h"
96#include "mozilla/Likely.h"
97#include "mozilla/SchedulerGroup.h"
98#include "mozilla/SpinEventLoopUntil.h"
99#include "mozilla/Sprintf.h"
100#include "mozilla/Unused.h"
101
102// Other Classes
103#include "mozilla/dom/BarProps.h"
104#include "nsLayoutStatics.h"
105#include "nsCCUncollectableMarker.h"
106#include "mozilla/dom/WorkerCommon.h"
107#include "mozilla/dom/ToJSValue.h"
108#include "nsJSPrincipals.h"
109#include "mozilla/Attributes.h"
110#include "mozilla/Components.h"
111#include "mozilla/Debug.h"
112#include "mozilla/EventListenerManager.h"
113#include "mozilla/MouseEvents.h"
114#include "mozilla/PresShell.h"
115#include "mozilla/ProcessHangMonitor.h"
116#include "mozilla/StaticPrefs_dom.h"
117#include "mozilla/StaticPrefs_full_screen_api.h"
118#include "mozilla/StaticPrefs_print.h"
119#include "mozilla/StaticPrefs_fission.h"
120#include "mozilla/ThrottledEventQueue.h"
121#include "AudioChannelService.h"
122#include "nsAboutProtocolUtils.h"
123#include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE
124#include "PostMessageEvent.h"
125#include "mozilla/dom/DocGroup.h"
126#include "mozilla/net/CookieJarSettings.h"
127
128// Interfaces Needed
129#include "nsIFrame.h"
130#include "nsCanvasFrame.h"
131#include "nsIWidget.h"
132#include "nsIWidgetListener.h"
133#include "nsIBaseWindow.h"
134#include "nsIDeviceSensors.h"
135#include "nsIContent.h"
136#include "nsIDocShell.h"
137#include "mozilla/dom/Document.h"
138#include "Crypto.h"
139#include "nsDOMString.h"
140#include "nsThreadUtils.h"
141#include "nsILoadContext.h"
142#include "nsView.h"
143#include "nsViewManager.h"
144#include "nsIPrompt.h"
145#include "nsIPromptService.h"
146#include "nsIPromptFactory.h"
147#include "nsIWritablePropertyBag2.h"
148#include "nsIWebNavigation.h"
149#include "nsIWebBrowserChrome.h"
150#include "nsIWebBrowserFind.h" // For window.find()
151#include "nsComputedDOMStyle.h"
152#include "nsDOMCID.h"
153#include "nsDOMWindowUtils.h"
154#include "nsIWindowWatcher.h"
155#include "nsPIWindowWatcher.h"
156#include "nsIDocumentViewer.h"
157#include "nsIScriptError.h"
158#include "nsISHistory.h"
159#include "nsIControllers.h"
160#include "nsGlobalWindowCommands.h"
161#include "nsQueryObject.h"
162#include "nsContentUtils.h"
163#include "nsCSSProps.h"
164#include "nsIURIFixup.h"
165#include "nsIURIMutator.h"
166#include "mozilla/EventDispatcher.h"
167#include "mozilla/EventStateManager.h"
168#include "mozilla/ScrollContainerFrame.h"
169#include "nsIObserverService.h"
170#include "nsFocusManager.h"
171#include "nsIAppWindow.h"
172#include "nsServiceManagerUtils.h"
173#include "mozilla/dom/CustomEvent.h"
174#include "nsIScreenManager.h"
175#include "nsIClassifiedChannel.h"
176#include "nsIXULRuntime.h"
177#include "xpcprivate.h"
178
179#ifdef NS_PRINTING1
180# include "nsIPrintSettings.h"
181# include "nsIPrintSettingsService.h"
182# include "nsIWebBrowserPrint.h"
183#endif
184
185#include "nsWindowRoot.h"
186#include "nsNetCID.h"
187#include "nsIArray.h"
188
189#include "nsIDOMXULCommandDispatcher.h"
190
191#include "mozilla/GlobalKeyListener.h"
192
193#include "nsIDragService.h"
194#include "mozilla/dom/Element.h"
195#include "mozilla/dom/Selection.h"
196#include "nsFrameLoader.h"
197#include "nsFrameLoaderOwner.h"
198#include "nsXPCOMCID.h"
199#include "mozilla/Logging.h"
200#include "mozilla/ProfilerMarkers.h"
201#include "prenv.h"
202
203#include "mozilla/dom/IDBFactory.h"
204#include "mozilla/dom/MessageChannel.h"
205#include "mozilla/dom/Promise.h"
206
207#include "mozilla/dom/Gamepad.h"
208#include "mozilla/dom/GamepadManager.h"
209
210#include "gfxVR.h"
211#include "VRShMem.h"
212#include "FxRWindowManager.h"
213#include "mozilla/dom/VRDisplay.h"
214#include "mozilla/dom/VRDisplayEvent.h"
215#include "mozilla/dom/VRDisplayEventBinding.h"
216#include "mozilla/dom/VREventObserver.h"
217
218#include "nsRefreshDriver.h"
219
220#include "mozilla/extensions/WebExtensionPolicy.h"
221
222#include "mozilla/BasePrincipal.h"
223#include "mozilla/Services.h"
224#include "mozilla/Telemetry.h"
225#include "mozilla/dom/Location.h"
226#include "nsHTMLDocument.h"
227#include "nsWrapperCacheInlines.h"
228#include "mozilla/DOMEventTargetHelper.h"
229#include "prrng.h"
230#include "nsSandboxFlags.h"
231#include "nsXULControllers.h"
232#include "mozilla/dom/AudioContext.h"
233#include "mozilla/dom/BrowserElementDictionariesBinding.h"
234#include "mozilla/dom/BrowsingContextGroup.h"
235#include "mozilla/dom/cache/CacheStorage.h"
236#include "mozilla/dom/Console.h"
237#include "mozilla/dom/Fetch.h"
238#include "mozilla/dom/FunctionBinding.h"
239#include "mozilla/dom/HashChangeEvent.h"
240#include "mozilla/dom/IntlUtils.h"
241#include "mozilla/dom/PopStateEvent.h"
242#include "mozilla/dom/PopupBlockedEvent.h"
243#include "mozilla/dom/PrimitiveConversions.h"
244#include "mozilla/dom/WindowBinding.h"
245#include "nsIBrowserChild.h"
246#include "mozilla/dom/MediaQueryList.h"
247#include "mozilla/dom/NavigatorBinding.h"
248#include "mozilla/dom/ImageBitmap.h"
249#include "mozilla/dom/ImageBitmapBinding.h"
250#include "mozilla/dom/ServiceWorkerRegistration.h"
251#include "mozilla/dom/WebIDLGlobalNameHash.h"
252#include "mozilla/dom/Worklet.h"
253#include "AccessCheck.h"
254
255#ifdef MOZ_WEBSPEECH1
256# include "mozilla/dom/SpeechSynthesis.h"
257#endif
258
259#ifdef ANDROID
260# include <android/log.h>
261#endif
262
263#ifdef XP_WIN
264# include <process.h>
265# define getpid _getpid
266#else
267# include <unistd.h> // for getpid()
268#endif
269
270using namespace mozilla;
271using namespace mozilla::dom;
272using namespace mozilla::dom::ipc;
273using mozilla::BasePrincipal;
274using mozilla::OriginAttributes;
275using mozilla::TimeStamp;
276using mozilla::layout::RemotePrintJobChild;
277
278static inline nsGlobalWindowInner* GetCurrentInnerWindowInternal(
279 const nsGlobalWindowOuter* aOuter) {
280 return nsGlobalWindowInner::Cast(aOuter->GetCurrentInnerWindow());
281}
282
283#define FORWARD_TO_INNER(method, args, err_rval)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 283); return err_rval; } return GetCurrentInnerWindowInternal
(this)->method args; } while (0)
\
284 PR_BEGIN_MACROdo { \
285 if (!mInnerWindow) { \
286 NS_WARNING("No inner window available!")NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 286)
; \
287 return err_rval; \
288 } \
289 return GetCurrentInnerWindowInternal(this)->method args; \
290 PR_END_MACRO} while (0)
291
292#define FORWARD_TO_INNER_VOID(method, args)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 292); return; } GetCurrentInnerWindowInternal(this)->method
args; return; } while (0)
\
293 PR_BEGIN_MACROdo { \
294 if (!mInnerWindow) { \
295 NS_WARNING("No inner window available!")NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 295)
; \
296 return; \
297 } \
298 GetCurrentInnerWindowInternal(this)->method args; \
299 return; \
300 PR_END_MACRO} while (0)
301
302// Same as FORWARD_TO_INNER, but this will create a fresh inner if an
303// inner doesn't already exists.
304#define FORWARD_TO_INNER_CREATE(method, args, err_rval)do { if (!mInnerWindow) { if (mIsClosed) { return err_rval; }
nsCOMPtr<Document> kungFuDeathGrip = GetDoc(); ::mozilla
::Unused << kungFuDeathGrip; if (!mInnerWindow) { return
err_rval; } } return GetCurrentInnerWindowInternal(this)->
method args; } while (0)
\
305 PR_BEGIN_MACROdo { \
306 if (!mInnerWindow) { \
307 if (mIsClosed) { \
308 return err_rval; \
309 } \
310 nsCOMPtr<Document> kungFuDeathGrip = GetDoc(); \
311 ::mozilla::Unused << kungFuDeathGrip; \
312 if (!mInnerWindow) { \
313 return err_rval; \
314 } \
315 } \
316 return GetCurrentInnerWindowInternal(this)->method args; \
317 PR_END_MACRO} while (0)
318
319static LazyLogModule gDOMLeakPRLogOuter("DOMLeakOuter");
320extern LazyLogModule gPageCacheLog;
321
322#ifdef DEBUG1
323static LazyLogModule gDocShellAndDOMWindowLeakLogging(
324 "DocShellAndDOMWindowLeak");
325#endif
326
327nsGlobalWindowOuter::OuterWindowByIdTable*
328 nsGlobalWindowOuter::sOuterWindowsById = nullptr;
329
330/* static */
331nsPIDOMWindowOuter* nsPIDOMWindowOuter::GetFromCurrentInner(
332 nsPIDOMWindowInner* aInner) {
333 if (!aInner) {
334 return nullptr;
335 }
336
337 nsPIDOMWindowOuter* outer = aInner->GetOuterWindow();
338 if (!outer || outer->GetCurrentInnerWindow() != aInner) {
339 return nullptr;
340 }
341
342 return outer;
343}
344
345//*****************************************************************************
346// nsOuterWindowProxy: Outer Window Proxy
347//*****************************************************************************
348
349// Give OuterWindowProxyClass 2 reserved slots, like the other wrappers, so
350// JSObject::swap can swap it with CrossCompartmentWrappers without requiring
351// malloc.
352//
353// We store the nsGlobalWindowOuter* in our first slot.
354//
355// We store our holder weakmap in the second slot.
356const JSClass OuterWindowProxyClass = PROXY_CLASS_DEF({"Proxy", JSClass::NON_NATIVE | JSCLASS_IS_PROXY | JSCLASS_DELAY_METADATA_BUILDER
| js::CheckProxyFlags<JSCLASS_HAS_RESERVED_SLOTS(2)>()
, &js::ProxyClassOps, JS_NULL_CLASS_SPEC, &js::ProxyClassExtension
, &js::ProxyObjectOps}
357 "Proxy", JSCLASS_HAS_RESERVED_SLOTS(2)){"Proxy", JSClass::NON_NATIVE | JSCLASS_IS_PROXY | JSCLASS_DELAY_METADATA_BUILDER
| js::CheckProxyFlags<JSCLASS_HAS_RESERVED_SLOTS(2)>()
, &js::ProxyClassOps, JS_NULL_CLASS_SPEC, &js::ProxyClassExtension
, &js::ProxyObjectOps}
; /* additional class flags */
358
359static const size_t OUTER_WINDOW_SLOT = 0;
360static const size_t HOLDER_WEAKMAP_SLOT = 1;
361
362class nsOuterWindowProxy : public MaybeCrossOriginObject<js::Wrapper> {
363 using Base = MaybeCrossOriginObject<js::Wrapper>;
364
365 public:
366 constexpr nsOuterWindowProxy() : Base(0) {}
367
368 bool finalizeInBackground(const JS::Value& priv) const override {
369 return false;
370 }
371
372 // Standard internal methods
373 /**
374 * Implementation of [[GetOwnProperty]] as defined at
375 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty
376 *
377 * "proxy" is the WindowProxy object involved. It may not be same-compartment
378 * with cx.
379 */
380 bool getOwnPropertyDescriptor(
381 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
382 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const override;
383
384 /*
385 * Implementation of the same-origin case of
386 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty>.
387 */
388 bool definePropertySameOrigin(JSContext* cx, JS::Handle<JSObject*> proxy,
389 JS::Handle<jsid> id,
390 JS::Handle<JS::PropertyDescriptor> desc,
391 JS::ObjectOpResult& result) const override;
392
393 /**
394 * Implementation of [[OwnPropertyKeys]] as defined at
395 *
396 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys
397 *
398 * "proxy" is the WindowProxy object involved. It may not be same-compartment
399 * with cx.
400 */
401 bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
402 JS::MutableHandleVector<jsid> props) const override;
403 /**
404 * Implementation of [[Delete]] as defined at
405 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-delete
406 *
407 * "proxy" is the WindowProxy object involved. It may not be same-compartment
408 * with cx.
409 */
410 bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
411 JS::ObjectOpResult& result) const override;
412
413 /**
414 * Implementaton of hook for superclass getPrototype() method.
415 */
416 JSObject* getSameOriginPrototype(JSContext* cx) const override;
417
418 /**
419 * Implementation of [[HasProperty]] internal method as defined at
420 * https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p
421 *
422 * "proxy" is the WindowProxy object involved. It may not be same-compartment
423 * with cx.
424 *
425 * Note that the HTML spec does not define an override for this internal
426 * method, so we just want the "normal object" behavior. We have to override
427 * it, because js::Wrapper also overrides, with "not normal" behavior.
428 */
429 bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
430 bool* bp) const override;
431
432 /**
433 * Implementation of [[Get]] internal method as defined at
434 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-get>.
435 *
436 * "proxy" is the WindowProxy object involved. It may or may not be
437 * same-compartment with "cx".
438 *
439 * "receiver" is the receiver ("this") for the get. It will be
440 * same-compartment with "cx".
441 *
442 * "vp" is the return value. It will be same-compartment with "cx".
443 */
444 bool get(JSContext* cx, JS::Handle<JSObject*> proxy,
445 JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
446 JS::MutableHandle<JS::Value> vp) const override;
447
448 /**
449 * Implementation of [[Set]] internal method as defined at
450 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-set>.
451 *
452 * "proxy" is the WindowProxy object involved. It may or may not be
453 * same-compartment with "cx".
454 *
455 * "v" is the value being set. It will be same-compartment with "cx".
456 *
457 * "receiver" is the receiver ("this") for the set. It will be
458 * same-compartment with "cx".
459 */
460 bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
461 JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
462 JS::ObjectOpResult& result) const override;
463
464 // SpiderMonkey extensions
465 /**
466 * Implementation of SpiderMonkey extension which just checks whether this
467 * object has the property. Basically Object.getOwnPropertyDescriptor(obj,
468 * prop) !== undefined. but does not require reifying the descriptor.
469 *
470 * We have to override this because js::Wrapper overrides it, but we want
471 * different behavior from js::Wrapper.
472 *
473 * "proxy" is the WindowProxy object involved. It may not be same-compartment
474 * with cx.
475 */
476 bool hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
477 bool* bp) const override;
478
479 /**
480 * Implementation of SpiderMonkey extension which is used as a fast path for
481 * enumerating.
482 *
483 * We have to override this because js::Wrapper overrides it, but we want
484 * different behavior from js::Wrapper.
485 *
486 * "proxy" is the WindowProxy object involved. It may not be same-compartment
487 * with cx.
488 */
489 bool getOwnEnumerablePropertyKeys(
490 JSContext* cx, JS::Handle<JSObject*> proxy,
491 JS::MutableHandleVector<jsid> props) const override;
492
493 /**
494 * Hook used by SpiderMonkey to implement Object.prototype.toString.
495 */
496 const char* className(JSContext* cx,
497 JS::Handle<JSObject*> wrapper) const override;
498
499 void finalize(JS::GCContext* gcx, JSObject* proxy) const override;
500 size_t objectMoved(JSObject* proxy, JSObject* old) const override;
501
502 bool isCallable(JSObject* obj) const override { return false; }
503 bool isConstructor(JSObject* obj) const override { return false; }
504
505 static const nsOuterWindowProxy singleton;
506
507 static nsGlobalWindowOuter* GetOuterWindow(JSObject* proxy) {
508 nsGlobalWindowOuter* outerWindow =
509 nsGlobalWindowOuter::FromSupports(static_cast<nsISupports*>(
510 js::GetProxyReservedSlot(proxy, OUTER_WINDOW_SLOT).toPrivate()));
511 return outerWindow;
512 }
513
514 protected:
515 // False return value means we threw an exception. True return value
516 // but false "found" means we didn't have a subframe at that index.
517 bool GetSubframeWindow(JSContext* cx, JS::Handle<JSObject*> proxy,
518 JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp,
519 bool& found) const;
520
521 // Returns a non-null window only if id is an index and we have a
522 // window at that index.
523 Nullable<WindowProxyHolder> GetSubframeWindow(JSContext* cx,
524 JS::Handle<JSObject*> proxy,
525 JS::Handle<jsid> id) const;
526
527 bool AppendIndexedPropertyNames(JSObject* proxy,
528 JS::MutableHandleVector<jsid> props) const;
529
530 using MaybeCrossOriginObjectMixins::EnsureHolder;
531 bool EnsureHolder(JSContext* cx, JS::Handle<JSObject*> proxy,
532 JS::MutableHandle<JSObject*> holder) const override;
533
534 // Helper method for creating a special "print" method that allows printing
535 // our PDF-viewer documents even if you're not same-origin with them.
536 //
537 // aProxy must be our nsOuterWindowProxy. It will not be same-compartment
538 // with aCx, since we only use this on the different-origin codepath!
539 //
540 // Can return true without filling in aDesc, which corresponds to not exposing
541 // a "print" method.
542 static bool MaybeGetPDFJSPrintMethod(
543 JSContext* cx, JS::Handle<JSObject*> proxy,
544 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc);
545
546 // The actual "print" method we use for the PDFJS case.
547 static bool PDFJSPrintMethod(JSContext* cx, unsigned argc, JS::Value* vp);
548
549 // Helper method to get the pre-PDF-viewer-messing-with-it principal from an
550 // inner window. Will return null if this is not a PDF-viewer inner or if the
551 // principal could not be found for some reason.
552 static already_AddRefed<nsIPrincipal> GetNoPDFJSPrincipal(
553 nsGlobalWindowInner* inner);
554};
555
556const char* nsOuterWindowProxy::className(JSContext* cx,
557 JS::Handle<JSObject*> proxy) const {
558 MOZ_ASSERT(js::IsProxy(proxy))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(js::IsProxy(proxy))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsProxy(proxy)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("js::IsProxy(proxy)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 558); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsProxy(proxy)"
")"); do { *((volatile int*)__null) = 558; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
559
560 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
561 return "Object";
562 }
563
564 return "Window";
565}
566
567void nsOuterWindowProxy::finalize(JS::GCContext* gcx, JSObject* proxy) const {
568 nsGlobalWindowOuter* outerWindow = GetOuterWindow(proxy);
569 if (outerWindow) {
570 outerWindow->ClearWrapper(proxy);
571 BrowsingContext* bc = outerWindow->GetBrowsingContext();
572 if (bc) {
573 bc->ClearWindowProxy();
574 }
575
576 // Ideally we would use OnFinalize here, but it's possible that
577 // EnsureScriptEnvironment will later be called on the window, and we don't
578 // want to create a new script object in that case. Therefore, we need to
579 // write a non-null value that will reliably crash when dereferenced.
580 outerWindow->PoisonOuterWindowProxy(proxy);
581 }
582}
583
584bool nsOuterWindowProxy::getOwnPropertyDescriptor(
585 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
586 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const {
587 // First check for indexed access. This is
588 // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty
589 // step 2, mostly.
590 JS::Rooted<JS::Value> subframe(cx);
591 bool found;
592 if (!GetSubframeWindow(cx, proxy, id, &subframe, found)) {
593 return false;
594 }
595 if (found) {
596 // Step 2.4.
597
598 desc.set(Some(JS::PropertyDescriptor::Data(
599 subframe, {
600 JS::PropertyAttribute::Configurable,
601 JS::PropertyAttribute::Enumerable,
602 })));
603 return true;
604 }
605
606 bool isSameOrigin = IsPlatformObjectSameOrigin(cx, proxy);
607
608 // If we did not find a subframe, we could still have an indexed property
609 // access. In that case we should throw a SecurityError in the cross-origin
610 // case.
611 if (!isSameOrigin && IsArrayIndex(GetArrayIndexFromId(id))) {
612 // Step 2.5.2.
613 return ReportCrossOriginDenial(cx, id, "access"_ns);
614 }
615
616 // Step 2.5.1 is handled via the forwarding to js::Wrapper; it saves us an
617 // IsArrayIndex(GetArrayIndexFromId(id)) here. We'll never have a property on
618 // the Window whose name is an index, because our defineProperty doesn't pass
619 // those on to the Window.
620
621 // Step 3.
622 if (isSameOrigin) {
623 if (StaticPrefs::dom_missing_prop_counters_enabled() && id.isAtom()) {
624 Window_Binding::CountMaybeMissingProperty(proxy, id);
625 }
626
627 // Fall through to js::Wrapper.
628 { // Scope for JSAutoRealm while we are dealing with js::Wrapper.
629 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
630 // for now. That's what js::Wrapper expects, and since we're same-origin
631 // anyway this is not changing any security behavior.
632 JSAutoRealm ar(cx, proxy);
633 JS_MarkCrossZoneId(cx, id);
634 bool ok = js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
635 if (!ok) {
636 return false;
637 }
638
639#if 0
640 // See https://github.com/tc39/ecma262/issues/672 for more information.
641 if (desc.isSome() &&
642 !IsNonConfigurableReadonlyPrimitiveGlobalProp(cx, id)) {
643 (*desc).setConfigurable(true);
644 }
645#endif
646 }
647
648 // Now wrap our descriptor back into the Realm that asked for it.
649 return JS_WrapPropertyDescriptor(cx, desc);
650 }
651
652 // Step 4.
653 if (!CrossOriginGetOwnPropertyHelper(cx, proxy, id, desc)) {
654 return false;
655 }
656
657 // Step 5
658 if (desc.isSome()) {
659 return true;
660 }
661
662 // Non-spec step for the PDF viewer's window.print(). This comes before we
663 // check for named subframes, because in the same-origin case print() would
664 // shadow those.
665 if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_PRINT)) {
666 if (!MaybeGetPDFJSPrintMethod(cx, proxy, desc)) {
667 return false;
668 }
669
670 if (desc.isSome()) {
671 return true;
672 }
673 }
674
675 // Step 6 -- check for named subframes.
676 if (id.isString()) {
677 nsAutoJSString name;
678 if (!name.init(cx, id.toString())) {
679 return false;
680 }
681 nsGlobalWindowOuter* win = GetOuterWindow(proxy);
682 if (RefPtr<BrowsingContext> childDOMWin = win->GetChildWindow(name)) {
683 JS::Rooted<JS::Value> childValue(cx);
684 if (!ToJSValue(cx, WindowProxyHolder(childDOMWin), &childValue)) {
685 return false;
686 }
687 desc.set(Some(JS::PropertyDescriptor::Data(
688 childValue, {JS::PropertyAttribute::Configurable})));
689 return true;
690 }
691 }
692
693 // And step 7.
694 return CrossOriginPropertyFallback(cx, proxy, id, desc);
695}
696
697bool nsOuterWindowProxy::definePropertySameOrigin(
698 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
699 JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result) const {
700 if (IsArrayIndex(GetArrayIndexFromId(id))) {
701 // Spec says to Reject whether this is a supported index or not,
702 // since we have no indexed setter or indexed creator. It is up
703 // to the caller to decide whether to throw a TypeError.
704 return result.failCantDefineWindowElement();
705 }
706
707 JS::ObjectOpResult ourResult;
708 bool ok = js::Wrapper::defineProperty(cx, proxy, id, desc, ourResult);
709 if (!ok) {
710 return false;
711 }
712
713 if (!ourResult.ok()) {
714 // It's possible that this failed because the page got the existing
715 // descriptor (which we force to claim to be configurable) and then tried to
716 // redefine the property with the descriptor it got but a different value.
717 // We want to allow this case to succeed, so check for it and if we're in
718 // that case try again but now with an attempt to define a non-configurable
719 // property.
720 if (!desc.hasConfigurable() || !desc.configurable()) {
721 // The incoming descriptor was not explicitly marked "configurable: true",
722 // so it failed for some other reason. Just propagate that reason out.
723 result = ourResult;
724 return true;
725 }
726
727 JS::Rooted<Maybe<JS::PropertyDescriptor>> existingDesc(cx);
728 ok = js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, &existingDesc);
729 if (!ok) {
730 return false;
731 }
732 if (existingDesc.isNothing() || existingDesc->configurable()) {
733 // We have no existing property, or its descriptor is already configurable
734 // (on the Window itself, where things really can be non-configurable).
735 // So we failed for some other reason, which we should propagate out.
736 result = ourResult;
737 return true;
738 }
739
740 JS::Rooted<JS::PropertyDescriptor> updatedDesc(cx, desc);
741 updatedDesc.setConfigurable(false);
742
743 JS::ObjectOpResult ourNewResult;
744 ok = js::Wrapper::defineProperty(cx, proxy, id, updatedDesc, ourNewResult);
745 if (!ok) {
746 return false;
747 }
748
749 if (!ourNewResult.ok()) {
750 // Twiddling the configurable flag didn't help. Just return this failure
751 // out to the caller.
752 result = ourNewResult;
753 return true;
754 }
755 }
756
757#if 0
758 // See https://github.com/tc39/ecma262/issues/672 for more information.
759 if (desc.hasConfigurable() && !desc.configurable() &&
760 !IsNonConfigurableReadonlyPrimitiveGlobalProp(cx, id)) {
761 // Give callers a way to detect that they failed to "really" define a
762 // non-configurable property.
763 result.failCantDefineWindowNonConfigurable();
764 return true;
765 }
766#endif
767
768 result.succeed();
769 return true;
770}
771
772bool nsOuterWindowProxy::ownPropertyKeys(
773 JSContext* cx, JS::Handle<JSObject*> proxy,
774 JS::MutableHandleVector<jsid> props) const {
775 // Just our indexed stuff followed by our "normal" own property names.
776 if (!AppendIndexedPropertyNames(proxy, props)) {
777 return false;
778 }
779
780 if (IsPlatformObjectSameOrigin(cx, proxy)) {
781 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
782 // for now. That's what js::Wrapper expects, and since we're same-origin
783 // anyway this is not changing any security behavior.
784 JS::RootedVector<jsid> innerProps(cx);
785 { // Scope for JSAutoRealm so we can mark the ids once we exit it
786 JSAutoRealm ar(cx, proxy);
787 if (!js::Wrapper::ownPropertyKeys(cx, proxy, &innerProps)) {
788 return false;
789 }
790 }
791 for (auto& id : innerProps) {
792 JS_MarkCrossZoneId(cx, id);
793 }
794 return js::AppendUnique(cx, props, innerProps);
795 }
796
797 // In the cross-origin case we purposefully exclude subframe names from the
798 // list of property names we report here.
799 JS::Rooted<JSObject*> holder(cx);
800 if (!EnsureHolder(cx, proxy, &holder)) {
801 return false;
802 }
803
804 JS::RootedVector<jsid> crossOriginProps(cx);
805 if (!js::GetPropertyKeys(cx, holder,
806 JSITER_OWNONLY0x8 | JSITER_HIDDEN0x10 | JSITER_SYMBOLS0x20,
807 &crossOriginProps) ||
808 !js::AppendUnique(cx, props, crossOriginProps)) {
809 return false;
810 }
811
812 // Add the "print" property if needed.
813 nsGlobalWindowOuter* outer = GetOuterWindow(proxy);
814 nsGlobalWindowInner* inner =
815 nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow());
816 if (inner) {
817 nsCOMPtr<nsIPrincipal> targetPrincipal = GetNoPDFJSPrincipal(inner);
818 if (targetPrincipal &&
819 nsContentUtils::SubjectPrincipal(cx)->Equals(targetPrincipal)) {
820 JS::RootedVector<jsid> printProp(cx);
821 if (!printProp.append(GetJSIDByIndex(cx, XPCJSContext::IDX_PRINT)) ||
822 !js::AppendUnique(cx, props, printProp)) {
823 return false;
824 }
825 }
826 }
827
828 return xpc::AppendCrossOriginWhitelistedPropNames(cx, props);
829}
830
831bool nsOuterWindowProxy::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
832 JS::Handle<jsid> id,
833 JS::ObjectOpResult& result) const {
834 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
835 return ReportCrossOriginDenial(cx, id, "delete"_ns);
836 }
837
838 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
839 // Fail (which means throw if strict, else return false).
840 return result.failCantDeleteWindowElement();
841 }
842
843 if (IsArrayIndex(GetArrayIndexFromId(id))) {
844 // Indexed, but not supported. Spec says return true.
845 return result.succeed();
846 }
847
848 // We're same-origin, so it should be safe to enter the Realm of "proxy".
849 // Let's do that, just in case, to avoid cross-compartment issues in our
850 // js::Wrapper caller..
851 JSAutoRealm ar(cx, proxy);
852 JS_MarkCrossZoneId(cx, id);
853 return js::Wrapper::delete_(cx, proxy, id, result);
854}
855
856JSObject* nsOuterWindowProxy::getSameOriginPrototype(JSContext* cx) const {
857 return Window_Binding::GetProtoObjectHandle(cx);
858}
859
860bool nsOuterWindowProxy::has(JSContext* cx, JS::Handle<JSObject*> proxy,
861 JS::Handle<jsid> id, bool* bp) const {
862 // We could just directly forward this method to js::BaseProxyHandler, but
863 // that involves reifying the actual property descriptor, which might be more
864 // work than we have to do for has() on the Window.
865
866 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
867 // In the cross-origin case we only have own properties. Just call hasOwn
868 // directly.
869 return hasOwn(cx, proxy, id, bp);
870 }
871
872 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
873 *bp = true;
874 return true;
875 }
876
877 // Just to be safe in terms of compartment asserts, enter the Realm of
878 // "proxy". We're same-origin with it, so this should be safe.
879 JSAutoRealm ar(cx, proxy);
880 JS_MarkCrossZoneId(cx, id);
881 return js::Wrapper::has(cx, proxy, id, bp);
882}
883
884bool nsOuterWindowProxy::hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy,
885 JS::Handle<jsid> id, bool* bp) const {
886 // We could just directly forward this method to js::BaseProxyHandler, but
887 // that involves reifying the actual property descriptor, which might be more
888 // work than we have to do for hasOwn() on the Window.
889
890 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
891 // Avoiding reifying the property descriptor here would require duplicating
892 // a bunch of "is this property exposed cross-origin" logic, which is
893 // probably not worth it. Just forward this along to the base
894 // implementation.
895 //
896 // It's very important to not forward this to js::Wrapper, because that will
897 // not do the right security and cross-origin checks and will pass through
898 // the call to the Window.
899 //
900 // The BaseProxyHandler code is OK with this happening without entering the
901 // compartment of "proxy".
902 return js::BaseProxyHandler::hasOwn(cx, proxy, id, bp);
903 }
904
905 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
906 *bp = true;
907 return true;
908 }
909
910 // Just to be safe in terms of compartment asserts, enter the Realm of
911 // "proxy". We're same-origin with it, so this should be safe.
912 JSAutoRealm ar(cx, proxy);
913 JS_MarkCrossZoneId(cx, id);
914 return js::Wrapper::hasOwn(cx, proxy, id, bp);
915}
916
917bool nsOuterWindowProxy::get(JSContext* cx, JS::Handle<JSObject*> proxy,
918 JS::Handle<JS::Value> receiver,
919 JS::Handle<jsid> id,
920 JS::MutableHandle<JS::Value> vp) const {
921 if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_WRAPPED_JSOBJECT) &&
922 xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
923 vp.set(JS::ObjectValue(*proxy));
924 return MaybeWrapValue(cx, vp);
925 }
926
927 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
928 return CrossOriginGet(cx, proxy, receiver, id, vp);
929 }
930
931 bool found;
932 if (!GetSubframeWindow(cx, proxy, id, vp, found)) {
933 return false;
934 }
935
936 if (found) {
937 return true;
938 }
939
940 if (StaticPrefs::dom_missing_prop_counters_enabled() && id.isAtom()) {
941 Window_Binding::CountMaybeMissingProperty(proxy, id);
942 }
943
944 { // Scope for JSAutoRealm
945 // Enter "proxy"'s Realm. We're in the same-origin case, so this should be
946 // safe.
947 JSAutoRealm ar(cx, proxy);
948
949 JS_MarkCrossZoneId(cx, id);
950
951 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
952 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
953 return false;
954 }
955
956 // Fall through to js::Wrapper.
957 if (!js::Wrapper::get(cx, proxy, wrappedReceiver, id, vp)) {
958 return false;
959 }
960 }
961
962 // Make sure our return value is in the caller compartment.
963 return MaybeWrapValue(cx, vp);
964}
965
966bool nsOuterWindowProxy::set(JSContext* cx, JS::Handle<JSObject*> proxy,
967 JS::Handle<jsid> id, JS::Handle<JS::Value> v,
968 JS::Handle<JS::Value> receiver,
969 JS::ObjectOpResult& result) const {
970 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
971 return CrossOriginSet(cx, proxy, id, v, receiver, result);
972 }
973
974 if (IsArrayIndex(GetArrayIndexFromId(id))) {
975 // Reject the set. It's up to the caller to decide whether to throw a
976 // TypeError. If the caller is strict mode JS code, it'll throw.
977 return result.failReadOnly();
978 }
979
980 // Do the rest in the Realm of "proxy", since we're in the same-origin case.
981 JSAutoRealm ar(cx, proxy);
982 JS::Rooted<JS::Value> wrappedArg(cx, v);
983 if (!MaybeWrapValue(cx, &wrappedArg)) {
984 return false;
985 }
986 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
987 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
988 return false;
989 }
990
991 JS_MarkCrossZoneId(cx, id);
992
993 return js::Wrapper::set(cx, proxy, id, wrappedArg, wrappedReceiver, result);
994}
995
996bool nsOuterWindowProxy::getOwnEnumerablePropertyKeys(
997 JSContext* cx, JS::Handle<JSObject*> proxy,
998 JS::MutableHandleVector<jsid> props) const {
999 // We could just stop overring getOwnEnumerablePropertyKeys and let our
1000 // superclasses deal (by falling back on the BaseProxyHandler implementation
1001 // that uses a combination of ownPropertyKeys and getOwnPropertyDescriptor to
1002 // only return the enumerable ones. But maybe there's value in having
1003 // somewhat faster for-in iteration on Window objects...
1004
1005 // Like ownPropertyKeys, our indexed stuff followed by our "normal" enumerable
1006 // own property names.
1007 if (!AppendIndexedPropertyNames(proxy, props)) {
1008 return false;
1009 }
1010
1011 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
1012 // All the cross-origin properties other than the indexed props are
1013 // non-enumerable, so we're done here.
1014 return true;
1015 }
1016
1017 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
1018 // for now. That's what js::Wrapper expects, and since we're same-origin
1019 // anyway this is not changing any security behavior.
1020 JS::RootedVector<jsid> innerProps(cx);
1021 { // Scope for JSAutoRealm so we can mark the ids once we exit it.
1022 JSAutoRealm ar(cx, proxy);
1023 if (!js::Wrapper::getOwnEnumerablePropertyKeys(cx, proxy, &innerProps)) {
1024 return false;
1025 }
1026 }
1027
1028 for (auto& id : innerProps) {
1029 JS_MarkCrossZoneId(cx, id);
1030 }
1031
1032 return js::AppendUnique(cx, props, innerProps);
1033}
1034
1035bool nsOuterWindowProxy::GetSubframeWindow(JSContext* cx,
1036 JS::Handle<JSObject*> proxy,
1037 JS::Handle<jsid> id,
1038 JS::MutableHandle<JS::Value> vp,
1039 bool& found) const {
1040 Nullable<WindowProxyHolder> frame = GetSubframeWindow(cx, proxy, id);
1041 if (frame.IsNull()) {
1042 found = false;
1043 return true;
1044 }
1045
1046 found = true;
1047 return WrapObject(cx, frame.Value(), vp);
1048}
1049
1050Nullable<WindowProxyHolder> nsOuterWindowProxy::GetSubframeWindow(
1051 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const {
1052 uint32_t index = GetArrayIndexFromId(id);
1053 if (!IsArrayIndex(index)) {
1054 return nullptr;
1055 }
1056
1057 nsGlobalWindowOuter* win = GetOuterWindow(proxy);
1058 return win->IndexedGetterOuter(index);
1059}
1060
1061bool nsOuterWindowProxy::AppendIndexedPropertyNames(
1062 JSObject* proxy, JS::MutableHandleVector<jsid> props) const {
1063 uint32_t length = GetOuterWindow(proxy)->Length();
1064 MOZ_ASSERT(int32_t(length) >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(length) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(length) >= 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(length) >= 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1064); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(length) >= 0"
")"); do { *((volatile int*)__null) = 1064; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1065 if (!props.reserve(props.length() + length)) {
1066 return false;
1067 }
1068 for (int32_t i = 0; i < int32_t(length); ++i) {
1069 if (!props.append(JS::PropertyKey::Int(i))) {
1070 return false;
1071 }
1072 }
1073
1074 return true;
1075}
1076
1077bool nsOuterWindowProxy::EnsureHolder(
1078 JSContext* cx, JS::Handle<JSObject*> proxy,
1079 JS::MutableHandle<JSObject*> holder) const {
1080 return EnsureHolder(cx, proxy, HOLDER_WEAKMAP_SLOT,
1081 Window_Binding::sCrossOriginProperties, holder);
1082}
1083
1084size_t nsOuterWindowProxy::objectMoved(JSObject* obj, JSObject* old) const {
1085 nsGlobalWindowOuter* outerWindow = GetOuterWindow(obj);
1086 if (outerWindow) {
1087 outerWindow->UpdateWrapper(obj, old);
1088 BrowsingContext* bc = outerWindow->GetBrowsingContext();
1089 if (bc) {
1090 bc->UpdateWindowProxy(obj, old);
1091 }
1092 }
1093 return 0;
1094}
1095
1096enum { PDFJS_SLOT_CALLEE = 0 };
1097
1098// static
1099bool nsOuterWindowProxy::MaybeGetPDFJSPrintMethod(
1100 JSContext* cx, JS::Handle<JSObject*> proxy,
1101 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) {
1102 MOZ_ASSERT(proxy)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(proxy)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(proxy))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("proxy", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "proxy" ")")
; do { *((volatile int*)__null) = 1102; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1103 MOZ_ASSERT(!desc.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!desc.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!desc.isSome()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!desc.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1103); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!desc.isSome()"
")"); do { *((volatile int*)__null) = 1103; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1104
1105 nsGlobalWindowOuter* outer = GetOuterWindow(proxy);
1106 nsGlobalWindowInner* inner =
1107 nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow());
1108 if (!inner) {
1109 // No print method to expose.
1110 return true;
1111 }
1112
1113 nsCOMPtr<nsIPrincipal> targetPrincipal = GetNoPDFJSPrincipal(inner);
1114 if (!targetPrincipal) {
1115 // Nothing special to be done.
1116 return true;
1117 }
1118
1119 if (!nsContentUtils::SubjectPrincipal(cx)->Equals(targetPrincipal)) {
1120 // Not our origin's PDF document.
1121 return true;
1122 }
1123
1124 // Get the function we plan to actually call.
1125 JS::Rooted<JSObject*> innerObj(cx, inner->GetGlobalJSObject());
1126 if (!innerObj) {
1127 // Really should not happen, but ok, let's just return.
1128 return true;
1129 }
1130
1131 JS::Rooted<JS::Value> targetFunc(cx);
1132 {
1133 JSAutoRealm ar(cx, innerObj);
1134 if (!JS_GetProperty(cx, innerObj, "print", &targetFunc)) {
1135 return false;
1136 }
1137 }
1138
1139 if (!targetFunc.isObject()) {
1140 // Who knows what's going on. Just return.
1141 return true;
1142 }
1143
1144 // The Realm of cx is the realm our caller is in and the realm we
1145 // should create our function in. Note that we can't use the
1146 // standard XPConnect function forwarder machinery because our
1147 // "this" is cross-origin, so we have to do thus by hand.
1148
1149 // Make sure targetFunc is wrapped into the right compartment.
1150 if (!MaybeWrapValue(cx, &targetFunc)) {
1151 return false;
1152 }
1153
1154 JSFunction* fun =
1155 js::NewFunctionWithReserved(cx, PDFJSPrintMethod, 0, 0, "print");
1156 if (!fun) {
1157 return false;
1158 }
1159
1160 JS::Rooted<JSObject*> funObj(cx, JS_GetFunctionObject(fun));
1161 js::SetFunctionNativeReserved(funObj, PDFJS_SLOT_CALLEE, targetFunc);
1162
1163 // { value: <print>, writable: true, enumerable: true, configurable: true }
1164 // because that's what it would have been in the same-origin case without
1165 // the PDF viewer messing with things.
1166 desc.set(Some(JS::PropertyDescriptor::Data(
1167 JS::ObjectValue(*funObj),
1168 {JS::PropertyAttribute::Configurable, JS::PropertyAttribute::Enumerable,
1169 JS::PropertyAttribute::Writable})));
1170 return true;
1171}
1172
1173// static
1174bool nsOuterWindowProxy::PDFJSPrintMethod(JSContext* cx, unsigned argc,
1175 JS::Value* vp) {
1176 JS::CallArgs args = CallArgsFromVp(argc, vp);
1177
1178 JS::Rooted<JSObject*> realCallee(
1179 cx, &js::GetFunctionNativeReserved(&args.callee(), PDFJS_SLOT_CALLEE)
1180 .toObject());
1181 // Unchecked unwrap, because we want to extract the thing we really had
1182 // before.
1183 realCallee = js::UncheckedUnwrap(realCallee);
1184
1185 JS::Rooted<JS::Value> thisv(cx, args.thisv());
1186 if (thisv.isNullOrUndefined()) {
1187 // Replace it with the global of our stashed callee, simulating the
1188 // global-assuming behavior of DOM methods.
1189 JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(realCallee));
1190 if (!MaybeWrapObject(cx, &global)) {
1191 return false;
1192 }
1193 thisv.setObject(*global);
1194 } else if (!thisv.isObject()) {
1195 return ThrowInvalidThis(cx, args, false, prototypes::id::Window);
1196 }
1197
1198 // We want to do an UncheckedUnwrap here, because we're going to directly
1199 // examine the principal of the inner window, if we have an inner window.
1200 JS::Rooted<JSObject*> unwrappedObj(cx,
1201 js::UncheckedUnwrap(&thisv.toObject()));
1202 nsGlobalWindowInner* inner = nullptr;
1203 {
1204 // Do the unwrap in the Realm of the object we're looking at.
1205 JSAutoRealm ar(cx, unwrappedObj);
1206 UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT(Window, &unwrappedObj, inner, cx)mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Window
, mozilla::dom::Window_Binding::NativeType>( &unwrappedObj
, inner, cx)
;
1207 }
1208 if (!inner) {
1209 return ThrowInvalidThis(cx, args, false, prototypes::id::Window);
1210 }
1211
1212 nsIPrincipal* callerPrincipal = nsContentUtils::SubjectPrincipal(cx);
1213 if (!callerPrincipal->SubsumesConsideringDomain(inner->GetPrincipal())) {
1214 // Check whether it's a PDF viewer from our origin.
1215 nsCOMPtr<nsIPrincipal> pdfPrincipal = GetNoPDFJSPrincipal(inner);
1216 if (!pdfPrincipal || !callerPrincipal->Equals(pdfPrincipal)) {
1217 // Security error.
1218 return ThrowInvalidThis(cx, args, true, prototypes::id::Window);
1219 }
1220 }
1221
1222 // Go ahead and enter the Realm of our real callee to call it. We'll pass it
1223 // our "thisv", just in case someone grabs a "print" method off one PDF
1224 // document and .call()s it on another one.
1225 {
1226 JSAutoRealm ar(cx, realCallee);
1227 if (!MaybeWrapValue(cx, &thisv)) {
1228 return false;
1229 }
1230
1231 // Don't bother passing through the args; they will get ignored anyway.
1232
1233 if (!JS::Call(cx, thisv, realCallee, JS::HandleValueArray::empty(),
1234 args.rval())) {
1235 return false;
1236 }
1237 }
1238
1239 // Wrap the return value (not that there should be any!) into the right
1240 // compartment.
1241 return MaybeWrapValue(cx, args.rval());
1242}
1243
1244// static
1245already_AddRefed<nsIPrincipal> nsOuterWindowProxy::GetNoPDFJSPrincipal(
1246 nsGlobalWindowInner* inner) {
1247 if (!nsContentUtils::IsPDFJS(inner->GetPrincipal())) {
1248 return nullptr;
1249 }
1250
1251 if (Document* doc = inner->GetExtantDoc()) {
1252 if (nsCOMPtr<nsIPropertyBag2> propBag =
1253 do_QueryInterface(doc->GetChannel())) {
1254 nsCOMPtr<nsIPrincipal> principal(
1255 do_GetProperty(propBag, u"noPDFJSPrincipal"_ns));
1256 return principal.forget();
1257 }
1258 }
1259 return nullptr;
1260}
1261
1262const nsOuterWindowProxy nsOuterWindowProxy::singleton;
1263
1264class nsChromeOuterWindowProxy : public nsOuterWindowProxy {
1265 public:
1266 constexpr nsChromeOuterWindowProxy() = default;
1267
1268 const char* className(JSContext* cx,
1269 JS::Handle<JSObject*> wrapper) const override;
1270
1271 static const nsChromeOuterWindowProxy singleton;
1272};
1273
1274const char* nsChromeOuterWindowProxy::className(
1275 JSContext* cx, JS::Handle<JSObject*> proxy) const {
1276 MOZ_ASSERT(js::IsProxy(proxy))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(js::IsProxy(proxy))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsProxy(proxy)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("js::IsProxy(proxy)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1276); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsProxy(proxy)"
")"); do { *((volatile int*)__null) = 1276; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1277
1278 return "ChromeWindow";
1279}
1280
1281const nsChromeOuterWindowProxy nsChromeOuterWindowProxy::singleton;
1282
1283static JSObject* NewOuterWindowProxy(JSContext* cx,
1284 JS::Handle<JSObject*> global,
1285 bool isChrome) {
1286 MOZ_ASSERT(JS_IsGlobalObject(global))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(JS_IsGlobalObject(global))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(JS_IsGlobalObject(global))))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("JS_IsGlobalObject(global)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1286); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JS_IsGlobalObject(global)"
")"); do { *((volatile int*)__null) = 1286; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1287
1288 JSAutoRealm ar(cx, global);
1289
1290 js::WrapperOptions options;
1291 options.setClass(&OuterWindowProxyClass);
1292 JSObject* obj =
1293 js::Wrapper::New(cx, global,
1294 isChrome ? &nsChromeOuterWindowProxy::singleton
1295 : &nsOuterWindowProxy::singleton,
1296 options);
1297 MOZ_ASSERT_IF(obj, js::IsWindowProxy(obj))do { if (obj) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(js::IsWindowProxy(obj))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsWindowProxy(obj)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("js::IsWindowProxy(obj)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1297); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(obj)"
")"); do { *((volatile int*)__null) = 1297; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1298 return obj;
1299}
1300
1301//*****************************************************************************
1302//*** nsGlobalWindowOuter: Object Management
1303//*****************************************************************************
1304
1305nsGlobalWindowOuter::nsGlobalWindowOuter(uint64_t aWindowID)
1306 : nsPIDOMWindowOuter(aWindowID),
1307 mFullscreenHasChangedDuringProcessing(false),
1308 mForceFullScreenInWidget(false),
1309 mIsClosed(false),
1310 mInClose(false),
1311 mHavePendingClose(false),
1312 mBlockScriptedClosingFlag(false),
1313 mWasOffline(false),
1314 mCreatingInnerWindow(false),
1315 mIsChrome(false),
1316 mAllowScriptsToClose(false),
1317 mTopLevelOuterContentWindow(false),
1318 mDelayedPrintUntilAfterLoad(false),
1319 mDelayedCloseForPrinting(false),
1320 mShouldDelayPrintUntilAfterLoad(false),
1321#ifdef DEBUG1
1322 mSerial(0),
1323 mSetOpenerWindowCalled(false),
1324#endif
1325 mCleanedUp(false),
1326 mCanSkipCCGeneration(0),
1327 mAutoActivateVRDisplayID(0) {
1328 AssertIsOnMainThread();
1329 SetIsOnMainThread();
1330 nsLayoutStatics::AddRef();
1331
1332 // Initialize the PRCList (this).
1333 PR_INIT_CLIST(this)do { (this)->next = (this); (this)->prev = (this); } while
(0)
;
1334
1335 // |this| is an outer window. Outer windows start out frozen and
1336 // remain frozen until they get an inner window.
1337 MOZ_ASSERT(IsFrozen())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFrozen())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFrozen()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("IsFrozen()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1337); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFrozen()"
")"); do { *((volatile int*)__null) = 1337; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1338
1339 // We could have failed the first time through trying
1340 // to create the entropy collector, so we should
1341 // try to get one until we succeed.
1342
1343#ifdef DEBUG1
1344 mSerial = nsContentUtils::InnerOrOuterWindowCreated();
1345
1346 MOZ_LOG(gDocShellAndDOMWindowLeakLogging, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n"
, nsContentUtils::GetCurrentInnerOrOuterWindowCount(), static_cast
<void*>(ToCanonicalSupports(this)), getpid(), mSerial, nullptr
); } } while (0)
1347 ("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n"
, nsContentUtils::GetCurrentInnerOrOuterWindowCount(), static_cast
<void*>(ToCanonicalSupports(this)), getpid(), mSerial, nullptr
); } } while (0)
1348 nsContentUtils::GetCurrentInnerOrOuterWindowCount(),do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n"
, nsContentUtils::GetCurrentInnerOrOuterWindowCount(), static_cast
<void*>(ToCanonicalSupports(this)), getpid(), mSerial, nullptr
); } } while (0)
1349 static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n"
, nsContentUtils::GetCurrentInnerOrOuterWindowCount(), static_cast
<void*>(ToCanonicalSupports(this)), getpid(), mSerial, nullptr
); } } while (0)
1350 nullptr))do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n"
, nsContentUtils::GetCurrentInnerOrOuterWindowCount(), static_cast
<void*>(ToCanonicalSupports(this)), getpid(), mSerial, nullptr
); } } while (0)
;
1351#endif
1352
1353 MOZ_LOG(gDOMLeakPRLogOuter, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDOMLeakPRLogOuter
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOMWINDOW %p created outer=nullptr", this
); } } while (0)
1354 ("DOMWINDOW %p created outer=nullptr", this))do { const ::mozilla::LogModule* moz_real_module = gDOMLeakPRLogOuter
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOMWINDOW %p created outer=nullptr", this
); } } while (0)
;
1355
1356 // Add ourselves to the outer windows list.
1357 MOZ_ASSERT(sOuterWindowsById, "Outer Windows hash table must be created!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sOuterWindowsById)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sOuterWindowsById))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("sOuterWindowsById"
" (" "Outer Windows hash table must be created!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sOuterWindowsById"
") (" "Outer Windows hash table must be created!" ")"); do {
*((volatile int*)__null) = 1357; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1358
1359 // |this| is an outer window, add to the outer windows list.
1360 MOZ_ASSERT(!sOuterWindowsById->Contains(mWindowID),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sOuterWindowsById->Contains(mWindowID))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!sOuterWindowsById->Contains(mWindowID)))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!sOuterWindowsById->Contains(mWindowID)"
" (" "This window shouldn't be in the hash table yet!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sOuterWindowsById->Contains(mWindowID)"
") (" "This window shouldn't be in the hash table yet!" ")")
; do { *((volatile int*)__null) = 1361; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1361 "This window shouldn't be in the hash table yet!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sOuterWindowsById->Contains(mWindowID))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!sOuterWindowsById->Contains(mWindowID)))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!sOuterWindowsById->Contains(mWindowID)"
" (" "This window shouldn't be in the hash table yet!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sOuterWindowsById->Contains(mWindowID)"
") (" "This window shouldn't be in the hash table yet!" ")")
; do { *((volatile int*)__null) = 1361; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1362 // We seem to see crashes in release builds because of null
1363 // |sOuterWindowsById|.
1364 if (sOuterWindowsById) {
1365 sOuterWindowsById->InsertOrUpdate(mWindowID, this);
1366 }
1367}
1368
1369#ifdef DEBUG1
1370
1371/* static */
1372void nsGlobalWindowOuter::AssertIsOnMainThread() {
1373 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1373); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 1373; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1374}
1375
1376#endif // DEBUG
1377
1378/* static */
1379void nsGlobalWindowOuter::Init() {
1380 AssertIsOnMainThread();
1381
1382 NS_ASSERTION(gDOMLeakPRLogOuter,do { if (!(gDOMLeakPRLogOuter)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "gDOMLeakPRLogOuter should have been initialized!", "gDOMLeakPRLogOuter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1383); MOZ_PretendNoReturn(); } } while (0)
1383 "gDOMLeakPRLogOuter should have been initialized!")do { if (!(gDOMLeakPRLogOuter)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "gDOMLeakPRLogOuter should have been initialized!", "gDOMLeakPRLogOuter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1383); MOZ_PretendNoReturn(); } } while (0)
;
1384
1385 sOuterWindowsById = new OuterWindowByIdTable();
1386}
1387
1388nsGlobalWindowOuter::~nsGlobalWindowOuter() {
1389 AssertIsOnMainThread();
1390
1391 if (sOuterWindowsById) {
1392 sOuterWindowsById->Remove(mWindowID);
1393 }
1394
1395 nsContentUtils::InnerOrOuterWindowDestroyed();
1396
1397#ifdef DEBUG1
1398 if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)(__builtin_expect(!!(mozilla::detail::log_test(gDocShellAndDOMWindowLeakLogging
, LogLevel::Info)), 0))
) {
1399 nsAutoCString url;
1400 if (mLastOpenedURI) {
1401 url = mLastOpenedURI->GetSpecOrDefault();
1402
1403 // Data URLs can be very long, so truncate to avoid flooding the log.
1404 const uint32_t maxURLLength = 1000;
1405 if (url.Length() > maxURLLength) {
1406 url.Truncate(maxURLLength);
1407 }
1408 }
1409
1410 MOZ_LOG(do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1411 gDocShellAndDOMWindowLeakLogging, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1412 ("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1413 "%s]\n",do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1414 nsContentUtils::GetCurrentInnerOrOuterWindowCount(),do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1415 static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1416 nullptr, url.get()))do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
;
1417 }
1418#endif
1419
1420 MOZ_LOG(gDOMLeakPRLogOuter, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDOMLeakPRLogOuter
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOMWINDOW %p destroyed", this); } } while
(0)
1421 ("DOMWINDOW %p destroyed", this))do { const ::mozilla::LogModule* moz_real_module = gDOMLeakPRLogOuter
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOMWINDOW %p destroyed", this); } } while
(0)
;
1422
1423 JSObject* proxy = GetWrapperMaybeDead();
1424 if (proxy) {
1425 if (mBrowsingContext && mBrowsingContext->GetUnbarrieredWindowProxy()) {
1426 nsGlobalWindowOuter* outer = nsOuterWindowProxy::GetOuterWindow(
1427 mBrowsingContext->GetUnbarrieredWindowProxy());
1428 // Check that the current WindowProxy object corresponds to this
1429 // nsGlobalWindowOuter, because we don't want to clear the WindowProxy if
1430 // we've replaced it with a cross-process WindowProxy.
1431 if (outer == this) {
1432 mBrowsingContext->ClearWindowProxy();
1433 }
1434 }
1435 js::SetProxyReservedSlot(proxy, OUTER_WINDOW_SLOT,
1436 JS::PrivateValue(nullptr));
1437 }
1438
1439 // An outer window is destroyed with inner windows still possibly
1440 // alive, iterate through the inner windows and null out their
1441 // back pointer to this outer, and pull them out of the list of
1442 // inner windows.
1443 //
1444 // Our linked list of inner windows both contains (an nsGlobalWindowOuter),
1445 // and our inner windows (nsGlobalWindowInners). This means that we need to
1446 // use PRCList*. We can then compare that PRCList* to `this` to see if its an
1447 // inner or outer window.
1448 PRCList* w;
1449 while ((w = PR_LIST_HEAD(this)(this)->next) != this) {
1450 PR_REMOVE_AND_INIT_LINK(w)do { (w)->prev->next = (w)->next; (w)->next->prev
= (w)->prev; (w)->next = (w); (w)->prev = (w); } while
(0)
;
1451 }
1452
1453 DropOuterWindowDocs();
1454
1455 // Outer windows are always supposed to call CleanUp before letting themselves
1456 // be destroyed.
1457 MOZ_ASSERT(mCleanedUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCleanedUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCleanedUp))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mCleanedUp", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1457); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCleanedUp"
")"); do { *((volatile int*)__null) = 1457; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1458
1459 nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID"@mozilla.org/devicesensors;1");
1460 if (ac) ac->RemoveWindowAsListener(this);
1461
1462 nsLayoutStatics::Release();
1463}
1464
1465// static
1466void nsGlobalWindowOuter::ShutDown() {
1467 AssertIsOnMainThread();
1468
1469 delete sOuterWindowsById;
1470 sOuterWindowsById = nullptr;
1471}
1472
1473void nsGlobalWindowOuter::DropOuterWindowDocs() {
1474 MOZ_ASSERT_IF(mDoc, !mDoc->EventHandlingSuppressed())do { if (mDoc) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!mDoc->EventHandlingSuppressed())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!mDoc->EventHandlingSuppressed()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mDoc->EventHandlingSuppressed()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1474); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDoc->EventHandlingSuppressed()"
")"); do { *((volatile int*)__null) = 1474; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1475 mDoc = nullptr;
1476 mSuspendedDocs.Clear();
1477}
1478
1479void nsGlobalWindowOuter::CleanUp() {
1480 // Guarantee idempotence.
1481 if (mCleanedUp) return;
1482 mCleanedUp = true;
1483
1484 StartDying();
1485
1486 mWindowUtils = nullptr;
1487
1488 ClearControllers();
1489
1490 mContext = nullptr; // Forces Release
1491 mChromeEventHandler = nullptr; // Forces Release
1492 mParentTarget = nullptr;
1493 mMessageManager = nullptr;
1494
1495 mArguments = nullptr;
1496}
1497
1498void nsGlobalWindowOuter::ClearControllers() {
1499 if (mControllers) {
1500 uint32_t count;
1501 mControllers->GetControllerCount(&count);
1502
1503 while (count--) {
1504 nsCOMPtr<nsIController> controller;
1505 mControllers->GetControllerAt(count, getter_AddRefs(controller));
1506
1507 nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
1508 if (context) context->SetCommandContext(nullptr);
1509 }
1510
1511 mControllers = nullptr;
1512 }
1513}
1514
1515//*****************************************************************************
1516// nsGlobalWindowOuter::nsISupports
1517//*****************************************************************************
1518
1519// QueryInterface implementation for nsGlobalWindowOuter
1520NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowOuter)nsresult nsGlobalWindowOuter::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1520); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = nsGlobalWindowOuter::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = nsGlobalWindowOuter::cycleCollection
::Upcast(this); return NS_OK; } foundInterface = nullptr; } else
1521 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRYif (aIID.Equals((nsWrapperCache::COMTypeInfo<nsWrapperCache
, void>::kIID))) { *aInstancePtr = static_cast<nsWrapperCache
*>(this); return NS_OK; } else
1522 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(static_cast<EventTarget*>(this)); else
1523 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIDOMWindow>)) foundInterface = static_cast
<nsIDOMWindow*>(this); else
1524 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIGlobalObject>)) foundInterface
= static_cast<nsIGlobalObject*>(this); else
1525 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIScriptGlobalObject>)) foundInterface
= static_cast<nsIScriptGlobalObject*>(this); else
1526 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIScriptObjectPrincipal>)) foundInterface
= static_cast<nsIScriptObjectPrincipal*>(this); else
1527 NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, mozilla::dom::EventTarget>)) foundInterface
= static_cast<mozilla::dom::EventTarget*>(this); else
1528 NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowOuter)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsPIDOMWindowOuter>)) foundInterface
= static_cast<nsPIDOMWindowOuter*>(this); else
1529 NS_INTERFACE_MAP_ENTRY(mozIDOMWindowProxy)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, mozIDOMWindowProxy>)) foundInterface
= static_cast<mozIDOMWindowProxy*>(this); else
1530 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
1531 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIInterfaceRequestor>)) foundInterface
= static_cast<nsIInterfaceRequestor*>(this); else
1532NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1532); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 1532; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
1533
1534NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindowOuter)MozExternalRefCountType nsGlobalWindowOuter::AddRef(void) { static_assert
(!std::is_destructible_v<nsGlobalWindowOuter>, "Reference-counted class "
"nsGlobalWindowOuter" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1534; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); _mOwningThread.AssertOwnership("nsGlobalWindowOuter"
" not thread-safe"); nsISupports* base = nsGlobalWindowOuter
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr
(base); NS_LogAddRef((this), (count), ("nsGlobalWindowOuter")
, (uint32_t)(sizeof(*this))); return count; }
1535NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindowOuter)MozExternalRefCountType nsGlobalWindowOuter::Release(void) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1535); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 1535
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("nsGlobalWindowOuter"
" not thread-safe"); nsISupports* base = nsGlobalWindowOuter
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.decr
(base); NS_LogRelease((this), (count), ("nsGlobalWindowOuter"
)); return count; } void nsGlobalWindowOuter::DeleteCycleCollectable
(void) { delete (this); }
1536
1537NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipReal(void* p
, bool aRemovingAllowed) { nsGlobalWindowOuter* tmp = DowncastCCParticipant
<nsGlobalWindowOuter>(p);
1538 if (tmp->IsBlackForCC(false)) {
1539 if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
1540 return true;
1541 }
1542 tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
1543 if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
1544 elm->MarkForCC();
1545 }
1546 return true;
1547 }
1548NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END(void)tmp; return false; }
1549
1550NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipInCCReal(void
* p) { nsGlobalWindowOuter* tmp = DowncastCCParticipant<nsGlobalWindowOuter
>(p);
1551 return tmp->IsBlackForCC(true);
1552NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END(void)tmp; return false; }
1553
1554NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipThisReal(void
* p) { nsGlobalWindowOuter* tmp = DowncastCCParticipant<nsGlobalWindowOuter
>(p);
1555 return tmp->IsBlackForCC(false);
1556NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END(void)tmp; return false; }
1557
1558NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowOuter)nsGlobalWindowOuter::cycleCollection nsGlobalWindowOuter::_cycleCollectorGlobal
;
1559
1560NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowOuter)nsresult nsGlobalWindowOuter::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1561 if (MOZ_UNLIKELY(cb.WantDebugInfo())(__builtin_expect(!!(cb.WantDebugInfo()), 0))) {
1562 char name[512];
1563 nsAutoCString uri;
1564 if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
1565 uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
1566 }
1567 SprintfLiteral(name, "nsGlobalWindowOuter # %" PRIu64"l" "u" " outer %s",
1568 tmp->mWindowID, uri.get());
1569 cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
1570 } else {
1571 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowOuter, tmp->mRefCnt.get())cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "nsGlobalWindowOuter"
);
1572 }
1573
1574 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)ImplCycleCollectionTraverse(cb, tmp->mContext, "mContext",
0);
1575
1576 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)ImplCycleCollectionTraverse(cb, tmp->mControllers, "mControllers"
, 0);
1577 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)ImplCycleCollectionTraverse(cb, tmp->mArguments, "mArguments"
, 0);
1578
1579 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)ImplCycleCollectionTraverse(cb, tmp->mLocalStorage, "mLocalStorage"
, 0);
1580 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDocs)ImplCycleCollectionTraverse(cb, tmp->mSuspendedDocs, "mSuspendedDocs"
, 0);
1581 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentPrincipal, "mDocumentPrincipal"
, 0);
1582 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCookiePrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentCookiePrincipal
, "mDocumentCookiePrincipal", 0);
1583 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentStoragePrincipal
, "mDocumentStoragePrincipal", 0);
1584 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPartitionedPrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentPartitionedPrincipal
, "mDocumentPartitionedPrincipal", 0);
1585 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)ImplCycleCollectionTraverse(cb, tmp->mDoc, "mDoc", 0);
1586
1587 // Traverse stuff from nsPIDOMWindow
1588 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)ImplCycleCollectionTraverse(cb, tmp->mChromeEventHandler, "mChromeEventHandler"
, 0);
1589 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)ImplCycleCollectionTraverse(cb, tmp->mParentTarget, "mParentTarget"
, 0);
1590 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)ImplCycleCollectionTraverse(cb, tmp->mMessageManager, "mMessageManager"
, 0);
1591 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)ImplCycleCollectionTraverse(cb, tmp->mFrameElement, "mFrameElement"
, 0);
1592
1593 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell)ImplCycleCollectionTraverse(cb, tmp->mDocShell, "mDocShell"
, 0);
1594 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)ImplCycleCollectionTraverse(cb, tmp->mBrowsingContext, "mBrowsingContext"
, 0);
1595
1596 tmp->TraverseObjectsInGlobal(cb);
1597
1598 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mBrowserDOMWindow)ImplCycleCollectionTraverse(cb, tmp->mChromeFields.mBrowserDOMWindow
, "mChromeFields.mBrowserDOMWindow", 0);
1599NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END(void)tmp; return NS_OK; }
1600
1601NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowOuter)void nsGlobalWindowOuter::cycleCollection::Unlink(void* p) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1602 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCEtmp->ClearWeakReferences();
1603 if (sOuterWindowsById) {
1604 sOuterWindowsById->Remove(tmp->mWindowID);
1605 }
1606
1607 NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)ImplCycleCollectionUnlink(tmp->mContext);
1608
1609 NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)ImplCycleCollectionUnlink(tmp->mControllers);
1610 NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)ImplCycleCollectionUnlink(tmp->mArguments);
1611
1612 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)ImplCycleCollectionUnlink(tmp->mLocalStorage);
1613 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDocs)ImplCycleCollectionUnlink(tmp->mSuspendedDocs);
1614 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)ImplCycleCollectionUnlink(tmp->mDocumentPrincipal);
1615 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCookiePrincipal)ImplCycleCollectionUnlink(tmp->mDocumentCookiePrincipal);
1616 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)ImplCycleCollectionUnlink(tmp->mDocumentStoragePrincipal);
1617 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPartitionedPrincipal)ImplCycleCollectionUnlink(tmp->mDocumentPartitionedPrincipal
);
1618 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)ImplCycleCollectionUnlink(tmp->mDoc);
1619
1620 // Unlink stuff from nsPIDOMWindow
1621 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)ImplCycleCollectionUnlink(tmp->mChromeEventHandler);
1622 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)ImplCycleCollectionUnlink(tmp->mParentTarget);
1623 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)ImplCycleCollectionUnlink(tmp->mMessageManager);
1624 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)ImplCycleCollectionUnlink(tmp->mFrameElement);
1625
1626 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)ImplCycleCollectionUnlink(tmp->mDocShell);
1627 if (tmp->mBrowsingContext) {
1628 if (tmp->mBrowsingContext->GetUnbarrieredWindowProxy()) {
1629 nsGlobalWindowOuter* outer = nsOuterWindowProxy::GetOuterWindow(
1630 tmp->mBrowsingContext->GetUnbarrieredWindowProxy());
1631 // Check that the current WindowProxy object corresponds to this
1632 // nsGlobalWindowOuter, because we don't want to clear the WindowProxy if
1633 // we've replaced it with a cross-process WindowProxy.
1634 if (outer == tmp) {
1635 tmp->mBrowsingContext->ClearWindowProxy();
1636 }
1637 }
1638 tmp->mBrowsingContext = nullptr;
1639 }
1640
1641 tmp->UnlinkObjectsInGlobal();
1642
1643 if (tmp->IsChromeWindow()) {
1644 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mBrowserDOMWindow)ImplCycleCollectionUnlink(tmp->mChromeFields.mBrowserDOMWindow
);
1645 }
1646
1647 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPERtmp->ReleaseWrapper(p);
1648NS_IMPL_CYCLE_COLLECTION_UNLINK_END(void)tmp; }
1649
1650NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowOuter)void nsGlobalWindowOuter::cycleCollection::Trace( void* p, const
TraceCallbacks& aCallbacks, void* aClosure) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1651 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPERtmp->TraceWrapper(aCallbacks, aClosure);
1652NS_IMPL_CYCLE_COLLECTION_TRACE_END(void)tmp; }
1653
1654bool nsGlobalWindowOuter::IsBlackForCC(bool aTracingNeeded) {
1655 if (!nsCCUncollectableMarker::sGeneration) {
1656 return false;
1657 }
1658
1659 // Unlike most wrappers, the outer window wrapper is not a wrapper for
1660 // the outer window. Instead, the outer window wrapper holds the inner
1661 // window binding object, which in turn holds the nsGlobalWindowInner, which
1662 // has a strong reference to the nsGlobalWindowOuter. We're using the
1663 // mInnerWindow pointer as a flag for that whole chain.
1664 return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
1665 (mInnerWindow && HasKnownLiveWrapper())) &&
1666 (!aTracingNeeded || HasNothingToTrace(ToSupports(this)));
1667}
1668
1669//*****************************************************************************
1670// nsGlobalWindowOuter::nsIScriptGlobalObject
1671//*****************************************************************************
1672
1673bool nsGlobalWindowOuter::ShouldResistFingerprinting(RFPTarget aTarget) const {
1674 if (mDoc) {
1675 return mDoc->ShouldResistFingerprinting(aTarget);
1676 }
1677 return nsContentUtils::ShouldResistFingerprinting(
1678 "If we do not have a document then we do not have any context"
1679 "to make an informed RFP choice, so we fall back to the global pref",
1680 aTarget);
1681}
1682
1683OriginTrials nsGlobalWindowOuter::Trials() const {
1684 return mInnerWindow ? nsGlobalWindowInner::Cast(mInnerWindow)->Trials()
1685 : OriginTrials();
1686}
1687
1688FontFaceSet* nsGlobalWindowOuter::GetFonts() {
1689 if (mDoc) {
1690 return mDoc->Fonts();
1691 }
1692 return nullptr;
1693}
1694
1695nsresult nsGlobalWindowOuter::EnsureScriptEnvironment() {
1696 if (GetWrapperPreserveColor()) {
1697 return NS_OK;
1698 }
1699
1700 NS_ENSURE_STATE(!mCleanedUp)do { if ((__builtin_expect(!!(!(!mCleanedUp)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!mCleanedUp" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1700); return NS_ERROR_UNEXPECTED; } } while (false)
;
1701
1702 NS_ASSERTION(!GetCurrentInnerWindowInternal(this),do { if (!(!GetCurrentInnerWindowInternal(this))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "No cached wrapper, but we have an inner window?"
, "!GetCurrentInnerWindowInternal(this)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1703); MOZ_PretendNoReturn(); } } while (0)
1703 "No cached wrapper, but we have an inner window?")do { if (!(!GetCurrentInnerWindowInternal(this))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "No cached wrapper, but we have an inner window?"
, "!GetCurrentInnerWindowInternal(this)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1703); MOZ_PretendNoReturn(); } } while (0)
;
1704 NS_ASSERTION(!mContext, "Will overwrite mContext!")do { if (!(!mContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Will overwrite mContext!"
, "!mContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1704); MOZ_PretendNoReturn(); } } while (0)
;
1705
1706 // If this window is an [i]frame, don't bother GC'ing when the frame's context
1707 // is destroyed since a GC will happen when the frameset or host document is
1708 // destroyed anyway.
1709 mContext = new nsJSContext(mBrowsingContext->IsTop(), this);
1710 return NS_OK;
1711}
1712
1713nsIScriptContext* nsGlobalWindowOuter::GetScriptContext() { return mContext; }
1714
1715bool nsGlobalWindowOuter::WouldReuseInnerWindow(Document* aNewDocument) {
1716 // We reuse the inner window when:
1717 // a. We are currently at our original document.
1718 // b. At least one of the following conditions are true:
1719 // -- The new document is the same as the old document. This means that we're
1720 // getting called from document.open().
1721 // -- The new document has the same origin as what we have loaded right now.
1722
1723 if (!mDoc || !aNewDocument) {
1724 return false;
1725 }
1726
1727 if (!mDoc->IsInitialDocument()) {
1728 return false;
1729 }
1730
1731#ifdef DEBUG1
1732 {
1733 nsCOMPtr<nsIURI> uri;
1734 NS_GetURIWithoutRef(mDoc->GetDocumentURI(), getter_AddRefs(uri));
1735 NS_ASSERTION(NS_IsAboutBlank(uri), "How'd this happen?")do { if (!(NS_IsAboutBlank(uri))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "How'd this happen?", "NS_IsAboutBlank(uri)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1735); MOZ_PretendNoReturn(); } } while (0)
;
1736 }
1737#endif
1738
1739 // Great, we're the original document, check for one of the other
1740 // conditions.
1741
1742 if (mDoc == aNewDocument) {
1743 return true;
1744 }
1745
1746 if (aNewDocument->IsStaticDocument()) {
1747 return false;
1748 }
1749
1750 if (BasePrincipal::Cast(mDoc->NodePrincipal())
1751 ->FastEqualsConsideringDomain(aNewDocument->NodePrincipal())) {
1752 // The origin is the same.
1753 return true;
1754 }
1755
1756 return false;
1757}
1758
1759void nsGlobalWindowOuter::SetInitialPrincipal(
1760 nsIPrincipal* aNewWindowPrincipal, nsIContentSecurityPolicy* aCSP,
1761 const Maybe<nsILoadInfo::CrossOriginEmbedderPolicy>& aCOEP) {
1762 // We should never create windows with an expanded principal.
1763 // If we have a system principal, make sure we're not using it for a content
1764 // docshell.
1765 // NOTE: Please keep this logic in sync with
1766 // nsAppShellService::JustCreateTopWindow
1767 if (nsContentUtils::IsExpandedPrincipal(aNewWindowPrincipal) ||
1768 (aNewWindowPrincipal->IsSystemPrincipal() &&
1769 GetBrowsingContext()->IsContent())) {
1770 aNewWindowPrincipal = nullptr;
1771 }
1772
1773 // If there's an existing document, bail if it either:
1774 if (mDoc) {
1775 // (a) is not an initial about:blank document, or
1776 if (!mDoc->IsInitialDocument()) return;
1777 // (b) already has the correct principal.
1778 if (mDoc->NodePrincipal() == aNewWindowPrincipal) return;
1779
1780#ifdef DEBUG1
1781 // If we have a document loaded at this point, it had better be about:blank.
1782 // Otherwise, something is really weird. An about:blank page has a
1783 // NullPrincipal.
1784 bool isNullPrincipal;
1785 MOZ_ASSERT(NS_SUCCEEDED(mDoc->NodePrincipal()->GetIsNullPrincipal(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->
NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal)
)), 1))) && isNullPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(((bool)(__builtin_expect(!!(
!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal
( &isNullPrincipal))), 1))) && isNullPrincipal)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1787); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1787; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1786 &isNullPrincipal)) &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->
NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal)
)), 1))) && isNullPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(((bool)(__builtin_expect(!!(
!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal
( &isNullPrincipal))), 1))) && isNullPrincipal)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1787); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1787; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1787 isNullPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->
NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal)
)), 1))) && isNullPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(((bool)(__builtin_expect(!!(
!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal
( &isNullPrincipal))), 1))) && isNullPrincipal)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1787); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1787; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1788#endif
1789 }
1790
1791 // Use the subject (or system) principal as the storage principal too until
1792 // the new window finishes navigating and gets a real storage principal.
1793 nsDocShell::Cast(GetDocShell())
1794 ->CreateAboutBlankDocumentViewer(aNewWindowPrincipal, aNewWindowPrincipal,
1795 aCSP, nullptr,
1796 /* aIsInitialDocument */ true, aCOEP);
1797
1798 if (mDoc) {
1799 MOZ_ASSERT(mDoc->IsInitialDocument(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDoc->IsInitialDocument())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDoc->IsInitialDocument()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDoc->IsInitialDocument()" " (" "document should be initial document"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc->IsInitialDocument()"
") (" "document should be initial document" ")"); do { *((volatile
int*)__null) = 1800; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
1800 "document should be initial document")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDoc->IsInitialDocument())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDoc->IsInitialDocument()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDoc->IsInitialDocument()" " (" "document should be initial document"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc->IsInitialDocument()"
") (" "document should be initial document" ")"); do { *((volatile
int*)__null) = 1800; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1801 }
1802
1803 RefPtr<PresShell> presShell = GetDocShell()->GetPresShell();
1804 if (presShell && !presShell->DidInitialize()) {
1805 // Ensure that if someone plays with this document they will get
1806 // layout happening.
1807 presShell->Initialize();
1808 }
1809}
1810
1811#define WINDOWSTATEHOLDER_IID{ 0x0b917c3e, 0xbd50, 0x4683, { 0xaf, 0xc9, 0xc7, 0x81, 0x07,
0xae, 0x33, 0x26 } }
\
1812 { \
1813 0x0b917c3e, 0xbd50, 0x4683, { \
1814 0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26 \
1815 } \
1816 }
1817
1818class WindowStateHolder final : public nsISupports {
1819 public:
1820 NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)template <typename T, typename U> struct COMTypeInfo;
1821 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
1822
1823 explicit WindowStateHolder(nsGlobalWindowInner* aWindow);
1824
1825 nsGlobalWindowInner* GetInnerWindow() { return mInnerWindow; }
1826
1827 void DidRestoreWindow() {
1828 mInnerWindow = nullptr;
1829 mInnerWindowReflector = nullptr;
1830 }
1831
1832 protected:
1833 ~WindowStateHolder();
1834
1835 nsGlobalWindowInner* mInnerWindow;
1836 // We hold onto this to make sure the inner window doesn't go away. The outer
1837 // window ends up recalculating it anyway.
1838 JS::PersistentRooted<JSObject*> mInnerWindowReflector;
1839};
1840
1841NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)template <typename T> struct WindowStateHolder::COMTypeInfo
<WindowStateHolder, T> { static const nsIID kIID __attribute__
((visibility("hidden"))); }; template <typename T> const
nsIID WindowStateHolder::COMTypeInfo<WindowStateHolder, T
>::kIID __attribute__((visibility("hidden"))) = { 0x0b917c3e
, 0xbd50, 0x4683, { 0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33,
0x26 } };
1842
1843WindowStateHolder::WindowStateHolder(nsGlobalWindowInner* aWindow)
1844 : mInnerWindow(aWindow),
1845 mInnerWindowReflector(RootingCx(), aWindow->GetWrapper()) {
1846 MOZ_ASSERT(aWindow, "null window")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWindow" " (" "null window"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1846); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ") ("
"null window" ")"); do { *((volatile int*)__null) = 1846; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
1847
1848 aWindow->Suspend();
1849
1850 // When a global goes into the bfcache, we disable script.
1851 xpc::Scriptability::Get(mInnerWindowReflector).SetWindowAllowsScript(false);
1852}
1853
1854WindowStateHolder::~WindowStateHolder() {
1855 if (mInnerWindow) {
1856 // This window was left in the bfcache and is now going away. We need to
1857 // free it up.
1858 // Note that FreeInnerObjects may already have been called on the
1859 // inner window if its outer has already had SetDocShell(null)
1860 // called.
1861 mInnerWindow->FreeInnerObjects();
1862 }
1863}
1864
1865NS_IMPL_ISUPPORTS(WindowStateHolder, WindowStateHolder)MozExternalRefCountType WindowStateHolder::AddRef(void) { static_assert
(!std::is_destructible_v<WindowStateHolder>, "Reference-counted class "
"WindowStateHolder" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1865; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WindowStateHolder" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WindowStateHolder" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WindowStateHolder\" != nullptr" " (" "Must specify a name"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WindowStateHolder\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1865; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("WindowStateHolder" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("WindowStateHolder"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
WindowStateHolder::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 1865
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WindowStateHolder" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WindowStateHolder" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WindowStateHolder\" != nullptr" " (" "Must specify a name"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WindowStateHolder\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1865; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("WindowStateHolder" " not thread-safe"); const
char* const nametmp = "WindowStateHolder"; nsrefcnt count = --
mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult WindowStateHolder::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1865); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<WindowStateHolder, WindowStateHolder>
, int32_t( reinterpret_cast<char*>(static_cast<WindowStateHolder
*>((WindowStateHolder*)0x1000)) - reinterpret_cast<char
*>((WindowStateHolder*)0x1000))}, {&mozilla::detail::kImplementedIID
<WindowStateHolder, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
WindowStateHolder*>((WindowStateHolder*)0x1000))) - reinterpret_cast
<char*>((WindowStateHolder*)0x1000))}, { nullptr, 0 } }
; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
1866
1867bool nsGlobalWindowOuter::ComputeIsSecureContext(Document* aDocument,
1868 SecureContextFlags aFlags) {
1869 nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
1870 if (principal->IsSystemPrincipal()) {
1871 return true;
1872 }
1873
1874 // Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object
1875 // With some modifications to allow for aFlags.
1876
1877 bool hadNonSecureContextCreator = false;
1878
1879 if (WindowContext* parentWindow =
1880 GetBrowsingContext()->GetParentWindowContext()) {
1881 hadNonSecureContextCreator = !parentWindow->GetIsSecureContext();
1882 }
1883
1884 if (hadNonSecureContextCreator) {
1885 return false;
1886 }
1887
1888 if (nsContentUtils::HttpsStateIsModern(aDocument)) {
1889 return true;
1890 }
1891
1892 if (principal->GetIsNullPrincipal()) {
1893 // If the NullPrincipal has a valid precursor URI we want to use it to
1894 // construct the principal otherwise we fall back to the original document
1895 // URI.
1896 nsCOMPtr<nsIPrincipal> precursorPrin = principal->GetPrecursorPrincipal();
1897 nsCOMPtr<nsIURI> uri = precursorPrin ? precursorPrin->GetURI() : nullptr;
1898 if (!uri) {
1899 uri = aDocument->GetOriginalURI();
1900 }
1901 // IsOriginPotentiallyTrustworthy doesn't care about origin attributes so
1902 // it doesn't actually matter what we use here, but reusing the document
1903 // principal's attributes is convenient.
1904 const OriginAttributes& attrs = principal->OriginAttributesRef();
1905 // CreateContentPrincipal correctly gets a useful principal for blob: and
1906 // other URI_INHERITS_SECURITY_CONTEXT URIs.
1907 principal = BasePrincipal::CreateContentPrincipal(uri, attrs);
1908 if (NS_WARN_IF(!principal)NS_warn_if_impl(!principal, "!principal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1908)
) {
1909 return false;
1910 }
1911 }
1912
1913 return principal->GetIsOriginPotentiallyTrustworthy();
1914}
1915
1916static bool InitializeLegacyNetscapeObject(JSContext* aCx,
1917 JS::Handle<JSObject*> aGlobal) {
1918 JSAutoRealm ar(aCx, aGlobal);
1919
1920 // Note: MathJax depends on window.netscape being exposed. See bug 791526.
1921 JS::Rooted<JSObject*> obj(aCx);
1922 obj = JS_DefineObject(aCx, aGlobal, "netscape", nullptr);
1923 NS_ENSURE_TRUE(obj, false)do { if ((__builtin_expect(!!(!(obj)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "obj" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1923); return false; } } while (false)
;
1924
1925 obj = JS_DefineObject(aCx, obj, "security", nullptr);
1926 NS_ENSURE_TRUE(obj, false)do { if ((__builtin_expect(!!(!(obj)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "obj" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1926); return false; } } while (false)
;
1927
1928 return true;
1929}
1930
1931struct MOZ_STACK_CLASS CompartmentFinderState {
1932 explicit CompartmentFinderState(nsIPrincipal* aPrincipal)
1933 : principal(aPrincipal), compartment(nullptr) {}
1934
1935 // Input: we look for a compartment which is same-origin with the
1936 // given principal.
1937 nsIPrincipal* principal;
1938
1939 // Output: We set this member if we find a compartment.
1940 JS::Compartment* compartment;
1941};
1942
1943static JS::CompartmentIterResult FindSameOriginCompartment(
1944 JSContext* aCx, void* aData, JS::Compartment* aCompartment) {
1945 auto* data = static_cast<CompartmentFinderState*>(aData);
1946 MOZ_ASSERT(!data->compartment, "Why are we getting called?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!data->compartment)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!data->compartment))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!data->compartment"
" (" "Why are we getting called?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!data->compartment"
") (" "Why are we getting called?" ")"); do { *((volatile int
*)__null) = 1946; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1947
1948 // If this compartment is not safe to share across globals, don't do
1949 // anything with it; in particular we should not be getting a
1950 // CompartmentPrivate from such a compartment, because it may be in
1951 // the middle of being collected and its CompartmentPrivate may no
1952 // longer be valid.
1953 if (!js::IsSharableCompartment(aCompartment)) {
1954 return JS::CompartmentIterResult::KeepGoing;
1955 }
1956
1957 auto* compartmentPrivate = xpc::CompartmentPrivate::Get(aCompartment);
1958 if (!compartmentPrivate->CanShareCompartmentWith(data->principal)) {
1959 // Can't reuse this one, keep going.
1960 return JS::CompartmentIterResult::KeepGoing;
1961 }
1962
1963 // We have a winner!
1964 data->compartment = aCompartment;
1965 return JS::CompartmentIterResult::Stop;
1966}
1967
1968static JS::RealmCreationOptions& SelectZone(
1969 JSContext* aCx, nsIPrincipal* aPrincipal, nsGlobalWindowInner* aNewInner,
1970 JS::RealmCreationOptions& aOptions) {
1971 // Use the shared system compartment for chrome windows.
1972 if (aPrincipal->IsSystemPrincipal()) {
1973 return aOptions.setExistingCompartment(xpc::PrivilegedJunkScope());
1974 }
1975
1976 BrowsingContext* bc = aNewInner->GetBrowsingContext();
1977 if (bc->IsTop()) {
1978 // We're a toplevel load. Use a new zone. This way, when we do
1979 // zone-based compartment sharing we won't share compartments
1980 // across navigations.
1981 return aOptions.setNewCompartmentAndZone();
1982 }
1983
1984 // Find the in-process ancestor highest in the hierarchy.
1985 nsGlobalWindowInner* ancestor = nullptr;
1986 for (WindowContext* wc = bc->GetParentWindowContext(); wc;
1987 wc = wc->GetParentWindowContext()) {
1988 if (nsGlobalWindowInner* win = wc->GetInnerWindow()) {
1989 ancestor = win;
1990 }
1991 }
1992
1993 // If we have an ancestor window, use its zone.
1994 if (ancestor && ancestor->GetGlobalJSObject()) {
1995 JS::Zone* zone = JS::GetObjectZone(ancestor->GetGlobalJSObject());
1996 // Now try to find an existing compartment that's same-origin
1997 // with our principal.
1998 CompartmentFinderState data(aPrincipal);
1999 JS_IterateCompartmentsInZone(aCx, zone, &data, FindSameOriginCompartment);
2000 if (data.compartment) {
2001 return aOptions.setExistingCompartment(data.compartment);
2002 }
2003 return aOptions.setNewCompartmentInExistingZone(
2004 ancestor->GetGlobalJSObject());
2005 }
2006
2007 return aOptions.setNewCompartmentAndZone();
2008}
2009
2010/**
2011 * Create a new global object that will be used for an inner window.
2012 * Return the native global and an nsISupports 'holder' that can be used
2013 * to manage the lifetime of it.
2014 */
2015static nsresult CreateNativeGlobalForInner(
2016 JSContext* aCx, nsGlobalWindowInner* aNewInner, Document* aDocument,
2017 JS::MutableHandle<JSObject*> aGlobal, bool aIsSecureContext,
2018 bool aDefineSharedArrayBufferConstructor) {
2019 MOZ_ASSERT(aCx)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aCx)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aCx))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aCx", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2019); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCx" ")"); do
{ *((volatile int*)__null) = 2019; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2020 MOZ_ASSERT(aNewInner)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewInner)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewInner))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNewInner", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewInner" ")"
); do { *((volatile int*)__null) = 2020; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2021
2022 nsCOMPtr<nsIURI> uri = aDocument->GetDocumentURI();
2023 nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
2024 MOZ_ASSERT(principal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(principal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(principal))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("principal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2024); AnnotateMozCrashReason("MOZ_ASSERT" "(" "principal" ")"
); do { *((volatile int*)__null) = 2024; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2025
2026 // DOMWindow with nsEP is not supported, we have to make sure
2027 // no one creates one accidentally.
2028 nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(principal);
2029 MOZ_RELEASE_ASSERT(!nsEP, "DOMWindow with nsEP is not supported")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!nsEP)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(!nsEP))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("!nsEP" " (" "DOMWindow with nsEP is not supported"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2029); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!nsEP"
") (" "DOMWindow with nsEP is not supported" ")"); do { *((volatile
int*)__null) = 2029; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2030
2031 JS::RealmOptions options;
2032 JS::RealmCreationOptions& creationOptions = options.creationOptions();
2033
2034 SelectZone(aCx, principal, aNewInner, creationOptions);
2035
2036 // Define the SharedArrayBuffer global constructor property only if shared
2037 // memory may be used and structured-cloned (e.g. through postMessage).
2038 //
2039 // When the global constructor property isn't defined, the SharedArrayBuffer
2040 // constructor can still be reached through Web Assembly. Omitting the global
2041 // property just prevents feature-tests from being misled. See bug 1624266.
2042 creationOptions.setDefineSharedArrayBufferConstructor(
2043 aDefineSharedArrayBufferConstructor);
2044
2045 xpc::InitGlobalObjectOptions(
2046 options, principal->IsSystemPrincipal(), aIsSecureContext,
2047 aDocument->ShouldResistFingerprinting(RFPTarget::JSDateTimeUTC),
2048 aDocument->ShouldResistFingerprinting(RFPTarget::JSMathFdlibm),
2049 aDocument->ShouldResistFingerprinting(RFPTarget::JSLocale));
2050
2051 // Determine if we need the Components object.
2052 bool needComponents = principal->IsSystemPrincipal();
2053 uint32_t flags = needComponents ? 0 : xpc::OMIT_COMPONENTS_OBJECT;
2054 flags |= xpc::DONT_FIRE_ONNEWGLOBALHOOK;
2055
2056 if (!Window_Binding::Wrap(aCx, aNewInner, aNewInner, options,
2057 nsJSPrincipals::get(principal), aGlobal) ||
2058 !xpc::InitGlobalObject(aCx, aGlobal, flags)) {
2059 return NS_ERROR_FAILURE;
2060 }
2061
2062 MOZ_ASSERT(aNewInner->GetWrapperPreserveColor() == aGlobal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewInner->GetWrapperPreserveColor() == aGlobal)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aNewInner->GetWrapperPreserveColor() == aGlobal))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aNewInner->GetWrapperPreserveColor() == aGlobal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewInner->GetWrapperPreserveColor() == aGlobal"
")"); do { *((volatile int*)__null) = 2062; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2063
2064 // Set the location information for the new global, so that tools like
2065 // about:memory may use that information
2066 xpc::SetLocationForGlobal(aGlobal, uri);
2067
2068 if (!InitializeLegacyNetscapeObject(aCx, aGlobal)) {
2069 return NS_ERROR_FAILURE;
2070 }
2071
2072 return NS_OK;
2073}
2074
2075nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
2076 nsISupports* aState,
2077 bool aForceReuseInnerWindow,
2078 WindowGlobalChild* aActor) {
2079 MOZ_ASSERT(mDocumentPrincipal == nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentPrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentPrincipal == nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDocumentPrincipal == nullptr" " (" "mDocumentPrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPrincipal == nullptr"
") (" "mDocumentPrincipal prematurely set!" ")"); do { *((volatile
int*)__null) = 2080; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
2080 "mDocumentPrincipal prematurely set!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentPrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentPrincipal == nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDocumentPrincipal == nullptr" " (" "mDocumentPrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPrincipal == nullptr"
") (" "mDocumentPrincipal prematurely set!" ")"); do { *((volatile
int*)__null) = 2080; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2081 MOZ_ASSERT(mDocumentCookiePrincipal == nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentCookiePrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentCookiePrincipal == nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDocumentCookiePrincipal == nullptr" " (" "mDocumentCookiePrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentCookiePrincipal == nullptr"
") (" "mDocumentCookiePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2082; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2082 "mDocumentCookiePrincipal prematurely set!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentCookiePrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentCookiePrincipal == nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDocumentCookiePrincipal == nullptr" " (" "mDocumentCookiePrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentCookiePrincipal == nullptr"
") (" "mDocumentCookiePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2082; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2083 MOZ_ASSERT(mDocumentStoragePrincipal == nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentStoragePrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentStoragePrincipal ==
nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDocumentStoragePrincipal == nullptr" " (" "mDocumentStoragePrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2084); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentStoragePrincipal == nullptr"
") (" "mDocumentStoragePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2084; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2084 "mDocumentStoragePrincipal prematurely set!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentStoragePrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentStoragePrincipal ==
nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDocumentStoragePrincipal == nullptr" " (" "mDocumentStoragePrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2084); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentStoragePrincipal == nullptr"
") (" "mDocumentStoragePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2084; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2085 MOZ_ASSERT(mDocumentPartitionedPrincipal == nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentPartitionedPrincipal == nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mDocumentPartitionedPrincipal == nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mDocumentPartitionedPrincipal == nullptr"
" (" "mDocumentPartitionedPrincipal prematurely set!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPartitionedPrincipal == nullptr"
") (" "mDocumentPartitionedPrincipal prematurely set!" ")");
do { *((volatile int*)__null) = 2086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2086 "mDocumentPartitionedPrincipal prematurely set!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentPartitionedPrincipal == nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mDocumentPartitionedPrincipal == nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mDocumentPartitionedPrincipal == nullptr"
" (" "mDocumentPartitionedPrincipal prematurely set!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPartitionedPrincipal == nullptr"
") (" "mDocumentPartitionedPrincipal prematurely set!" ")");
do { *((volatile int*)__null) = 2086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2087 MOZ_ASSERT(aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocument))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2087); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")"
); do { *((volatile int*)__null) = 2087; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2088
2089 // Bail out early if we're in process of closing down the window.
2090 NS_ENSURE_STATE(!mCleanedUp)do { if ((__builtin_expect(!!(!(!mCleanedUp)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!mCleanedUp" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2090); return NS_ERROR_UNEXPECTED; } } while (false)
;
2091
2092 NS_ASSERTION(!GetCurrentInnerWindow() ||do { if (!(!GetCurrentInnerWindow() || GetCurrentInnerWindow(
)->GetExtantDoc() == mDoc)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Uh, mDoc doesn't match the current inner window " "document!"
, "!GetCurrentInnerWindow() || GetCurrentInnerWindow()->GetExtantDoc() == mDoc"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2095); MOZ_PretendNoReturn(); } } while (0)
2093 GetCurrentInnerWindow()->GetExtantDoc() == mDoc,do { if (!(!GetCurrentInnerWindow() || GetCurrentInnerWindow(
)->GetExtantDoc() == mDoc)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Uh, mDoc doesn't match the current inner window " "document!"
, "!GetCurrentInnerWindow() || GetCurrentInnerWindow()->GetExtantDoc() == mDoc"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2095); MOZ_PretendNoReturn(); } } while (0)
2094 "Uh, mDoc doesn't match the current inner window "do { if (!(!GetCurrentInnerWindow() || GetCurrentInnerWindow(
)->GetExtantDoc() == mDoc)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Uh, mDoc doesn't match the current inner window " "document!"
, "!GetCurrentInnerWindow() || GetCurrentInnerWindow()->GetExtantDoc() == mDoc"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2095); MOZ_PretendNoReturn(); } } while (0)
2095 "document!")do { if (!(!GetCurrentInnerWindow() || GetCurrentInnerWindow(
)->GetExtantDoc() == mDoc)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Uh, mDoc doesn't match the current inner window " "document!"
, "!GetCurrentInnerWindow() || GetCurrentInnerWindow()->GetExtantDoc() == mDoc"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2095); MOZ_PretendNoReturn(); } } while (0)
;
2096 bool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
2097 if (aForceReuseInnerWindow && !wouldReuseInnerWindow && mDoc &&
2098 mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
2099 NS_ERROR("Attempted forced inner window reuse while changing principal")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Attempted forced inner window reuse while changing principal"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2099); MOZ_PretendNoReturn(); } while (0)
;
2100 return NS_ERROR_UNEXPECTED;
2101 }
2102
2103 if (!mBrowsingContext->AncestorsAreCurrent()) {
2104 return NS_ERROR_NOT_AVAILABLE;
2105 }
2106
2107 RefPtr<Document> oldDoc = mDoc;
2108 MOZ_RELEASE_ASSERT(oldDoc != aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(oldDoc != aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(oldDoc != aDocument))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("oldDoc != aDocument"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2108); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "oldDoc != aDocument"
")"); do { *((volatile int*)__null) = 2108; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2109
2110 AutoJSAPI jsapi;
2111 jsapi.Init();
2112 JSContext* cx = jsapi.cx();
2113
2114 // Check if we're anywhere near the stack limit before we reach the
2115 // transplanting code, since it has no good way to handle errors. This uses
2116 // the untrusted script limit, which is not strictly necessary since no
2117 // actual script should run.
2118 js::AutoCheckRecursionLimit recursion(cx);
2119 if (!recursion.checkConservativeDontReport(cx)) {
2120 NS_WARNING("Overrecursion in SetNewDocument")NS_DebugBreak(NS_DEBUG_WARNING, "Overrecursion in SetNewDocument"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2120)
;
2121 return NS_ERROR_FAILURE;
2122 }
2123
2124 if (!mDoc) {
2125 // First document load.
2126
2127 // Get our private root. If it is equal to us, then we need to
2128 // attach our global key bindings that handles browser scrolling
2129 // and other browser commands.
2130 nsPIDOMWindowOuter* privateRoot = GetPrivateRoot();
2131
2132 if (privateRoot == this) {
2133 RootWindowGlobalKeyListener::AttachKeyHandler(mChromeEventHandler);
2134 }
2135 }
2136
2137 MaybeResetWindowName(aDocument);
2138
2139 /* No mDocShell means we're already been partially closed down. When that
2140 happens, setting status isn't a big requirement, so don't. (Doesn't happen
2141 under normal circumstances, but bug 49615 describes a case.) */
2142
2143 nsContentUtils::AddScriptRunner(
2144 NewRunnableMethod("nsGlobalWindowOuter::ClearStatus", this,
2145 &nsGlobalWindowOuter::ClearStatus));
2146
2147 // Sometimes, WouldReuseInnerWindow() returns true even if there's no inner
2148 // window (see bug 776497). Be safe.
2149 bool reUseInnerWindow = (aForceReuseInnerWindow || wouldReuseInnerWindow) &&
2150 GetCurrentInnerWindowInternal(this);
2151
2152 nsresult rv;
2153
2154 // We set mDoc even though this is an outer window to avoid
2155 // having to *always* reach into the inner window to find the
2156 // document.
2157 mDoc = aDocument;
2158
2159 nsDocShell::Cast(mDocShell)->MaybeRestoreWindowName();
2160
2161 // We drop the print request for the old document on the floor, it never made
2162 // it. We don't close the window here either even if we were asked to.
2163 mShouldDelayPrintUntilAfterLoad = true;
2164 mDelayedCloseForPrinting = false;
2165 mDelayedPrintUntilAfterLoad = false;
2166
2167 // Take this opportunity to clear mSuspendedDocs. Our old inner window is now
2168 // responsible for unsuspending it.
2169 mSuspendedDocs.Clear();
2170
2171#ifdef DEBUG1
2172 mLastOpenedURI = aDocument->GetDocumentURI();
2173#endif
2174
2175 RefPtr<nsGlobalWindowInner> currentInner =
2176 GetCurrentInnerWindowInternal(this);
2177
2178 if (currentInner && currentInner->mNavigator) {
2179 currentInner->mNavigator->OnNavigation();
2180 }
2181
2182 RefPtr<nsGlobalWindowInner> newInnerWindow;
2183 bool createdInnerWindow = false;
2184
2185 bool thisChrome = IsChromeWindow();
2186
2187 nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
2188 NS_ASSERTION(!aState || wsh,do { if (!(!aState || wsh)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "What kind of weird state are you giving me here?", "!aState || wsh"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2189); MOZ_PretendNoReturn(); } } while (0)
2189 "What kind of weird state are you giving me here?")do { if (!(!aState || wsh)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "What kind of weird state are you giving me here?", "!aState || wsh"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2189); MOZ_PretendNoReturn(); } } while (0)
;
2190
2191 bool doomCurrentInner = false;
2192
2193 // Only non-gray (i.e. exposed to JS) objects should be assigned to
2194 // newInnerGlobal.
2195 JS::Rooted<JSObject*> newInnerGlobal(cx);
2196 if (reUseInnerWindow) {
2197 // We're reusing the current inner window.
2198 NS_ASSERTION(!currentInner->IsFrozen(),do { if (!(!currentInner->IsFrozen())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We should never be reusing a shared inner window", "!currentInner->IsFrozen()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2199); MOZ_PretendNoReturn(); } } while (0)
2199 "We should never be reusing a shared inner window")do { if (!(!currentInner->IsFrozen())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We should never be reusing a shared inner window", "!currentInner->IsFrozen()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2199); MOZ_PretendNoReturn(); } } while (0)
;
2200 newInnerWindow = currentInner;
2201 newInnerGlobal = currentInner->GetWrapper();
2202
2203 // We're reusing the inner window, but this still counts as a navigation,
2204 // so all expandos and such defined on the outer window should go away.
2205 // Force all Xray wrappers to be recomputed.
2206 JS::Rooted<JSObject*> rootedObject(cx, GetWrapper());
2207 if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) {
2208 return NS_ERROR_FAILURE;
2209 }
2210
2211 // Inner windows are only reused for same-origin principals, but the
2212 // principals don't necessarily match exactly. Update the principal on the
2213 // realm to match the new document. NB: We don't just call
2214 // currentInner->RefreshRealmPrincipals() here because we haven't yet set
2215 // its mDoc to aDocument.
2216 JS::Realm* realm = js::GetNonCCWObjectRealm(newInnerGlobal);
2217#ifdef DEBUG1
2218 bool sameOrigin = false;
2219 nsIPrincipal* existing = nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
2220 aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
2221 MOZ_ASSERT(sameOrigin)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sameOrigin)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sameOrigin))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("sameOrigin", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sameOrigin"
")"); do { *((volatile int*)__null) = 2221; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2222#endif
2223 JS::SetRealmPrincipals(realm,
2224 nsJSPrincipals::get(aDocument->NodePrincipal()));
2225 } else {
2226 if (aState) {
2227 newInnerWindow = wsh->GetInnerWindow();
2228 newInnerGlobal = newInnerWindow->GetWrapper();
2229 } else {
2230 newInnerWindow = nsGlobalWindowInner::Create(this, thisChrome, aActor);
2231 if (StaticPrefs::dom_timeout_defer_during_load()) {
2232 // ensure the initial loading state is known
2233 newInnerWindow->SetActiveLoadingState(
2234 aDocument->GetReadyStateEnum() ==
2235 Document::ReadyState::READYSTATE_LOADING);
2236 }
2237
2238 // The outer window is automatically treated as frozen when we
2239 // null out the inner window. As a result, initializing classes
2240 // on the new inner won't end up reaching into the old inner
2241 // window for classes etc.
2242 //
2243 // [This happens with Object.prototype when XPConnect creates
2244 // a temporary global while initializing classes; the reason
2245 // being that xpconnect creates the temp global w/o a parent
2246 // and proto, which makes the JS engine look up classes in
2247 // cx->globalObject, i.e. this outer window].
2248
2249 mInnerWindow = nullptr;
2250
2251 mCreatingInnerWindow = true;
2252
2253 // The SharedArrayBuffer global constructor property should not be present
2254 // in a fresh global object when shared memory objects aren't allowed
2255 // (because COOP/COEP support isn't enabled, or because COOP/COEP don't
2256 // act to isolate this page to a separate process).
2257
2258 // Every script context we are initialized with must create a
2259 // new global.
2260 rv = CreateNativeGlobalForInner(
2261 cx, newInnerWindow, aDocument, &newInnerGlobal,
2262 ComputeIsSecureContext(aDocument),
2263 newInnerWindow->IsSharedMemoryAllowedInternal(
2264 aDocument->NodePrincipal()));
2265 NS_ASSERTION(do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor
() == newInnerGlobal)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to get script global"
, "NS_SUCCEEDED(rv) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2268); MOZ_PretendNoReturn(); } } while (0)
2266 NS_SUCCEEDED(rv) && newInnerGlobal &&do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor
() == newInnerGlobal)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to get script global"
, "NS_SUCCEEDED(rv) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2268); MOZ_PretendNoReturn(); } } while (0)
2267 newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor
() == newInnerGlobal)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to get script global"
, "NS_SUCCEEDED(rv) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2268); MOZ_PretendNoReturn(); } } while (0)
2268 "Failed to get script global")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor
() == newInnerGlobal)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to get script global"
, "NS_SUCCEEDED(rv) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2268); MOZ_PretendNoReturn(); } } while (0)
;
2269
2270 mCreatingInnerWindow = false;
2271 createdInnerWindow = true;
2272
2273 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2273); return rv; } } while (false)
;
2274 }
2275
2276 if (currentInner && currentInner->GetWrapperPreserveColor()) {
2277 // Don't free objects on our current inner window if it's going to be
2278 // held in the bfcache.
2279 if (!currentInner->IsFrozen()) {
2280 doomCurrentInner = true;
2281 }
2282 }
2283
2284 mInnerWindow = newInnerWindow;
2285 MOZ_ASSERT(mInnerWindow)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mInnerWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mInnerWindow))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mInnerWindow", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2285); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mInnerWindow"
")"); do { *((volatile int*)__null) = 2285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2286 mInnerWindow->TryToCacheTopInnerWindow();
2287
2288 if (!GetWrapperPreserveColor()) {
2289 JS::Rooted<JSObject*> outer(
2290 cx, NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
2291 NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(outer)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "outer" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2291); return NS_ERROR_FAILURE; } } while (false)
;
2292
2293 mBrowsingContext->CleanUpDanglingRemoteOuterWindowProxies(cx, &outer);
2294 MOZ_ASSERT(js::IsWindowProxy(outer))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(js::IsWindowProxy(outer))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsWindowProxy(outer)))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("js::IsWindowProxy(outer)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2294); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(outer)"
")"); do { *((volatile int*)__null) = 2294; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2295
2296 js::SetProxyReservedSlot(outer, OUTER_WINDOW_SLOT,
2297 JS::PrivateValue(ToSupports(this)));
2298
2299 // Inform the nsJSContext, which is the canonical holder of the outer.
2300 mContext->SetWindowProxy(outer);
2301
2302 SetWrapper(mContext->GetWindowProxy());
2303 } else {
2304 JS::Rooted<JSObject*> outerObject(
2305 cx, NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
2306 if (!outerObject) {
2307 NS_ERROR("out of memory")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "out of memory", "Error"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2307); MOZ_PretendNoReturn(); } while (0)
;
2308 return NS_ERROR_FAILURE;
2309 }
2310
2311 JS::Rooted<JSObject*> obj(cx, GetWrapper());
2312
2313 MOZ_ASSERT(js::IsWindowProxy(obj))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(js::IsWindowProxy(obj))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsWindowProxy(obj)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("js::IsWindowProxy(obj)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(obj)"
")"); do { *((volatile int*)__null) = 2313; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2314
2315 js::SetProxyReservedSlot(obj, OUTER_WINDOW_SLOT,
2316 JS::PrivateValue(nullptr));
2317 js::SetProxyReservedSlot(outerObject, OUTER_WINDOW_SLOT,
2318 JS::PrivateValue(nullptr));
2319 js::SetProxyReservedSlot(obj, HOLDER_WEAKMAP_SLOT, JS::UndefinedValue());
2320
2321 outerObject = xpc::TransplantObjectNukingXrayWaiver(cx, obj, outerObject);
2322
2323 if (!outerObject) {
2324 mBrowsingContext->ClearWindowProxy();
2325 NS_ERROR("unable to transplant wrappers, probably OOM")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "unable to transplant wrappers, probably OOM"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2325); MOZ_PretendNoReturn(); } while (0)
;
2326 return NS_ERROR_FAILURE;
2327 }
2328
2329 js::SetProxyReservedSlot(outerObject, OUTER_WINDOW_SLOT,
2330 JS::PrivateValue(ToSupports(this)));
2331
2332 SetWrapper(outerObject);
2333
2334 MOZ_ASSERT(JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2334); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal"
")"); do { *((volatile int*)__null) = 2334; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2335
2336 // Inform the nsJSContext, which is the canonical holder of the outer.
2337 mContext->SetWindowProxy(outerObject);
2338 }
2339
2340 // Enter the new global's realm.
2341 JSAutoRealm ar(cx, GetWrapperPreserveColor());
2342
2343 {
2344 JS::Rooted<JSObject*> outer(cx, GetWrapperPreserveColor());
2345 js::SetWindowProxy(cx, newInnerGlobal, outer);
2346 mBrowsingContext->SetWindowProxy(outer);
2347 }
2348
2349 // Set scriptability based on the state of the WindowContext.
2350 WindowContext* wc = mInnerWindow->GetWindowContext();
2351 bool allow =
2352 wc ? wc->CanExecuteScripts() : mBrowsingContext->CanExecuteScripts();
2353 xpc::Scriptability::Get(GetWrapperPreserveColor())
2354 .SetWindowAllowsScript(allow);
2355
2356 if (!aState) {
2357 // Get the "window" property once so it will be cached on our inner. We
2358 // have to do this here, not in binding code, because this has to happen
2359 // after we've created the outer window proxy and stashed it in the outer
2360 // nsGlobalWindowOuter, so GetWrapperPreserveColor() on that outer
2361 // nsGlobalWindowOuter doesn't return null and
2362 // nsGlobalWindowOuter::OuterObject works correctly.
2363 JS::Rooted<JS::Value> unused(cx);
2364 if (!JS_GetProperty(cx, newInnerGlobal, "window", &unused)) {
2365 NS_ERROR("can't create the 'window' property")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "can't create the 'window' property"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2365); MOZ_PretendNoReturn(); } while (0)
;
2366 return NS_ERROR_FAILURE;
2367 }
2368
2369 // And same thing for the "self" property.
2370 if (!JS_GetProperty(cx, newInnerGlobal, "self", &unused)) {
2371 NS_ERROR("can't create the 'self' property")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "can't create the 'self' property"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2371); MOZ_PretendNoReturn(); } while (0)
;
2372 return NS_ERROR_FAILURE;
2373 }
2374 }
2375 }
2376
2377 JSAutoRealm ar(cx, GetWrapperPreserveColor());
2378
2379 if (!aState && !reUseInnerWindow) {
2380 // Loading a new page and creating a new inner window, *not*
2381 // restoring from session history.
2382
2383 // Now that both the the inner and outer windows are initialized
2384 // let the script context do its magic to hook them together.
2385 MOZ_ASSERT(mContext->GetWindowProxy() == GetWrapperPreserveColor())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mContext->GetWindowProxy() == GetWrapperPreserveColor
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mContext->GetWindowProxy() == GetWrapperPreserveColor
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mContext->GetWindowProxy() == GetWrapperPreserveColor()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2385); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mContext->GetWindowProxy() == GetWrapperPreserveColor()"
")"); do { *((volatile int*)__null) = 2385; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2386#ifdef DEBUG1
2387 JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
2388 JS::Rooted<JSObject*> proto1(cx), proto2(cx);
2389 JS_GetPrototype(cx, rootedJSObject, &proto1);
2390 JS_GetPrototype(cx, newInnerGlobal, &proto2);
2391 NS_ASSERTION(proto1 == proto2,do { if (!(proto1 == proto2)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "outer and inner globals should have the same prototype", "proto1 == proto2"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2392); MOZ_PretendNoReturn(); } } while (0)
2392 "outer and inner globals should have the same prototype")do { if (!(proto1 == proto2)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "outer and inner globals should have the same prototype", "proto1 == proto2"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2392); MOZ_PretendNoReturn(); } } while (0)
;
2393#endif
2394
2395 mInnerWindow->SyncStateFromParentWindow();
2396 }
2397
2398 // Add an extra ref in case we release mContext during GC.
2399 nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
2400
2401 // Make sure the inner's document is set correctly before we call
2402 // SetScriptGlobalObject, because that might try to examine document-dependent
2403 // state. Unfortunately, we can't do some of the other clearing/resetting
2404 // work we do below until after SetScriptGlobalObject(), because it might
2405 // depend on the document having the right scope object.
2406 if (aState) {
2407 MOZ_RELEASE_ASSERT(newInnerWindow->mDoc == aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newInnerWindow->mDoc == aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newInnerWindow->mDoc == aDocument
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"newInnerWindow->mDoc == aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2407); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc == aDocument"
")"); do { *((volatile int*)__null) = 2407; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2408 } else {
2409 if (reUseInnerWindow) {
2410 MOZ_RELEASE_ASSERT(newInnerWindow->mDoc != aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newInnerWindow->mDoc != aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newInnerWindow->mDoc != aDocument
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"newInnerWindow->mDoc != aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2410); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc != aDocument"
")"); do { *((volatile int*)__null) = 2410; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2411 }
2412 newInnerWindow->mDoc = aDocument;
2413 }
2414
2415 aDocument->SetScriptGlobalObject(newInnerWindow);
2416
2417 MOZ_RELEASE_ASSERT(newInnerWindow->mDoc == aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newInnerWindow->mDoc == aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newInnerWindow->mDoc == aDocument
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"newInnerWindow->mDoc == aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2417); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc == aDocument"
")"); do { *((volatile int*)__null) = 2417; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2418
2419 if (mBrowsingContext->IsTopContent()) {
2420 net::CookieJarSettings::Cast(aDocument->CookieJarSettings())
2421 ->SetTopLevelWindowContextId(aDocument->InnerWindowID());
2422 }
2423
2424 newInnerWindow->RefreshReduceTimerPrecisionCallerType();
2425
2426 if (!aState) {
2427 if (reUseInnerWindow) {
2428 // The StorageAccess state may have changed. Invalidate the cached
2429 // StorageAllowed field, so that the next call to StorageAllowedForWindow
2430 // recomputes it.
2431 newInnerWindow->ClearStorageAllowedCache();
2432
2433 // The storage objects contain the URL of the window. We have to
2434 // recreate them when the innerWindow is reused.
2435 newInnerWindow->mLocalStorage = nullptr;
2436 newInnerWindow->mSessionStorage = nullptr;
2437 newInnerWindow->mPerformance = nullptr;
2438
2439 // This must be called after nullifying the internal objects because
2440 // here we could recreate them, calling the getter methods, and store
2441 // them into the JS slots. If we nullify them after, the slot values and
2442 // the objects will be out of sync.
2443 newInnerWindow->ClearDocumentDependentSlots(cx);
2444 } else {
2445 newInnerWindow->InitDocumentDependentState(cx);
2446
2447 // Initialize DOM classes etc on the inner window.
2448 JS::Rooted<JSObject*> obj(cx, newInnerGlobal);
2449 rv = kungFuDeathGrip->InitClasses(obj);
2450 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2450); return rv; } } while (false)
;
2451 }
2452
2453 // When replacing an initial about:blank document we call
2454 // ExecutionReady again to update the client creation URL.
2455 rv = newInnerWindow->ExecutionReady();
2456 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2456); return rv; } } while (false)
;
2457
2458 if (mArguments) {
2459 newInnerWindow->DefineArgumentsProperty(mArguments);
2460 mArguments = nullptr;
2461 }
2462
2463 // Give the new inner window our chrome event handler (since it
2464 // doesn't have one).
2465 newInnerWindow->mChromeEventHandler = mChromeEventHandler;
2466 }
2467
2468 if (!aState && reUseInnerWindow) {
2469 // Notify our WindowGlobalChild that it has a new document. If `aState` was
2470 // passed, we're restoring the window from the BFCache, so the document
2471 // hasn't changed.
2472 // If we didn't have a window global child before, then initializing
2473 // it will have set all the required state, so we don't need to do
2474 // it again.
2475 mInnerWindow->GetWindowGlobalChild()->OnNewDocument(aDocument);
2476 }
2477
2478 // Update the current window for our BrowsingContext.
2479 RefPtr<BrowsingContext> bc = GetBrowsingContext();
2480
2481 if (bc->IsOwnedByProcess()) {
2482 MOZ_ALWAYS_SUCCEEDS(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))
), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash
("" "NS_SUCCEEDED(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2482); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))"
")"); do { *((volatile int*)__null) = 2482; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
2483 }
2484
2485 // We no longer need the old inner window. Start its destruction if
2486 // its not being reused and clear our reference.
2487 if (doomCurrentInner) {
2488 currentInner->FreeInnerObjects();
2489 }
2490 currentInner = nullptr;
2491
2492 // We wait to fire the debugger hook until the window is all set up and hooked
2493 // up with the outer. See bug 969156.
2494 if (createdInnerWindow) {
2495 nsContentUtils::AddScriptRunner(NewRunnableMethod(
2496 "nsGlobalWindowInner::FireOnNewGlobalObject", newInnerWindow,
2497 &nsGlobalWindowInner::FireOnNewGlobalObject));
2498 }
2499
2500 if (!newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
2501 // We should probably notify. However if this is the, arguably bad,
2502 // situation when we're creating a temporary non-chrome-about-blank
2503 // document in a chrome docshell, don't notify just yet. Instead wait
2504 // until we have a real chrome doc.
2505 const bool isContentAboutBlankInChromeDocshell = [&] {
2506 if (!mDocShell) {
2507 return false;
2508 }
2509
2510 RefPtr<BrowsingContext> bc = mDocShell->GetBrowsingContext();
2511 if (!bc || bc->GetType() != BrowsingContext::Type::Chrome) {
2512 return false;
2513 }
2514
2515 return !mDoc->NodePrincipal()->IsSystemPrincipal();
2516 }();
2517
2518 if (!isContentAboutBlankInChromeDocshell) {
2519 newInnerWindow->mHasNotifiedGlobalCreated = true;
2520 nsContentUtils::AddScriptRunner(NewRunnableMethod(
2521 "nsGlobalWindowOuter::DispatchDOMWindowCreated", this,
2522 &nsGlobalWindowOuter::DispatchDOMWindowCreated));
2523 }
2524 }
2525
2526 PreloadLocalStorage();
2527
2528 // Do this here rather than in say the Document constructor, since
2529 // we need a WindowContext available.
2530 mDoc->InitUseCounters();
2531
2532 return NS_OK;
2533}
2534
2535/* static */
2536void nsGlobalWindowOuter::PrepareForProcessChange(JSObject* aProxy) {
2537 JS::Rooted<JSObject*> localProxy(RootingCx(), aProxy);
2538 MOZ_ASSERT(js::IsWindowProxy(localProxy))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(js::IsWindowProxy(localProxy))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsWindowProxy(localProxy
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("js::IsWindowProxy(localProxy)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(localProxy)"
")"); do { *((volatile int*)__null) = 2538; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2539
2540 RefPtr<nsGlobalWindowOuter> outerWindow =
2541 nsOuterWindowProxy::GetOuterWindow(localProxy);
2542 if (!outerWindow) {
2543 return;
2544 }
2545
2546 AutoJSAPI jsapi;
2547 jsapi.Init();
2548 JSContext* cx = jsapi.cx();
2549
2550 JSAutoRealm ar(cx, localProxy);
2551
2552 // Clear out existing references from the browsing context and outer window to
2553 // the proxy, and from the proxy to the outer window. These references will
2554 // become invalid once the proxy is transplanted. Clearing the window proxy
2555 // from the browsing context is also necessary to indicate that it is for an
2556 // out of process window.
2557 outerWindow->ClearWrapper(localProxy);
2558 RefPtr<BrowsingContext> bc = outerWindow->GetBrowsingContext();
2559 MOZ_ASSERT(bc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(bc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("bc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2559); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc" ")"); do
{ *((volatile int*)__null) = 2559; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2560 MOZ_ASSERT(bc->GetWindowProxy() == localProxy)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc->GetWindowProxy() == localProxy)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(bc->GetWindowProxy() == localProxy))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("bc->GetWindowProxy() == localProxy"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2560); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc->GetWindowProxy() == localProxy"
")"); do { *((volatile int*)__null) = 2560; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2561 bc->ClearWindowProxy();
2562 js::SetProxyReservedSlot(localProxy, OUTER_WINDOW_SLOT,
2563 JS::PrivateValue(nullptr));
2564 js::SetProxyReservedSlot(localProxy, HOLDER_WEAKMAP_SLOT,
2565 JS::UndefinedValue());
2566
2567 // Create a new remote outer window proxy, and transplant to it.
2568 JS::Rooted<JSObject*> remoteProxy(cx);
2569
2570 if (!mozilla::dom::GetRemoteOuterWindowProxy(cx, bc, localProxy,
2571 &remoteProxy)) {
2572 MOZ_CRASH("PrepareForProcessChange GetRemoteOuterWindowProxy")do { do { } while (false); MOZ_ReportCrash("" "PrepareForProcessChange GetRemoteOuterWindowProxy"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2572); AnnotateMozCrashReason("MOZ_CRASH(" "PrepareForProcessChange GetRemoteOuterWindowProxy"
")"); do { *((volatile int*)__null) = 2572; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2573 }
2574
2575 if (!xpc::TransplantObjectNukingXrayWaiver(cx, localProxy, remoteProxy)) {
2576 MOZ_CRASH("PrepareForProcessChange TransplantObject")do { do { } while (false); MOZ_ReportCrash("" "PrepareForProcessChange TransplantObject"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2576); AnnotateMozCrashReason("MOZ_CRASH(" "PrepareForProcessChange TransplantObject"
")"); do { *((volatile int*)__null) = 2576; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2577 }
2578}
2579
2580void nsGlobalWindowOuter::PreloadLocalStorage() {
2581 if (!Storage::StoragePrefIsEnabled()) {
2582 return;
2583 }
2584
2585 if (IsChromeWindow()) {
2586 return;
2587 }
2588
2589 nsIPrincipal* principal = GetPrincipal();
2590 nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
2591 if (!principal || !storagePrincipal) {
2592 return;
2593 }
2594
2595 nsresult rv;
2596
2597 nsCOMPtr<nsIDOMStorageManager> storageManager =
2598 do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
2599 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2600 return;
2601 }
2602
2603 // private browsing windows do not persist local storage to disk so we should
2604 // only try to precache storage when we're not a private browsing window.
2605 if (!principal->GetIsInPrivateBrowsing()) {
2606 RefPtr<Storage> storage;
2607 rv = storageManager->PrecacheStorage(principal, storagePrincipal,
2608 getter_AddRefs(storage));
2609 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2610 mLocalStorage = storage;
2611 }
2612 }
2613}
2614
2615void nsGlobalWindowOuter::DispatchDOMWindowCreated() {
2616 if (!mDoc) {
2617 return;
2618 }
2619
2620 // Fire DOMWindowCreated at chrome event listeners
2621 nsContentUtils::DispatchChromeEvent(mDoc, mDoc, u"DOMWindowCreated"_ns,
2622 CanBubble::eYes, Cancelable::eNo);
2623
2624 nsCOMPtr<nsIObserverService> observerService =
2625 mozilla::services::GetObserverService();
2626
2627 // The event dispatching could possibly cause docshell destory, and
2628 // consequently cause mDoc to be set to nullptr by DropOuterWindowDocs(),
2629 // so check it again here.
2630 if (observerService && mDoc) {
2631 nsAutoString origin;
2632 nsIPrincipal* principal = mDoc->NodePrincipal();
2633 nsContentUtils::GetWebExposedOriginSerialization(principal, origin);
2634 observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
2635 principal->IsSystemPrincipal()
2636 ? "chrome-document-global-created"
2637 : "content-document-global-created",
2638 origin.get());
2639 }
2640}
2641
2642void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); }
2643
2644void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) {
2645 MOZ_ASSERT(aDocShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocShell))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2645); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocShell" ")"
); do { *((volatile int*)__null) = 2645; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2646
2647 if (aDocShell == mDocShell) {
2648 return;
2649 }
2650
2651 mDocShell = aDocShell;
2652 mBrowsingContext = aDocShell->GetBrowsingContext();
2653
2654 RefPtr<BrowsingContext> parentContext = mBrowsingContext->GetParent();
2655
2656 MOZ_RELEASE_ASSERT(!parentContext ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!parentContext || GetBrowsingContextGroup() == parentContext
->Group())>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!parentContext || GetBrowsingContextGroup
() == parentContext->Group()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2657); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
")"); do { *((volatile int*)__null) = 2657; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2657 GetBrowsingContextGroup() == parentContext->Group())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!parentContext || GetBrowsingContextGroup() == parentContext
->Group())>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!parentContext || GetBrowsingContextGroup
() == parentContext->Group()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2657); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
")"); do { *((volatile int*)__null) = 2657; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2658
2659 mTopLevelOuterContentWindow = mBrowsingContext->IsTopContent();
2660
2661 // Get our enclosing chrome shell and retrieve its global window impl, so
2662 // that we can do some forwarding to the chrome document.
2663 RefPtr<EventTarget> chromeEventHandler;
2664 mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
2665 mChromeEventHandler = chromeEventHandler;
2666 if (!mChromeEventHandler) {
2667 // We have no chrome event handler. If we have a parent,
2668 // get our chrome event handler from the parent. If
2669 // we don't have a parent, then we need to make a new
2670 // window root object that will function as a chrome event
2671 // handler and receive all events that occur anywhere inside
2672 // our window.
2673 nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetInProcessParent();
2674 if (parentWindow.get() != this) {
2675 mChromeEventHandler = parentWindow->GetChromeEventHandler();
2676 } else {
2677 mChromeEventHandler = NS_NewWindowRoot(this);
2678 mIsRootOuterWindow = true;
2679 }
2680 }
2681
2682 SetIsBackgroundInternal(!mBrowsingContext->IsActive());
2683}
2684
2685void nsGlobalWindowOuter::DetachFromDocShell(bool aIsBeingDiscarded) {
2686 // DetachFromDocShell means the window is being torn down. Drop our
2687 // reference to the script context, allowing it to be deleted
2688 // later. Meanwhile, keep our weak reference to the script object
2689 // so that it can be retrieved later (until it is finalized by the JS GC).
2690
2691 // Call FreeInnerObjects on all inner windows, not just the current
2692 // one, since some could be held by WindowStateHolder objects that
2693 // are GC-owned.
2694 RefPtr<nsGlobalWindowInner> inner;
2695 for (PRCList* node = PR_LIST_HEAD(this)(this)->next; node != this;
2696 node = PR_NEXT_LINK(inner)((inner)->next)) {
2697 // This cast is safe because `node != this`. Non-this nodes are inner
2698 // windows.
2699 inner = static_cast<nsGlobalWindowInner*>(node);
2700 MOZ_ASSERT(!inner->mOuterWindow || inner->mOuterWindow == this)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inner->mOuterWindow || inner->mOuterWindow ==
this)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!inner->mOuterWindow || inner->mOuterWindow ==
this))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!inner->mOuterWindow || inner->mOuterWindow == this",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2700); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inner->mOuterWindow || inner->mOuterWindow == this"
")"); do { *((volatile int*)__null) = 2700; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2701 inner->FreeInnerObjects();
2702 }
2703
2704 // Don't report that we were detached to the nsWindowMemoryReporter, as it
2705 // only tracks inner windows.
2706
2707 NotifyWindowIDDestroyed("outer-window-destroyed");
2708
2709 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(this);
2710
2711 if (currentInner) {
2712 NS_ASSERTION(mDoc, "Must have doc!")do { if (!(mDoc)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Must have doc!"
, "mDoc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2712); MOZ_PretendNoReturn(); } } while (0)
;
2713
2714 // Remember the document's principal and URI.
2715 mDocumentPrincipal = mDoc->NodePrincipal();
2716 mDocumentCookiePrincipal = mDoc->EffectiveCookiePrincipal();
2717 mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
2718 mDocumentPartitionedPrincipal = mDoc->PartitionedPrincipal();
2719 mDocumentURI = mDoc->GetDocumentURI();
2720
2721 // Release our document reference
2722 DropOuterWindowDocs();
2723 }
2724
2725 ClearControllers();
2726
2727 mChromeEventHandler = nullptr; // force release now
2728
2729 if (mContext) {
2730 // When we're about to destroy a top level content window
2731 // (for example a tab), we trigger a full GC by passing null as the last
2732 // param. We also trigger a full GC for chrome windows.
2733 nsJSContext::PokeGC(JS::GCReason::SET_DOC_SHELL,
2734 (mTopLevelOuterContentWindow || mIsChrome)
2735 ? nullptr
2736 : GetWrapperPreserveColor());
2737 mContext = nullptr;
2738 }
2739
2740 if (aIsBeingDiscarded) {
2741 // If our BrowsingContext is being discarded, make a note that our current
2742 // inner window was active at the time it went away.
2743 if (nsGlobalWindowInner* currentInner =
2744 GetCurrentInnerWindowInternal(this)) {
2745 currentInner->SetWasCurrentInnerWindow();
2746 }
2747 }
2748
2749 mDocShell = nullptr;
2750 mBrowsingContext->ClearDocShell();
2751
2752 CleanUp();
2753}
2754
2755void nsGlobalWindowOuter::UpdateParentTarget() {
2756 // NOTE: This method is nearly identical to
2757 // nsGlobalWindowInner::UpdateParentTarget(). IF YOU UPDATE THIS METHOD,
2758 // UPDATE THE OTHER ONE TOO! The one difference is that this method updates
2759 // mMessageManager as well, which inner windows don't have.
2760
2761 // Try to get our frame element's tab child global (its in-process message
2762 // manager). If that fails, fall back to the chrome event handler's tab
2763 // child global, and if it doesn't have one, just use the chrome event
2764 // handler itself.
2765
2766 nsCOMPtr<Element> frameElement = GetFrameElementInternal();
2767 mMessageManager = nsContentUtils::TryGetBrowserChildGlobal(frameElement);
2768
2769 if (!mMessageManager) {
2770 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
2771 if (topWin) {
2772 frameElement = topWin->GetFrameElementInternal();
2773 mMessageManager = nsContentUtils::TryGetBrowserChildGlobal(frameElement);
2774 }
2775 }
2776
2777 if (!mMessageManager) {
2778 mMessageManager =
2779 nsContentUtils::TryGetBrowserChildGlobal(mChromeEventHandler);
2780 }
2781
2782 if (mMessageManager) {
2783 mParentTarget = mMessageManager;
2784 } else {
2785 mParentTarget = mChromeEventHandler;
2786 }
2787}
2788
2789EventTarget* nsGlobalWindowOuter::GetTargetForEventTargetChain() {
2790 return GetCurrentInnerWindowInternal(this);
2791}
2792
2793void nsGlobalWindowOuter::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
2794 MOZ_CRASH("The outer window should not be part of an event path")do { do { } while (false); MOZ_ReportCrash("" "The outer window should not be part of an event path"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2794); AnnotateMozCrashReason("MOZ_CRASH(" "The outer window should not be part of an event path"
")"); do { *((volatile int*)__null) = 2794; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2795}
2796
2797bool nsGlobalWindowOuter::ShouldPromptToBlockDialogs() {
2798 if (!nsContentUtils::GetCurrentJSContext()) {
2799 return false; // non-scripted caller.
2800 }
2801
2802 BrowsingContextGroup* group = GetBrowsingContextGroup();
2803 if (!group) {
2804 return true;
2805 }
2806
2807 return group->DialogsAreBeingAbused();
2808}
2809
2810bool nsGlobalWindowOuter::AreDialogsEnabled() {
2811 BrowsingContextGroup* group = mBrowsingContext->Group();
2812 if (!group) {
2813 NS_ERROR("AreDialogsEnabled() called without a browsing context group?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "AreDialogsEnabled() called without a browsing context group?"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2813); MOZ_PretendNoReturn(); } while (0)
;
2814 return false;
2815 }
2816
2817 // Dialogs are blocked if the content viewer is hidden
2818 if (mDocShell) {
2819 nsCOMPtr<nsIDocumentViewer> viewer;
2820 mDocShell->GetDocViewer(getter_AddRefs(viewer));
2821
2822 bool isHidden;
2823 viewer->GetIsHidden(&isHidden);
2824 if (isHidden) {
2825 return false;
2826 }
2827 }
2828
2829 // Dialogs are also blocked if the document is sandboxed with SANDBOXED_MODALS
2830 // (or if we have no document, of course). Which document? Who knows; the
2831 // spec is daft. See <https://github.com/whatwg/html/issues/1206>. For now
2832 // just go ahead and check mDoc, since in everything except edge cases in
2833 // which a frame is allow-same-origin but not allow-scripts and is being poked
2834 // at by some other window this should be the right thing anyway.
2835 if (!mDoc || (mDoc->GetSandboxFlags() & SANDBOXED_MODALS)) {
2836 return false;
2837 }
2838
2839 return group->GetAreDialogsEnabled();
2840}
2841
2842void nsGlobalWindowOuter::DisableDialogs() {
2843 BrowsingContextGroup* group = mBrowsingContext->Group();
2844 if (!group) {
2845 NS_ERROR("DisableDialogs() called without a browsing context group?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "DisableDialogs() called without a browsing context group?"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2845); MOZ_PretendNoReturn(); } while (0)
;
2846 return;
2847 }
2848
2849 if (group) {
2850 group->SetAreDialogsEnabled(false);
2851 }
2852}
2853
2854void nsGlobalWindowOuter::EnableDialogs() {
2855 BrowsingContextGroup* group = mBrowsingContext->Group();
2856 if (!group) {
2857 NS_ERROR("EnableDialogs() called without a browsing context group?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "EnableDialogs() called without a browsing context group?"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2857); MOZ_PretendNoReturn(); } while (0)
;
2858 return;
2859 }
2860
2861 if (group) {
2862 group->SetAreDialogsEnabled(true);
2863 }
2864}
2865
2866nsresult nsGlobalWindowOuter::PostHandleEvent(EventChainPostVisitor& aVisitor) {
2867 MOZ_CRASH("The outer window should not be part of an event path")do { do { } while (false); MOZ_ReportCrash("" "The outer window should not be part of an event path"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2867); AnnotateMozCrashReason("MOZ_CRASH(" "The outer window should not be part of an event path"
")"); do { *((volatile int*)__null) = 2867; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2868}
2869
2870void nsGlobalWindowOuter::PoisonOuterWindowProxy(JSObject* aObject) {
2871 if (aObject == GetWrapperMaybeDead()) {
2872 PoisonWrapper();
2873 }
2874}
2875
2876nsresult nsGlobalWindowOuter::SetArguments(nsIArray* aArguments) {
2877 nsresult rv;
2878
2879 // We've now mostly separated them, but the difference is still opaque to
2880 // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
2881 // embedding waltz we do here).
2882 //
2883 // So we need to demultiplex the two cases here.
2884 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(this);
2885
2886 mArguments = aArguments;
2887 rv = currentInner->DefineArgumentsProperty(aArguments);
2888 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2888); return rv; } } while (false)
;
2889
2890 return NS_OK;
2891}
2892
2893//*****************************************************************************
2894// nsGlobalWindowOuter::nsIScriptObjectPrincipal
2895//*****************************************************************************
2896
2897nsIPrincipal* nsGlobalWindowOuter::GetPrincipal() {
2898 if (mDoc) {
2899 // If we have a document, get the principal from the document
2900 return mDoc->NodePrincipal();
2901 }
2902
2903 if (mDocumentPrincipal) {
2904 return mDocumentPrincipal;
2905 }
2906
2907 // If we don't have a principal and we don't have a document we
2908 // ask the parent window for the principal. This can happen when
2909 // loading a frameset that has a <frame src="javascript:xxx">, in
2910 // that case the global window is used in JS before we've loaded
2911 // a document into the window.
2912
2913 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2914 do_QueryInterface(GetInProcessParentInternal());
2915
2916 if (objPrincipal) {
2917 return objPrincipal->GetPrincipal();
2918 }
2919
2920 return nullptr;
2921}
2922
2923nsIPrincipal* nsGlobalWindowOuter::GetEffectiveCookiePrincipal() {
2924 if (mDoc) {
2925 // If we have a document, get the principal from the document
2926 return mDoc->EffectiveCookiePrincipal();
2927 }
2928
2929 if (mDocumentCookiePrincipal) {
2930 return mDocumentCookiePrincipal;
2931 }
2932
2933 // If we don't have a cookie principal and we don't have a document we ask
2934 // the parent window for the cookie principal.
2935
2936 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2937 do_QueryInterface(GetInProcessParentInternal());
2938
2939 if (objPrincipal) {
2940 return objPrincipal->GetEffectiveCookiePrincipal();
2941 }
2942
2943 return nullptr;
2944}
2945
2946nsIPrincipal* nsGlobalWindowOuter::GetEffectiveStoragePrincipal() {
2947 if (mDoc) {
2948 // If we have a document, get the principal from the document
2949 return mDoc->EffectiveStoragePrincipal();
2950 }
2951
2952 if (mDocumentStoragePrincipal) {
2953 return mDocumentStoragePrincipal;
2954 }
2955
2956 // If we don't have a storage principal and we don't have a document we ask
2957 // the parent window for the storage principal.
2958
2959 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2960 do_QueryInterface(GetInProcessParentInternal());
2961
2962 if (objPrincipal) {
2963 return objPrincipal->GetEffectiveStoragePrincipal();
2964 }
2965
2966 return nullptr;
2967}
2968
2969nsIPrincipal* nsGlobalWindowOuter::PartitionedPrincipal() {
2970 if (mDoc) {
2971 // If we have a document, get the principal from the document
2972 return mDoc->PartitionedPrincipal();
2973 }
2974
2975 if (mDocumentPartitionedPrincipal) {
2976 return mDocumentPartitionedPrincipal;
2977 }
2978
2979 // If we don't have a partitioned principal and we don't have a document we
2980 // ask the parent window for the partitioned principal.
2981
2982 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2983 do_QueryInterface(GetInProcessParentInternal());
2984
2985 if (objPrincipal) {
2986 return objPrincipal->PartitionedPrincipal();
2987 }
2988
2989 return nullptr;
2990}
2991
2992//*****************************************************************************
2993// nsGlobalWindowOuter::nsIDOMWindow
2994//*****************************************************************************
2995
2996Element* nsPIDOMWindowOuter::GetFrameElementInternal() const {
2997 return mFrameElement;
2998}
2999
3000void nsPIDOMWindowOuter::SetFrameElementInternal(Element* aFrameElement) {
3001 mFrameElement = aFrameElement;
3002}
3003
3004Navigator* nsGlobalWindowOuter::GetNavigator() {
3005 FORWARD_TO_INNER(Navigator, (), nullptr)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3005); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Navigator (); } while (0)
;
3006}
3007
3008nsScreen* nsGlobalWindowOuter::GetScreen() {
3009 FORWARD_TO_INNER(Screen, (), nullptr)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3009); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Screen (); } while (0)
;
3010}
3011
3012void nsPIDOMWindowOuter::ActivateMediaComponents() {
3013 if (!ShouldDelayMediaFromStart()) {
3014 return;
3015 }
3016 MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = AudioChannelService
::GetAudioChannelLog(); if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Debug, "nsPIDOMWindowOuter, ActiveMediaComponents, "
"no longer to delay media from start, this = %p\n", this); }
} while (0)
3017 ("nsPIDOMWindowOuter, ActiveMediaComponents, "do { const ::mozilla::LogModule* moz_real_module = AudioChannelService
::GetAudioChannelLog(); if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Debug, "nsPIDOMWindowOuter, ActiveMediaComponents, "
"no longer to delay media from start, this = %p\n", this); }
} while (0)
3018 "no longer to delay media from start, this = %p\n",do { const ::mozilla::LogModule* moz_real_module = AudioChannelService
::GetAudioChannelLog(); if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Debug, "nsPIDOMWindowOuter, ActiveMediaComponents, "
"no longer to delay media from start, this = %p\n", this); }
} while (0)
3019 this))do { const ::mozilla::LogModule* moz_real_module = AudioChannelService
::GetAudioChannelLog(); if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Debug, "nsPIDOMWindowOuter, ActiveMediaComponents, "
"no longer to delay media from start, this = %p\n", this); }
} while (0)
;
3020 if (BrowsingContext* bc = GetBrowsingContext()) {
3021 Unused << bc->Top()->SetShouldDelayMediaFromStart(false);
3022 }
3023 NotifyResumingDelayedMedia();
3024}
3025
3026bool nsPIDOMWindowOuter::ShouldDelayMediaFromStart() const {
3027 BrowsingContext* bc = GetBrowsingContext();
3028 return bc && bc->Top()->GetShouldDelayMediaFromStart();
3029}
3030
3031void nsPIDOMWindowOuter::NotifyResumingDelayedMedia() {
3032 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
3033 if (service) {
3034 service->NotifyResumingDelayedMedia(this);
3035 }
3036}
3037
3038bool nsPIDOMWindowOuter::GetAudioMuted() const {
3039 BrowsingContext* bc = GetBrowsingContext();
3040 return bc && bc->Top()->GetMuted();
3041}
3042
3043void nsPIDOMWindowOuter::RefreshMediaElementsVolume() {
3044 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
3045 if (service) {
3046 // TODO: RefreshAgentsVolume can probably be simplified further.
3047 service->RefreshAgentsVolume(this, 1.0f, GetAudioMuted());
3048 }
3049}
3050
3051mozilla::dom::BrowsingContextGroup*
3052nsPIDOMWindowOuter::GetBrowsingContextGroup() const {
3053 return mBrowsingContext ? mBrowsingContext->Group() : nullptr;
3054}
3055
3056Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetParentOuter() {
3057 BrowsingContext* bc = GetBrowsingContext();
3058 return bc ? bc->GetParent(IgnoreErrors()) : nullptr;
3059}
3060
3061/**
3062 * GetInProcessScriptableParent used to be called when a script read
3063 * window.parent. Under Fission, that is now handled by
3064 * BrowsingContext::GetParent, and the result is a WindowProxyHolder rather than
3065 * an actual global window. This method still exists for legacy callers which
3066 * relied on the old logic, and require in-process windows. However, it only
3067 * works correctly when no out-of-process frames exist between this window and
3068 * the top-level window, so it should not be used in new code.
3069 *
3070 * In contrast to GetRealParent, GetInProcessScriptableParent respects <iframe
3071 * mozbrowser> boundaries, so if |this| is contained by an <iframe
3072 * mozbrowser>, we will return |this| as its own parent.
3073 */
3074nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableParent() {
3075 if (!mDocShell) {
3076 return nullptr;
3077 }
3078
3079 if (BrowsingContext* parentBC = GetBrowsingContext()->GetParent()) {
3080 if (nsCOMPtr<nsPIDOMWindowOuter> parent = parentBC->GetDOMWindow()) {
3081 return parent;
3082 }
3083 }
3084 return this;
3085}
3086
3087/**
3088 * Behavies identically to GetInProcessScriptableParent extept that it returns
3089 * null if GetInProcessScriptableParent would return this window.
3090 */
3091nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableParentOrNull() {
3092 nsPIDOMWindowOuter* parent = GetInProcessScriptableParent();
3093 return (nsGlobalWindowOuter::Cast(parent) == this) ? nullptr : parent;
3094}
3095
3096already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetInProcessParent() {
3097 if (!mDocShell) {
3098 return nullptr;
3099 }
3100
3101 if (auto* parentBC = GetBrowsingContext()->GetParent()) {
3102 if (auto* parent = parentBC->GetDOMWindow()) {
3103 return do_AddRef(parent);
3104 }
3105 }
3106 return do_AddRef(this);
3107}
3108
3109static nsresult GetTopImpl(nsGlobalWindowOuter* aWin, nsIURI* aURIBeingLoaded,
3110 nsPIDOMWindowOuter** aTop, bool aScriptable,
3111 bool aExcludingExtensionAccessibleContentFrames) {
3112 *aTop = nullptr;
3113
3114 MOZ_ASSERT_IF(aExcludingExtensionAccessibleContentFrames, !aScriptable)do { if (aExcludingExtensionAccessibleContentFrames) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(!aScriptable
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aScriptable))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aScriptable", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3114); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aScriptable"
")"); do { *((volatile int*)__null) = 3114; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3115
3116 // Walk up the parent chain.
3117
3118 nsCOMPtr<nsPIDOMWindowOuter> prevParent = aWin;
3119 nsCOMPtr<nsPIDOMWindowOuter> parent = aWin;
3120 do {
3121 if (!parent) {
3122 break;
3123 }
3124
3125 prevParent = parent;
3126
3127 if (aScriptable) {
3128 parent = parent->GetInProcessScriptableParent();
3129 } else {
3130 parent = parent->GetInProcessParent();
3131 }
3132
3133 if (aExcludingExtensionAccessibleContentFrames) {
3134 if (auto* p = nsGlobalWindowOuter::Cast(parent)) {
3135 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(p);
3136 nsIURI* uri = prevParent->GetDocumentURI();
3137 if (!uri) {
3138 // If our parent doesn't have a URI yet, we have a document that is in
3139 // the process of being loaded. In that case, our caller is
3140 // responsible for passing in the URI for the document that is being
3141 // loaded, so we fall back to using that URI here.
3142 uri = aURIBeingLoaded;
3143 }
3144
3145 if (currentInner && uri) {
3146 // If we find an inner window, we better find the uri for the current
3147 // window we're looking at. If we can't find it directly, it is the
3148 // responsibility of our caller to provide it to us.
3149 MOZ_DIAGNOSTIC_ASSERT(uri)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(uri)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(uri))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("uri", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3149); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "uri"
")"); do { *((volatile int*)__null) = 3149; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3150
3151 // If the new parent has permission to load the current page, we're
3152 // at a moz-extension:// frame which has a host permission that allows
3153 // it to load the document that we've loaded. In that case, stop at
3154 // this frame and consider it the top-level frame.
3155 //
3156 // Note that it's possible for the set of URIs accepted by
3157 // AddonAllowsLoad() to change at runtime, but we don't need to cache
3158 // the result of this check, since the important consumer of this code
3159 // (which is nsIHttpChannelInternal.topWindowURI) already caches the
3160 // result after computing it the first time.
3161 if (BasePrincipal::Cast(p->GetPrincipal())
3162 ->AddonAllowsLoad(uri, true)) {
3163 parent = prevParent;
3164 break;
3165 }
3166 }
3167 }
3168 }
3169
3170 } while (parent != prevParent);
3171
3172 if (parent) {
3173 parent.swap(*aTop);
3174 }
3175
3176 return NS_OK;
3177}
3178
3179/**
3180 * GetInProcessScriptableTop used to be called when a script read window.top.
3181 * Under Fission, that is now handled by BrowsingContext::Top, and the result is
3182 * a WindowProxyHolder rather than an actual global window. This method still
3183 * exists for legacy callers which relied on the old logic, and require
3184 * in-process windows. However, it only works correctly when no out-of-process
3185 * frames exist between this window and the top-level window, so it should not
3186 * be used in new code.
3187 *
3188 * In contrast to GetRealTop, GetInProcessScriptableTop respects <iframe
3189 * mozbrowser> boundaries. If we encounter a window owned by an <iframe
3190 * mozbrowser> while walking up the window hierarchy, we'll stop and return that
3191 * window.
3192 */
3193nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableTop() {
3194 nsCOMPtr<nsPIDOMWindowOuter> window;
3195 GetTopImpl(this, /* aURIBeingLoaded = */ nullptr, getter_AddRefs(window),
3196 /* aScriptable = */ true,
3197 /* aExcludingExtensionAccessibleContentFrames = */ false);
3198 return window.get();
3199}
3200
3201already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetInProcessTop() {
3202 nsCOMPtr<nsPIDOMWindowOuter> window;
3203 GetTopImpl(this, /* aURIBeingLoaded = */ nullptr, getter_AddRefs(window),
3204 /* aScriptable = */ false,
3205 /* aExcludingExtensionAccessibleContentFrames = */ false);
3206 return window.forget();
3207}
3208
3209already_AddRefed<nsPIDOMWindowOuter>
3210nsGlobalWindowOuter::GetTopExcludingExtensionAccessibleContentFrames(
3211 nsIURI* aURIBeingLoaded) {
3212 // There is a parent-process equivalent of this in DocumentLoadListener.cpp
3213 // GetTopWindowExcludingExtensionAccessibleContentFrames
3214 nsCOMPtr<nsPIDOMWindowOuter> window;
3215 GetTopImpl(this, aURIBeingLoaded, getter_AddRefs(window),
3216 /* aScriptable = */ false,
3217 /* aExcludingExtensionAccessibleContentFrames = */ true);
3218 return window.forget();
3219}
3220
3221void nsGlobalWindowOuter::GetContentOuter(JSContext* aCx,
3222 JS::MutableHandle<JSObject*> aRetval,
3223 CallerType aCallerType,
3224 ErrorResult& aError) {
3225 RefPtr<BrowsingContext> content = GetContentInternal(aCallerType, aError);
3226 if (aError.Failed()) {
3227 return;
3228 }
3229
3230 if (!content) {
3231 aRetval.set(nullptr);
3232 return;
3233 }
3234
3235 JS::Rooted<JS::Value> val(aCx);
3236 if (!ToJSValue(aCx, WindowProxyHolder{content}, &val)) {
3237 aError.Throw(NS_ERROR_UNEXPECTED);
3238 return;
3239 }
3240
3241 MOZ_ASSERT(val.isObjectOrNull())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(val.isObjectOrNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(val.isObjectOrNull()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("val.isObjectOrNull()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3241); AnnotateMozCrashReason("MOZ_ASSERT" "(" "val.isObjectOrNull()"
")"); do { *((volatile int*)__null) = 3241; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3242 aRetval.set(val.toObjectOrNull());
3243}
3244
3245already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetContentInternal(
3246 CallerType aCallerType, ErrorResult& aError) {
3247 // First check for a named frame named "content"
3248 if (RefPtr<BrowsingContext> named = GetChildWindow(u"content"_ns)) {
3249 return named.forget();
3250 }
3251
3252 // If we're in the parent process, and being called by system code, `content`
3253 // should return the current primary content frame (if it's in-process).
3254 //
3255 // We return `nullptr` if the current primary content frame is out-of-process,
3256 // rather than a remote window proxy, as that is the existing behaviour as of
3257 // bug 1597437.
3258 if (XRE_IsParentProcess() && aCallerType == CallerType::System) {
3259 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
3260 if (!treeOwner) {
3261 aError.Throw(NS_ERROR_FAILURE);
3262 return nullptr;
3263 }
3264
3265 nsCOMPtr<nsIDocShellTreeItem> primaryContent;
3266 treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
3267 if (!primaryContent) {
3268 return nullptr;
3269 }
3270
3271 return do_AddRef(primaryContent->GetBrowsingContext());
3272 }
3273
3274 // For legacy untrusted callers we always return the same value as
3275 // `window.top`
3276 if (mDoc && aCallerType != CallerType::System) {
3277 mDoc->WarnOnceAbout(DeprecatedOperations::eWindowContentUntrusted);
3278 }
3279
3280 MOZ_ASSERT(mBrowsingContext->IsContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mBrowsingContext->IsContent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mBrowsingContext->IsContent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mBrowsingContext->IsContent()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3280); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mBrowsingContext->IsContent()"
")"); do { *((volatile int*)__null) = 3280; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3281 return do_AddRef(mBrowsingContext->Top());
3282}
3283
3284nsresult nsGlobalWindowOuter::GetPrompter(nsIPrompt** aPrompt) {
3285 if (!mDocShell) return NS_ERROR_FAILURE;
3286
3287 nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
3288 NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE)do { if ((__builtin_expect(!!(!(prompter)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "prompter" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3288); return NS_ERROR_NO_INTERFACE; } } while (false)
;
3289
3290 prompter.forget(aPrompt);
3291 return NS_OK;
3292}
3293
3294bool nsGlobalWindowOuter::GetClosedOuter() {
3295 // If someone called close(), or if we don't have a docshell, we're closed.
3296 return mIsClosed || !mDocShell;
3297}
3298
3299bool nsGlobalWindowOuter::Closed() { return GetClosedOuter(); }
3300
3301Nullable<WindowProxyHolder> nsGlobalWindowOuter::IndexedGetterOuter(
3302 uint32_t aIndex) {
3303 BrowsingContext* bc = GetBrowsingContext();
3304 NS_ENSURE_TRUE(bc, nullptr)do { if ((__builtin_expect(!!(!(bc)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "bc" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3304); return nullptr; } } while (false)
;
3305
3306 Span<RefPtr<BrowsingContext>> children = bc->NonSyntheticChildren();
3307
3308 if (aIndex < children.Length()) {
3309 return WindowProxyHolder(children[aIndex]);
3310 }
3311 return nullptr;
3312}
3313
3314nsIControllers* nsGlobalWindowOuter::GetControllersOuter(ErrorResult& aError) {
3315 if (!mControllers) {
3316 mControllers = new nsXULControllers();
3317 if (!mControllers) {
3318 aError.Throw(NS_ERROR_FAILURE);
3319 return nullptr;
3320 }
3321
3322 // Add in the default controller
3323 RefPtr<nsBaseCommandController> commandController =
3324 nsBaseCommandController::CreateWindowController();
3325 if (!commandController) {
3326 aError.Throw(NS_ERROR_FAILURE);
3327 return nullptr;
3328 }
3329
3330 mControllers->InsertControllerAt(0, commandController);
3331 commandController->SetCommandContext(static_cast<nsIDOMWindow*>(this));
3332 }
3333
3334 return mControllers;
3335}
3336
3337nsresult nsGlobalWindowOuter::GetControllers(nsIControllers** aResult) {
3338 FORWARD_TO_INNER(GetControllers, (aResult), NS_ERROR_UNEXPECTED)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3338); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetControllers (aResult); } while (0)
;
3339}
3340
3341already_AddRefed<BrowsingContext>
3342nsGlobalWindowOuter::GetOpenerBrowsingContext() {
3343 RefPtr<BrowsingContext> opener = GetBrowsingContext()->GetOpener();
3344 MOZ_DIAGNOSTIC_ASSERT(!opener ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!opener || opener->Group() == GetBrowsingContext(
)->Group())>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!opener || opener->Group() == GetBrowsingContext
()->Group()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!opener || opener->Group() == GetBrowsingContext()->Group()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3345); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!opener || opener->Group() == GetBrowsingContext()->Group()"
")"); do { *((volatile int*)__null) = 3345; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3345 opener->Group() == GetBrowsingContext()->Group())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!opener || opener->Group() == GetBrowsingContext(
)->Group())>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!opener || opener->Group() == GetBrowsingContext
()->Group()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!opener || opener->Group() == GetBrowsingContext()->Group()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3345); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!opener || opener->Group() == GetBrowsingContext()->Group()"
")"); do { *((volatile int*)__null) = 3345; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3346 if (!opener || opener->Group() != GetBrowsingContext()->Group()) {
3347 return nullptr;
3348 }
3349
3350 // Catch the case where we're chrome but the opener is not...
3351 if (nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
3352 GetPrincipal() == nsContentUtils::GetSystemPrincipal()) {
3353 auto* openerWin = nsGlobalWindowOuter::Cast(opener->GetDOMWindow());
3354 if (!openerWin ||
3355 openerWin->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
3356 return nullptr;
3357 }
3358 }
3359
3360 return opener.forget();
3361}
3362
3363nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSameProcessOpener() {
3364 if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
3365 return opener->GetDOMWindow();
3366 }
3367 return nullptr;
3368}
3369
3370Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpenerWindowOuter() {
3371 if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
3372 return WindowProxyHolder(std::move(opener));
3373 }
3374 return nullptr;
3375}
3376
3377Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpener() {
3378 return GetOpenerWindowOuter();
3379}
3380
3381void nsGlobalWindowOuter::GetStatusOuter(nsAString& aStatus) {
3382 aStatus = mStatus;
3383}
3384
3385void nsGlobalWindowOuter::SetStatusOuter(const nsAString& aStatus) {
3386 mStatus = aStatus;
3387
3388 // We don't support displaying window.status in the UI, so there's nothing
3389 // left to do here.
3390}
3391
3392void nsGlobalWindowOuter::GetNameOuter(nsAString& aName) {
3393 if (mDocShell) {
3394 mDocShell->GetName(aName);
3395 }
3396}
3397
3398void nsGlobalWindowOuter::SetNameOuter(const nsAString& aName,
3399 mozilla::ErrorResult& aError) {
3400 if (mDocShell) {
3401 aError = mDocShell->SetName(aName);
3402 }
3403}
3404
3405// NOTE: The idea of this function is that it should return the same as
3406// nsPresContext::CSSToDeviceScale() if it was in aWindow synchronously. For
3407// that, we use the UnscaledDevicePixelsPerCSSPixel() (which contains the device
3408// scale and the OS zoom scale) and then account for the browsing context full
3409// zoom. See the declaration of this function for context about why this is
3410// needed.
3411CSSToLayoutDeviceScale nsGlobalWindowOuter::CSSToDevScaleForBaseWindow(
3412 nsIBaseWindow* aWindow) {
3413 MOZ_ASSERT(aWindow)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWindow", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3413); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")"
); do { *((volatile int*)__null) = 3413; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3414 auto scale = aWindow->UnscaledDevicePixelsPerCSSPixel();
3415 if (mBrowsingContext) {
3416 scale.scale *= mBrowsingContext->FullZoom();
3417 }
3418 return scale;
3419}
3420
3421nsresult nsGlobalWindowOuter::GetInnerSize(CSSSize& aSize) {
3422 EnsureSizeAndPositionUpToDate();
3423
3424 NS_ENSURE_STATE(mDocShell)do { if ((__builtin_expect(!!(!(mDocShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3424); return NS_ERROR_UNEXPECTED; } } while (false)
;
3425
3426 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3427 PresShell* presShell = mDocShell->GetPresShell();
3428
3429 if (!presContext || !presShell) {
3430 aSize = {};
3431 return NS_OK;
3432 }
3433
3434 // Whether or not the css viewport has been overridden, we can get the
3435 // correct value by looking at the visible area of the presContext.
3436 if (RefPtr<nsViewManager> viewManager = presShell->GetViewManager()) {
3437 viewManager->FlushDelayedResize();
3438 }
3439
3440 // FIXME: Bug 1598487 - Return the layout viewport instead of the ICB.
3441 nsSize viewportSize = presContext->GetVisibleArea().Size();
3442 if (presContext->GetDynamicToolbarState() == DynamicToolbarState::Collapsed) {
3443 viewportSize =
3444 nsLayoutUtils::ExpandHeightForViewportUnits(presContext, viewportSize);
3445 }
3446
3447 aSize = CSSPixel::FromAppUnits(viewportSize);
3448
3449 switch (StaticPrefs::dom_innerSize_rounding()) {
3450 case 1:
3451 aSize.width = std::roundf(aSize.width);
3452 aSize.height = std::roundf(aSize.height);
3453 break;
3454 case 2:
3455 aSize.width = std::truncf(aSize.width);
3456 aSize.height = std::truncf(aSize.height);
3457 break;
3458 default:
3459 break;
3460 }
3461
3462 return NS_OK;
3463}
3464
3465double nsGlobalWindowOuter::GetInnerWidthOuter(ErrorResult& aError) {
3466 CSSSize size;
3467 aError = GetInnerSize(size);
3468 return size.width;
3469}
3470
3471nsresult nsGlobalWindowOuter::GetInnerWidth(double* aInnerWidth) {
3472 FORWARD_TO_INNER(GetInnerWidth, (aInnerWidth), NS_ERROR_UNEXPECTED)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3472); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetInnerWidth (aInnerWidth); } while (0)
;
3473}
3474
3475double nsGlobalWindowOuter::GetInnerHeightOuter(ErrorResult& aError) {
3476 CSSSize size;
3477 aError = GetInnerSize(size);
3478 return size.height;
3479}
3480
3481nsresult nsGlobalWindowOuter::GetInnerHeight(double* aInnerHeight) {
3482 FORWARD_TO_INNER(GetInnerHeight, (aInnerHeight), NS_ERROR_UNEXPECTED)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3482); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetInnerHeight (aInnerHeight); } while (0)
;
3483}
3484
3485CSSIntSize nsGlobalWindowOuter::GetOuterSize(CallerType aCallerType,
3486 ErrorResult& aError) {
3487 if (nsIGlobalObject::ShouldResistFingerprinting(aCallerType,
3488 RFPTarget::WindowOuterSize)) {
3489 if (BrowsingContext* bc = GetBrowsingContext()) {
3490 return bc->Top()->GetTopInnerSizeForRFP();
3491 }
3492 return {};
3493 }
3494
3495 // Windows showing documents in RDM panes and any subframes within them
3496 // return the simulated device size.
3497 if (mDoc) {
3498 Maybe<CSSIntSize> deviceSize = GetRDMDeviceSize(*mDoc);
3499 if (deviceSize.isSome()) {
3500 return *deviceSize;
3501 }
3502 }
3503
3504 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3505 if (!treeOwnerAsWin) {
3506 aError.Throw(NS_ERROR_FAILURE);
3507 return {};
3508 }
3509
3510 return RoundedToInt(treeOwnerAsWin->GetSize() /
3511 CSSToDevScaleForBaseWindow(treeOwnerAsWin));
3512}
3513
3514int32_t nsGlobalWindowOuter::GetOuterWidthOuter(CallerType aCallerType,
3515 ErrorResult& aError) {
3516 return GetOuterSize(aCallerType, aError).width;
3517}
3518
3519int32_t nsGlobalWindowOuter::GetOuterHeightOuter(CallerType aCallerType,
3520 ErrorResult& aError) {
3521 return GetOuterSize(aCallerType, aError).height;
3522}
3523
3524CSSPoint nsGlobalWindowOuter::ScreenEdgeSlop() {
3525 if (NS_WARN_IF(!mDocShell)NS_warn_if_impl(!mDocShell, "!mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3525)
) {
3526 return {};
3527 }
3528 RefPtr<nsPresContext> pc = mDocShell->GetPresContext();
3529 if (NS_WARN_IF(!pc)NS_warn_if_impl(!pc, "!pc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3529)
) {
3530 return {};
3531 }
3532 nsCOMPtr<nsIWidget> widget = GetMainWidget();
3533 if (NS_WARN_IF(!widget)NS_warn_if_impl(!widget, "!widget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3533)
) {
3534 return {};
3535 }
3536 LayoutDeviceIntPoint pt = widget->GetScreenEdgeSlop();
3537 auto auPoint =
3538 LayoutDeviceIntPoint::ToAppUnits(pt, pc->AppUnitsPerDevPixel());
3539 return CSSPoint::FromAppUnits(auPoint);
3540}
3541
3542CSSIntPoint nsGlobalWindowOuter::GetScreenXY(CallerType aCallerType,
3543 ErrorResult& aError) {
3544 // When resisting fingerprinting, always return (0,0)
3545 if (nsIGlobalObject::ShouldResistFingerprinting(aCallerType,
3546 RFPTarget::WindowScreenXY)) {
3547 return CSSIntPoint(0, 0);
3548 }
3549
3550 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3551 if (!treeOwnerAsWin) {
3552 aError.Throw(NS_ERROR_FAILURE);
3553 return CSSIntPoint(0, 0);
3554 }
3555
3556 LayoutDeviceIntPoint windowPos;
3557 aError = treeOwnerAsWin->GetPosition(&windowPos.x.value, &windowPos.y.value);
3558
3559 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3560 if (!presContext) {
3561 // XXX Fishy LayoutDevice to CSS conversion?
3562 return CSSIntPoint(windowPos.x, windowPos.y);
3563 }
3564
3565 nsDeviceContext* context = presContext->DeviceContext();
3566 auto windowPosAppUnits = LayoutDeviceIntPoint::ToAppUnits(
3567 windowPos, context->AppUnitsPerDevPixel());
3568 return CSSIntPoint::FromAppUnitsRounded(windowPosAppUnits);
3569}
3570
3571int32_t nsGlobalWindowOuter::GetScreenXOuter(CallerType aCallerType,
3572 ErrorResult& aError) {
3573 return GetScreenXY(aCallerType, aError).x;
3574}
3575
3576nsRect nsGlobalWindowOuter::GetInnerScreenRect() {
3577 if (!mDocShell) {
3578 return nsRect();
3579 }
3580
3581 EnsureSizeAndPositionUpToDate();
3582
3583 if (!mDocShell) {
3584 return nsRect();
3585 }
3586
3587 PresShell* presShell = mDocShell->GetPresShell();
3588 if (!presShell) {
3589 return nsRect();
3590 }
3591 nsIFrame* rootFrame = presShell->GetRootFrame();
3592 if (!rootFrame) {
3593 return nsRect();
3594 }
3595
3596 return rootFrame->GetScreenRectInAppUnits();
3597}
3598
3599Maybe<CSSIntSize> nsGlobalWindowOuter::GetRDMDeviceSize(
3600 const Document& aDocument) {
3601 // RDM device size should reflect the simulated device resolution, and
3602 // be independent of any full zoom or resolution zoom applied to the
3603 // content. To get this value, we get the "unscaled" browser child size,
3604 // and divide by the full zoom. "Unscaled" in this case means unscaled
3605 // from device to screen but it has been affected (multiplied) by the
3606 // full zoom and we need to compensate for that.
3607 MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3607); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3607; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3608
3609 // Bug 1576256: This does not work for cross-process subframes.
3610 const Document* topInProcessContentDoc =
3611 aDocument.GetTopLevelContentDocumentIfSameProcess();
3612 BrowsingContext* bc = topInProcessContentDoc
3613 ? topInProcessContentDoc->GetBrowsingContext()
3614 : nullptr;
3615 if (bc && bc->InRDMPane()) {
3616 nsIDocShell* docShell = topInProcessContentDoc->GetDocShell();
3617 if (docShell) {
3618 nsPresContext* presContext = docShell->GetPresContext();
3619 if (presContext) {
3620 nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild();
3621 if (child) {
3622 // We intentionally use GetFullZoom here instead of
3623 // GetDeviceFullZoom, because the unscaledInnerSize is based
3624 // on the full zoom and not the device full zoom (which is
3625 // rounded to result in integer device pixels).
3626 float zoom = presContext->GetFullZoom();
3627 BrowserChild* bc = static_cast<BrowserChild*>(child.get());
3628 CSSSize unscaledSize = bc->GetUnscaledInnerSize();
3629 return Some(CSSIntSize(gfx::RoundedToInt(unscaledSize / zoom)));
3630 }
3631 }
3632 }
3633 }
3634 return Nothing();
3635}
3636
3637float nsGlobalWindowOuter::GetMozInnerScreenXOuter(CallerType aCallerType) {
3638 // When resisting fingerprinting, always return 0.
3639 if (nsIGlobalObject::ShouldResistFingerprinting(
3640 aCallerType, RFPTarget::WindowInnerScreenXY)) {
3641 return 0.0;
3642 }
3643
3644 nsRect r = GetInnerScreenRect();
3645 return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
3646}
3647
3648float nsGlobalWindowOuter::GetMozInnerScreenYOuter(CallerType aCallerType) {
3649 // Return 0 to prevent fingerprinting.
3650 if (nsIGlobalObject::ShouldResistFingerprinting(
3651 aCallerType, RFPTarget::WindowInnerScreenXY)) {
3652 return 0.0;
3653 }
3654
3655 nsRect r = GetInnerScreenRect();
3656 return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
3657}
3658
3659int32_t nsGlobalWindowOuter::GetScreenYOuter(CallerType aCallerType,
3660 ErrorResult& aError) {
3661 return GetScreenXY(aCallerType, aError).y;
3662}
3663
3664// NOTE: Arguments to this function should have values scaled to
3665// CSS pixels, not device pixels.
3666void nsGlobalWindowOuter::CheckSecurityWidthAndHeight(int32_t* aWidth,
3667 int32_t* aHeight,
3668 CallerType aCallerType) {
3669 if (aCallerType != CallerType::System) {
3670 // if attempting to resize the window, hide any open popups
3671 nsContentUtils::HidePopupsInDocument(mDoc);
3672 }
3673
3674 // This one is easy. Just ensure the variable is greater than 100;
3675 if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
3676 // Check security state for use in determing window dimensions
3677
3678 if (aCallerType != CallerType::System) {
3679 // sec check failed
3680 if (aWidth && *aWidth < 100) {
3681 *aWidth = 100;
3682 }
3683 if (aHeight && *aHeight < 100) {
3684 *aHeight = 100;
3685 }
3686 }
3687 }
3688}
3689
3690// NOTE: Arguments to this function should have values in app units
3691void nsGlobalWindowOuter::SetCSSViewportWidthAndHeight(nscoord aInnerWidth,
3692 nscoord aInnerHeight) {
3693 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3694
3695 nsRect shellArea = presContext->GetVisibleArea();
3696 shellArea.SetHeight(aInnerHeight);
3697 shellArea.SetWidth(aInnerWidth);
3698
3699 // FIXME(emilio): This doesn't seem to be ok, this doesn't reflow or
3700 // anything... Should go through PresShell::ResizeReflow.
3701 //
3702 // But I don't think this can be reached by content, as we don't allow to set
3703 // inner{Width,Height}.
3704 presContext->SetVisibleArea(shellArea);
3705}
3706
3707// NOTE: Arguments to this function should have values scaled to
3708// CSS pixels, not device pixels.
3709void nsGlobalWindowOuter::CheckSecurityLeftAndTop(int32_t* aLeft, int32_t* aTop,
3710 CallerType aCallerType) {
3711 // This one is harder. We have to get the screen size and window dimensions.
3712
3713 // Check security state for use in determing window dimensions
3714
3715 if (aCallerType != CallerType::System) {
3716 // if attempting to move the window, hide any open popups
3717 nsContentUtils::HidePopupsInDocument(mDoc);
3718
3719 if (nsGlobalWindowOuter* rootWindow =
3720 nsGlobalWindowOuter::Cast(GetPrivateRoot())) {
3721 rootWindow->FlushPendingNotifications(FlushType::Layout);
3722 }
3723
3724 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3725
3726 RefPtr<nsScreen> screen = GetScreen();
3727
3728 if (treeOwnerAsWin && screen) {
3729 CSSToLayoutDeviceScale scale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
3730 CSSIntRect winRect =
3731 CSSIntRect::Round(treeOwnerAsWin->GetPositionAndSize() / scale);
3732
3733 // Get the screen dimensions
3734 // XXX This should use nsIScreenManager once it's fully fleshed out.
3735 int32_t screenLeft = screen->AvailLeft();
3736 int32_t screenWidth = screen->AvailWidth();
3737 int32_t screenHeight = screen->AvailHeight();
3738#if defined(XP_MACOSX)
3739 /* The mac's coordinate system is different from the assumed Windows'
3740 system. It offsets by the height of the menubar so that a window
3741 placed at (0,0) will be entirely visible. Unfortunately that
3742 correction is made elsewhere (in Widget) and the meaning of
3743 the Avail... coordinates is overloaded. Here we allow a window
3744 to be placed at (0,0) because it does make sense to do so.
3745 */
3746 int32_t screenTop = screen->Top();
3747#else
3748 int32_t screenTop = screen->AvailTop();
3749#endif
3750
3751 if (aLeft) {
3752 if (screenLeft + screenWidth < *aLeft + winRect.width)
3753 *aLeft = screenLeft + screenWidth - winRect.width;
3754 if (screenLeft > *aLeft) *aLeft = screenLeft;
3755 }
3756 if (aTop) {
3757 if (screenTop + screenHeight < *aTop + winRect.height)
3758 *aTop = screenTop + screenHeight - winRect.height;
3759 if (screenTop > *aTop) *aTop = screenTop;
3760 }
3761 } else {
3762 if (aLeft) *aLeft = 0;
3763 if (aTop) *aTop = 0;
3764 }
3765 }
3766}
3767
3768int32_t nsGlobalWindowOuter::GetScrollBoundaryOuter(Side aSide) {
3769 FlushPendingNotifications(FlushType::Layout);
3770 if (ScrollContainerFrame* sf = GetScrollContainerFrame()) {
3771 return nsPresContext::AppUnitsToIntCSSPixels(
3772 sf->GetScrollRange().Edge(aSide));
3773 }
3774 return 0;
3775}
3776
3777CSSPoint nsGlobalWindowOuter::GetScrollXY(bool aDoFlush) {
3778 if (aDoFlush) {
3779 FlushPendingNotifications(FlushType::Layout);
3780 } else {
3781 EnsureSizeAndPositionUpToDate();
3782 }
3783
3784 ScrollContainerFrame* sf = GetScrollContainerFrame();
3785 if (!sf) {
3786 return CSSIntPoint(0, 0);
3787 }
3788
3789 nsPoint scrollPos = sf->GetScrollPosition();
3790 if (scrollPos != nsPoint(0, 0) && !aDoFlush) {
3791 // Oh, well. This is the expensive case -- the window is scrolled and we
3792 // didn't actually flush yet. Repeat, but with a flush, since the content
3793 // may get shorter and hence our scroll position may decrease.
3794 return GetScrollXY(true);
3795 }
3796
3797 return CSSPoint::FromAppUnits(scrollPos);
3798}
3799
3800double nsGlobalWindowOuter::GetScrollXOuter() { return GetScrollXY(false).x; }
3801
3802double nsGlobalWindowOuter::GetScrollYOuter() { return GetScrollXY(false).y; }
3803
3804uint32_t nsGlobalWindowOuter::Length() {
3805 BrowsingContext* bc = GetBrowsingContext();
3806 return bc ? bc->NonSyntheticChildren().Length() : 0;
3807}
3808
3809Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetTopOuter() {
3810 BrowsingContext* bc = GetBrowsingContext();
3811 return bc ? bc->GetTop(IgnoreErrors()) : nullptr;
3812}
3813
3814already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetChildWindow(
3815 const nsAString& aName) {
3816 NS_ENSURE_TRUE(mBrowsingContext, nullptr)do { if ((__builtin_expect(!!(!(mBrowsingContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mBrowsingContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3816); return nullptr; } } while (false)
;
3817 NS_ENSURE_TRUE(mInnerWindow, nullptr)do { if ((__builtin_expect(!!(!(mInnerWindow)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mInnerWindow" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3817); return nullptr; } } while (false)
;
3818 NS_ENSURE_TRUE(mInnerWindow->GetWindowGlobalChild(), nullptr)do { if ((__builtin_expect(!!(!(mInnerWindow->GetWindowGlobalChild
())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"mInnerWindow->GetWindowGlobalChild()" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3818); return nullptr; } } while (false)
;
3819
3820 return do_AddRef(mBrowsingContext->FindChildWithName(
3821 aName, *mInnerWindow->GetWindowGlobalChild()));
3822}
3823
3824bool nsGlobalWindowOuter::DispatchCustomEvent(
3825 const nsAString& aEventName, ChromeOnlyDispatch aChromeOnlyDispatch) {
3826 bool defaultActionEnabled = true;
3827
3828 if (aChromeOnlyDispatch == ChromeOnlyDispatch::eYes) {
3829 nsContentUtils::DispatchEventOnlyToChrome(mDoc, this, aEventName,
3830 CanBubble::eYes, Cancelable::eYes,
3831 &defaultActionEnabled);
3832 } else {
3833 nsContentUtils::DispatchTrustedEvent(mDoc, this, aEventName,
3834 CanBubble::eYes, Cancelable::eYes,
3835 &defaultActionEnabled);
3836 }
3837
3838 return defaultActionEnabled;
3839}
3840
3841bool nsGlobalWindowOuter::DispatchResizeEvent(const CSSIntSize& aSize) {
3842 ErrorResult res;
3843 RefPtr<Event> domEvent =
3844 mDoc->CreateEvent(u"CustomEvent"_ns, CallerType::System, res);
3845 if (res.Failed()) {
3846 return false;
3847 }
3848
3849 // We don't init the AutoJSAPI with ourselves because we don't want it
3850 // reporting errors to our onerror handlers.
3851 AutoJSAPI jsapi;
3852 jsapi.Init();
3853 JSContext* cx = jsapi.cx();
3854 JSAutoRealm ar(cx, GetWrapperPreserveColor());
3855
3856 DOMWindowResizeEventDetail detail;
3857 detail.mWidth = aSize.width;
3858 detail.mHeight = aSize.height;
3859 JS::Rooted<JS::Value> detailValue(cx);
3860 if (!ToJSValue(cx, detail, &detailValue)) {
3861 return false;
3862 }
3863
3864 CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
3865 customEvent->InitCustomEvent(cx, u"DOMWindowResize"_ns,
3866 /* aCanBubble = */ true,
3867 /* aCancelable = */ true, detailValue);
3868
3869 domEvent->SetTrusted(true);
3870 domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
3871
3872 nsCOMPtr<EventTarget> target = this;
3873 domEvent->SetTarget(target);
3874
3875 return target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
3876}
3877
3878bool nsGlobalWindowOuter::WindowExists(const nsAString& aName,
3879 bool aForceNoOpener,
3880 bool aLookForCallerOnJSStack) {
3881 MOZ_ASSERT(mDocShell, "Must have docshell")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocShell))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mDocShell" " (" "Must have docshell"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3881); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocShell" ") ("
"Must have docshell" ")"); do { *((volatile int*)__null) = 3881
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3882
3883 if (aForceNoOpener) {
3884 return aName.LowerCaseEqualsLiteral("_self") ||
3885 aName.LowerCaseEqualsLiteral("_top") ||
3886 aName.LowerCaseEqualsLiteral("_parent");
3887 }
3888
3889 if (WindowGlobalChild* wgc = mInnerWindow->GetWindowGlobalChild()) {
3890 return wgc->FindBrowsingContextWithName(aName, aLookForCallerOnJSStack);
3891 }
3892 return false;
3893}
3894
3895already_AddRefed<nsIWidget> nsGlobalWindowOuter::GetMainWidget() {
3896 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3897
3898 nsCOMPtr<nsIWidget> widget;
3899
3900 if (treeOwnerAsWin) {
3901 treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
3902 }
3903
3904 return widget.forget();
3905}
3906
3907nsIWidget* nsGlobalWindowOuter::GetNearestWidget() const {
3908 nsIDocShell* docShell = GetDocShell();
3909 if (!docShell) {
3910 return nullptr;
3911 }
3912 PresShell* presShell = docShell->GetPresShell();
3913 if (!presShell) {
3914 return nullptr;
3915 }
3916 nsIFrame* rootFrame = presShell->GetRootFrame();
3917 if (!rootFrame) {
3918 return nullptr;
3919 }
3920 return rootFrame->GetView()->GetNearestWidget(nullptr);
3921}
3922
3923void nsGlobalWindowOuter::SetFullscreenOuter(bool aFullscreen,
3924 mozilla::ErrorResult& aError) {
3925 aError =
3926 SetFullscreenInternal(FullscreenReason::ForFullscreenMode, aFullscreen);
3927}
3928
3929nsresult nsGlobalWindowOuter::SetFullScreen(bool aFullscreen) {
3930 return SetFullscreenInternal(FullscreenReason::ForFullscreenMode,
3931 aFullscreen);
3932}
3933
3934static void FinishDOMFullscreenChange(Document* aDoc, bool aInDOMFullscreen) {
3935 if (aInDOMFullscreen) {
3936 // Ask the document to handle any pending DOM fullscreen change.
3937 if (!Document::HandlePendingFullscreenRequests(aDoc)) {
3938 // If we don't end up having anything in fullscreen,
3939 // async request exiting fullscreen.
3940 Document::AsyncExitFullscreen(aDoc);
3941 }
3942 } else {
3943 // If the window is leaving fullscreen state, also ask the document
3944 // to exit from DOM Fullscreen.
3945 Document::ExitFullscreenInDocTree(aDoc);
3946 }
3947}
3948
3949struct FullscreenTransitionDuration {
3950 // The unit of the durations is millisecond
3951 uint16_t mFadeIn = 0;
3952 uint16_t mFadeOut = 0;
3953 bool IsSuppressed() const { return mFadeIn == 0 && mFadeOut == 0; }
3954};
3955
3956static void GetFullscreenTransitionDuration(
3957 bool aEnterFullscreen, FullscreenTransitionDuration* aDuration) {
3958 const char* pref = aEnterFullscreen
3959 ? "full-screen-api.transition-duration.enter"
3960 : "full-screen-api.transition-duration.leave";
3961 nsAutoCString prefValue;
3962 Preferences::GetCString(pref, prefValue);
3963 if (!prefValue.IsEmpty()) {
3964 sscanf(prefValue.get(), "%hu%hu", &aDuration->mFadeIn,
3965 &aDuration->mFadeOut);
3966 }
3967}
3968
3969class FullscreenTransitionTask : public Runnable {
3970 public:
3971 FullscreenTransitionTask(const FullscreenTransitionDuration& aDuration,
3972 nsGlobalWindowOuter* aWindow, bool aFullscreen,
3973 nsIWidget* aWidget, nsISupports* aTransitionData)
3974 : mozilla::Runnable("FullscreenTransitionTask"),
3975 mWindow(aWindow),
3976 mWidget(aWidget),
3977 mTransitionData(aTransitionData),
3978 mDuration(aDuration),
3979 mStage(eBeforeToggle),
3980 mFullscreen(aFullscreen) {}
3981
3982 NS_IMETHODvirtual nsresult Run() override;
3983
3984 private:
3985 ~FullscreenTransitionTask() override = default;
3986
3987 /**
3988 * The flow of fullscreen transition:
3989 *
3990 * parent process | child process
3991 * ----------------------------------------------------------------
3992 *
3993 * | request/exit fullscreen
3994 * <-----|
3995 * BeforeToggle stage |
3996 * |
3997 * ToggleFullscreen stage *1 |----->
3998 * | HandleFullscreenRequests
3999 * |
4000 * <-----| MozAfterPaint event
4001 * AfterToggle stage *2 |
4002 * |
4003 * End stage |
4004 *
4005 * Note we also start a timer at *1 so that if we don't get MozAfterPaint
4006 * from the child process in time, we continue going to *2.
4007 */
4008 enum Stage {
4009 // BeforeToggle stage happens before we enter or leave fullscreen
4010 // state. In this stage, the task triggers the pre-toggle fullscreen
4011 // transition on the widget.
4012 eBeforeToggle,
4013 // ToggleFullscreen stage actually executes the fullscreen toggle,
4014 // and wait for the next paint on the content to continue.
4015 eToggleFullscreen,
4016 // AfterToggle stage happens after we toggle the fullscreen state.
4017 // In this stage, the task triggers the post-toggle fullscreen
4018 // transition on the widget.
4019 eAfterToggle,
4020 // End stage is triggered after the final transition finishes.
4021 eEnd
4022 };
4023
4024 class Observer final : public nsIObserver, public nsINamed {
4025 public:
4026 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
4027 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
4028 NS_DECL_NSINAMEDvirtual nsresult GetName(nsACString& aName) override;
4029
4030 explicit Observer(FullscreenTransitionTask* aTask) : mTask(aTask) {}
4031
4032 private:
4033 ~Observer() = default;
4034
4035 RefPtr<FullscreenTransitionTask> mTask;
4036 };
4037
4038 static const char* const kPaintedTopic;
4039
4040 RefPtr<nsGlobalWindowOuter> mWindow;
4041 nsCOMPtr<nsIWidget> mWidget;
4042 nsCOMPtr<nsITimer> mTimer;
4043 nsCOMPtr<nsISupports> mTransitionData;
4044
4045 TimeStamp mFullscreenChangeStartTime;
4046 FullscreenTransitionDuration mDuration;
4047 Stage mStage;
4048 bool mFullscreen;
4049};
4050
4051const char* const FullscreenTransitionTask::kPaintedTopic =
4052 "fullscreen-painted";
4053
4054NS_IMETHODIMPnsresult
4055FullscreenTransitionTask::Run() {
4056 Stage stage = mStage;
4057 mStage = Stage(mStage + 1);
4058 if (MOZ_UNLIKELY(mWidget->Destroyed())(__builtin_expect(!!(mWidget->Destroyed()), 0))) {
4059 // If the widget has been destroyed before we get here, don't try to
4060 // do anything more. Just let it go and release ourselves.
4061 NS_WARNING("The widget to fullscreen has been destroyed")NS_DebugBreak(NS_DEBUG_WARNING, "The widget to fullscreen has been destroyed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4061)
;
4062 mWindow->mIsInFullScreenTransition = false;
4063 return NS_OK;
4064 }
4065 if (stage == eBeforeToggle) {
4066 PROFILER_MARKER_UNTYPED("Fullscreen transition start", DOM)do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Fullscreen transition start", ::geckoprofiler::category::DOM
); } } while (false); } while (false)
;
4067
4068 mWindow->mIsInFullScreenTransition = true;
4069
4070 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4071 NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(obs)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "obs" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4071); return NS_ERROR_FAILURE; } } while (false)
;
4072 obs->NotifyObservers(nullptr, "fullscreen-transition-start", nullptr);
4073
4074 mWidget->PerformFullscreenTransition(nsIWidget::eBeforeFullscreenToggle,
4075 mDuration.mFadeIn, mTransitionData,
4076 this);
4077 } else if (stage == eToggleFullscreen) {
4078 PROFILER_MARKER_UNTYPED("Fullscreen toggle start", DOM)do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Fullscreen toggle start", ::geckoprofiler::category::DOM); }
} while (false); } while (false)
;
4079 mFullscreenChangeStartTime = TimeStamp::Now();
4080 // Toggle the fullscreen state on the widget
4081 if (!mWindow->SetWidgetFullscreen(FullscreenReason::ForFullscreenAPI,
4082 mFullscreen, mWidget)) {
4083 // Fail to setup the widget, call FinishFullscreenChange to
4084 // complete fullscreen change directly.
4085 mWindow->FinishFullscreenChange(mFullscreen);
4086 }
4087 // Set observer for the next content paint.
4088 nsCOMPtr<nsIObserver> observer = new Observer(this);
4089 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4090 obs->AddObserver(observer, kPaintedTopic, false);
4091 // There are several edge cases where we may never get the paint
4092 // notification, including:
4093 // 1. the window/tab is closed before the next paint;
4094 // 2. the user has switched to another tab before we get here.
4095 // Completely fixing those cases seems to be tricky, and since they
4096 // should rarely happen, it probably isn't worth to fix. Hence we
4097 // simply add a timeout here to ensure we never hang forever.
4098 // In addition, if the page is complicated or the machine is less
4099 // powerful, layout could take a long time, in which case, staying
4100 // in black screen for that long could hurt user experience even
4101 // more than exposing an intermediate state.
4102 uint32_t timeout =
4103 Preferences::GetUint("full-screen-api.transition.timeout", 1000);
4104 NS_NewTimerWithObserver(getter_AddRefs(mTimer), observer, timeout,
4105 nsITimer::TYPE_ONE_SHOT);
4106 } else if (stage == eAfterToggle) {
4107 Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS,
4108 mFullscreenChangeStartTime);
4109 mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,
4110 mDuration.mFadeOut, mTransitionData,
4111 this);
4112 } else if (stage == eEnd) {
4113 PROFILER_MARKER_UNTYPED("Fullscreen transition end", DOM)do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Fullscreen transition end", ::geckoprofiler::category::DOM)
; } } while (false); } while (false)
;
4114
4115 mWindow->mIsInFullScreenTransition = false;
4116
4117 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4118 NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(obs)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "obs" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4118); return NS_ERROR_FAILURE; } } while (false)
;
4119 obs->NotifyObservers(nullptr, "fullscreen-transition-end", nullptr);
4120
4121 mWidget->CleanupFullscreenTransition();
4122 }
4123 return NS_OK;
4124}
4125
4126NS_IMPL_ISUPPORTS(FullscreenTransitionTask::Observer, nsIObserver, nsINamed)MozExternalRefCountType FullscreenTransitionTask::Observer::AddRef
(void) { static_assert(!std::is_destructible_v<FullscreenTransitionTask
::Observer>, "Reference-counted class " "FullscreenTransitionTask::Observer"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
4126; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("FullscreenTransitionTask::Observer" != nullptr)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("FullscreenTransitionTask::Observer" != nullptr))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("\"FullscreenTransitionTask::Observer\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionTask::Observer\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 4126; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("FullscreenTransitionTask::Observer" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"FullscreenTransitionTask::Observer"), (uint32_t)(sizeof(*this
))); return count; } MozExternalRefCountType FullscreenTransitionTask
::Observer::Release(void) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 4126
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("FullscreenTransitionTask::Observer" != nullptr)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("FullscreenTransitionTask::Observer" != nullptr))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("\"FullscreenTransitionTask::Observer\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionTask::Observer\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 4126; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("FullscreenTransitionTask::Observer" " not thread-safe"
); const char* const nametmp = "FullscreenTransitionTask::Observer"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult FullscreenTransitionTask::Observer
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4126); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<FullscreenTransitionTask::Observer, nsIObserver
>, int32_t( reinterpret_cast<char*>(static_cast<nsIObserver
*>((FullscreenTransitionTask::Observer*)0x1000)) - reinterpret_cast
<char*>((FullscreenTransitionTask::Observer*)0x1000))},
{&mozilla::detail::kImplementedIID<FullscreenTransitionTask
::Observer, nsINamed>, int32_t( reinterpret_cast<char*>
(static_cast<nsINamed*>((FullscreenTransitionTask::Observer
*)0x1000)) - reinterpret_cast<char*>((FullscreenTransitionTask
::Observer*)0x1000))}, {&mozilla::detail::kImplementedIID
<FullscreenTransitionTask::Observer, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIObserver*>((FullscreenTransitionTask::
Observer*)0x1000))) - reinterpret_cast<char*>((FullscreenTransitionTask
::Observer*)0x1000))}, { nullptr, 0 } } ; static_assert(std::
size(table) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
4127
4128NS_IMETHODIMPnsresult
4129FullscreenTransitionTask::Observer::Observe(nsISupports* aSubject,
4130 const char* aTopic,
4131 const char16_t* aData) {
4132 bool shouldContinue = false;
4133 if (strcmp(aTopic, FullscreenTransitionTask::kPaintedTopic) == 0) {
4134 nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aSubject));
4135 nsCOMPtr<nsIWidget> widget =
4136 win ? nsGlobalWindowInner::Cast(win)->GetMainWidget() : nullptr;
4137 if (widget == mTask->mWidget) {
4138 // The paint notification arrives first. Cancel the timer.
4139 mTask->mTimer->Cancel();
4140 shouldContinue = true;
4141 PROFILER_MARKER_UNTYPED("Fullscreen toggle end", DOM)do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Fullscreen toggle end", ::geckoprofiler::category::DOM); } }
while (false); } while (false)
;
4142 }
4143 } else {
4144#ifdef DEBUG1
4145 MOZ_ASSERT(strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC) == 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(strcmp(aTopic, "timer-callback") == 0)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(strcmp(aTopic, "timer-callback") == 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("strcmp(aTopic, \"timer-callback\") == 0"
" (" "Should only get fullscreen-painted or timer-callback" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(aTopic, \"timer-callback\") == 0"
") (" "Should only get fullscreen-painted or timer-callback"
")"); do { *((volatile int*)__null) = 4146; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4146 "Should only get fullscreen-painted or timer-callback")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(strcmp(aTopic, "timer-callback") == 0)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(strcmp(aTopic, "timer-callback") == 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("strcmp(aTopic, \"timer-callback\") == 0"
" (" "Should only get fullscreen-painted or timer-callback" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(aTopic, \"timer-callback\") == 0"
") (" "Should only get fullscreen-painted or timer-callback"
")"); do { *((volatile int*)__null) = 4146; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4147 nsCOMPtr<nsITimer> timer(do_QueryInterface(aSubject));
4148 MOZ_ASSERT(timer && timer == mTask->mTimer,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(timer && timer == mTask->mTimer)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(timer && timer == mTask->mTimer))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("timer && timer == mTask->mTimer"
" (" "Should only trigger this with the timer the task created"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "timer && timer == mTask->mTimer"
") (" "Should only trigger this with the timer the task created"
")"); do { *((volatile int*)__null) = 4149; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4149 "Should only trigger this with the timer the task created")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(timer && timer == mTask->mTimer)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(timer && timer == mTask->mTimer))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("timer && timer == mTask->mTimer"
" (" "Should only trigger this with the timer the task created"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "timer && timer == mTask->mTimer"
") (" "Should only trigger this with the timer the task created"
")"); do { *((volatile int*)__null) = 4149; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4150#endif
4151 shouldContinue = true;
4152 PROFILER_MARKER_UNTYPED("Fullscreen toggle timeout", DOM)do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Fullscreen toggle timeout", ::geckoprofiler::category::DOM)
; } } while (false); } while (false)
;
4153 }
4154 if (shouldContinue) {
4155 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4156 obs->RemoveObserver(this, kPaintedTopic);
4157 mTask->mTimer = nullptr;
4158 mTask->Run();
4159 }
4160 return NS_OK;
4161}
4162
4163NS_IMETHODIMPnsresult
4164FullscreenTransitionTask::Observer::GetName(nsACString& aName) {
4165 aName.AssignLiteral("FullscreenTransitionTask");
4166 return NS_OK;
4167}
4168
4169static bool MakeWidgetFullscreen(nsGlobalWindowOuter* aWindow,
4170 FullscreenReason aReason, bool aFullscreen) {
4171 nsCOMPtr<nsIWidget> widget = aWindow->GetMainWidget();
4172 if (!widget) {
4173 return false;
4174 }
4175
4176 FullscreenTransitionDuration duration;
4177 bool performTransition = false;
4178 nsCOMPtr<nsISupports> transitionData;
4179 if (aReason == FullscreenReason::ForFullscreenAPI) {
4180 GetFullscreenTransitionDuration(aFullscreen, &duration);
4181 if (!duration.IsSuppressed()) {
4182 performTransition = widget->PrepareForFullscreenTransition(
4183 getter_AddRefs(transitionData));
4184 }
4185 }
4186
4187 if (!performTransition) {
4188 return aWindow->SetWidgetFullscreen(aReason, aFullscreen, widget);
4189 }
4190
4191 nsCOMPtr<nsIRunnable> task = new FullscreenTransitionTask(
4192 duration, aWindow, aFullscreen, widget, transitionData);
4193 task->Run();
4194 return true;
4195}
4196
4197nsresult nsGlobalWindowOuter::ProcessWidgetFullscreenRequest(
4198 FullscreenReason aReason, bool aFullscreen) {
4199 mInProcessFullscreenRequest.emplace(aReason, aFullscreen);
4200
4201 // Prevent chrome documents which are still loading from resizing
4202 // the window after we set fullscreen mode.
4203 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4204 nsCOMPtr<nsIAppWindow> appWin(do_GetInterface(treeOwnerAsWin));
4205 if (aFullscreen && appWin) {
4206 appWin->SetIntrinsicallySized(false);
4207 }
4208
4209 // Sometimes we don't want the top-level widget to actually go fullscreen:
4210 // - in the B2G desktop client, we don't want the emulated screen dimensions
4211 // to appear to increase when entering fullscreen mode; we just want the
4212 // content to fill the entire client area of the emulator window.
4213 // - in FxR Desktop, we don't want fullscreen to take over the monitor, but
4214 // instead we want fullscreen to fill the FxR window in the the headset.
4215 if (!StaticPrefs::full_screen_api_ignore_widgets() &&
4216 !mForceFullScreenInWidget) {
4217 if (MakeWidgetFullscreen(this, aReason, aFullscreen)) {
4218 // The rest of code for switching fullscreen is in nsGlobalWindowOuter::
4219 // FinishFullscreenChange() which will be called after sizemodechange
4220 // event is dispatched.
4221 return NS_OK;
4222 }
4223 }
4224
4225#if defined(NIGHTLY_BUILD1) && defined(XP_WIN)
4226 if (FxRWindowManager::GetInstance()->IsFxRWindow(mWindowID)) {
4227 mozilla::gfx::VRShMem shmem(nullptr, true /*aRequiresMutex*/);
4228 shmem.SendFullscreenState(mWindowID, aFullscreen);
4229 }
4230#endif // NIGHTLY_BUILD && XP_WIN
4231 FinishFullscreenChange(aFullscreen);
4232 return NS_OK;
4233}
4234
4235nsresult nsGlobalWindowOuter::SetFullscreenInternal(FullscreenReason aReason,
4236 bool aFullscreen) {
4237 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nsContentUtils::IsSafeToRunScript())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::IsSafeToRunScript
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nsContentUtils::IsSafeToRunScript()" " (" "Requires safe to run script as it "
"may call FinishDOMFullscreenChange" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4239; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4238 "Requires safe to run script as it "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nsContentUtils::IsSafeToRunScript())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::IsSafeToRunScript
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nsContentUtils::IsSafeToRunScript()" " (" "Requires safe to run script as it "
"may call FinishDOMFullscreenChange" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4239; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4239 "may call FinishDOMFullscreenChange")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nsContentUtils::IsSafeToRunScript())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::IsSafeToRunScript
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nsContentUtils::IsSafeToRunScript()" " (" "Requires safe to run script as it "
"may call FinishDOMFullscreenChange" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4239; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4240
4241 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4241); return NS_ERROR_FAILURE; } } while (false)
;
4242
4243 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aReason != FullscreenReason::ForForceExitFullscreen ||
!aFullscreen)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aReason != FullscreenReason::ForForceExitFullscreen
|| !aFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
" (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4246; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4244 aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aReason != FullscreenReason::ForForceExitFullscreen ||
!aFullscreen)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aReason != FullscreenReason::ForForceExitFullscreen
|| !aFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
" (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4246; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4245 "FullscreenReason::ForForceExitFullscreen can "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aReason != FullscreenReason::ForForceExitFullscreen ||
!aFullscreen)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aReason != FullscreenReason::ForForceExitFullscreen
|| !aFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
" (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4246; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4246 "only be used with exiting fullscreen")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aReason != FullscreenReason::ForForceExitFullscreen ||
!aFullscreen)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aReason != FullscreenReason::ForForceExitFullscreen
|| !aFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
" (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4246; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4247
4248 // Only chrome can change our fullscreen mode. Otherwise, the state
4249 // can only be changed for DOM fullscreen.
4250 if (aReason == FullscreenReason::ForFullscreenMode &&
4251 !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
4252 return NS_OK;
4253 }
4254
4255 // SetFullscreen needs to be called on the root window, so get that
4256 // via the DocShell tree, and if we are not already the root,
4257 // call SetFullscreen on that window instead.
4258 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4259 mDocShell->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
4260 nsCOMPtr<nsPIDOMWindowOuter> window =
4261 rootItem ? rootItem->GetWindow() : nullptr;
4262 if (!window) return NS_ERROR_FAILURE;
4263 if (rootItem != mDocShell)
4264 return window->SetFullscreenInternal(aReason, aFullscreen);
4265
4266 // make sure we don't try to set full screen on a non-chrome window,
4267 // which might happen in embedding world
4268 if (mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome)
4269 return NS_ERROR_FAILURE;
4270
4271 // FullscreenReason::ForForceExitFullscreen can only be used with exiting
4272 // fullscreen
4273 MOZ_ASSERT_IF(do { if (mFullscreen.isSome()) { do { static_assert( mozilla::
detail::AssertionConditionType<decltype(mFullscreen.value(
) != FullscreenReason::ForForceExitFullscreen)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFullscreen.value() != FullscreenReason
::ForForceExitFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4274 mFullscreen.isSome(),do { if (mFullscreen.isSome()) { do { static_assert( mozilla::
detail::AssertionConditionType<decltype(mFullscreen.value(
) != FullscreenReason::ForForceExitFullscreen)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFullscreen.value() != FullscreenReason
::ForForceExitFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4275 mFullscreen.value() != FullscreenReason::ForForceExitFullscreen)do { if (mFullscreen.isSome()) { do { static_assert( mozilla::
detail::AssertionConditionType<decltype(mFullscreen.value(
) != FullscreenReason::ForForceExitFullscreen)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFullscreen.value() != FullscreenReason
::ForForceExitFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4276
4277 // If we are already in full screen mode, just return, we don't care about the
4278 // reason here, because,
4279 // - If we are in fullscreen mode due to browser fullscreen mode, requesting
4280 // DOM fullscreen does not change anything.
4281 // - If we are in fullscreen mode due to DOM fullscreen, requesting browser
4282 // fullscreen should not change anything, either. Note that we should not
4283 // update reason to ForFullscreenMode, otherwise the subsequent DOM
4284 // fullscreen exit will be ignored and user will be confused. And ideally
4285 // this should never happen as `window.fullscreen` returns `true` for DOM
4286 // fullscreen as well.
4287 if (mFullscreen.isSome() == aFullscreen) {
4288 // How come we get browser fullscreen request while we are already in DOM
4289 // fullscreen?
4290 MOZ_ASSERT_IF(aFullscreen && aReason == FullscreenReason::ForFullscreenMode,do { if (aFullscreen && aReason == FullscreenReason::
ForFullscreenMode) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(mFullscreen.value() != FullscreenReason::ForFullscreenAPI
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mFullscreen.value() != FullscreenReason::ForFullscreenAPI
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mFullscreen.value() != FullscreenReason::ForFullscreenAPI", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4291); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForFullscreenAPI"
")"); do { *((volatile int*)__null) = 4291; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4291 mFullscreen.value() != FullscreenReason::ForFullscreenAPI)do { if (aFullscreen && aReason == FullscreenReason::
ForFullscreenMode) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(mFullscreen.value() != FullscreenReason::ForFullscreenAPI
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mFullscreen.value() != FullscreenReason::ForFullscreenAPI
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mFullscreen.value() != FullscreenReason::ForFullscreenAPI", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4291); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForFullscreenAPI"
")"); do { *((volatile int*)__null) = 4291; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4292 return NS_OK;
4293 }
4294
4295 // Note that although entering DOM fullscreen could also cause
4296 // consequential calls to this method, those calls will be skipped
4297 // at the condition above.
4298 if (aReason == FullscreenReason::ForFullscreenMode) {
4299 if (!aFullscreen && mFullscreen &&
4300 mFullscreen.value() == FullscreenReason::ForFullscreenAPI) {
4301 // If we are exiting fullscreen mode, but we actually didn't
4302 // entered browser fullscreen mode, the fullscreen state was only for
4303 // the Fullscreen API. Change the reason here so that we can
4304 // perform transition for it.
4305 aReason = FullscreenReason::ForFullscreenAPI;
4306 }
4307 } else {
4308 // If we are exiting from DOM fullscreen while we initially make
4309 // the window fullscreen because of browser fullscreen mode, don't restore
4310 // the window. But we still need to exit the DOM fullscreen state.
4311 if (!aFullscreen && mFullscreen &&
4312 mFullscreen.value() == FullscreenReason::ForFullscreenMode) {
4313 // If there is a in-process fullscreen request, FinishDOMFullscreenChange
4314 // will be called when the request is finished.
4315 if (!mInProcessFullscreenRequest.isSome()) {
4316 FinishDOMFullscreenChange(mDoc, false);
4317 }
4318 return NS_OK;
4319 }
4320 }
4321
4322 // Set this before so if widget sends an event indicating its
4323 // gone full screen, the state trap above works.
4324 if (aFullscreen) {
4325 mFullscreen.emplace(aReason);
4326 } else {
4327 mFullscreen.reset();
4328 }
4329
4330 // If we are in process of fullscreen request, only keep the latest fullscreen
4331 // state, we will sync up later while the processing request is finished.
4332 if (mInProcessFullscreenRequest.isSome()) {
4333 mFullscreenHasChangedDuringProcessing = true;
4334 return NS_OK;
4335 }
4336
4337 return ProcessWidgetFullscreenRequest(aReason, aFullscreen);
4338}
4339
4340// Support a per-window, dynamic equivalent of enabling
4341// full-screen-api.ignore-widgets
4342void nsGlobalWindowOuter::ForceFullScreenInWidget() {
4343 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4343); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4343; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4344
4345 mForceFullScreenInWidget = true;
4346}
4347
4348bool nsGlobalWindowOuter::SetWidgetFullscreen(FullscreenReason aReason,
4349 bool aIsFullscreen,
4350 nsIWidget* aWidget) {
4351 MOZ_ASSERT(this == GetInProcessTopInternal(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(this == GetInProcessTopInternal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(this == GetInProcessTopInternal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("this == GetInProcessTopInternal()" " (" "Only topmost window should call this"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4352); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this == GetInProcessTopInternal()"
") (" "Only topmost window should call this" ")"); do { *((volatile
int*)__null) = 4352; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
4352 "Only topmost window should call this")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(this == GetInProcessTopInternal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(this == GetInProcessTopInternal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("this == GetInProcessTopInternal()" " (" "Only topmost window should call this"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4352); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this == GetInProcessTopInternal()"
") (" "Only topmost window should call this" ")"); do { *((volatile
int*)__null) = 4352; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4353 MOZ_ASSERT(!GetFrameElementInternal(), "Content window should not call this")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!GetFrameElementInternal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!GetFrameElementInternal()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!GetFrameElementInternal()"
" (" "Content window should not call this" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetFrameElementInternal()"
") (" "Content window should not call this" ")"); do { *((volatile
int*)__null) = 4353; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4354 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_GetProcessType() == GeckoProcessType_Default)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(XRE_GetProcessType() == GeckoProcessType_Default))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_GetProcessType() == GeckoProcessType_Default"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_GetProcessType() == GeckoProcessType_Default"
")"); do { *((volatile int*)__null) = 4354; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4355
4356 if (!NS_WARN_IF(!IsChromeWindow())NS_warn_if_impl(!IsChromeWindow(), "!IsChromeWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4356)
) {
4357 if (!NS_WARN_IF(mChromeFields.mFullscreenPresShell)NS_warn_if_impl(mChromeFields.mFullscreenPresShell, "mChromeFields.mFullscreenPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4357)
) {
4358 if (PresShell* presShell = mDocShell->GetPresShell()) {
4359 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
4360 mChromeFields.mFullscreenPresShell = do_GetWeakReference(presShell);
4361 MOZ_ASSERT(mChromeFields.mFullscreenPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChromeFields.mFullscreenPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mChromeFields.mFullscreenPresShell
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mChromeFields.mFullscreenPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChromeFields.mFullscreenPresShell"
")"); do { *((volatile int*)__null) = 4361; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4362 rd->SetIsResizeSuppressed();
4363 rd->Freeze();
4364 }
4365 }
4366 }
4367 }
4368 nsresult rv = aReason == FullscreenReason::ForFullscreenMode
4369 ?
4370 // If we enter fullscreen for fullscreen mode, we want
4371 // the native system behavior.
4372 aWidget->MakeFullScreenWithNativeTransition(aIsFullscreen)
4373 : aWidget->MakeFullScreen(aIsFullscreen);
4374 return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
4375}
4376
4377/* virtual */
4378void nsGlobalWindowOuter::FullscreenWillChange(bool aIsFullscreen) {
4379 if (!mInProcessFullscreenRequest.isSome()) {
4380 // If there is no in-process fullscreen request, the fullscreen state change
4381 // is triggered from the OS directly, e.g. user use built-in window button
4382 // to enter/exit fullscreen on macOS.
4383 mInProcessFullscreenRequest.emplace(FullscreenReason::ForFullscreenMode,
4384 aIsFullscreen);
4385 if (mFullscreen.isSome() != aIsFullscreen) {
4386 if (aIsFullscreen) {
4387 mFullscreen.emplace(FullscreenReason::ForFullscreenMode);
4388 } else {
4389 mFullscreen.reset();
4390 }
4391 } else {
4392 // It is possible that FullscreenWillChange is notified with current
4393 // fullscreen state, e.g. browser goes into fullscreen when widget
4394 // fullscreen is prevented, and then user triggers fullscreen from the OS
4395 // directly again.
4396 MOZ_ASSERT(StaticPrefs::full_screen_api_ignore_widgets() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
" (" "This should only happen when widget fullscreen is prevented"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4398); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4398; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4397 mForceFullScreenInWidget,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
" (" "This should only happen when widget fullscreen is prevented"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4398); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4398; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4398 "This should only happen when widget fullscreen is prevented")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
" (" "This should only happen when widget fullscreen is prevented"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4398); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4398; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4399 }
4400 }
4401 if (aIsFullscreen) {
4402 DispatchCustomEvent(u"willenterfullscreen"_ns, ChromeOnlyDispatch::eYes);
4403 } else {
4404 DispatchCustomEvent(u"willexitfullscreen"_ns, ChromeOnlyDispatch::eYes);
4405 }
4406}
4407
4408/* virtual */
4409void nsGlobalWindowOuter::FinishFullscreenChange(bool aIsFullscreen) {
4410 mozilla::Maybe<FullscreenRequest> currentInProcessRequest =
4411 std::move(mInProcessFullscreenRequest);
4412 if (!mFullscreenHasChangedDuringProcessing &&
4413 aIsFullscreen != mFullscreen.isSome()) {
4414 NS_WARNING("Failed to toggle fullscreen state of the widget")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to toggle fullscreen state of the widget"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4414)
;
4415 // We failed to make the widget enter fullscreen.
4416 // Stop further changes and restore the state.
4417 if (!aIsFullscreen) {
4418 mFullscreen.reset();
4419 } else {
4420#ifndef XP_MACOSX
4421 MOZ_ASSERT_UNREACHABLE("Failed to exit fullscreen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Failed to exit fullscreen?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4421); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Failed to exit fullscreen?" ")")
; do { *((volatile int*)__null) = 4421; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4422#endif
4423 // Restore fullscreen state with FullscreenReason::ForFullscreenAPI reason
4424 // in order to make subsequent DOM fullscreen exit request can exit
4425 // browser fullscreen mode.
4426 mFullscreen.emplace(FullscreenReason::ForFullscreenAPI);
4427 }
4428 return;
4429 }
4430
4431 // Note that we must call this to toggle the DOM fullscreen state
4432 // of the document before dispatching the "fullscreen" event, so
4433 // that the chrome can distinguish between browser fullscreen mode
4434 // and DOM fullscreen.
4435 FinishDOMFullscreenChange(mDoc, aIsFullscreen);
4436
4437 // dispatch a "fullscreen" DOM event so that XUL apps can
4438 // respond visually if we are kicked into full screen mode
4439 DispatchCustomEvent(u"fullscreen"_ns, ChromeOnlyDispatch::eYes);
4440
4441 if (!NS_WARN_IF(!IsChromeWindow())NS_warn_if_impl(!IsChromeWindow(), "!IsChromeWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4441)
) {
4442 if (RefPtr<PresShell> presShell =
4443 do_QueryReferent(mChromeFields.mFullscreenPresShell)) {
4444 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
4445 rd->Thaw();
4446 }
4447 mChromeFields.mFullscreenPresShell = nullptr;
4448 }
4449 }
4450
4451 // If fullscreen state has changed during processing fullscreen request, we
4452 // need to ensure widget matches our latest fullscreen state here.
4453 if (mFullscreenHasChangedDuringProcessing) {
4454 mFullscreenHasChangedDuringProcessing = false;
4455 // Widget doesn't care about the reason that makes it entering/exiting
4456 // fullscreen, so here we just need to ensure the fullscreen state is
4457 // matched.
4458 if (aIsFullscreen != mFullscreen.isSome()) {
4459 // If we end up need to exit fullscreen, use the same reason that brings
4460 // us into fullscreen mode, so that we will perform the same fullscreen
4461 // transistion effect for exiting.
4462 ProcessWidgetFullscreenRequest(
4463 mFullscreen.isSome() ? mFullscreen.value()
4464 : currentInProcessRequest.value().mReason,
4465 mFullscreen.isSome());
4466 }
4467 }
4468}
4469
4470/* virtual */
4471void nsGlobalWindowOuter::MacFullscreenMenubarOverlapChanged(
4472 mozilla::DesktopCoord aOverlapAmount) {
4473 ErrorResult res;
4474 RefPtr<Event> domEvent =
4475 mDoc->CreateEvent(u"CustomEvent"_ns, CallerType::System, res);
4476 if (res.Failed()) {
4477 return;
4478 }
4479
4480 AutoJSAPI jsapi;
4481 jsapi.Init();
4482 JSContext* cx = jsapi.cx();
4483 JSAutoRealm ar(cx, GetWrapperPreserveColor());
4484
4485 JS::Rooted<JS::Value> detailValue(cx);
4486 if (!ToJSValue(cx, aOverlapAmount, &detailValue)) {
4487 return;
4488 }
4489
4490 CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
4491 customEvent->InitCustomEvent(cx, u"MacFullscreenMenubarRevealUpdate"_ns,
4492 /* aCanBubble = */ true,
4493 /* aCancelable = */ true, detailValue);
4494 domEvent->SetTrusted(true);
4495 domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
4496
4497 nsCOMPtr<EventTarget> target = this;
4498 domEvent->SetTarget(target);
4499
4500 target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
4501}
4502
4503bool nsGlobalWindowOuter::Fullscreen() const {
4504 NS_ENSURE_TRUE(mDocShell, mFullscreen.isSome())do { if ((__builtin_expect(!!(!(mDocShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4504); return mFullscreen.isSome(); } } while (false)
;
4505
4506 // Get the fullscreen value of the root window, to always have the value
4507 // accurate, even when called from content.
4508 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4509 mDocShell->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
4510 if (rootItem == mDocShell) {
4511 if (!XRE_IsContentProcess()) {
4512 // We are the root window. Return our internal value.
4513 return mFullscreen.isSome();
4514 }
4515 if (nsCOMPtr<nsIWidget> widget = GetNearestWidget()) {
4516 // We are in content process, figure out the value from
4517 // the sizemode of the puppet widget.
4518 return widget->SizeMode() == nsSizeMode_Fullscreen;
4519 }
4520 return false;
4521 }
4522
4523 nsCOMPtr<nsPIDOMWindowOuter> window = rootItem->GetWindow();
4524 NS_ENSURE_TRUE(window, mFullscreen.isSome())do { if ((__builtin_expect(!!(!(window)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "window" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4524); return mFullscreen.isSome(); } } while (false)
;
4525
4526 return nsGlobalWindowOuter::Cast(window)->Fullscreen();
4527}
4528
4529bool nsGlobalWindowOuter::GetFullscreenOuter() { return Fullscreen(); }
4530
4531bool nsGlobalWindowOuter::GetFullScreen() {
4532 FORWARD_TO_INNER(GetFullScreen, (), false)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4532); return false; } return GetCurrentInnerWindowInternal
(this)->GetFullScreen (); } while (0)
;
4533}
4534
4535void nsGlobalWindowOuter::EnsureReflowFlushAndPaint() {
4536 NS_ASSERTION(mDocShell,do { if (!(mDocShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "EnsureReflowFlushAndPaint() called with no "
"docshell!", "mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4538); MOZ_PretendNoReturn(); } } while (0)
4537 "EnsureReflowFlushAndPaint() called with no "do { if (!(mDocShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "EnsureReflowFlushAndPaint() called with no "
"docshell!", "mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4538); MOZ_PretendNoReturn(); } } while (0)
4538 "docshell!")do { if (!(mDocShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "EnsureReflowFlushAndPaint() called with no "
"docshell!", "mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4538); MOZ_PretendNoReturn(); } } while (0)
;
4539
4540 if (!mDocShell) return;
4541
4542 RefPtr<PresShell> presShell = mDocShell->GetPresShell();
4543 if (!presShell) {
4544 return;
4545 }
4546
4547 // Flush pending reflows.
4548 if (mDoc) {
4549 mDoc->FlushPendingNotifications(FlushType::Layout);
4550 }
4551
4552 // Unsuppress painting.
4553 presShell->UnsuppressPainting();
4554}
4555
4556// static
4557void nsGlobalWindowOuter::MakeMessageWithPrincipal(
4558 nsAString& aOutMessage, nsIPrincipal* aSubjectPrincipal, bool aUseHostPort,
4559 const char* aNullMessage, const char* aContentMessage,
4560 const char* aFallbackMessage) {
4561 MOZ_ASSERT(aSubjectPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubjectPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSubjectPrincipal))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aSubjectPrincipal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4561); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubjectPrincipal"
")"); do { *((volatile int*)__null) = 4561; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4562
4563 aOutMessage.Truncate();
4564
4565 // Try to get a host from the running principal -- this will do the
4566 // right thing for javascript: and data: documents.
4567
4568 nsAutoCString contentDesc;
4569
4570 if (aSubjectPrincipal->GetIsNullPrincipal()) {
4571 nsContentUtils::GetLocalizedString(
4572 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, aNullMessage, aOutMessage);
4573 } else {
4574 auto* addonPolicy = BasePrincipal::Cast(aSubjectPrincipal)->AddonPolicy();
4575 if (addonPolicy) {
4576 nsContentUtils::FormatLocalizedString(
4577 aOutMessage, nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4578 aContentMessage, addonPolicy->Name());
4579 } else {
4580 nsresult rv = NS_ERROR_FAILURE;
4581 if (aUseHostPort) {
4582 nsCOMPtr<nsIURI> uri = aSubjectPrincipal->GetURI();
4583 if (uri) {
4584 rv = uri->GetDisplayHostPort(contentDesc);
4585 }
4586 }
4587 if (!aUseHostPort || NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4588 rv = aSubjectPrincipal->GetExposablePrePath(contentDesc);
4589 }
4590 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !contentDesc.IsEmpty()) {
4591 NS_ConvertUTF8toUTF16 ucsPrePath(contentDesc);
4592 nsContentUtils::FormatLocalizedString(
4593 aOutMessage, nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4594 aContentMessage, ucsPrePath);
4595 }
4596 }
4597 }
4598
4599 if (aOutMessage.IsEmpty()) {
4600 // We didn't find a host so use the generic heading
4601 nsContentUtils::GetLocalizedString(
4602 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, aFallbackMessage,
4603 aOutMessage);
4604 }
4605
4606 // Just in case
4607 if (aOutMessage.IsEmpty()) {
4608 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "could not get ScriptDlgGenericHeading string from string bundle"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4609)
4609 "could not get ScriptDlgGenericHeading string from string bundle")NS_DebugBreak(NS_DEBUG_WARNING, "could not get ScriptDlgGenericHeading string from string bundle"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4609)
;
4610 aOutMessage.AssignLiteral("[Script]");
4611 }
4612}
4613
4614bool nsGlobalWindowOuter::CanMoveResizeWindows(CallerType aCallerType) {
4615 // When called from chrome, we can avoid the following checks.
4616 if (aCallerType != CallerType::System) {
4617 // Don't allow scripts to move or resize windows that were not opened by a
4618 // script.
4619 if (!mBrowsingContext->GetTopLevelCreatedByWebContent()) {
4620 return false;
4621 }
4622
4623 if (!CanSetProperty("dom.disable_window_move_resize")) {
4624 return false;
4625 }
4626
4627 // Ignore the request if we have more than one tab in the window.
4628 if (mBrowsingContext->Top()->HasSiblings()) {
4629 return false;
4630 }
4631 }
4632
4633 if (mDocShell) {
4634 bool allow;
4635 nsresult rv = mDocShell->GetAllowWindowControl(&allow);
4636 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !allow) return false;
4637 }
4638
4639 if (nsGlobalWindowInner::sMouseDown &&
4640 !nsGlobalWindowInner::sDragServiceDisabled) {
4641 nsCOMPtr<nsIDragService> ds =
4642 do_GetService("@mozilla.org/widget/dragservice;1");
4643 if (ds) {
4644 nsGlobalWindowInner::sDragServiceDisabled = true;
4645 ds->Suppress();
4646 }
4647 }
4648 return true;
4649}
4650
4651bool nsGlobalWindowOuter::AlertOrConfirm(bool aAlert, const nsAString& aMessage,
4652 nsIPrincipal& aSubjectPrincipal,
4653 ErrorResult& aError) {
4654 // XXX This method is very similar to nsGlobalWindowOuter::Prompt, make
4655 // sure any modifications here don't need to happen over there!
4656 if (!AreDialogsEnabled()) {
4657 // Just silently return. In the case of alert(), the return value is
4658 // ignored. In the case of confirm(), returning false is the same thing as
4659 // would happen if the user cancels.
4660 return false;
4661 }
4662
4663 // Reset popup state while opening a modal dialog, and firing events
4664 // about the dialog, to prevent the current state from being active
4665 // the whole time a modal dialog is open.
4666 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
4667
4668 // Before bringing up the window, unsuppress painting and flush
4669 // pending reflows.
4670 EnsureReflowFlushAndPaint();
4671
4672 nsAutoString title;
4673 MakeMessageWithPrincipal(title, &aSubjectPrincipal, false,
4674 "ScriptDlgNullPrincipalHeading", "ScriptDlgHeading",
4675 "ScriptDlgGenericHeading");
4676
4677 // Remove non-terminating null characters from the
4678 // string. See bug #310037.
4679 nsAutoString final;
4680 nsContentUtils::StripNullChars(aMessage, final);
4681 nsContentUtils::PlatformToDOMLineBreaks(final);
4682
4683 nsresult rv;
4684 nsCOMPtr<nsIPromptFactory> promptFac =
4685 do_GetService("@mozilla.org/prompter;1", &rv);
4686 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4687 aError.Throw(rv);
4688 return false;
4689 }
4690
4691 nsCOMPtr<nsIPrompt> prompt;
4692 aError =
4693 promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt)(nsIPrompt::COMTypeInfo<nsIPrompt, void>::kIID), getter_AddRefs(prompt));
4694 if (aError.Failed()) {
4695 return false;
4696 }
4697
4698 // Always allow content modal prompts for alert and confirm.
4699 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4700 promptBag->SetPropertyAsUint32(u"modalType"_ns,
4701 nsIPrompt::MODAL_TYPE_CONTENT);
4702 }
4703
4704 bool result = false;
4705 nsAutoSyncOperation sync(mDoc, SyncOperationBehavior::eSuspendInput);
4706 if (ShouldPromptToBlockDialogs()) {
4707 bool disallowDialog = false;
4708 nsAutoString label;
4709 MakeMessageWithPrincipal(
4710 label, &aSubjectPrincipal, true, "ScriptDialogLabelNullPrincipal",
4711 "ScriptDialogLabelContentPrincipal", "ScriptDialogLabelNullPrincipal");
4712
4713 aError = aAlert
4714 ? prompt->AlertCheck(title.get(), final.get(), label.get(),
4715 &disallowDialog)
4716 : prompt->ConfirmCheck(title.get(), final.get(), label.get(),
4717 &disallowDialog, &result);
4718
4719 if (disallowDialog) {
4720 DisableDialogs();
4721 }
4722 } else {
4723 aError = aAlert ? prompt->Alert(title.get(), final.get())
4724 : prompt->Confirm(title.get(), final.get(), &result);
4725 }
4726
4727 return result;
4728}
4729
4730void nsGlobalWindowOuter::AlertOuter(const nsAString& aMessage,
4731 nsIPrincipal& aSubjectPrincipal,
4732 ErrorResult& aError) {
4733 AlertOrConfirm(/* aAlert = */ true, aMessage, aSubjectPrincipal, aError);
4734}
4735
4736bool nsGlobalWindowOuter::ConfirmOuter(const nsAString& aMessage,
4737 nsIPrincipal& aSubjectPrincipal,
4738 ErrorResult& aError) {
4739 return AlertOrConfirm(/* aAlert = */ false, aMessage, aSubjectPrincipal,
4740 aError);
4741}
4742
4743void nsGlobalWindowOuter::PromptOuter(const nsAString& aMessage,
4744 const nsAString& aInitial,
4745 nsAString& aReturn,
4746 nsIPrincipal& aSubjectPrincipal,
4747 ErrorResult& aError) {
4748 // XXX This method is very similar to nsGlobalWindowOuter::AlertOrConfirm,
4749 // make sure any modifications here don't need to happen over there!
4750 SetDOMStringToNull(aReturn);
4751
4752 if (!AreDialogsEnabled()) {
4753 // Return null, as if the user just canceled the prompt.
4754 return;
4755 }
4756
4757 // Reset popup state while opening a modal dialog, and firing events
4758 // about the dialog, to prevent the current state from being active
4759 // the whole time a modal dialog is open.
4760 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
4761
4762 // Before bringing up the window, unsuppress painting and flush
4763 // pending reflows.
4764 EnsureReflowFlushAndPaint();
4765
4766 nsAutoString title;
4767 MakeMessageWithPrincipal(title, &aSubjectPrincipal, false,
4768 "ScriptDlgNullPrincipalHeading", "ScriptDlgHeading",
4769 "ScriptDlgGenericHeading");
4770
4771 // Remove non-terminating null characters from the
4772 // string. See bug #310037.
4773 nsAutoString fixedMessage, fixedInitial;
4774 nsContentUtils::StripNullChars(aMessage, fixedMessage);
4775 nsContentUtils::PlatformToDOMLineBreaks(fixedMessage);
4776 nsContentUtils::StripNullChars(aInitial, fixedInitial);
4777
4778 nsresult rv;
4779 nsCOMPtr<nsIPromptFactory> promptFac =
4780 do_GetService("@mozilla.org/prompter;1", &rv);
4781 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4782 aError.Throw(rv);
4783 return;
4784 }
4785
4786 nsCOMPtr<nsIPrompt> prompt;
4787 aError =
4788 promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt)(nsIPrompt::COMTypeInfo<nsIPrompt, void>::kIID), getter_AddRefs(prompt));
4789 if (aError.Failed()) {
4790 return;
4791 }
4792
4793 // Always allow content modal prompts for prompt.
4794 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4795 promptBag->SetPropertyAsUint32(u"modalType"_ns,
4796 nsIPrompt::MODAL_TYPE_CONTENT);
4797 }
4798
4799 // Pass in the default value, if any.
4800 char16_t* inoutValue = ToNewUnicode(fixedInitial);
4801 bool disallowDialog = false;
4802
4803 nsAutoString label;
4804 label.SetIsVoid(true);
4805 if (ShouldPromptToBlockDialogs()) {
4806 nsContentUtils::GetLocalizedString(
4807 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, "ScriptDialogLabel", label);
4808 }
4809
4810 nsAutoSyncOperation sync(mDoc, SyncOperationBehavior::eSuspendInput);
4811 bool ok;
4812 aError = prompt->Prompt(title.get(), fixedMessage.get(), &inoutValue,
4813 label.IsVoid() ? nullptr : label.get(),
4814 &disallowDialog, &ok);
4815
4816 if (disallowDialog) {
4817 DisableDialogs();
4818 }
4819
4820 // XXX Doesn't this leak inoutValue?
4821 if (aError.Failed()) {
4822 return;
4823 }
4824
4825 nsString outValue;
4826 outValue.Adopt(inoutValue);
4827 if (ok && inoutValue) {
4828 aReturn = std::move(outValue);
4829 }
4830}
4831
4832void nsGlobalWindowOuter::FocusOuter(CallerType aCallerType,
4833 bool aFromOtherProcess,
4834 uint64_t aActionId) {
4835 RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
4836 if (MOZ_UNLIKELY(!fm)(__builtin_expect(!!(!fm), 0))) {
4837 return;
4838 }
4839
4840 auto [canFocus, isActive] = GetBrowsingContext()->CanFocusCheck(aCallerType);
4841 if (aFromOtherProcess) {
4842 // We trust that the check passed in a process that's, in principle,
4843 // untrusted, because we don't have the required caller context available
4844 // here. Also, the worst that the other process can do in this case is to
4845 // raise a window it's not supposed to be allowed to raise.
4846 // https://bugzilla.mozilla.org/show_bug.cgi?id=1677899
4847 MOZ_ASSERT(XRE_IsContentProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()"
" (" "Parent should not trust other processes." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4848); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "Parent should not trust other processes." ")"); do { *
((volatile int*)__null) = 4848; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
4848 "Parent should not trust other processes.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()"
" (" "Parent should not trust other processes." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4848); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "Parent should not trust other processes." ")"); do { *
((volatile int*)__null) = 4848; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4849 canFocus = true;
4850 }
4851
4852 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4853 if (treeOwnerAsWin && (canFocus || isActive)) {
4854 bool isEnabled = true;
4855 if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled))((bool)(__builtin_expect(!!(!NS_FAILED_impl(treeOwnerAsWin->
GetEnabled(&isEnabled))), 1)))
&& !isEnabled) {
4856 NS_WARNING("Should not try to set the focus on a disabled window")NS_DebugBreak(NS_DEBUG_WARNING, "Should not try to set the focus on a disabled window"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4856)
;
4857 return;
4858 }
4859 }
4860
4861 if (!mDocShell) {
4862 return;
4863 }
4864
4865 // If the window has a child frame focused, clear the focus. This
4866 // ensures that focus will be in this frame and not in a child.
4867 if (nsIContent* content = GetFocusedElement()) {
4868 if (HTMLIFrameElement::FromNode(content)) {
4869 fm->ClearFocus(this);
4870 }
4871 }
4872
4873 RefPtr<BrowsingContext> parent;
4874 BrowsingContext* bc = GetBrowsingContext();
4875 if (bc) {
4876 parent = bc->GetParent();
4877 if (!parent && XRE_IsParentProcess()) {
4878 parent = bc->Canonical()->GetParentCrossChromeBoundary();
4879 }
4880 }
4881 if (parent) {
4882 if (!parent->IsInProcess()) {
4883 if (isActive) {
4884 OwningNonNull<nsGlobalWindowOuter> kungFuDeathGrip(*this);
4885 fm->WindowRaised(kungFuDeathGrip, aActionId);
4886 } else {
4887 ContentChild* contentChild = ContentChild::GetSingleton();
4888 MOZ_ASSERT(contentChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentChild))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("contentChild", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4888); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 4888; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4889 contentChild->SendFinalizeFocusOuter(bc, canFocus, aCallerType);
4890 }
4891 return;
4892 }
4893
4894 MOZ_ASSERT(mDoc, "Call chain should have ensured document creation.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDoc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(mDoc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mDoc" " (" "Call chain should have ensured document creation."
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4894); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc" ") ("
"Call chain should have ensured document creation." ")"); do
{ *((volatile int*)__null) = 4894; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4895 if (mDoc) {
4896 if (Element* frame = mDoc->GetEmbedderElement()) {
4897 nsContentUtils::RequestFrameFocus(*frame, canFocus, aCallerType);
4898 }
4899 }
4900 return;
4901 }
4902
4903 if (canFocus) {
4904 // if there is no parent, this must be a toplevel window, so raise the
4905 // window if canFocus is true. If this is a child process, the raise
4906 // window request will get forwarded to the parent by the puppet widget.
4907 OwningNonNull<nsGlobalWindowOuter> kungFuDeathGrip(*this);
4908 fm->RaiseWindow(kungFuDeathGrip, aCallerType, aActionId);
4909 }
4910}
4911
4912nsresult nsGlobalWindowOuter::Focus(CallerType aCallerType) {
4913 FORWARD_TO_INNER(Focus, (aCallerType), NS_ERROR_UNEXPECTED)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4913); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->Focus (aCallerType); } while (0)
;
4914}
4915
4916void nsGlobalWindowOuter::BlurOuter(CallerType aCallerType) {
4917 if (!GetBrowsingContext()->CanBlurCheck(aCallerType)) {
4918 return;
4919 }
4920
4921 nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
4922 if (chrome) {
4923 chrome->Blur();
4924 }
4925}
4926
4927void nsGlobalWindowOuter::StopOuter(ErrorResult& aError) {
4928 // IsNavigationAllowed checks are usually done in nsDocShell directly,
4929 // however nsDocShell::Stop has a bunch of internal users that would fail
4930 // the IsNavigationAllowed check.
4931 if (!mDocShell || !nsDocShell::Cast(mDocShell)->IsNavigationAllowed()) {
4932 return;
4933 }
4934
4935 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4936 if (webNav) {
4937 aError = webNav->Stop(nsIWebNavigation::STOP_ALL);
4938 }
4939}
4940
4941void nsGlobalWindowOuter::PrintOuter(ErrorResult& aError) {
4942 if (!AreDialogsEnabled()) {
4943 // Per spec, silently return. https://github.com/whatwg/html/commit/21a1de1
4944 return;
4945 }
4946
4947 // Printing is disabled, silently return.
4948 if (!StaticPrefs::print_enabled()) {
4949 return;
4950 }
4951
4952 // If we're loading, queue the print for later. This is a special-case that
4953 // only applies to the window.print() call, for compat with other engines and
4954 // pre-existing behavior.
4955 if (mShouldDelayPrintUntilAfterLoad) {
4956 if (nsIDocShell* docShell = GetDocShell()) {
4957 if (docShell->GetBusyFlags() & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) {
4958 mDelayedPrintUntilAfterLoad = true;
4959 return;
4960 }
4961 }
4962 }
4963
4964#ifdef NS_PRINTING1
4965 RefPtr<BrowsingContext> top =
4966 mBrowsingContext ? mBrowsingContext->Top() : nullptr;
4967 if (NS_WARN_IF(top && top->GetIsPrinting())NS_warn_if_impl(top && top->GetIsPrinting(), "top && top->GetIsPrinting()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4967)
) {
4968 return;
4969 }
4970
4971 if (top) {
4972 Unused << top->SetIsPrinting(true);
4973 }
4974
4975 auto unset = MakeScopeExit([&] {
4976 if (top) {
4977 Unused << top->SetIsPrinting(false);
4978 }
4979 });
4980
4981 const bool forPreview =
4982 !StaticPrefs::print_always_print_silent() &&
4983 !Preferences::GetBool("print.prefer_system_dialog", false);
4984 Print(nullptr, nullptr, nullptr, nullptr, IsPreview(forPreview),
4985 IsForWindowDotPrint::Yes, nullptr, nullptr, aError);
4986#endif
4987}
4988
4989class MOZ_RAII AutoModalState {
4990 public:
4991 explicit AutoModalState(nsGlobalWindowOuter& aWin)
4992 : mModalStateWin(aWin.EnterModalState()) {}
4993
4994 ~AutoModalState() {
4995 if (mModalStateWin) {
4996 mModalStateWin->LeaveModalState();
4997 }
4998 }
4999
5000 RefPtr<nsGlobalWindowOuter> mModalStateWin;
5001};
5002
5003Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
5004 nsIPrintSettings* aPrintSettings, RemotePrintJobChild* aRemotePrintJob,
5005 nsIWebProgressListener* aListener, nsIDocShell* aDocShellToCloneInto,
5006 IsPreview aIsPreview, IsForWindowDotPrint aForWindowDotPrint,
5007 PrintPreviewResolver&& aPrintPreviewCallback,
5008 RefPtr<BrowsingContext>* aCachedBrowsingContext, ErrorResult& aError) {
5009#ifdef NS_PRINTING1
5010 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
5011 do_GetService("@mozilla.org/gfx/printsettings-service;1");
5012 if (!printSettingsService) {
5013 // we currently return here in headless mode - should we?
5014 aError.ThrowNotSupportedError("No print settings service");
5015 return nullptr;
5016 }
5017
5018 nsCOMPtr<nsIPrintSettings> ps = aPrintSettings;
5019 if (!ps) {
5020 // We shouldn't need this once bug 1776169 is fixed.
5021 printSettingsService->GetDefaultPrintSettingsForPrinting(
5022 getter_AddRefs(ps));
5023 }
5024
5025 RefPtr<Document> docToPrint = mDoc;
5026 if (NS_WARN_IF(!docToPrint)NS_warn_if_impl(!docToPrint, "!docToPrint", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5026)
) {
5027 aError.ThrowNotSupportedError("Document is gone");
5028 return nullptr;
5029 }
5030
5031 RefPtr<BrowsingContext> sourceBC = docToPrint->GetBrowsingContext();
5032 MOZ_DIAGNOSTIC_ASSERT(sourceBC)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sourceBC)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sourceBC))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("sourceBC", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5032); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "sourceBC"
")"); do { *((volatile int*)__null) = 5032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5033 if (!sourceBC) {
5034 aError.ThrowNotSupportedError("No browsing context for source document");
5035 return nullptr;
5036 }
5037
5038 nsAutoSyncOperation sync(docToPrint, SyncOperationBehavior::eAllowInput);
5039 AutoModalState modalState(*this);
5040
5041 nsCOMPtr<nsIDocumentViewer> viewer;
5042 RefPtr<BrowsingContext> bc;
5043 bool hasPrintCallbacks = false;
5044 bool wasStaticDocument = docToPrint->IsStaticDocument();
5045 bool usingCachedBrowsingContext = false;
5046 if (aCachedBrowsingContext && *aCachedBrowsingContext) {
5047 MOZ_ASSERT(!wasStaticDocument,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!wasStaticDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!wasStaticDocument))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!wasStaticDocument"
" (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5049); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5049; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
5048 "Why pass in non-empty aCachedBrowsingContext if original "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!wasStaticDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!wasStaticDocument))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!wasStaticDocument"
" (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5049); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5049; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
5049 "document is already static?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!wasStaticDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!wasStaticDocument))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!wasStaticDocument"
" (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5049); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5049; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
5050 if (!wasStaticDocument) {
5051 // The passed in document is not a static clone and the caller passed in a
5052 // static clone to reuse, so swap it in.
5053 docToPrint = (*aCachedBrowsingContext)->GetDocument();
5054 MOZ_ASSERT(docToPrint)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(docToPrint)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(docToPrint))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("docToPrint", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5054); AnnotateMozCrashReason("MOZ_ASSERT" "(" "docToPrint"
")"); do { *((volatile int*)__null) = 5054; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5055 MOZ_ASSERT(docToPrint->IsStaticDocument())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(docToPrint->IsStaticDocument())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(docToPrint->IsStaticDocument
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("docToPrint->IsStaticDocument()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5055); AnnotateMozCrashReason("MOZ_ASSERT" "(" "docToPrint->IsStaticDocument()"
")"); do { *((volatile int*)__null) = 5055; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5056 wasStaticDocument = true;
5057 usingCachedBrowsingContext = true;
5058 }
5059 }
5060 if (wasStaticDocument) {
5061 if (aForWindowDotPrint == IsForWindowDotPrint::Yes) {
5062 aError.ThrowNotSupportedError(
5063 "Calling print() from a print preview is unsupported, did you intend "
5064 "to call printPreview() instead?");
5065 return nullptr;
5066 }
5067 if (usingCachedBrowsingContext) {
5068 bc = docToPrint->GetBrowsingContext();
5069 } else {
5070 // We're already a print preview window, just reuse our browsing context /
5071 // content viewer.
5072 bc = sourceBC;
5073 }
5074 nsCOMPtr<nsIDocShell> docShell = bc->GetDocShell();
5075 if (!docShell) {
5076 aError.ThrowNotSupportedError("No docshell");
5077 return nullptr;
5078 }
5079 // We could handle this if needed.
5080 if (aDocShellToCloneInto && aDocShellToCloneInto != docShell) {
5081 aError.ThrowNotSupportedError(
5082 "We don't handle cloning a print preview doc into a different "
5083 "docshell");
5084 return nullptr;
5085 }
5086 docShell->GetDocViewer(getter_AddRefs(viewer));
5087 MOZ_DIAGNOSTIC_ASSERT(viewer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(viewer)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(viewer))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("viewer", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5087); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "viewer"
")"); do { *((volatile int*)__null) = 5087; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5088 } else {
5089 if (aDocShellToCloneInto) {
5090 // Ensure the content viewer is created if needed.
5091 Unused << aDocShellToCloneInto->GetDocument();
5092 bc = aDocShellToCloneInto->GetBrowsingContext();
5093 } else {
5094 AutoNoJSAPI nojsapi;
5095 auto printKind = aForWindowDotPrint == IsForWindowDotPrint::Yes
5096 ? PrintKind::WindowDotPrint
5097 : PrintKind::InternalPrint;
5098 // For PrintKind::WindowDotPrint, this call will not only make the parent
5099 // process create a CanonicalBrowsingContext for the returned `bc`, but
5100 // it will also make the parent process initiate the print/print preview.
5101 // See the handling of OPEN_PRINT_BROWSER in browser.js.
5102 aError = OpenInternal(""_ns, u""_ns, u""_ns,
5103 false, // aDialog
5104 true, // aCalledNoScript
5105 false, // aDoJSFixups
5106 true, // aNavigate
5107 nullptr, // No args
5108 nullptr, // aLoadState
5109 false, // aForceNoOpener
5110 printKind, getter_AddRefs(bc));
5111 if (NS_WARN_IF(aError.Failed())NS_warn_if_impl(aError.Failed(), "aError.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5111)
) {
5112 return nullptr;
5113 }
5114 if (aCachedBrowsingContext) {
5115 MOZ_ASSERT(!*aCachedBrowsingContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!*aCachedBrowsingContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!*aCachedBrowsingContext))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!*aCachedBrowsingContext"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5115); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!*aCachedBrowsingContext"
")"); do { *((volatile int*)__null) = 5115; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5116 *aCachedBrowsingContext = bc;
5117 }
5118 }
5119 if (!bc) {
5120 aError.ThrowNotAllowedError("No browsing context");
5121 return nullptr;
5122 }
5123
5124 Unused << bc->Top()->SetIsPrinting(true);
5125 nsCOMPtr<nsIDocShell> cloneDocShell = bc->GetDocShell();
5126 MOZ_DIAGNOSTIC_ASSERT(cloneDocShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cloneDocShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cloneDocShell))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("cloneDocShell",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5126); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "cloneDocShell"
")"); do { *((volatile int*)__null) = 5126; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5127 cloneDocShell->GetDocViewer(getter_AddRefs(viewer));
5128 MOZ_DIAGNOSTIC_ASSERT(viewer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(viewer)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(viewer))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("viewer", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5128); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "viewer"
")"); do { *((volatile int*)__null) = 5128; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5129 if (!viewer) {
5130 aError.ThrowNotSupportedError("Didn't end up with a content viewer");
5131 return nullptr;
5132 }
5133
5134 if (bc != sourceBC) {
5135 MOZ_ASSERT(bc->IsTopContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc->IsTopContent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bc->IsTopContent()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("bc->IsTopContent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5135); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc->IsTopContent()"
")"); do { *((volatile int*)__null) = 5135; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5136 // If we are cloning from a document in a different BrowsingContext, we
5137 // need to make sure to copy over our opener policy information from that
5138 // BrowsingContext. In the case where the source is an iframe, this
5139 // information needs to be copied from the toplevel source
5140 // BrowsingContext, as we may be making a static clone of a single
5141 // subframe.
5142 MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy
()))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash
("" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5143); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")"); do { *((volatile int*)__null) = 5143; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
5143 bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy
()))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash
("" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5143); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")"); do { *((volatile int*)__null) = 5143; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
5144 MOZ_DIAGNOSTIC_ASSERT(bc->Group() == sourceBC->Group())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc->Group() == sourceBC->Group())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(bc->Group() == sourceBC->Group()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("bc->Group() == sourceBC->Group()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5144); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "bc->Group() == sourceBC->Group()"
")"); do { *((volatile int*)__null) = 5144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5145 }
5146
5147 if (RefPtr<Document> doc = viewer->GetDocument()) {
5148 if (doc->IsShowing()) {
5149 // We're going to drop this document on the floor, in the SetDocument
5150 // call below. Make sure to run OnPageHide() to keep state consistent
5151 // and avoids assertions in the document destructor.
5152 doc->OnPageHide(false, nullptr);
5153 }
5154 }
5155
5156 AutoPrintEventDispatcher dispatcher(*docToPrint);
5157
5158 nsAutoScriptBlocker blockScripts;
5159 RefPtr<Document> clone = docToPrint->CreateStaticClone(
5160 cloneDocShell, viewer, ps, &hasPrintCallbacks);
5161 if (!clone) {
5162 aError.ThrowNotSupportedError("Clone operation for printing failed");
5163 return nullptr;
5164 }
5165 }
5166
5167 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint = do_QueryInterface(viewer);
5168 if (!webBrowserPrint) {
5169 aError.ThrowNotSupportedError(
5170 "Content viewer didn't implement nsIWebBrowserPrint");
5171 return nullptr;
5172 }
5173 bool closeWindowAfterPrint;
5174 if (wasStaticDocument) {
5175 // Here the document was a static clone to begin with that this code did not
5176 // create, so we should not clean it up.
5177 // The exception is if we're using the passed-in aCachedBrowsingContext, in
5178 // which case this is the second print with this static document clone that
5179 // we created the first time through, and we are responsible for cleaning it
5180 // up.
5181 closeWindowAfterPrint = usingCachedBrowsingContext;
5182 } else {
5183 // In this case the document was not a static clone, so we made a static
5184 // clone for printing purposes and must clean it up after the print is done.
5185 // The exception is if aCachedBrowsingContext is non-NULL, meaning the
5186 // caller is intending to print this document again, so we need to defer the
5187 // cleanup until after the second print.
5188 closeWindowAfterPrint = !aCachedBrowsingContext;
5189 }
5190 webBrowserPrint->SetCloseWindowAfterPrint(closeWindowAfterPrint);
5191
5192 // For window.print(), we postpone making these calls until the round-trip to
5193 // the parent process (triggered by the OpenInternal call above) calls us
5194 // again. Only a call from the parent can provide a valid nsPrintSettings
5195 // object and RemotePrintJobChild object.
5196 if (aForWindowDotPrint == IsForWindowDotPrint::No) {
5197 if (aIsPreview == IsPreview::Yes) {
5198 aError = webBrowserPrint->PrintPreview(ps, aListener,
5199 std::move(aPrintPreviewCallback));
5200 if (aError.Failed()) {
5201 return nullptr;
5202 }
5203 } else {
5204 // Historically we've eaten this error.
5205 webBrowserPrint->Print(ps, aRemotePrintJob, aListener);
5206 }
5207 }
5208
5209 // When using window.print() with the new UI, we usually want to block until
5210 // the print dialog is hidden. But we can't really do that if we have print
5211 // callbacks, because we are inside a sync operation, and we want to run
5212 // microtasks / etc that the print callbacks may create. It is really awkward
5213 // to have this subtle behavior difference...
5214 //
5215 // We also want to do this for fuzzing, so that they can test window.print().
5216 const bool shouldBlock = [&] {
5217 if (aForWindowDotPrint == IsForWindowDotPrint::No) {
5218 return false;
5219 }
5220 if (aIsPreview == IsPreview::Yes) {
5221 return !hasPrintCallbacks;
5222 }
5223 return StaticPrefs::dom_window_print_fuzzing_block_while_printing();
5224 }();
5225
5226 if (shouldBlock) {
5227 SpinEventLoopUntil("nsGlobalWindowOuter::Print"_ns,
5228 [&] { return bc->IsDiscarded(); });
5229 }
5230
5231 return WindowProxyHolder(std::move(bc));
5232#else
5233 return nullptr;
5234#endif // NS_PRINTING
5235}
5236
5237void nsGlobalWindowOuter::MoveToOuter(int32_t aXPos, int32_t aYPos,
5238 CallerType aCallerType,
5239 ErrorResult& aError) {
5240 /*
5241 * If caller is not chrome and the user has not explicitly exempted the site,
5242 * prevent window.moveTo() by exiting early
5243 */
5244
5245 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5246 return;
5247 }
5248
5249 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5250 if (!treeOwnerAsWin) {
5251 aError.Throw(NS_ERROR_FAILURE);
5252 return;
5253 }
5254
5255 // We need to do the same transformation GetScreenXY does.
5256 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
5257 if (!presContext) {
5258 return;
5259 }
5260
5261 CSSIntPoint cssPos(aXPos, aYPos);
5262 CheckSecurityLeftAndTop(&cssPos.x.value, &cssPos.y.value, aCallerType);
5263
5264 nsDeviceContext* context = presContext->DeviceContext();
5265
5266 auto devPos = LayoutDeviceIntPoint::FromAppUnitsRounded(
5267 CSSIntPoint::ToAppUnits(cssPos), context->AppUnitsPerDevPixel());
5268
5269 aError = treeOwnerAsWin->SetPosition(devPos.x, devPos.y);
5270 CheckForDPIChange();
5271}
5272
5273void nsGlobalWindowOuter::MoveByOuter(int32_t aXDif, int32_t aYDif,
5274 CallerType aCallerType,
5275 ErrorResult& aError) {
5276 /*
5277 * If caller is not chrome and the user has not explicitly exempted the site,
5278 * prevent window.moveBy() by exiting early
5279 */
5280
5281 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5282 return;
5283 }
5284
5285 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5286 if (!treeOwnerAsWin) {
5287 aError.Throw(NS_ERROR_FAILURE);
5288 return;
5289 }
5290
5291 // To do this correctly we have to convert what we get from GetPosition
5292 // into CSS pixels, add the arguments, do the security check, and
5293 // then convert back to device pixels for the call to SetPosition.
5294
5295 int32_t x, y;
5296 aError = treeOwnerAsWin->GetPosition(&x, &y);
5297 if (aError.Failed()) {
5298 return;
5299 }
5300
5301 auto cssScale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
5302 CSSIntPoint cssPos = RoundedToInt(treeOwnerAsWin->GetPosition() / cssScale);
5303
5304 cssPos.x += aXDif;
5305 cssPos.y += aYDif;
5306
5307 CheckSecurityLeftAndTop(&cssPos.x.value, &cssPos.y.value, aCallerType);
5308
5309 LayoutDeviceIntPoint newDevPos = RoundedToInt(cssPos * cssScale);
5310 aError = treeOwnerAsWin->SetPosition(newDevPos.x, newDevPos.y);
5311
5312 CheckForDPIChange();
5313}
5314
5315nsresult nsGlobalWindowOuter::MoveBy(int32_t aXDif, int32_t aYDif) {
5316 ErrorResult rv;
5317 MoveByOuter(aXDif, aYDif, CallerType::System, rv);
5318
5319 return rv.StealNSResult();
5320}
5321
5322void nsGlobalWindowOuter::ResizeToOuter(int32_t aWidth, int32_t aHeight,
5323 CallerType aCallerType,
5324 ErrorResult& aError) {
5325 /*
5326 * If caller is not chrome and the user has not explicitly exempted the site,
5327 * prevent window.resizeTo() by exiting early
5328 */
5329
5330 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5331 return;
5332 }
5333
5334 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5335 if (!treeOwnerAsWin) {
5336 aError.Throw(NS_ERROR_FAILURE);
5337 return;
5338 }
5339
5340 CSSIntSize cssSize(aWidth, aHeight);
5341 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5342
5343 LayoutDeviceIntSize devSize =
5344 RoundedToInt(cssSize * CSSToDevScaleForBaseWindow(treeOwnerAsWin));
5345 aError = treeOwnerAsWin->SetSize(devSize.width, devSize.height, true);
5346
5347 CheckForDPIChange();
5348}
5349
5350void nsGlobalWindowOuter::ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif,
5351 CallerType aCallerType,
5352 ErrorResult& aError) {
5353 /*
5354 * If caller is not chrome and the user has not explicitly exempted the site,
5355 * prevent window.resizeBy() by exiting early
5356 */
5357
5358 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5359 return;
5360 }
5361
5362 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5363 if (!treeOwnerAsWin) {
5364 aError.Throw(NS_ERROR_FAILURE);
5365 return;
5366 }
5367
5368 LayoutDeviceIntSize size = treeOwnerAsWin->GetSize();
5369
5370 // To do this correctly we have to convert what we got from GetSize
5371 // into CSS pixels, add the arguments, do the security check, and
5372 // then convert back to device pixels for the call to SetSize.
5373
5374 auto scale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
5375 CSSIntSize cssSize = RoundedToInt(size / scale);
5376
5377 cssSize.width += aWidthDif;
5378 cssSize.height += aHeightDif;
5379
5380 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5381
5382 LayoutDeviceIntSize newDevSize = RoundedToInt(cssSize * scale);
5383
5384 aError = treeOwnerAsWin->SetSize(newDevSize.width, newDevSize.height, true);
5385
5386 CheckForDPIChange();
5387}
5388
5389void nsGlobalWindowOuter::SizeToContentOuter(
5390 const SizeToContentConstraints& aConstraints, ErrorResult& aError) {
5391 if (!mDocShell) {
5392 return;
5393 }
5394
5395 if (mBrowsingContext->IsSubframe()) {
5396 return;
5397 }
5398
5399 // The content viewer does a check to make sure that it's a content
5400 // viewer for a toplevel docshell.
5401 nsCOMPtr<nsIDocumentViewer> viewer;
5402 mDocShell->GetDocViewer(getter_AddRefs(viewer));
5403 if (!viewer) {
5404 return aError.Throw(NS_ERROR_FAILURE);
5405 }
5406
5407 auto contentSize = viewer->GetContentSize(
5408 aConstraints.mMaxWidth, aConstraints.mMaxHeight, aConstraints.mPrefWidth);
5409 if (!contentSize) {
5410 return aError.Throw(NS_ERROR_FAILURE);
5411 }
5412
5413 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
5414 if (!treeOwner) {
5415 return aError.Throw(NS_ERROR_FAILURE);
5416 }
5417
5418 // Don't use DevToCSSIntPixelsForBaseWindow() nor
5419 // CSSToDevIntPixelsForBaseWindow() here because contentSize is comes from
5420 // nsIDocumentViewer::GetContentSize() and it's computed with nsPresContext so
5421 // that we need to work with nsPresContext here too.
5422 RefPtr<nsPresContext> presContext = viewer->GetPresContext();
5423 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(presContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(presContext))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("presContext" " ("
"Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5424 presContext,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(presContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(presContext))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("presContext" " ("
"Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5425 "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(presContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(presContext))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("presContext" " ("
"Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5426 CSSIntSize cssSize = *contentSize;
5427
5428 LayoutDeviceIntSize newDevSize(
5429 presContext->CSSPixelsToDevPixels(cssSize.width),
5430 presContext->CSSPixelsToDevPixels(cssSize.height));
5431
5432 nsCOMPtr<nsIDocShell> docShell = mDocShell;
5433 aError =
5434 treeOwner->SizeShellTo(docShell, newDevSize.width, newDevSize.height);
5435}
5436
5437already_AddRefed<nsPIWindowRoot> nsGlobalWindowOuter::GetTopWindowRoot() {
5438 nsPIDOMWindowOuter* piWin = GetPrivateRoot();
5439 if (!piWin) {
5440 return nullptr;
5441 }
5442
5443 nsCOMPtr<nsPIWindowRoot> window =
5444 do_QueryInterface(piWin->GetChromeEventHandler());
5445 return window.forget();
5446}
5447
5448void nsGlobalWindowOuter::FirePopupBlockedEvent(
5449 Document* aDoc, nsIURI* aPopupURI, const nsAString& aPopupWindowName,
5450 const nsAString& aPopupWindowFeatures) {
5451 MOZ_ASSERT(aDoc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDoc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aDoc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aDoc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5451); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDoc" ")");
do { *((volatile int*)__null) = 5451; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5452
5453 // Fire a "DOMPopupBlocked" event so that the UI can hear about
5454 // blocked popups.
5455 PopupBlockedEventInit init;
5456 init.mBubbles = true;
5457 init.mCancelable = true;
5458 // XXX: This is a different object, but webidl requires an inner window here
5459 // now.
5460 init.mRequestingWindow = GetCurrentInnerWindowInternal(this);
5461 init.mPopupWindowURI = aPopupURI;
5462 init.mPopupWindowName = aPopupWindowName;
5463 init.mPopupWindowFeatures = aPopupWindowFeatures;
5464
5465 RefPtr<PopupBlockedEvent> event =
5466 PopupBlockedEvent::Constructor(aDoc, u"DOMPopupBlocked"_ns, init);
5467
5468 event->SetTrusted(true);
5469
5470 aDoc->DispatchEvent(*event);
5471}
5472
5473// static
5474bool nsGlobalWindowOuter::CanSetProperty(const char* aPrefName) {
5475 // Chrome can set any property.
5476 if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
5477 return true;
5478 }
5479
5480 // If the pref is set to true, we can not set the property
5481 // and vice versa.
5482 return !Preferences::GetBool(aPrefName, true);
5483}
5484
5485/* If a window open is blocked, fire the appropriate DOM events. */
5486void nsGlobalWindowOuter::FireAbuseEvents(
5487 const nsACString& aPopupURL, const nsAString& aPopupWindowName,
5488 const nsAString& aPopupWindowFeatures) {
5489 // fetch the URI of the window requesting the opened window
5490 nsCOMPtr<Document> currentDoc = GetDoc();
5491 nsCOMPtr<nsIURI> popupURI;
5492
5493 // build the URI of the would-have-been popup window
5494 // (see nsWindowWatcher::URIfromURL)
5495
5496 // first, fetch the opener's base URI
5497
5498 nsIURI* baseURL = nullptr;
5499
5500 nsCOMPtr<Document> doc = GetEntryDocument();
5501 if (doc) baseURL = doc->GetDocBaseURI();
5502
5503 // use the base URI to build what would have been the popup's URI
5504 Unused << NS_NewURI(getter_AddRefs(popupURI), aPopupURL, nullptr, baseURL);
5505
5506 // fire an event block full of informative URIs
5507 FirePopupBlockedEvent(currentDoc, popupURI, aPopupWindowName,
5508 aPopupWindowFeatures);
5509}
5510
5511Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenOuter(
5512 const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
5513 ErrorResult& aError) {
5514 RefPtr<BrowsingContext> bc;
5515 NS_ConvertUTF16toUTF8 url(aUrl);
5516 nsresult rv = OpenJS(url, aName, aOptions, getter_AddRefs(bc));
5517 if (rv == NS_ERROR_MALFORMED_URI) {
5518 aError.ThrowSyntaxError("Unable to open a window with invalid URL '"_ns +
5519 url + "'."_ns);
5520 return nullptr;
5521 }
5522
5523 // XXX Is it possible that some internal errors are thrown here?
5524 aError = rv;
5525
5526 if (!bc) {
5527 return nullptr;
5528 }
5529 return WindowProxyHolder(std::move(bc));
5530}
5531
5532nsresult nsGlobalWindowOuter::Open(const nsACString& aUrl,
5533 const nsAString& aName,
5534 const nsAString& aOptions,
5535 nsDocShellLoadState* aLoadState,
5536 bool aForceNoOpener,
5537 BrowsingContext** _retval) {
5538 return OpenInternal(aUrl, aName, aOptions,
5539 false, // aDialog
5540 true, // aCalledNoScript
5541 false, // aDoJSFixups
5542 true, // aNavigate
5543 nullptr, // No args
5544 aLoadState, aForceNoOpener, PrintKind::None, _retval);
5545}
5546
5547nsresult nsGlobalWindowOuter::OpenJS(const nsACString& aUrl,
5548 const nsAString& aName,
5549 const nsAString& aOptions,
5550 BrowsingContext** _retval) {
5551 return OpenInternal(aUrl, aName, aOptions,
5552 false, // aDialog
5553 false, // aCalledNoScript
5554 true, // aDoJSFixups
5555 true, // aNavigate
5556 nullptr, // No args
5557 nullptr, // aLoadState
5558 false, // aForceNoOpener
5559 PrintKind::None, _retval);
5560}
5561
5562// like Open, but attaches to the new window any extra parameters past
5563// [features] as a JS property named "arguments"
5564nsresult nsGlobalWindowOuter::OpenDialog(const nsACString& aUrl,
5565 const nsAString& aName,
5566 const nsAString& aOptions,
5567 nsIArray* aArguments,
5568 BrowsingContext** _retval) {
5569 return OpenInternal(aUrl, aName, aOptions,
5570 true, // aDialog
5571 true, // aCalledNoScript
5572 false, // aDoJSFixups
5573 true, // aNavigate
5574 aArguments, // Arguments
5575 nullptr, // aLoadState
5576 false, // aForceNoOpener
5577 PrintKind::None, _retval);
5578}
5579
5580// Like Open, but passes aNavigate=false.
5581/* virtual */
5582nsresult nsGlobalWindowOuter::OpenNoNavigate(const nsACString& aUrl,
5583 const nsAString& aName,
5584 const nsAString& aOptions,
5585 BrowsingContext** _retval) {
5586 return OpenInternal(aUrl, aName, aOptions,
5587 false, // aDialog
5588 true, // aCalledNoScript
5589 false, // aDoJSFixups
5590 false, // aNavigate
5591 nullptr, // No args
5592 nullptr, // aLoadState
5593 false, // aForceNoOpener
5594 PrintKind::None, _retval);
5595}
5596
5597Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenDialogOuter(
5598 JSContext* aCx, const nsAString& aUrl, const nsAString& aName,
5599 const nsAString& aOptions, const Sequence<JS::Value>& aExtraArgument,
5600 ErrorResult& aError) {
5601 nsCOMPtr<nsIJSArgArray> argvArray;
5602 aError =
5603 NS_CreateJSArgv(aCx, aExtraArgument.Length(), aExtraArgument.Elements(),
5604 getter_AddRefs(argvArray));
5605 if (aError.Failed()) {
5606 return nullptr;
5607 }
5608
5609 RefPtr<BrowsingContext> dialog;
5610 aError = OpenInternal(NS_ConvertUTF16toUTF8(aUrl), aName, aOptions,
5611 true, // aDialog
5612 false, // aCalledNoScript
5613 false, // aDoJSFixups
5614 true, // aNavigate
5615 argvArray, // Arguments
5616 nullptr, // aLoadState
5617 false, // aForceNoOpener
5618 PrintKind::None, getter_AddRefs(dialog));
5619 if (!dialog) {
5620 return nullptr;
5621 }
5622 return WindowProxyHolder(std::move(dialog));
5623}
5624
5625WindowProxyHolder nsGlobalWindowOuter::GetFramesOuter() {
5626 RefPtr<nsPIDOMWindowOuter> frames(this);
5627 FlushPendingNotifications(FlushType::ContentAndNotify);
5628 return WindowProxyHolder(mBrowsingContext);
5629}
5630
5631/* static */
5632bool nsGlobalWindowOuter::GatherPostMessageData(
5633 JSContext* aCx, const nsAString& aTargetOrigin, BrowsingContext** aSource,
5634 nsAString& aOrigin, nsIURI** aTargetOriginURI,
5635 nsIPrincipal** aCallerPrincipal, nsGlobalWindowInner** aCallerInnerWindow,
5636 nsIURI** aCallerURI, Maybe<nsID>* aCallerAgentClusterId,
5637 nsACString* aScriptLocation, ErrorResult& aError) {
5638 //
5639 // Window.postMessage is an intentional subversion of the same-origin policy.
5640 // As such, this code must be particularly careful in the information it
5641 // exposes to calling code.
5642 //
5643 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5644 //
5645
5646 // First, get the caller's window
5647 RefPtr<nsGlobalWindowInner> callerInnerWin =
5648 nsContentUtils::IncumbentInnerWindow();
5649 nsIPrincipal* callerPrin;
5650 if (callerInnerWin) {
5651 RefPtr<Document> doc = callerInnerWin->GetExtantDoc();
5652 if (!doc) {
5653 return false;
5654 }
5655 NS_IF_ADDREF(*aCallerURI = doc->GetDocumentURI())ns_if_addref(*aCallerURI = doc->GetDocumentURI());
5656
5657 // Compute the caller's origin either from its principal or, in the case the
5658 // principal doesn't carry a URI (e.g. the system principal), the caller's
5659 // document. We must get this now instead of when the event is created and
5660 // dispatched, because ultimately it is the identity of the calling window
5661 // *now* that determines who sent the message (and not an identity which
5662 // might have changed due to intervening navigations).
5663 callerPrin = callerInnerWin->GetPrincipal();
5664 } else {
5665 // In case the global is not a window, it can be a sandbox, and the
5666 // sandbox's principal can be used for the security check.
5667 nsIGlobalObject* global = GetIncumbentGlobal();
5668 NS_ASSERTION(global, "Why is there no global object?")do { if (!(global)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Why is there no global object?"
, "global", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5668); MOZ_PretendNoReturn(); } } while (0)
;
5669 callerPrin = global->PrincipalOrNull();
5670 if (callerPrin) {
5671 BasePrincipal::Cast(callerPrin)->GetScriptLocation(*aScriptLocation);
5672 }
5673 }
5674 if (!callerPrin) {
5675 return false;
5676 }
5677
5678 // if the principal has a URI, use that to generate the origin
5679 if (!callerPrin->IsSystemPrincipal()) {
5680 nsAutoCString webExposedOriginSerialization;
5681 callerPrin->GetWebExposedOriginSerialization(webExposedOriginSerialization);
5682 CopyUTF8toUTF16(webExposedOriginSerialization, aOrigin);
5683 } else if (callerInnerWin) {
5684 if (!*aCallerURI) {
5685 return false;
5686 }
5687 // otherwise use the URI of the document to generate origin
5688 nsContentUtils::GetWebExposedOriginSerialization(*aCallerURI, aOrigin);
5689 } else {
5690 // in case of a sandbox with a system principal origin can be empty
5691 if (!callerPrin->IsSystemPrincipal()) {
5692 return false;
5693 }
5694 }
5695 NS_IF_ADDREF(*aCallerPrincipal = callerPrin)ns_if_addref(*aCallerPrincipal = callerPrin);
5696
5697 // "/" indicates same origin as caller, "*" indicates no specific origin is
5698 // required.
5699 if (!aTargetOrigin.EqualsASCII("/") && !aTargetOrigin.EqualsASCII("*")) {
5700 nsCOMPtr<nsIURI> targetOriginURI;
5701 if (NS_FAILED(NS_NewURI(getter_AddRefs(targetOriginURI), aTargetOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_NewURI(getter_AddRefs
(targetOriginURI), aTargetOrigin))), 0)))
) {
5702 aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
5703 return false;
5704 }
5705
5706 nsresult rv = NS_MutateURI(targetOriginURI)
5707 .SetUserPass(""_ns)
5708 .SetPathQueryRef(""_ns)
5709 .Finalize(aTargetOriginURI);
5710 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5711 return false;
5712 }
5713 }
5714
5715 if (!nsContentUtils::IsCallerChrome() && callerInnerWin &&
5716 callerInnerWin->GetOuterWindowInternal()) {
5717 NS_ADDREF(*aSource = callerInnerWin->GetOuterWindowInternal()(*aSource = callerInnerWin->GetOuterWindowInternal() ->
GetBrowsingContext())->AddRef()
5718 ->GetBrowsingContext())(*aSource = callerInnerWin->GetOuterWindowInternal() ->
GetBrowsingContext())->AddRef()
;
5719 } else {
5720 *aSource = nullptr;
5721 }
5722
5723 if (aCallerAgentClusterId && callerInnerWin &&
5724 callerInnerWin->GetDocGroup()) {
5725 *aCallerAgentClusterId =
5726 Some(callerInnerWin->GetDocGroup()->AgentClusterId());
5727 }
5728
5729 callerInnerWin.forget(aCallerInnerWindow);
5730
5731 return true;
5732}
5733
5734bool nsGlobalWindowOuter::GetPrincipalForPostMessage(
5735 const nsAString& aTargetOrigin, nsIURI* aTargetOriginURI,
5736 nsIPrincipal* aCallerPrincipal, nsIPrincipal& aSubjectPrincipal,
5737 nsIPrincipal** aProvidedPrincipal) {
5738 //
5739 // Window.postMessage is an intentional subversion of the same-origin policy.
5740 // As such, this code must be particularly careful in the information it
5741 // exposes to calling code.
5742 //
5743 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5744 //
5745
5746 // Convert the provided origin string into a URI for comparison purposes.
5747 nsCOMPtr<nsIPrincipal> providedPrincipal;
5748
5749 if (aTargetOrigin.EqualsASCII("/")) {
5750 providedPrincipal = aCallerPrincipal;
5751 }
5752 // "*" indicates no specific origin is required.
5753 else if (!aTargetOrigin.EqualsASCII("*")) {
5754 OriginAttributes attrs = aSubjectPrincipal.OriginAttributesRef();
5755 if (aSubjectPrincipal.IsSystemPrincipal()) {
5756 auto principal = BasePrincipal::Cast(GetPrincipal());
5757
5758 if (attrs != principal->OriginAttributesRef()) {
5759 nsAutoCString targetURL;
5760 nsAutoCString sourceOrigin;
5761 nsAutoCString targetOrigin;
5762
5763 if (NS_FAILED(principal->GetAsciiSpec(targetURL))((bool)(__builtin_expect(!!(NS_FAILED_impl(principal->GetAsciiSpec
(targetURL))), 0)))
||
5764 NS_FAILED(principal->GetOrigin(targetOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(principal->GetOrigin
(targetOrigin))), 0)))
||
5765 NS_FAILED(aSubjectPrincipal.GetOrigin(sourceOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(aSubjectPrincipal.
GetOrigin(sourceOrigin))), 0)))
) {
5766 NS_WARNING("Failed to get source and target origins")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to get source and target origins"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5766)
;
5767 return false;
5768 }
5769
5770 nsContentUtils::LogSimpleConsoleError(
5771 NS_ConvertUTF8toUTF16(nsPrintfCString(
5772 R"(Attempting to post a message to window with url "%s" and )"
5773 R"(origin "%s" from a system principal scope with mismatched )"
5774 R"(origin "%s".)",
5775 targetURL.get(), targetOrigin.get(), sourceOrigin.get())),
5776 "DOM"_ns, !!principal->PrivateBrowsingId(),
5777 principal->IsSystemPrincipal());
5778
5779 attrs = principal->OriginAttributesRef();
5780 }
5781 }
5782
5783 // Create a nsIPrincipal inheriting the app/browser attributes from the
5784 // caller.
5785 providedPrincipal =
5786 BasePrincipal::CreateContentPrincipal(aTargetOriginURI, attrs);
5787 if (NS_WARN_IF(!providedPrincipal)NS_warn_if_impl(!providedPrincipal, "!providedPrincipal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5787)
) {
5788 return false;
5789 }
5790 } else {
5791 // We still need to check the originAttributes if the target origin is '*'.
5792 // But we will ingore the FPD here since the FPDs are possible to be
5793 // different.
5794 auto principal = BasePrincipal::Cast(GetPrincipal());
5795 NS_ENSURE_TRUE(principal, false)do { if ((__builtin_expect(!!(!(principal)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "principal" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5795); return false; } } while (false)
;
5796
5797 OriginAttributes targetAttrs = principal->OriginAttributesRef();
5798 OriginAttributes sourceAttrs = aSubjectPrincipal.OriginAttributesRef();
5799 // We have to exempt the check of OA if the subject prioncipal is a system
5800 // principal since there are many tests try to post messages to content from
5801 // chrome with a mismatch OA. For example, using the ContentTask.spawn() to
5802 // post a message into a private browsing window. The injected code in
5803 // ContentTask.spawn() will be executed under the system principal and the
5804 // OA of the system principal mismatches with the OA of a private browsing
5805 // window.
5806 MOZ_DIAGNOSTIC_ASSERT(aSubjectPrincipal.IsSystemPrincipal() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs
.EqualsIgnoringFPD(targetAttrs))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSubjectPrincipal.IsSystemPrincipal
() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5807); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
")"); do { *((volatile int*)__null) = 5807; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5807 sourceAttrs.EqualsIgnoringFPD(targetAttrs))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs
.EqualsIgnoringFPD(targetAttrs))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSubjectPrincipal.IsSystemPrincipal
() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5807); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
")"); do { *((volatile int*)__null) = 5807; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5808
5809 // If 'privacy.firstparty.isolate.block_post_message' is true, we will block
5810 // postMessage across different first party domains.
5811 if (OriginAttributes::IsBlockPostMessageForFPI() &&
5812 !aSubjectPrincipal.IsSystemPrincipal() &&
5813 sourceAttrs.mFirstPartyDomain != targetAttrs.mFirstPartyDomain) {
5814 return false;
5815 }
5816 }
5817
5818 providedPrincipal.forget(aProvidedPrincipal);
5819 return true;
5820}
5821
5822void nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx,
5823 JS::Handle<JS::Value> aMessage,
5824 const nsAString& aTargetOrigin,
5825 JS::Handle<JS::Value> aTransfer,
5826 nsIPrincipal& aSubjectPrincipal,
5827 ErrorResult& aError) {
5828 RefPtr<BrowsingContext> sourceBc;
5829 nsAutoString origin;
5830 nsCOMPtr<nsIURI> targetOriginURI;
5831 nsCOMPtr<nsIPrincipal> callerPrincipal;
5832 RefPtr<nsGlobalWindowInner> callerInnerWindow;
5833 nsCOMPtr<nsIURI> callerURI;
5834 Maybe<nsID> callerAgentClusterId = Nothing();
5835 nsAutoCString scriptLocation;
5836 if (!GatherPostMessageData(
5837 aCx, aTargetOrigin, getter_AddRefs(sourceBc), origin,
5838 getter_AddRefs(targetOriginURI), getter_AddRefs(callerPrincipal),
5839 getter_AddRefs(callerInnerWindow), getter_AddRefs(callerURI),
5840 &callerAgentClusterId, &scriptLocation, aError)) {
5841 return;
5842 }
5843
5844 nsCOMPtr<nsIPrincipal> providedPrincipal;
5845 if (!GetPrincipalForPostMessage(aTargetOrigin, targetOriginURI,
5846 callerPrincipal, aSubjectPrincipal,
5847 getter_AddRefs(providedPrincipal))) {
5848 return;
5849 }
5850
5851 // Create and asynchronously dispatch a runnable which will handle actual DOM
5852 // event creation and dispatch.
5853 RefPtr<PostMessageEvent> event = new PostMessageEvent(
5854 sourceBc, origin, this, providedPrincipal,
5855 callerInnerWindow ? callerInnerWindow->WindowID() : 0, callerURI,
5856 scriptLocation, callerAgentClusterId);
5857
5858 JS::CloneDataPolicy clonePolicy;
5859
5860 if (GetDocGroup() && callerAgentClusterId.isSome() &&
5861 GetDocGroup()->AgentClusterId().Equals(callerAgentClusterId.value())) {
5862 clonePolicy.allowIntraClusterClonableSharedObjects();
5863 }
5864
5865 if (callerInnerWindow && callerInnerWindow->IsSharedMemoryAllowed()) {
5866 clonePolicy.allowSharedMemoryObjects();
5867 }
5868
5869 event->Write(aCx, aMessage, aTransfer, clonePolicy, aError);
5870 if (NS_WARN_IF(aError.Failed())NS_warn_if_impl(aError.Failed(), "aError.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5870)
) {
5871 return;
5872 }
5873
5874 event->DispatchToTargetThread(aError);
5875}
5876
5877class nsCloseEvent : public Runnable {
5878 RefPtr<nsGlobalWindowOuter> mWindow;
5879 bool mIndirect;
5880
5881 nsCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect)
5882 : mozilla::Runnable("nsCloseEvent"),
5883 mWindow(aWindow),
5884 mIndirect(aIndirect) {}
5885
5886 public:
5887 static nsresult PostCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect) {
5888 nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
5889 return aWindow->Dispatch(ev.forget());
5890 }
5891
5892 NS_IMETHODvirtual nsresult Run() override {
5893 if (mWindow) {
5894 if (mIndirect) {
5895 return PostCloseEvent(mWindow, false);
5896 }
5897 mWindow->ReallyCloseWindow();
5898 }
5899 return NS_OK;
5900 }
5901};
5902
5903bool nsGlobalWindowOuter::CanClose() {
5904 if (mIsChrome) {
5905 nsCOMPtr<nsIBrowserDOMWindow> bwin = GetBrowserDOMWindow();
5906
5907 bool canClose = true;
5908 if (bwin && NS_SUCCEEDED(bwin->CanClose(&canClose))((bool)(__builtin_expect(!!(!NS_FAILED_impl(bwin->CanClose
(&canClose))), 1)))
) {
5909 return canClose;
5910 }
5911 }
5912
5913 if (!mDocShell) {
5914 return true;
5915 }
5916
5917 nsCOMPtr<nsIDocumentViewer> viewer;
5918 mDocShell->GetDocViewer(getter_AddRefs(viewer));
5919 if (viewer) {
5920 bool canClose;
5921 nsresult rv = viewer->PermitUnload(&canClose);
5922 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !canClose) return false;
5923 }
5924
5925 // If we still have to print, we delay the closing until print has happened.
5926 if (mShouldDelayPrintUntilAfterLoad && mDelayedPrintUntilAfterLoad) {
5927 mDelayedCloseForPrinting = true;
5928 return false;
5929 }
5930
5931 return true;
5932}
5933
5934void nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller) {
5935 if (!mDocShell || IsInModalState() || mBrowsingContext->IsSubframe()) {
5936 // window.close() is called on a frame in a frameset, on a window
5937 // that's already closed, or on a window for which there's
5938 // currently a modal dialog open. Ignore such calls.
5939 return;
5940 }
5941
5942 if (mHavePendingClose) {
5943 // We're going to be closed anyway; do nothing since we don't want
5944 // to double-close
5945 return;
5946 }
5947
5948 if (mBlockScriptedClosingFlag) {
5949 // A script's popup has been blocked and we don't want
5950 // the window to be closed directly after this event,
5951 // so the user can see that there was a blocked popup.
5952 return;
5953 }
5954
5955 // Don't allow scripts from content to close non-neterror windows that
5956 // were not opened by script.
5957 if (mDoc) {
5958 nsAutoString url;
5959 nsresult rv = mDoc->GetURL(url);
5960 NS_ENSURE_SUCCESS_VOID(rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5960); return; } } while (false)
;
5961
5962 if (!StringBeginsWith(url, u"about:neterror"_ns) &&
5963 !mBrowsingContext->GetTopLevelCreatedByWebContent() &&
5964 !aTrustedCaller && !IsOnlyTopLevelDocumentInSHistory()) {
5965 bool allowClose =
5966 mAllowScriptsToClose ||
5967 Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
5968 if (!allowClose) {
5969 // We're blocking the close operation
5970 // report localized error msg in JS console
5971 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
5972 "DOM Window"_ns,
5973 mDoc, // Better name for the category?
5974 nsContentUtils::eDOM_PROPERTIES,
5975 "WindowCloseByScriptBlockedWarning");
5976
5977 return;
5978 }
5979 }
5980 }
5981
5982 if (!mInClose && !mIsClosed && !CanClose()) {
5983 return;
5984 }
5985
5986 // Fire a DOM event notifying listeners that this window is about to
5987 // be closed. The tab UI code may choose to cancel the default
5988 // action for this event, if so, we won't actually close the window
5989 // (since the tab UI code will close the tab in stead). Sure, this
5990 // could be abused by content code, but do we care? I don't think
5991 // so...
5992
5993 bool wasInClose = mInClose;
5994 mInClose = true;
5995
5996 if (!DispatchCustomEvent(u"DOMWindowClose"_ns, ChromeOnlyDispatch::eYes)) {
5997 // Someone chose to prevent the default action for this event, if
5998 // so, let's not close this window after all...
5999
6000 mInClose = wasInClose;
6001 return;
6002 }
6003
6004 FinalClose();
6005}
6006
6007bool nsGlobalWindowOuter::IsOnlyTopLevelDocumentInSHistory() {
6008 NS_ENSURE_TRUE(mDocShell && mBrowsingContext, false)do { if ((__builtin_expect(!!(!(mDocShell && mBrowsingContext
)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocShell && mBrowsingContext"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6008); return false; } } while (false)
;
6009 // Disabled since IsFrame() is buggy in Fission
6010 // MOZ_ASSERT(mBrowsingContext->IsTop());
6011
6012 if (mozilla::SessionHistoryInParent()) {
6013 return mBrowsingContext->GetIsSingleToplevelInHistory();
6014 }
6015
6016 RefPtr<ChildSHistory> csh = nsDocShell::Cast(mDocShell)->GetSessionHistory();
6017 if (csh && csh->LegacySHistory()) {
6018 return csh->LegacySHistory()->IsEmptyOrHasEntriesForSingleTopLevelPage();
6019 }
6020
6021 return false;
6022}
6023
6024nsresult nsGlobalWindowOuter::Close() {
6025 CloseOuter(/* aTrustedCaller = */ true);
6026 return NS_OK;
6027}
6028
6029void nsGlobalWindowOuter::ForceClose() {
6030 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_GetProcessType() == GeckoProcessType_Default)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(XRE_GetProcessType() == GeckoProcessType_Default))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_GetProcessType() == GeckoProcessType_Default"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6030); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_GetProcessType() == GeckoProcessType_Default"
")"); do { *((volatile int*)__null) = 6030; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6031
6032 if (mBrowsingContext->IsSubframe() || !mDocShell) {
6033 // This may be a frame in a frameset, or a window that's already closed.
6034 // Ignore such calls.
6035 return;
6036 }
6037
6038 if (mHavePendingClose) {
6039 // We're going to be closed anyway; do nothing since we don't want
6040 // to double-close
6041 return;
6042 }
6043
6044 mInClose = true;
6045
6046 DispatchCustomEvent(u"DOMWindowClose"_ns, ChromeOnlyDispatch::eYes);
6047
6048 FinalClose();
6049}
6050
6051void nsGlobalWindowOuter::FinalClose() {
6052 // Flag that we were closed.
6053 mIsClosed = true;
6054
6055 if (!mBrowsingContext->IsDiscarded()) {
6056 MOZ_ALWAYS_SUCCEEDS(mBrowsingContext->SetClosed(true))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(mBrowsingContext->SetClosed(true))), 1)))), 1))) { } else
{ do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(mBrowsingContext->SetClosed(true))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6056); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(mBrowsingContext->SetClosed(true))"
")"); do { *((volatile int*)__null) = 6056; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
6057 }
6058
6059 // If we get here from CloseOuter then it means that the parent process is
6060 // going to close our window for us. It's just important to set mIsClosed.
6061 if (XRE_GetProcessType() == GeckoProcessType_Content) {
6062 return;
6063 }
6064
6065 // This stuff is non-sensical but incredibly fragile. The reasons for the
6066 // behavior here don't make sense today and may not have ever made sense,
6067 // but various bits of frontend code break when you change them. If you need
6068 // to fix up this behavior, feel free to. It's a righteous task, but involves
6069 // wrestling with various download manager tests, frontend code, and possible
6070 // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
6071 // testing ground.
6072 //
6073 // In particular, if some inner of |win| is the entry global, we must
6074 // complete _two_ round-trips to the event loop before the call to
6075 // ReallyCloseWindow. This allows setTimeout handlers that are set after
6076 // FinalClose() is called to run before the window is torn down.
6077 nsCOMPtr<nsPIDOMWindowInner> entryWindow =
6078 do_QueryInterface(GetEntryGlobal());
6079 bool indirect = entryWindow && entryWindow->GetOuterWindow() == this;
6080 if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsCloseEvent::PostCloseEvent
(this, indirect))), 0)))
) {
6081 ReallyCloseWindow();
6082 } else {
6083 mHavePendingClose = true;
6084 }
6085}
6086
6087void nsGlobalWindowOuter::ReallyCloseWindow() {
6088 // Make sure we never reenter this method.
6089 mHavePendingClose = true;
6090
6091 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
6092 if (!treeOwnerAsWin) {
6093 return;
6094 }
6095
6096 treeOwnerAsWin->Destroy();
6097 CleanUp();
6098}
6099
6100void nsGlobalWindowOuter::SuppressEventHandling() {
6101 if (mSuppressEventHandlingDepth == 0) {
6102 if (BrowsingContext* bc = GetBrowsingContext()) {
6103 bc->PreOrderWalk([&](BrowsingContext* aBC) {
6104 if (nsCOMPtr<nsPIDOMWindowOuter> win = aBC->GetDOMWindow()) {
6105 if (RefPtr<Document> doc = win->GetExtantDoc()) {
6106 mSuspendedDocs.AppendElement(doc);
6107 // Note: Document::SuppressEventHandling will also automatically
6108 // suppress event handling for any in-process sub-documents.
6109 // However, since we need to deal with cases where remote
6110 // BrowsingContexts may be interleaved with in-process ones, we
6111 // still need to walk the entire tree ourselves. This may be
6112 // slightly redundant in some cases, but since event handling
6113 // suppressions maintain a count of current blockers, it does not
6114 // cause any problems.
6115 doc->SuppressEventHandling();
6116 }
6117 }
6118 });
6119 }
6120 }
6121 mSuppressEventHandlingDepth++;
6122}
6123
6124void nsGlobalWindowOuter::UnsuppressEventHandling() {
6125 MOZ_ASSERT(mSuppressEventHandlingDepth != 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSuppressEventHandlingDepth != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSuppressEventHandlingDepth !=
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mSuppressEventHandlingDepth != 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6125); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSuppressEventHandlingDepth != 0"
")"); do { *((volatile int*)__null) = 6125; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6126 mSuppressEventHandlingDepth--;
6127
6128 if (mSuppressEventHandlingDepth == 0 && mSuspendedDocs.Length()) {
6129 RefPtr<Document> currentDoc = GetExtantDoc();
6130 bool fireEvent = currentDoc == mSuspendedDocs[0];
6131 nsTArray<RefPtr<Document>> suspendedDocs = std::move(mSuspendedDocs);
6132 for (const auto& doc : suspendedDocs) {
6133 doc->UnsuppressEventHandlingAndFireEvents(fireEvent);
6134 }
6135 }
6136}
6137
6138nsGlobalWindowOuter* nsGlobalWindowOuter::EnterModalState() {
6139 // GetInProcessScriptableTop, not GetInProcessTop, so that EnterModalState
6140 // works properly with <iframe mozbrowser>.
6141 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6142
6143 if (!topWin) {
6144 NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Uh, EnterModalState() called w/o a reachable top window?"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6144); MOZ_PretendNoReturn(); } while (0)
;
6145 return nullptr;
6146 }
6147
6148 // If there is an active ESM in this window, clear it. Otherwise, this can
6149 // cause a problem if a modal state is entered during a mouseup event.
6150 EventStateManager* activeESM = static_cast<EventStateManager*>(
6151 EventStateManager::GetActiveEventStateManager());
6152 if (activeESM && activeESM->GetPresContext()) {
6153 PresShell* activePresShell = activeESM->GetPresContext()->GetPresShell();
6154 if (activePresShell && (nsContentUtils::ContentIsCrossDocDescendantOf(
6155 activePresShell->GetDocument(), mDoc) ||
6156 nsContentUtils::ContentIsCrossDocDescendantOf(
6157 mDoc, activePresShell->GetDocument()))) {
6158 EventStateManager::ClearGlobalActiveContent(activeESM);
6159
6160 PresShell::ReleaseCapturingContent();
6161
6162 if (activePresShell) {
6163 RefPtr<nsFrameSelection> frameSelection =
6164 activePresShell->FrameSelection();
6165 frameSelection->SetDragState(false);
6166 }
6167 }
6168 }
6169
6170 // If there are any drag and drop operations in flight, try to end them.
6171 nsCOMPtr<nsIDragService> ds =
6172 do_GetService("@mozilla.org/widget/dragservice;1");
6173 if (ds && topWin->GetDocShell()) {
6174 if (PresShell* presShell = topWin->GetDocShell()->GetPresShell()) {
6175 if (nsViewManager* vm = presShell->GetViewManager()) {
6176 RefPtr<nsIWidget> widget = vm->GetRootWidget();
6177 if (nsCOMPtr<nsIDragSession> session = ds->GetCurrentSession(widget)) {
6178 session->EndDragSession(true, 0);
6179 }
6180 }
6181 }
6182 }
6183
6184 // Clear the capturing content if it is under topDoc.
6185 // Usually the activeESM check above does that, but there are cases when
6186 // we don't have activeESM, or it is for different document.
6187 Document* topDoc = topWin->GetExtantDoc();
6188 nsIContent* capturingContent = PresShell::GetCapturingContent();
6189 if (capturingContent && topDoc &&
6190 nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
6191 PresShell::ReleaseCapturingContent();
6192 }
6193
6194 if (topWin->mModalStateDepth == 0) {
6195 topWin->SuppressEventHandling();
6196
6197 if (nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(topWin)) {
6198 inner->Suspend();
6199 }
6200 }
6201 topWin->mModalStateDepth++;
6202 return topWin;
6203}
6204
6205void nsGlobalWindowOuter::LeaveModalState() {
6206 {
6207 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6208 if (!topWin) {
6209 NS_WARNING("Uh, LeaveModalState() called w/o a reachable top window?")NS_DebugBreak(NS_DEBUG_WARNING, "Uh, LeaveModalState() called w/o a reachable top window?"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6209)
;
6210 return;
6211 }
6212
6213 if (topWin != this) {
6214 MOZ_ASSERT(IsSuspended())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsSuspended())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsSuspended()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("IsSuspended()",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSuspended()"
")"); do { *((volatile int*)__null) = 6214; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6215 return topWin->LeaveModalState();
6216 }
6217 }
6218
6219 MOZ_ASSERT(mModalStateDepth != 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mModalStateDepth != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mModalStateDepth != 0))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("mModalStateDepth != 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mModalStateDepth != 0"
")"); do { *((volatile int*)__null) = 6219; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6220 MOZ_ASSERT(IsSuspended())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsSuspended())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsSuspended()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("IsSuspended()",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSuspended()"
")"); do { *((volatile int*)__null) = 6220; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6221 mModalStateDepth--;
6222
6223 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6224 if (mModalStateDepth == 0) {
6225 if (inner) {
6226 inner->Resume();
6227 }
6228
6229 UnsuppressEventHandling();
6230 }
6231
6232 // Remember the time of the last dialog quit.
6233 if (auto* bcg = GetBrowsingContextGroup()) {
6234 bcg->SetLastDialogQuitTime(TimeStamp::Now());
6235 }
6236
6237 if (mModalStateDepth == 0) {
6238 RefPtr<Event> event = NS_NewDOMEvent(inner, nullptr, nullptr);
6239 event->InitEvent(u"endmodalstate"_ns, true, false);
6240 event->SetTrusted(true);
6241 event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
6242 DispatchEvent(*event);
6243 }
6244}
6245
6246bool nsGlobalWindowOuter::IsInModalState() {
6247 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6248
6249 if (!topWin) {
6250 // IsInModalState() getting called w/o a reachable top window is a bit
6251 // iffy, but valid enough not to make noise about it. See bug 404828
6252 return false;
6253 }
6254
6255 return topWin->mModalStateDepth != 0;
6256}
6257
6258void nsGlobalWindowOuter::NotifyWindowIDDestroyed(const char* aTopic) {
6259 nsCOMPtr<nsIRunnable> runnable =
6260 new WindowDestroyedEvent(this, mWindowID, aTopic);
6261 Dispatch(runnable.forget());
6262}
6263
6264Element* nsGlobalWindowOuter::GetFrameElement(nsIPrincipal& aSubjectPrincipal) {
6265 // Per HTML5, the frameElement getter returns null in cross-origin situations.
6266 Element* element = GetFrameElement();
6267 if (!element) {
6268 return nullptr;
6269 }
6270
6271 if (!aSubjectPrincipal.SubsumesConsideringDomain(element->NodePrincipal())) {
6272 return nullptr;
6273 }
6274
6275 return element;
6276}
6277
6278Element* nsGlobalWindowOuter::GetFrameElement() {
6279 if (!mBrowsingContext || mBrowsingContext->IsTop()) {
6280 return nullptr;
6281 }
6282 return mBrowsingContext->GetEmbedderElement();
6283}
6284
6285namespace {
6286class ChildCommandDispatcher : public Runnable {
6287 public:
6288 ChildCommandDispatcher(nsPIWindowRoot* aRoot, nsIBrowserChild* aBrowserChild,
6289 nsPIDOMWindowOuter* aWindow, const nsAString& aAction)
6290 : mozilla::Runnable("ChildCommandDispatcher"),
6291 mRoot(aRoot),
6292 mBrowserChild(aBrowserChild),
6293 mWindow(aWindow),
6294 mAction(aAction) {}
6295
6296 NS_IMETHODvirtual nsresult Run() override {
6297 AutoTArray<nsCString, 70> enabledCommands, disabledCommands;
6298 mRoot->GetEnabledDisabledCommands(enabledCommands, disabledCommands);
6299 if (enabledCommands.Length() || disabledCommands.Length()) {
6300 BrowserChild* bc = static_cast<BrowserChild*>(mBrowserChild.get());
6301 bc->SendEnableDisableCommands(mWindow->GetBrowsingContext(), mAction,
6302 enabledCommands, disabledCommands);
6303 }
6304
6305 return NS_OK;
6306 }
6307
6308 private:
6309 nsCOMPtr<nsPIWindowRoot> mRoot;
6310 nsCOMPtr<nsIBrowserChild> mBrowserChild;
6311 nsCOMPtr<nsPIDOMWindowOuter> mWindow;
6312 nsString mAction;
6313};
6314
6315class CommandDispatcher : public Runnable {
6316 public:
6317 CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
6318 const nsAString& aAction)
6319 : mozilla::Runnable("CommandDispatcher"),
6320 mDispatcher(aDispatcher),
6321 mAction(aAction) {}
6322
6323 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230, bug 1535398)
6324 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODvirtual nsresult Run() override {
6325 return mDispatcher->UpdateCommands(mAction);
6326 }
6327
6328 const nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
6329 nsString mAction;
6330};
6331} // anonymous namespace
6332
6333void nsGlobalWindowOuter::UpdateCommands(const nsAString& anAction) {
6334 // If this is a child process, redirect to the parent process.
6335 if (nsIDocShell* docShell = GetDocShell()) {
6336 if (nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild()) {
6337 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
6338 if (root) {
6339 nsContentUtils::AddScriptRunner(
6340 new ChildCommandDispatcher(root, child, this, anAction));
6341 }
6342 return;
6343 }
6344 }
6345
6346 nsPIDOMWindowOuter* rootWindow = GetPrivateRoot();
6347 if (!rootWindow) {
6348 return;
6349 }
6350
6351 Document* doc = rootWindow->GetExtantDoc();
6352
6353 if (!doc) {
6354 return;
6355 }
6356
6357 // Retrieve the command dispatcher and call updateCommands on it.
6358 nsIDOMXULCommandDispatcher* xulCommandDispatcher =
6359 doc->GetCommandDispatcher();
6360 if (xulCommandDispatcher) {
6361 nsContentUtils::AddScriptRunner(
6362 new CommandDispatcher(xulCommandDispatcher, anAction));
6363 }
6364}
6365
6366Selection* nsGlobalWindowOuter::GetSelectionOuter() {
6367 if (!mDocShell) {
6368 return nullptr;
6369 }
6370
6371 PresShell* presShell = mDocShell->GetPresShell();
6372 if (!presShell) {
6373 return nullptr;
6374 }
6375 return presShell->GetCurrentSelection(SelectionType::eNormal);
6376}
6377
6378already_AddRefed<Selection> nsGlobalWindowOuter::GetSelection() {
6379 RefPtr<Selection> selection = GetSelectionOuter();
6380 return selection.forget();
6381}
6382
6383bool nsGlobalWindowOuter::FindOuter(const nsAString& aString,
6384 bool aCaseSensitive, bool aBackwards,
6385 bool aWrapAround, bool aWholeWord,
6386 bool aSearchInFrames, bool aShowDialog,
6387 ErrorResult& aError) {
6388 Unused << aShowDialog;
6389
6390 nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
6391 if (!finder) {
6392 aError.Throw(NS_ERROR_NOT_AVAILABLE);
6393 return false;
6394 }
6395
6396 // Set the options of the search
6397 aError = finder->SetSearchString(aString);
6398 if (aError.Failed()) {
6399 return false;
6400 }
6401 finder->SetMatchCase(aCaseSensitive);
6402 finder->SetFindBackwards(aBackwards);
6403 finder->SetWrapFind(aWrapAround);
6404 finder->SetEntireWord(aWholeWord);
6405 finder->SetSearchFrames(aSearchInFrames);
6406
6407 // the nsIWebBrowserFind is initialized to use this window
6408 // as the search root, but uses focus to set the current search
6409 // frame. If we're being called from JS (as here), this window
6410 // should be the current search frame.
6411 nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
6412 if (framesFinder) {
6413 framesFinder->SetRootSearchFrame(this); // paranoia
6414 framesFinder->SetCurrentSearchFrame(this);
6415 }
6416
6417 if (aString.IsEmpty()) {
6418 return false;
6419 }
6420
6421 // Launch the search with the passed in search string
6422 bool didFind = false;
6423 aError = finder->FindNext(&didFind);
6424 return didFind;
6425}
6426
6427//*****************************************************************************
6428// EventTarget
6429//*****************************************************************************
6430
6431nsPIDOMWindowOuter* nsGlobalWindowOuter::GetOwnerGlobalForBindingsInternal() {
6432 return this;
6433}
6434
6435nsIGlobalObject* nsGlobalWindowOuter::GetOwnerGlobal() const {
6436 return GetCurrentInnerWindowInternal(this);
6437}
6438
6439bool nsGlobalWindowOuter::DispatchEvent(Event& aEvent, CallerType aCallerType,
6440 ErrorResult& aRv) {
6441 FORWARD_TO_INNER(DispatchEvent, (aEvent, aCallerType, aRv), false)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6441); return false; } return GetCurrentInnerWindowInternal
(this)->DispatchEvent (aEvent, aCallerType, aRv); } while (
0)
;
6442}
6443
6444bool nsGlobalWindowOuter::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
6445 // It's OK that we just return false here on failure to create an
6446 // inner. GetOrCreateListenerManager() will likewise fail, and then
6447 // we won't be adding any listeners anyway.
6448 FORWARD_TO_INNER_CREATE(ComputeDefaultWantsUntrusted, (aRv), false)do { if (!mInnerWindow) { if (mIsClosed) { return false; } nsCOMPtr
<Document> kungFuDeathGrip = GetDoc(); ::mozilla::Unused
<< kungFuDeathGrip; if (!mInnerWindow) { return false;
} } return GetCurrentInnerWindowInternal(this)->ComputeDefaultWantsUntrusted
(aRv); } while (0)
;
6449}
6450
6451EventListenerManager* nsGlobalWindowOuter::GetOrCreateListenerManager() {
6452 FORWARD_TO_INNER_CREATE(GetOrCreateListenerManager, (), nullptr)do { if (!mInnerWindow) { if (mIsClosed) { return nullptr; } nsCOMPtr
<Document> kungFuDeathGrip = GetDoc(); ::mozilla::Unused
<< kungFuDeathGrip; if (!mInnerWindow) { return nullptr
; } } return GetCurrentInnerWindowInternal(this)->GetOrCreateListenerManager
(); } while (0)
;
6453}
6454
6455EventListenerManager* nsGlobalWindowOuter::GetExistingListenerManager() const {
6456 FORWARD_TO_INNER(GetExistingListenerManager, (), nullptr)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6456); return nullptr; } return GetCurrentInnerWindowInternal
(this)->GetExistingListenerManager (); } while (0)
;
6457}
6458
6459//*****************************************************************************
6460// nsGlobalWindowOuter::nsPIDOMWindow
6461//*****************************************************************************
6462
6463nsPIDOMWindowOuter* nsGlobalWindowOuter::GetPrivateParent() {
6464 nsCOMPtr<nsPIDOMWindowOuter> parent = GetInProcessParent();
6465
6466 if (this == parent) {
6467 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6468 if (!chromeElement)
6469 return nullptr; // This is ok, just means a null parent.
6470
6471 Document* doc = chromeElement->GetComposedDoc();
6472 if (!doc) return nullptr; // This is ok, just means a null parent.
6473
6474 return doc->GetWindow();
6475 }
6476
6477 return parent;
6478}
6479
6480nsPIDOMWindowOuter* nsGlobalWindowOuter::GetPrivateRoot() {
6481 nsCOMPtr<nsPIDOMWindowOuter> top = GetInProcessTop();
6482
6483 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6484 if (chromeElement) {
6485 Document* doc = chromeElement->GetComposedDoc();
6486 if (doc) {
6487 nsCOMPtr<nsPIDOMWindowOuter> parent = doc->GetWindow();
6488 if (parent) {
6489 top = parent->GetInProcessTop();
6490 }
6491 }
6492 }
6493
6494 return top;
6495}
6496
6497// This has a caller in Windows-only code (nsNativeAppSupportWin).
6498Location* nsGlobalWindowOuter::GetLocation() {
6499 // This method can be called on the outer window as well.
6500 FORWARD_TO_INNER(Location, (), nullptr)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6500); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Location (); } while (0)
;
6501}
6502
6503void nsGlobalWindowOuter::SetIsBackground(bool aIsBackground) {
6504 bool changed = aIsBackground != IsBackground();
6505 SetIsBackgroundInternal(aIsBackground);
6506
6507 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6508
6509 if (inner && changed) {
6510 inner->UpdateBackgroundState();
6511 }
6512
6513 if (aIsBackground) {
6514 // Notify gamepadManager we are at the background window,
6515 // we need to stop vibrate.
6516 // Stop the vr telemery time spent when it switches to
6517 // the background window.
6518 if (inner && changed) {
6519 inner->StopGamepadHaptics();
6520 inner->StopVRActivity();
6521 // true is for asking to set the delta time to
6522 // the telemetry.
6523 inner->ResetVRTelemetry(true);
6524 }
6525 return;
6526 }
6527
6528 if (inner) {
6529 // When switching to be as a top tab, restart the telemetry.
6530 // false is for only resetting the timestamp.
6531 inner->ResetVRTelemetry(false);
6532 inner->SyncGamepadState();
6533 inner->StartVRActivity();
6534 }
6535}
6536
6537void nsGlobalWindowOuter::SetIsBackgroundInternal(bool aIsBackground) {
6538 mIsBackground = aIsBackground;
6539}
6540
6541void nsGlobalWindowOuter::SetChromeEventHandler(
6542 EventTarget* aChromeEventHandler) {
6543 SetChromeEventHandlerInternal(aChromeEventHandler);
6544 // update the chrome event handler on all our inner windows
6545 RefPtr<nsGlobalWindowInner> inner;
6546 for (PRCList* node = PR_LIST_HEAD(this)(this)->next; node != this;
6547 node = PR_NEXT_LINK(inner)((inner)->next)) {
6548 // This cast is only safe if `node != this`, as nsGlobalWindowOuter is also
6549 // in the list.
6550 inner = static_cast<nsGlobalWindowInner*>(node);
6551 NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,do { if (!(!inner->mOuterWindow || inner->mOuterWindow ==
this)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad outer window pointer"
, "!inner->mOuterWindow || inner->mOuterWindow == this"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6552); MOZ_PretendNoReturn(); } } while (0)
6552 "bad outer window pointer")do { if (!(!inner->mOuterWindow || inner->mOuterWindow ==
this)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad outer window pointer"
, "!inner->mOuterWindow || inner->mOuterWindow == this"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6552); MOZ_PretendNoReturn(); } } while (0)
;
6553 inner->SetChromeEventHandlerInternal(aChromeEventHandler);
6554 }
6555}
6556
6557void nsGlobalWindowOuter::SetFocusedElement(Element* aElement,
6558 uint32_t aFocusMethod,
6559 bool aNeedsFocus) {
6560 FORWARD_TO_INNER_VOID(SetFocusedElement,do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6561); return; } GetCurrentInnerWindowInternal(this)->SetFocusedElement
(aElement, aFocusMethod, aNeedsFocus); return; } while (0)
6561 (aElement, aFocusMethod, aNeedsFocus))do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6561); return; } GetCurrentInnerWindowInternal(this)->SetFocusedElement
(aElement, aFocusMethod, aNeedsFocus); return; } while (0)
;
6562}
6563
6564uint32_t nsGlobalWindowOuter::GetFocusMethod() {
6565 FORWARD_TO_INNER(GetFocusMethod, (), 0)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6565); return 0; } return GetCurrentInnerWindowInternal(this
)->GetFocusMethod (); } while (0)
;
6566}
6567
6568bool nsGlobalWindowOuter::ShouldShowFocusRing() {
6569 FORWARD_TO_INNER(ShouldShowFocusRing, (), false)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6569); return false; } return GetCurrentInnerWindowInternal
(this)->ShouldShowFocusRing (); } while (0)
;
6570}
6571
6572bool nsGlobalWindowOuter::TakeFocus(bool aFocus, uint32_t aFocusMethod) {
6573 FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), false)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6573); return false; } return GetCurrentInnerWindowInternal
(this)->TakeFocus (aFocus, aFocusMethod); } while (0)
;
6574}
6575
6576void nsGlobalWindowOuter::SetReadyForFocus() {
6577 FORWARD_TO_INNER_VOID(SetReadyForFocus, ())do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6577); return; } GetCurrentInnerWindowInternal(this)->SetReadyForFocus
(); return; } while (0)
;
6578}
6579
6580void nsGlobalWindowOuter::PageHidden(bool aIsEnteringBFCacheInParent) {
6581 FORWARD_TO_INNER_VOID(PageHidden, (aIsEnteringBFCacheInParent))do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6581); return; } GetCurrentInnerWindowInternal(this)->PageHidden
(aIsEnteringBFCacheInParent); return; } while (0)
;
6582}
6583
6584already_AddRefed<nsICSSDeclaration>
6585nsGlobalWindowOuter::GetComputedStyleHelperOuter(Element& aElt,
6586 const nsAString& aPseudoElt,
6587 bool aDefaultStylesOnly,
6588 ErrorResult& aRv) {
6589 if (!mDoc) {
6590 return nullptr;
6591 }
6592
6593 RefPtr<nsICSSDeclaration> compStyle = NS_NewComputedDOMStyle(
6594 &aElt, aPseudoElt, mDoc,
6595 aDefaultStylesOnly ? nsComputedDOMStyle::StyleType::DefaultOnly
6596 : nsComputedDOMStyle::StyleType::All,
6597 aRv);
6598
6599 return compStyle.forget();
6600}
6601
6602//*****************************************************************************
6603// nsGlobalWindowOuter::nsIInterfaceRequestor
6604//*****************************************************************************
6605
6606nsresult nsGlobalWindowOuter::GetInterfaceInternal(const nsIID& aIID,
6607 void** aSink) {
6608 NS_ENSURE_ARG_POINTER(aSink)do { if ((__builtin_expect(!!(!(aSink)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aSink" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6608); return NS_ERROR_INVALID_POINTER; } } while (false)
;
6609 *aSink = nullptr;
6610
6611 if (aIID.Equals(NS_GET_IID(nsIWebNavigation)(nsIWebNavigation::COMTypeInfo<nsIWebNavigation, void>::
kIID)
)) {
6612 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
6613 webNav.forget(aSink);
6614 } else if (aIID.Equals(NS_GET_IID(nsIDocShell)(nsIDocShell::COMTypeInfo<nsIDocShell, void>::kIID))) {
6615 nsCOMPtr<nsIDocShell> docShell = mDocShell;
6616 docShell.forget(aSink);
6617 }
6618#ifdef NS_PRINTING1
6619 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint)(nsIWebBrowserPrint::COMTypeInfo<nsIWebBrowserPrint, void>
::kIID)
)) {
6620 if (mDocShell) {
6621 nsCOMPtr<nsIDocumentViewer> viewer;
6622 mDocShell->GetDocViewer(getter_AddRefs(viewer));
6623 if (viewer) {
6624 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
6625 webBrowserPrint.forget(aSink);
6626 }
6627 }
6628 }
6629#endif
6630 else if (aIID.Equals(NS_GET_IID(nsILoadContext)(nsILoadContext::COMTypeInfo<nsILoadContext, void>::kIID
)
)) {
6631 nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(mDocShell));
6632 loadContext.forget(aSink);
6633 }
6634
6635 return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
6636}
6637
6638NS_IMETHODIMPnsresult
6639nsGlobalWindowOuter::GetInterface(const nsIID& aIID, void** aSink) {
6640 nsresult rv = GetInterfaceInternal(aIID, aSink);
6641 if (rv == NS_ERROR_NO_INTERFACE) {
6642 return QueryInterface(aIID, aSink);
6643 }
6644 return rv;
6645}
6646
6647bool nsGlobalWindowOuter::IsSuspended() const {
6648 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6648); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6648; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6649 // No inner means we are effectively suspended
6650 if (!mInnerWindow) {
6651 return true;
6652 }
6653 return mInnerWindow->IsSuspended();
6654}
6655
6656bool nsGlobalWindowOuter::IsFrozen() const {
6657 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6657; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6658 // No inner means we are effectively frozen
6659 if (!mInnerWindow) {
6660 return true;
6661 }
6662 return mInnerWindow->IsFrozen();
6663}
6664
6665nsresult nsGlobalWindowOuter::FireDelayedDOMEvents(bool aIncludeSubWindows) {
6666 FORWARD_TO_INNER(FireDelayedDOMEvents, (aIncludeSubWindows),do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6667); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->FireDelayedDOMEvents (aIncludeSubWindows); } while
(0)
6667 NS_ERROR_UNEXPECTED)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6667); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->FireDelayedDOMEvents (aIncludeSubWindows); } while
(0)
;
6668}
6669
6670//*****************************************************************************
6671// nsGlobalWindowOuter: Window Control Functions
6672//*****************************************************************************
6673
6674nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessParentInternal() {
6675 nsCOMPtr<nsPIDOMWindowOuter> parent = GetInProcessParent();
6676
6677 if (parent && parent != this) {
6678 return parent;
6679 }
6680
6681 return nullptr;
6682}
6683
6684void nsGlobalWindowOuter::UnblockScriptedClosing() {
6685 mBlockScriptedClosingFlag = false;
6686}
6687
6688class AutoUnblockScriptClosing {
6689 private:
6690 RefPtr<nsGlobalWindowOuter> mWin;
6691
6692 public:
6693 explicit AutoUnblockScriptClosing(nsGlobalWindowOuter* aWin) : mWin(aWin) {
6694 MOZ_ASSERT(mWin)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWin)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(mWin))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mWin", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6694); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWin" ")");
do { *((volatile int*)__null) = 6694; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6695 }
6696 ~AutoUnblockScriptClosing() {
6697 void (nsGlobalWindowOuter::*run)() =
6698 &nsGlobalWindowOuter::UnblockScriptedClosing;
6699 nsCOMPtr<nsIRunnable> caller = NewRunnableMethod(
6700 "AutoUnblockScriptClosing::~AutoUnblockScriptClosing", mWin, run);
6701 mWin->Dispatch(caller.forget());
6702 }
6703};
6704
6705nsresult nsGlobalWindowOuter::OpenInternal(
6706 const nsACString& aUrl, const nsAString& aName, const nsAString& aOptions,
6707 bool aDialog, bool aCalledNoScript, bool aDoJSFixups, bool aNavigate,
6708 nsIArray* aArguments, nsDocShellLoadState* aLoadState, bool aForceNoOpener,
6709 PrintKind aPrintKind, BrowsingContext** aReturn) {
6710 mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
6711
6712 // Calls to window.open from script should navigate.
6713 MOZ_ASSERT(aCalledNoScript || aNavigate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aCalledNoScript || aNavigate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aCalledNoScript || aNavigate
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aCalledNoScript || aNavigate", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6713); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCalledNoScript || aNavigate"
")"); do { *((volatile int*)__null) = 6713; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1
Assuming 'aCalledNoScript' is false
2
Assuming the condition is false
3
Taking false branch
4
Loop condition is false. Exiting loop
6714
6715 *aReturn = nullptr;
6716
6717 nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
6718 if (!chrome) {
5
Taking false branch
6719 // No chrome means we don't want to go through with this open call
6720 // -- see nsIWindowWatcher.idl
6721 return NS_ERROR_NOT_AVAILABLE;
6722 }
6723
6724 NS_ASSERTION(mDocShell, "Must have docshell here")do { if (!(mDocShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Must have docshell here"
, "mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6724); MOZ_PretendNoReturn(); } } while (0)
;
6
Taking false branch
7
Loop condition is false. Exiting loop
6725
6726 NS_ConvertUTF16toUTF8 optionsUtf8(aOptions);
6727
6728 WindowFeatures features;
6729 if (!features.Tokenize(optionsUtf8)) {
8
Assuming the condition is false
9
Taking false branch
6730 return NS_ERROR_FAILURE;
6731 }
6732
6733 bool forceNoOpener = aForceNoOpener;
6734 if (features.Exists("noopener")) {
10
Taking true branch
6735 forceNoOpener = features.GetBool("noopener");
6736 features.Remove("noopener");
11
Calling 'WindowFeatures::Remove'
6737 }
6738
6739 bool forceNoReferrer = false;
6740 if (features.Exists("noreferrer")) {
6741 forceNoReferrer = features.GetBool("noreferrer");
6742 if (forceNoReferrer) {
6743 // noreferrer implies noopener
6744 forceNoOpener = true;
6745 }
6746 features.Remove("noreferrer");
6747 }
6748
6749 nsAutoCString options;
6750 features.Stringify(options);
6751
6752 // If noopener is force-enabled for the current document, then set noopener to
6753 // true, and clear the name to "_blank".
6754 nsAutoString windowName(aName);
6755 if (nsDocShell::Cast(GetDocShell())->NoopenerForceEnabled() &&
6756 aPrintKind == PrintKind::None) {
6757 MOZ_DIAGNOSTIC_ASSERT(aNavigate,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNavigate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNavigate))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNavigate" " (" "cannot OpenNoNavigate if noopener is force-enabled"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6758); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNavigate"
") (" "cannot OpenNoNavigate if noopener is force-enabled" ")"
); do { *((volatile int*)__null) = 6758; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6758 "cannot OpenNoNavigate if noopener is force-enabled")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNavigate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNavigate))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNavigate" " (" "cannot OpenNoNavigate if noopener is force-enabled"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6758); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNavigate"
") (" "cannot OpenNoNavigate if noopener is force-enabled" ")"
); do { *((volatile int*)__null) = 6758; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6759
6760 forceNoOpener = true;
6761 windowName = u"_blank"_ns;
6762 }
6763
6764 bool windowExists = WindowExists(windowName, forceNoOpener, !aCalledNoScript);
6765
6766 // XXXbz When this gets fixed to not use LegacyIsCallerNativeCode()
6767 // (indirectly) maybe we can nix the AutoJSAPI usage OnLinkClickEvent::Run.
6768 // But note that if you change this to GetEntryGlobal(), say, then
6769 // OnLinkClickEvent::Run will need a full-blown AutoEntryScript. (Bug 1930445)
6770 const bool checkForPopup = [&]() {
6771 if (aDialog) {
6772 return false;
6773 }
6774 if (windowExists) {
6775 return false;
6776 }
6777 if (aLoadState && aLoadState->IsFormSubmission()) {
6778 return true;
6779 }
6780 return !nsContentUtils::LegacyIsCallerChromeOrNativeCode();
6781 }();
6782
6783 nsCOMPtr<nsIURI> uri;
6784
6785 // It's important to do this security check before determining whether this
6786 // window opening should be blocked, to ensure that we don't FireAbuseEvents
6787 // for a window opening that wouldn't have succeeded in the first place.
6788 if (!aUrl.IsEmpty()) {
6789 // It's safe to skip the security check below if we're a dialog because
6790 // window.openDialog is not callable from content script. See bug 56851.
6791 //
6792 // If we're not navigating, we assume that whoever *does* navigate the
6793 // window will do a security check of their own.
6794 auto result =
6795 URIfromURLAndMaybeDoSecurityCheck(aUrl, !aDialog && aNavigate);
6796 if (result.isErr()) {
6797 return result.unwrapErr();
6798 }
6799
6800 uri = result.unwrap();
6801 } else if (mDoc) {
6802 mDoc->SetUseCounter(eUseCounter_custom_WindowOpenEmptyUrl);
6803 }
6804
6805 UserActivation::Modifiers modifiers;
6806 mBrowsingContext->GetUserActivationModifiersForPopup(&modifiers);
6807
6808 // Need to create loadState before the user activation is consumed in
6809 // BrowsingContext::RevisePopupAbuseLevel() below.
6810 RefPtr<nsDocShellLoadState> loadState = aLoadState;
6811 if (!loadState && aNavigate && uri) {
6812 loadState = nsWindowWatcher::CreateLoadState(uri, this);
6813 }
6814
6815 PopupBlocker::PopupControlState abuseLevel =
6816 PopupBlocker::GetPopupControlState();
6817 if (checkForPopup) {
6818 abuseLevel = mBrowsingContext->RevisePopupAbuseLevel(abuseLevel);
6819 if (abuseLevel >= PopupBlocker::openBlocked) {
6820 if (!aCalledNoScript) {
6821 // If script in some other window is doing a window.open on us and
6822 // it's being blocked, then it's OK to close us afterwards, probably.
6823 // But if we're doing a window.open on ourselves and block the popup,
6824 // prevent this window from closing until after this script terminates
6825 // so that whatever popup blocker UI the app has will be visible.
6826 nsCOMPtr<nsPIDOMWindowInner> entryWindow =
6827 do_QueryInterface(GetEntryGlobal());
6828 // Note that entryWindow can be null here if some JS component was the
6829 // place where script was entered for this JS execution.
6830 if (entryWindow && entryWindow->GetOuterWindow() == this) {
6831 mBlockScriptedClosingFlag = true;
6832 closeUnblocker.emplace(this);
6833 }
6834 }
6835
6836 FireAbuseEvents(aUrl, windowName, aOptions);
6837 return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
6838 }
6839 }
6840
6841 // Per https://github.com/whatwg/html/pull/10547, we should always consume
6842 // user activation when opening a new window, even if the popup blocker is
6843 // disabled or the website has popup permission.
6844 if (!windowExists && mDoc) {
6845 mDoc->ConsumeTransientUserGestureActivation();
6846 }
6847
6848 RefPtr<BrowsingContext> domReturn;
6849
6850 nsresult rv = NS_OK;
6851 nsCOMPtr<nsIWindowWatcher> wwatch =
6852 do_GetService(NS_WINDOWWATCHER_CONTRACTID"@mozilla.org/embedcomp/window-watcher;1", &rv);
6853 NS_ENSURE_TRUE(wwatch, rv)do { if ((__builtin_expect(!!(!(wwatch)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "wwatch" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6853); return rv; } } while (false)
;
6854
6855 NS_ConvertUTF16toUTF8 name(windowName);
6856
6857 nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
6858 NS_ENSURE_STATE(pwwatch)do { if ((__builtin_expect(!!(!(pwwatch)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "pwwatch" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6858); return NS_ERROR_UNEXPECTED; } } while (false)
;
6859
6860 MOZ_ASSERT_IF(checkForPopup, abuseLevel < PopupBlocker::openBlocked)do { if (checkForPopup) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(abuseLevel < PopupBlocker
::openBlocked)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(abuseLevel < PopupBlocker::openBlocked
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"abuseLevel < PopupBlocker::openBlocked", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "abuseLevel < PopupBlocker::openBlocked"
")"); do { *((volatile int*)__null) = 6860; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6861 // At this point we should know for a fact that if checkForPopup then
6862 // abuseLevel < PopupBlocker::openBlocked, so we could just check for
6863 // abuseLevel == PopupBlocker::openControlled. But let's be defensive just in
6864 // case and treat anything that fails the above assert as a spam popup too, if
6865 // it ever happens.
6866 bool isPopupSpamWindow =
6867 checkForPopup && (abuseLevel >= PopupBlocker::openControlled);
6868
6869 const auto wwPrintKind = [&] {
6870 switch (aPrintKind) {
6871 case PrintKind::None:
6872 return nsPIWindowWatcher::PRINT_NONE;
6873 case PrintKind::InternalPrint:
6874 return nsPIWindowWatcher::PRINT_INTERNAL;
6875 case PrintKind::WindowDotPrint:
6876 return nsPIWindowWatcher::PRINT_WINDOW_DOT_PRINT;
6877 }
6878 MOZ_ASSERT_UNREACHABLE("Wat")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Wat" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Wat" ")"); do { *((volatile int*
)__null) = 6878; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6879 return nsPIWindowWatcher::PRINT_NONE;
6880 }();
6881
6882 {
6883 // Reset popup state while opening a window to prevent the
6884 // current state from being active the whole time a modal
6885 // dialog is open.
6886 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
6887
6888 if (!aCalledNoScript) {
6889 // We asserted at the top of this function that aNavigate is true for
6890 // !aCalledNoScript.
6891 rv = pwwatch->OpenWindow2(this, uri, name, options, modifiers,
6892 /* aCalledFromScript = */ true, aDialog,
6893 aNavigate, aArguments, isPopupSpamWindow,
6894 forceNoOpener, forceNoReferrer, wwPrintKind,
6895 loadState, getter_AddRefs(domReturn));
6896 } else {
6897 // Force a system caller here so that the window watcher won't screw us
6898 // up. We do NOT want this case looking at the JS context on the stack
6899 // when searching. Compare comments on
6900 // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
6901
6902 // Note: Because nsWindowWatcher is so broken, it's actually important
6903 // that we don't force a system caller here, because that screws it up
6904 // when it tries to compute the caller principal to associate with dialog
6905 // arguments. That whole setup just really needs to be rewritten. :-(
6906 AutoNoJSAPI nojsapi;
6907 rv = pwwatch->OpenWindow2(this, uri, name, options, modifiers,
6908 /* aCalledFromScript = */ false, aDialog,
6909 aNavigate, aArguments, isPopupSpamWindow,
6910 forceNoOpener, forceNoReferrer, wwPrintKind,
6911 loadState, getter_AddRefs(domReturn));
6912 }
6913 }
6914
6915 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6915); return rv; } } while (false)
;
6916
6917 // success!
6918
6919 if (!aCalledNoScript && !windowExists && uri && !forceNoOpener) {
6920 MaybeAllowStorageForOpenedWindow(uri);
6921 }
6922
6923 if (domReturn && aDoJSFixups) {
6924 nsPIDOMWindowOuter* outer = domReturn->GetDOMWindow();
6925 if (outer && !nsGlobalWindowOuter::Cast(outer)->IsChromeWindow()) {
6926 // A new non-chrome window was created from a call to
6927 // window.open() from JavaScript, make sure there's a document in
6928 // the new window. We do this by simply asking the new window for
6929 // its document, this will synchronously create an empty document
6930 // if there is no document in the window.
6931 // XXXbz should this just use EnsureInnerWindow()?
6932
6933 // Force document creation.
6934 nsCOMPtr<Document> doc = outer->GetDoc();
6935 Unused << doc;
6936 }
6937 }
6938
6939 domReturn.forget(aReturn);
6940 return NS_OK;
6941}
6942
6943void nsGlobalWindowOuter::MaybeAllowStorageForOpenedWindow(nsIURI* aURI) {
6944 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6945 if (NS_WARN_IF(!inner)NS_warn_if_impl(!inner, "!inner", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6945)
) {
6946 return;
6947 }
6948
6949 // No 3rd party URL/window.
6950 if (!AntiTrackingUtils::IsThirdPartyWindow(inner, aURI)) {
6951 return;
6952 }
6953
6954 Document* doc = inner->GetDoc();
6955 if (!doc) {
6956 return;
6957 }
6958 nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateContentPrincipal(
6959 aURI, doc->NodePrincipal()->OriginAttributesRef());
6960
6961 // We don't care when the asynchronous work finishes here.
6962 // Without e10s or fission enabled this is run in the parent process.
6963 if (XRE_IsParentProcess()) {
6964 Unused << StorageAccessAPIHelper::AllowAccessForOnParentProcess(
6965 principal, GetBrowsingContext(), ContentBlockingNotifier::eOpener);
6966 } else {
6967 Unused << StorageAccessAPIHelper::AllowAccessForOnChildProcess(
6968 principal, GetBrowsingContext(), ContentBlockingNotifier::eOpener);
6969 }
6970}
6971
6972//*****************************************************************************
6973// nsGlobalWindowOuter: Helper Functions
6974//*****************************************************************************
6975
6976already_AddRefed<nsIDocShellTreeOwner> nsPIDOMWindowOuter::GetTreeOwner() {
6977 // If there's no docShellAsItem, this window must have been closed,
6978 // in that case there is no tree owner.
6979
6980 if (!mDocShell) {
6981 return nullptr;
6982 }
6983
6984 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
6985 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
6986 return treeOwner.forget();
6987}
6988
6989already_AddRefed<nsIBaseWindow> nsPIDOMWindowOuter::GetTreeOwnerWindow() {
6990 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
6991
6992 // If there's no mDocShell, this window must have been closed,
6993 // in that case there is no tree owner.
6994
6995 if (mDocShell) {
6996 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
6997 }
6998
6999 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
7000 return baseWindow.forget();
7001}
7002
7003already_AddRefed<nsIWebBrowserChrome>
7004nsPIDOMWindowOuter::GetWebBrowserChrome() {
7005 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
7006
7007 nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
7008 return browserChrome.forget();
7009}
7010
7011ScrollContainerFrame* nsGlobalWindowOuter::GetScrollContainerFrame() {
7012 if (!mDocShell) {
7013 return nullptr;
7014 }
7015
7016 PresShell* presShell = mDocShell->GetPresShell();
7017 if (presShell) {
7018 return presShell->GetRootScrollContainerFrame();
7019 }
7020 return nullptr;
7021}
7022
7023Result<already_AddRefed<nsIURI>, nsresult>
7024nsGlobalWindowOuter::URIfromURLAndMaybeDoSecurityCheck(const nsACString& aURL,
7025 bool aSecurityCheck) {
7026 nsCOMPtr<nsPIDOMWindowInner> sourceWindow =
7027 do_QueryInterface(GetEntryGlobal());
7028 if (!sourceWindow) {
7029 sourceWindow = GetCurrentInnerWindow();
7030 }
7031
7032 // Resolve the baseURI, which could be relative to the calling window.
7033 //
7034 // Note the algorithm to get the base URI should match the one
7035 // used to actually kick off the load in nsWindowWatcher.cpp.
7036 nsCOMPtr<Document> doc = sourceWindow->GetDoc();
7037 nsIURI* baseURI = nullptr;
7038 auto encoding = UTF_8_ENCODING; // default to utf-8
7039 if (doc) {
7040 baseURI = doc->GetDocBaseURI();
7041 encoding = doc->GetDocumentCharacterSet();
7042 }
7043 nsCOMPtr<nsIURI> uri;
7044 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, encoding, baseURI);
7045 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7045)
) {
7046 return Err(NS_ERROR_DOM_SYNTAX_ERR);
7047 }
7048
7049 if (aSecurityCheck) {
7050 AutoJSContext cx;
7051 nsGlobalWindowInner* sourceWin = nsGlobalWindowInner::Cast(sourceWindow);
7052 JSAutoRealm ar(cx, sourceWin->GetGlobalJSObject());
7053
7054 if (NS_FAILED(nsContentUtils::GetSecurityManager()->CheckLoadURIFromScript(((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckLoadURIFromScript( cx, uri))), 0)))
7055 cx, uri))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckLoadURIFromScript( cx, uri))), 0)))
) {
7056 return Err(NS_ERROR_FAILURE);
7057 }
7058 }
7059
7060 return uri.forget();
7061}
7062
7063void nsGlobalWindowOuter::FlushPendingNotifications(FlushType aType) {
7064 if (mDoc) {
7065 mDoc->FlushPendingNotifications(aType);
7066 }
7067}
7068
7069void nsGlobalWindowOuter::EnsureSizeAndPositionUpToDate() {
7070 // If we're a subframe, make sure our size is up to date. Make sure to go
7071 // through the document chain rather than the window chain to not flush on
7072 // detached iframes, see bug 1545516.
7073 if (mDoc && mDoc->StyleOrLayoutObservablyDependsOnParentDocumentLayout()) {
7074 RefPtr<Document> parent = mDoc->GetInProcessParentDocument();
7075 parent->FlushPendingNotifications(FlushType::Layout);
7076 }
7077}
7078
7079already_AddRefed<nsISupports> nsGlobalWindowOuter::SaveWindowState() {
7080 MOZ_ASSERT(!mozilla::SessionHistoryInParent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mozilla::SessionHistoryInParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mozilla::SessionHistoryInParent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mozilla::SessionHistoryInParent()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mozilla::SessionHistoryInParent()"
")"); do { *((volatile int*)__null) = 7080; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7081
7082 if (!mContext || !GetWrapperPreserveColor()) {
7083 // The window may be getting torn down; don't bother saving state.
7084 return nullptr;
7085 }
7086
7087 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
7088 NS_ASSERTION(inner, "No inner window to save")do { if (!(inner)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "No inner window to save"
, "inner", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7088); MOZ_PretendNoReturn(); } } while (0)
;
7089
7090 if (WindowContext* wc = inner->GetWindowContext()) {
7091 MOZ_ASSERT(!wc->GetWindowStateSaved())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!wc->GetWindowStateSaved())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!wc->GetWindowStateSaved(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!wc->GetWindowStateSaved()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wc->GetWindowStateSaved()"
")"); do { *((volatile int*)__null) = 7091; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7092 Unused << wc->SetWindowStateSaved(true);
7093 }
7094
7095 // Don't do anything else to this inner window! After this point, all
7096 // calls to SetTimeoutOrInterval will create entries in the timeout
7097 // list that will only run after this window has come out of the bfcache.
7098 // Also, while we're frozen, we won't dispatch online/offline events
7099 // to the page.
7100 inner->Freeze();
7101
7102 nsCOMPtr<nsISupports> state = new WindowStateHolder(inner);
7103
7104 MOZ_LOG(gPageCacheLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gPageCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "saving window state, state = %p", (void*)
state); } } while (0)
7105 ("saving window state, state = %p", (void*)state))do { const ::mozilla::LogModule* moz_real_module = gPageCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "saving window state, state = %p", (void*)
state); } } while (0)
;
7106
7107 return state.forget();
7108}
7109
7110nsresult nsGlobalWindowOuter::RestoreWindowState(nsISupports* aState) {
7111 MOZ_ASSERT(!mozilla::SessionHistoryInParent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mozilla::SessionHistoryInParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mozilla::SessionHistoryInParent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mozilla::SessionHistoryInParent()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7111); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mozilla::SessionHistoryInParent()"
")"); do { *((volatile int*)__null) = 7111; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7112
7113 if (!mContext || !GetWrapperPreserveColor()) {
7114 // The window may be getting torn down; don't bother restoring state.
7115 return NS_OK;
7116 }
7117
7118 nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
7119 NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(holder)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "holder" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7119); return NS_ERROR_FAILURE; } } while (false)
;
7120
7121 MOZ_LOG(gPageCacheLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gPageCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "restoring window state, state = %p", (void
*)holder); } } while (0)
7122 ("restoring window state, state = %p", (void*)holder))do { const ::mozilla::LogModule* moz_real_module = gPageCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "restoring window state, state = %p", (void
*)holder); } } while (0)
;
7123
7124 // And we're ready to go!
7125 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
7126
7127 // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
7128 // it easy to tell which link was last clicked when going back a page.
7129 RefPtr<Element> focusedElement = inner->GetFocusedElement();
7130 if (nsContentUtils::ContentIsLink(focusedElement)) {
7131 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
7132 fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
7133 nsIFocusManager::FLAG_SHOWRING);
7134 }
7135 }
7136
7137 if (WindowContext* wc = inner->GetWindowContext()) {
7138 MOZ_ASSERT(wc->GetWindowStateSaved())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(wc->GetWindowStateSaved())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(wc->GetWindowStateSaved()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"wc->GetWindowStateSaved()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7138); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wc->GetWindowStateSaved()"
")"); do { *((volatile int*)__null) = 7138; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7139 Unused << wc->SetWindowStateSaved(false);
7140 }
7141
7142 inner->Thaw();
7143
7144 holder->DidRestoreWindow();
7145
7146 return NS_OK;
7147}
7148
7149void nsGlobalWindowOuter::AddSizeOfIncludingThis(
7150 nsWindowSizes& aWindowSizes) const {
7151 aWindowSizes.mDOMSizes.mDOMOtherSize +=
7152 aWindowSizes.mState.mMallocSizeOf(this);
7153}
7154
7155uint32_t nsGlobalWindowOuter::GetAutoActivateVRDisplayID() {
7156 uint32_t retVal = mAutoActivateVRDisplayID;
7157 mAutoActivateVRDisplayID = 0;
7158 return retVal;
7159}
7160
7161void nsGlobalWindowOuter::SetAutoActivateVRDisplayID(
7162 uint32_t aAutoActivateVRDisplayID) {
7163 mAutoActivateVRDisplayID = aAutoActivateVRDisplayID;
7164}
7165
7166already_AddRefed<nsWindowRoot> nsGlobalWindowOuter::GetWindowRootOuter() {
7167 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
7168 return root.forget().downcast<nsWindowRoot>();
7169}
7170
7171nsIDOMWindowUtils* nsGlobalWindowOuter::WindowUtils() {
7172 if (!mWindowUtils) {
7173 mWindowUtils = new nsDOMWindowUtils(this);
7174 }
7175 return mWindowUtils;
7176}
7177
7178bool nsGlobalWindowOuter::IsInSyncOperation() {
7179 return GetExtantDoc() && GetExtantDoc()->IsInSyncOperation();
7180}
7181
7182// Note: This call will lock the cursor, it will not change as it moves.
7183// To unlock, the cursor must be set back to Auto.
7184void nsGlobalWindowOuter::SetCursorOuter(const nsACString& aCursor,
7185 ErrorResult& aError) {
7186 auto cursor = StyleCursorKind::Auto;
7187 if (!Servo_CursorKind_Parse(&aCursor, &cursor)) {
7188 // FIXME: It's a bit weird that this doesn't throw but stuff below does, but
7189 // matches previous behavior so...
7190 return;
7191 }
7192
7193 RefPtr<nsPresContext> presContext;
7194 if (mDocShell) {
7195 presContext = mDocShell->GetPresContext();
7196 }
7197
7198 if (presContext) {
7199 // Need root widget.
7200 PresShell* presShell = mDocShell->GetPresShell();
7201 if (!presShell) {
7202 aError.Throw(NS_ERROR_FAILURE);
7203 return;
7204 }
7205
7206 nsViewManager* vm = presShell->GetViewManager();
7207 if (!vm) {
7208 aError.Throw(NS_ERROR_FAILURE);
7209 return;
7210 }
7211
7212 nsView* rootView = vm->GetRootView();
7213 if (!rootView) {
7214 aError.Throw(NS_ERROR_FAILURE);
7215 return;
7216 }
7217
7218 nsIWidget* widget = rootView->GetNearestWidget(nullptr);
7219 if (!widget) {
7220 aError.Throw(NS_ERROR_FAILURE);
7221 return;
7222 }
7223
7224 // Call esm and set cursor.
7225 aError = presContext->EventStateManager()->SetCursor(
7226 cursor, nullptr, {}, Nothing(), widget, true);
7227 }
7228}
7229
7230nsIBrowserDOMWindow* nsGlobalWindowOuter::GetBrowserDOMWindow() {
7231 MOZ_RELEASE_ASSERT(IsChromeWindow())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsChromeWindow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsChromeWindow()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsChromeWindow()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7231); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "IsChromeWindow()"
")"); do { *((volatile int*)__null) = 7231; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7232 return mChromeFields.mBrowserDOMWindow;
7233}
7234
7235void nsGlobalWindowOuter::SetBrowserDOMWindowOuter(
7236 nsIBrowserDOMWindow* aBrowserWindow) {
7237 MOZ_ASSERT(IsChromeWindow())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsChromeWindow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsChromeWindow()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsChromeWindow()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsChromeWindow()"
")"); do { *((volatile int*)__null) = 7237; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7238 mChromeFields.mBrowserDOMWindow = aBrowserWindow;
7239}
7240
7241ChromeMessageBroadcaster* nsGlobalWindowOuter::GetMessageManager() {
7242 if (!mInnerWindow) {
7243 NS_WARNING("No inner window available!")NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7243)
;
7244 return nullptr;
7245 }
7246 return GetCurrentInnerWindowInternal(this)->MessageManager();
7247}
7248
7249ChromeMessageBroadcaster* nsGlobalWindowOuter::GetGroupMessageManager(
7250 const nsAString& aGroup) {
7251 if (!mInnerWindow) {
7252 NS_WARNING("No inner window available!")NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7252)
;
7253 return nullptr;
7254 }
7255 return GetCurrentInnerWindowInternal(this)->GetGroupMessageManager(aGroup);
7256}
7257
7258void nsGlobalWindowOuter::InitWasOffline() { mWasOffline = NS_IsOffline(); }
7259
7260#if defined(_WINDOWS_) && !defined(MOZ_WRAPPED_WINDOWS_H)
7261# pragma message( \
7262 "wrapper failure reason: " MOZ_WINDOWS_WRAPPER_DISABLED_REASON)
7263# error "Never include unwrapped windows.h in this file!"
7264#endif
7265
7266// Helper called by methods that move/resize the window,
7267// to ensure the presContext (if any) is aware of resolution
7268// change that may happen in multi-monitor configuration.
7269void nsGlobalWindowOuter::CheckForDPIChange() {
7270 if (mDocShell) {
7271 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
7272 if (presContext) {
7273 if (presContext->DeviceContext()->CheckDPIChange()) {
7274 presContext->UIResolutionChanged();
7275 }
7276 }
7277 }
7278}
7279
7280nsresult nsGlobalWindowOuter::Dispatch(
7281 already_AddRefed<nsIRunnable>&& aRunnable) const {
7282 MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7282); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 7282; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7283 return NS_DispatchToCurrentThread(std::move(aRunnable));
7284}
7285
7286nsISerialEventTarget* nsGlobalWindowOuter::SerialEventTarget() const {
7287 MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7287); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 7287; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7288 return GetMainThreadSerialEventTarget();
7289}
7290
7291void nsGlobalWindowOuter::MaybeResetWindowName(Document* aNewDocument) {
7292 MOZ_ASSERT(aNewDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewDocument))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aNewDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7292); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewDocument"
")"); do { *((volatile int*)__null) = 7292; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7293
7294 if (!StaticPrefs::privacy_window_name_update_enabled()) {
7295 return;
7296 }
7297
7298 const LoadingSessionHistoryInfo* info =
7299 nsDocShell::Cast(mDocShell)->GetLoadingSessionHistoryInfo();
7300 if (!info || info->mForceMaybeResetName.isNothing()) {
7301 // We only reset the window name for the top-level content as well as
7302 // storing in session entries.
7303 if (!GetBrowsingContext()->IsTopContent()) {
7304 return;
7305 }
7306
7307 // Following implements https://html.spec.whatwg.org/#history-traversal:
7308 // Step 4.2. Check if the loading document has a different origin than the
7309 // previous document.
7310
7311 // We don't need to do anything if we haven't loaded a non-initial document.
7312 if (!GetBrowsingContext()->GetHasLoadedNonInitialDocument()) {
7313 return;
7314 }
7315
7316 // If we have an existing document, directly check the document prinicpals
7317 // with the new document to know if it is cross-origin.
7318 //
7319 // Note that there will be an issue of initial document handling in Fission
7320 // when running the WPT unset_context_name-1.html. In the test, the first
7321 // about:blank page would be loaded with the principal of the testing domain
7322 // in Fission and the window.name will be set there. Then, The window.name
7323 // won't be reset after navigating to the testing page because the principal
7324 // is the same. But, it won't be the case for non-Fission mode that the
7325 // first about:blank will be loaded with a null principal and the
7326 // window.name will be reset when loading the test page.
7327 if (mDoc && mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal())) {
7328 return;
7329 }
7330
7331 // If we don't have an existing document, and if it's not the initial
7332 // about:blank, we could be loading a document because of the
7333 // process-switching. In this case, this should be a cross-origin
7334 // navigation.
7335 } else if (!info->mForceMaybeResetName.ref()) {
7336 return;
7337 }
7338
7339 // Step 4.2.2 Store the window.name into all session history entries that have
7340 // the same origin as the previous document.
7341 nsDocShell::Cast(mDocShell)->StoreWindowNameToSHEntries();
7342
7343 // Step 4.2.3 Clear the window.name if the browsing context is the top-level
7344 // content and doesn't have an opener.
7345
7346 // We need to reset the window name in case of a cross-origin navigation,
7347 // without an opener.
7348 RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext();
7349 if (opener) {
7350 return;
7351 }
7352
7353 Unused << mBrowsingContext->SetName(EmptyString());
7354}
7355
7356nsGlobalWindowOuter::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
7357 BrowsingContext* aBC) {
7358 BrowsingContextGroup* group = aBC->Group();
7359 if (!group) {
7360 NS_ERROR(do { NS_DebugBreak(NS_DEBUG_ASSERTION, "nsGlobalWindowOuter::TemporarilyDisableDialogs called without a "
"browsing context group?", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7362); MOZ_PretendNoReturn(); } while (0)
7361 "nsGlobalWindowOuter::TemporarilyDisableDialogs called without a "do { NS_DebugBreak(NS_DEBUG_ASSERTION, "nsGlobalWindowOuter::TemporarilyDisableDialogs called without a "
"browsing context group?", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7362); MOZ_PretendNoReturn(); } while (0)
7362 "browsing context group?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "nsGlobalWindowOuter::TemporarilyDisableDialogs called without a "
"browsing context group?", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7362); MOZ_PretendNoReturn(); } while (0)
;
7363 return;
7364 }
7365
7366 if (group) {
7367 mGroup = group;
7368 mSavedDialogsEnabled = group->GetAreDialogsEnabled();
7369 group->SetAreDialogsEnabled(false);
7370 }
7371}
7372
7373nsGlobalWindowOuter::TemporarilyDisableDialogs::~TemporarilyDisableDialogs() {
7374 if (mGroup) {
7375 mGroup->SetAreDialogsEnabled(mSavedDialogsEnabled);
7376 }
7377}
7378
7379/* static */
7380already_AddRefed<nsGlobalWindowOuter> nsGlobalWindowOuter::Create(
7381 nsDocShell* aDocShell, bool aIsChrome) {
7382 uint64_t outerWindowID = aDocShell->GetOuterWindowID();
7383 RefPtr<nsGlobalWindowOuter> window = new nsGlobalWindowOuter(outerWindowID);
7384 if (aIsChrome) {
7385 window->mIsChrome = true;
7386 }
7387 window->SetDocShell(aDocShell);
7388
7389 window->InitWasOffline();
7390 return window.forget();
7391}
7392
7393nsIURI* nsPIDOMWindowOuter::GetDocumentURI() const {
7394 return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
7395}
7396
7397void nsPIDOMWindowOuter::MaybeCreateDoc() {
7398 MOZ_ASSERT(!mDoc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDoc)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(!mDoc))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("!mDoc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7398); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDoc" ")")
; do { *((volatile int*)__null) = 7398; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7399 if (nsIDocShell* docShell = GetDocShell()) {
7400 // Note that |document| here is the same thing as our mDoc, but we
7401 // don't have to explicitly set the member variable because the docshell
7402 // has already called SetNewDocument().
7403 nsCOMPtr<Document> document = docShell->GetDocument();
7404 Unused << document;
7405 }
7406}
7407
7408void nsPIDOMWindowOuter::SetChromeEventHandlerInternal(
7409 EventTarget* aChromeEventHandler) {
7410 // Out-of-line so we don't need to include ContentFrameMessageManager.h in
7411 // nsPIDOMWindow.h.
7412 mChromeEventHandler = aChromeEventHandler;
7413
7414 // mParentTarget and mMessageManager will be set when the next event is
7415 // dispatched or someone asks for our message manager.
7416 mParentTarget = nullptr;
7417 mMessageManager = nullptr;
7418}
7419
7420mozilla::dom::DocGroup* nsPIDOMWindowOuter::GetDocGroup() const {
7421 Document* doc = GetExtantDoc();
7422 if (doc) {
7423 return doc->GetDocGroup();
7424 }
7425 return nullptr;
7426}
7427
7428nsPIDOMWindowOuter::nsPIDOMWindowOuter(uint64_t aWindowID)
7429 : mFrameElement(nullptr),
7430 mModalStateDepth(0),
7431 mSuppressEventHandlingDepth(0),
7432 mIsBackground(false),
7433 mIsRootOuterWindow(false),
7434 mInnerWindow(nullptr),
7435 mWindowID(aWindowID),
7436 mMarkedCCGeneration(0) {}
7437
7438nsPIDOMWindowOuter::~nsPIDOMWindowOuter() = default;

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/dom/WindowFeatures.h

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#ifndef mozilla_dom_WindowFeatures_h
8#define mozilla_dom_WindowFeatures_h
9
10#include "nsString.h"
11#include "mozilla/Assertions.h" // MOZ_ASSERT
12#include "mozilla/HashTable.h" // mozilla::HashMap
13
14#include "nsStringFwd.h" // nsCString, nsACString, nsAutoCString, nsLiteralCString
15#include "nsTStringHasher.h" // mozilla::DefaultHasher<nsCString>
16
17namespace mozilla::dom {
18
19// Represents `tokenizedFeatures` in
20// https://html.spec.whatwg.org/multipage/window-object.html#concept-window-open-features-tokenize
21// with accessor methods for values.
22class WindowFeatures {
23 public:
24 WindowFeatures() = default;
25
26 WindowFeatures(const WindowFeatures& aOther) = delete;
27 WindowFeatures& operator=(const WindowFeatures& aOther) = delete;
28
29 WindowFeatures(WindowFeatures&& aOther) = delete;
30 WindowFeatures& operator=(WindowFeatures&& aOther) = delete;
31
32 // Tokenizes `aFeatures` and stores the result map in member field.
33 // This should be called at the begining, only once.
34 //
35 // Returns true if successfully tokenized, false otherwise.
36 bool Tokenize(const nsACString& aFeatures);
37
38 // Returns true if the `aName` feature is specified.
39 template <size_t N>
40 bool Exists(const char (&aName)[N]) const {
41 MOZ_ASSERT(IsLowerCase(aName))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsLowerCase(aName))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsLowerCase(aName)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("IsLowerCase(aName)"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/dom/WindowFeatures.h"
, 41); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsLowerCase(aName)"
")"); do { *((volatile int*)__null) = 41; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
42 nsLiteralCString name(aName);
43 return tokenizedFeatures_.has(name);
44 }
45
46 // Returns string value of `aName` feature.
47 // The feature must exist.
48 template <size_t N>
49 const nsCString& Get(const char (&aName)[N]) const {
50 MOZ_ASSERT(IsLowerCase(aName))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsLowerCase(aName))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsLowerCase(aName)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("IsLowerCase(aName)"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/dom/WindowFeatures.h"
, 50); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsLowerCase(aName)"
")"); do { *((volatile int*)__null) = 50; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
51 nsLiteralCString name(aName);
52 auto p = tokenizedFeatures_.lookup(name);
53 MOZ_ASSERT(p.found())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(p.found())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(p.found()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("p.found()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/dom/WindowFeatures.h"
, 53); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p.found()" ")"
); do { *((volatile int*)__null) = 53; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
54
55 return p->value();
56 }
57
58 // Returns integer value of `aName` feature.
59 // The feature must exist.
60 template <size_t N>
61 int32_t GetInt(const char (&aName)[N]) const {
62 const nsCString& value = Get(aName);
63 return ParseIntegerWithFallback(value);
64 }
65
66 // Returns bool value of `aName` feature.
67 // The feature must exist.
68 template <size_t N>
69 bool GetBool(const char (&aName)[N]) const {
70 const nsCString& value = Get(aName);
71 return ParseBool(value);
72 }
73
74 // Returns bool value of `aName` feature.
75 // If the feature doesn't exist, returns `aDefault`.
76 //
77 // If `aPresenceFlag` is provided and the feature exists, it's set to `true`.
78 // (note that the value isn't overwritten if the feature doesn't exist)
79 template <size_t N>
80 bool GetBoolWithDefault(const char (&aName)[N], bool aDefault,
81 bool* aPresenceFlag = nullptr) const {
82 MOZ_ASSERT(IsLowerCase(aName))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsLowerCase(aName))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsLowerCase(aName)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("IsLowerCase(aName)"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/dom/WindowFeatures.h"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsLowerCase(aName)"
")"); do { *((volatile int*)__null) = 82; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
83 nsLiteralCString name(aName);
84 auto p = tokenizedFeatures_.lookup(name);
85 if (p.found()) {
86 if (aPresenceFlag) {
87 *aPresenceFlag = true;
88 }
89 return ParseBool(p->value());
90 }
91 return aDefault;
92 }
93
94 // Remove the feature from the map.
95 template <size_t N>
96 void Remove(const char (&aName)[N]) {
97 MOZ_ASSERT(IsLowerCase(aName))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsLowerCase(aName))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsLowerCase(aName)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("IsLowerCase(aName)"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/dom/WindowFeatures.h"
, 97); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsLowerCase(aName)"
")"); do { *((volatile int*)__null) = 97; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
12
Assuming the condition is false
13
Taking false branch
14
Loop condition is false. Exiting loop
98 nsLiteralCString name(aName);
99 tokenizedFeatures_.remove(name);
15
Calling 'HashMap::remove'
100 }
101
102 // Returns true if there was no feature specified, or all features are
103 // removed by `Remove`.
104 //
105 // Note that this can be true even if `aFeatures` parameter of `Tokenize`
106 // is not empty, in case it contains no feature with non-empty name.
107 bool IsEmpty() const { return tokenizedFeatures_.empty(); }
108
109 // Stringify the map into `aOutput`.
110 // The result can be parsed again with `Tokenize`.
111 void Stringify(nsAutoCString& aOutput);
112
113 private:
114#ifdef DEBUG1
115 // Returns true if `text` does not contain any character that gets modified by
116 // `ToLowerCase`.
117 static bool IsLowerCase(const char* text);
118#endif
119
120 static int32_t ParseIntegerWithFallback(const nsCString& aValue);
121 static bool ParseBool(const nsCString& aValue);
122
123 // A map from feature name to feature value.
124 // If value is not provided, it's empty string.
125 mozilla::HashMap<nsCString, nsCString> tokenizedFeatures_;
126};
127
128} // namespace mozilla::dom
129
130#endif // #ifndef mozilla_dom_WindowFeatures_h

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7//---------------------------------------------------------------------------
8// Overview
9//---------------------------------------------------------------------------
10//
11// This file defines HashMap<Key, Value> and HashSet<T>, hash tables that are
12// fast and have a nice API.
13//
14// Both hash tables have two optional template parameters.
15//
16// - HashPolicy. This defines the operations for hashing and matching keys. The
17// default HashPolicy is appropriate when both of the following two
18// conditions are true.
19//
20// - The key type stored in the table (|Key| for |HashMap<Key, Value>|, |T|
21// for |HashSet<T>|) is an integer, pointer, UniquePtr, float, or double.
22//
23// - The type used for lookups (|Lookup|) is the same as the key type. This
24// is usually the case, but not always.
25//
26// There is also a |CStringHasher| policy for |char*| keys. If your keys
27// don't match any of the above cases, you must provide your own hash policy;
28// see the "Hash Policy" section below.
29//
30// - AllocPolicy. This defines how allocations are done by the table.
31//
32// - |MallocAllocPolicy| is the default and is usually appropriate; note that
33// operations (such as insertions) that might cause allocations are
34// fallible and must be checked for OOM. These checks are enforced by the
35// use of [[nodiscard]].
36//
37// - |InfallibleAllocPolicy| is another possibility; it allows the
38// abovementioned OOM checks to be done with MOZ_ALWAYS_TRUE().
39//
40// Note that entry storage allocation is lazy, and not done until the first
41// lookupForAdd(), put(), or putNew() is performed.
42//
43// See AllocPolicy.h for more details.
44//
45// Documentation on how to use HashMap and HashSet, including examples, is
46// present within those classes. Search for "class HashMap" and "class
47// HashSet".
48//
49// Both HashMap and HashSet are implemented on top of a third class, HashTable.
50// You only need to look at HashTable if you want to understand the
51// implementation.
52//
53// How does mozilla::HashTable (this file) compare with PLDHashTable (and its
54// subclasses, such as nsTHashtable)?
55//
56// - mozilla::HashTable is a lot faster, largely because it uses templates
57// throughout *and* inlines everything. PLDHashTable inlines operations much
58// less aggressively, and also uses "virtual ops" for operations like hashing
59// and matching entries that require function calls.
60//
61// - Correspondingly, mozilla::HashTable use is likely to increase executable
62// size much more than PLDHashTable.
63//
64// - mozilla::HashTable has a nicer API, with a proper HashSet vs. HashMap
65// distinction.
66//
67// - mozilla::HashTable requires more explicit OOM checking. As mentioned
68// above, the use of |InfallibleAllocPolicy| can simplify things.
69//
70// - mozilla::HashTable has a default capacity on creation of 32 and a minimum
71// capacity of 4. PLDHashTable has a default capacity on creation of 8 and a
72// minimum capacity of 8.
73
74#ifndef mozilla_HashTable_h
75#define mozilla_HashTable_h
76
77#include <utility>
78#include <type_traits>
79
80#include "mozilla/AllocPolicy.h"
81#include "mozilla/Assertions.h"
82#include "mozilla/Attributes.h"
83#include "mozilla/Casting.h"
84#include "mozilla/HashFunctions.h"
85#include "mozilla/MathAlgorithms.h"
86#include "mozilla/Maybe.h"
87#include "mozilla/MemoryChecking.h"
88#include "mozilla/MemoryReporting.h"
89#include "mozilla/Opaque.h"
90#include "mozilla/OperatorNewExtensions.h"
91#include "mozilla/ReentrancyGuard.h"
92#include "mozilla/UniquePtr.h"
93#include "mozilla/WrappingOperations.h"
94
95namespace mozilla {
96
97template <class, class = void>
98struct DefaultHasher;
99
100template <class, class>
101class HashMapEntry;
102
103namespace detail {
104
105template <typename T>
106class HashTableEntry;
107
108template <class T, class HashPolicy, class AllocPolicy>
109class HashTable;
110
111} // namespace detail
112
113// The "generation" of a hash table is an opaque value indicating the state of
114// modification of the hash table through its lifetime. If the generation of
115// a hash table compares equal at times T1 and T2, then lookups in the hash
116// table, pointers to (or into) hash table entries, etc. at time T1 are valid
117// at time T2. If the generation compares unequal, these computations are all
118// invalid and must be performed again to be used.
119//
120// Generations are meaningfully comparable only with respect to a single hash
121// table. It's always nonsensical to compare the generation of distinct hash
122// tables H1 and H2.
123using Generation = Opaque<uint64_t>;
124
125//---------------------------------------------------------------------------
126// HashMap
127//---------------------------------------------------------------------------
128
129// HashMap is a fast hash-based map from keys to values.
130//
131// Template parameter requirements:
132// - Key/Value: movable, destructible, assignable.
133// - HashPolicy: see the "Hash Policy" section below.
134// - AllocPolicy: see AllocPolicy.h.
135//
136// Note:
137// - HashMap is not reentrant: Key/Value/HashPolicy/AllocPolicy members
138// called by HashMap must not call back into the same HashMap object.
139//
140template <class Key, class Value, class HashPolicy = DefaultHasher<Key>,
141 class AllocPolicy = MallocAllocPolicy>
142class HashMap {
143 // -- Implementation details -----------------------------------------------
144
145 // HashMap is not copyable or assignable.
146 HashMap(const HashMap& hm) = delete;
147 HashMap& operator=(const HashMap& hm) = delete;
148
149 using TableEntry = HashMapEntry<Key, Value>;
150
151 struct MapHashPolicy : HashPolicy {
152 using Base = HashPolicy;
153 using KeyType = Key;
154
155 static const Key& getKey(TableEntry& aEntry) { return aEntry.key(); }
156
157 static void setKey(TableEntry& aEntry, Key& aKey) {
158 HashPolicy::rekey(aEntry.mutableKey(), aKey);
159 }
160 };
161
162 using Impl = detail::HashTable<TableEntry, MapHashPolicy, AllocPolicy>;
163 Impl mImpl;
164
165 friend class Impl::Enum;
166
167 public:
168 using Lookup = typename HashPolicy::Lookup;
169 using Entry = TableEntry;
170
171 // -- Initialization -------------------------------------------------------
172
173 explicit HashMap(AllocPolicy aAllocPolicy = AllocPolicy(),
174 uint32_t aLen = Impl::sDefaultLen)
175 : mImpl(std::move(aAllocPolicy), aLen) {}
176
177 explicit HashMap(uint32_t aLen) : mImpl(AllocPolicy(), aLen) {}
178
179 // HashMap is movable.
180 HashMap(HashMap&& aRhs) = default;
181 HashMap& operator=(HashMap&& aRhs) = default;
182
183 // Swap the contents of this hash map with another.
184 void swap(HashMap& aOther) { mImpl.swap(aOther.mImpl); }
185
186 // -- Status and sizing ----------------------------------------------------
187
188 // The map's current generation.
189 Generation generation() const { return mImpl.generation(); }
190
191 // Is the map empty?
192 bool empty() const { return mImpl.empty(); }
193
194 // Number of keys/values in the map.
195 uint32_t count() const { return mImpl.count(); }
196
197 // Number of key/value slots in the map. Note: resize will happen well before
198 // count() == capacity().
199 uint32_t capacity() const { return mImpl.capacity(); }
200
201 // The size of the map's entry storage, in bytes. If the keys/values contain
202 // pointers to other heap blocks, you must iterate over the map and measure
203 // them separately; hence the "shallow" prefix.
204 size_t shallowSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
205 return mImpl.shallowSizeOfExcludingThis(aMallocSizeOf);
206 }
207 size_t shallowSizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
208 return aMallocSizeOf(this) +
209 mImpl.shallowSizeOfExcludingThis(aMallocSizeOf);
210 }
211
212 // Attempt to minimize the capacity(). If the table is empty, this will free
213 // the empty storage and upon regrowth it will be given the minimum capacity.
214 void compact() { mImpl.compact(); }
215
216 // Attempt to reserve enough space to fit at least |aLen| elements. This is
217 // total capacity, including elements already present. Does nothing if the
218 // map already has sufficient capacity.
219 [[nodiscard]] bool reserve(uint32_t aLen) { return mImpl.reserve(aLen); }
220
221 // -- Lookups --------------------------------------------------------------
222
223 // Does the map contain a key/value matching |aLookup|?
224 bool has(const Lookup& aLookup) const {
225 return mImpl.lookup(aLookup).found();
226 }
227
228 // Return a Ptr indicating whether a key/value matching |aLookup| is
229 // present in the map. E.g.:
230 //
231 // using HM = HashMap<int,char>;
232 // HM h;
233 // if (HM::Ptr p = h.lookup(3)) {
234 // assert(p->key() == 3);
235 // char val = p->value();
236 // }
237 //
238 using Ptr = typename Impl::Ptr;
239 MOZ_ALWAYS_INLINEinline Ptr lookup(const Lookup& aLookup) const {
240 return mImpl.lookup(aLookup);
17
Calling 'HashTable::lookup'
27
Returning from 'HashTable::lookup'
241 }
242
243 // Like lookup(), but does not assert if two threads call it at the same
244 // time. Only use this method when none of the threads will modify the map.
245 MOZ_ALWAYS_INLINEinline Ptr readonlyThreadsafeLookup(const Lookup& aLookup) const {
246 return mImpl.readonlyThreadsafeLookup(aLookup);
247 }
248
249 // -- Insertions -----------------------------------------------------------
250
251 // Overwrite existing value with |aValue|, or add it if not present. Returns
252 // false on OOM.
253 template <typename KeyInput, typename ValueInput>
254 [[nodiscard]] bool put(KeyInput&& aKey, ValueInput&& aValue) {
255 return put(aKey, std::forward<KeyInput>(aKey),
256 std::forward<ValueInput>(aValue));
257 }
258
259 template <typename KeyInput, typename ValueInput>
260 [[nodiscard]] bool put(const Lookup& aLookup, KeyInput&& aKey,
261 ValueInput&& aValue) {
262 AddPtr p = lookupForAdd(aLookup);
263 if (p) {
264 p->value() = std::forward<ValueInput>(aValue);
265 return true;
266 }
267 return add(p, std::forward<KeyInput>(aKey),
268 std::forward<ValueInput>(aValue));
269 }
270
271 // Like put(), but slightly faster. Must only be used when the given key is
272 // not already present. (In debug builds, assertions check this.)
273 template <typename KeyInput, typename ValueInput>
274 [[nodiscard]] bool putNew(KeyInput&& aKey, ValueInput&& aValue) {
275 return mImpl.putNew(aKey, std::forward<KeyInput>(aKey),
276 std::forward<ValueInput>(aValue));
277 }
278
279 template <typename KeyInput, typename ValueInput>
280 [[nodiscard]] bool putNew(const Lookup& aLookup, KeyInput&& aKey,
281 ValueInput&& aValue) {
282 return mImpl.putNew(aLookup, std::forward<KeyInput>(aKey),
283 std::forward<ValueInput>(aValue));
284 }
285
286 // Like putNew(), but should be only used when the table is known to be big
287 // enough for the insertion, and hashing cannot fail. Typically this is used
288 // to populate an empty map with known-unique keys after reserving space with
289 // reserve(), e.g.
290 //
291 // using HM = HashMap<int,char>;
292 // HM h;
293 // if (!h.reserve(3)) {
294 // MOZ_CRASH("OOM");
295 // }
296 // h.putNewInfallible(1, 'a'); // unique key
297 // h.putNewInfallible(2, 'b'); // unique key
298 // h.putNewInfallible(3, 'c'); // unique key
299 //
300 template <typename KeyInput, typename ValueInput>
301 void putNewInfallible(KeyInput&& aKey, ValueInput&& aValue) {
302 mImpl.putNewInfallible(aKey, std::forward<KeyInput>(aKey),
303 std::forward<ValueInput>(aValue));
304 }
305
306 // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient
307 // insertion of Key |k| (where |HashPolicy::match(k,l) == true|) using
308 // |add(p,k,v)|. After |add(p,k,v)|, |p| points to the new key/value. E.g.:
309 //
310 // using HM = HashMap<int,char>;
311 // HM h;
312 // HM::AddPtr p = h.lookupForAdd(3);
313 // if (!p) {
314 // if (!h.add(p, 3, 'a')) {
315 // return false;
316 // }
317 // }
318 // assert(p->key() == 3);
319 // char val = p->value();
320 //
321 // N.B. The caller must ensure that no mutating hash table operations occur
322 // between a pair of lookupForAdd() and add() calls. To avoid looking up the
323 // key a second time, the caller may use the more efficient relookupOrAdd()
324 // method. This method reuses part of the hashing computation to more
325 // efficiently insert the key if it has not been added. For example, a
326 // mutation-handling version of the previous example:
327 //
328 // HM::AddPtr p = h.lookupForAdd(3);
329 // if (!p) {
330 // call_that_may_mutate_h();
331 // if (!h.relookupOrAdd(p, 3, 'a')) {
332 // return false;
333 // }
334 // }
335 // assert(p->key() == 3);
336 // char val = p->value();
337 //
338 using AddPtr = typename Impl::AddPtr;
339 MOZ_ALWAYS_INLINEinline AddPtr lookupForAdd(const Lookup& aLookup) {
340 return mImpl.lookupForAdd(aLookup);
341 }
342
343 // Add a key/value. Returns false on OOM.
344 template <typename KeyInput, typename ValueInput>
345 [[nodiscard]] bool add(AddPtr& aPtr, KeyInput&& aKey, ValueInput&& aValue) {
346 return mImpl.add(aPtr, std::forward<KeyInput>(aKey),
347 std::forward<ValueInput>(aValue));
348 }
349
350 // See the comment above lookupForAdd() for details.
351 template <typename KeyInput, typename ValueInput>
352 [[nodiscard]] bool relookupOrAdd(AddPtr& aPtr, KeyInput&& aKey,
353 ValueInput&& aValue) {
354 return mImpl.relookupOrAdd(aPtr, aKey, std::forward<KeyInput>(aKey),
355 std::forward<ValueInput>(aValue));
356 }
357
358 // -- Removal --------------------------------------------------------------
359
360 // Lookup and remove the key/value matching |aLookup|, if present.
361 void remove(const Lookup& aLookup) {
362 if (Ptr p = lookup(aLookup)) {
16
Calling 'HashMap::lookup'
28
Returning from 'HashMap::lookup'
29
'p' initialized here
30
Assuming the condition is true
31
Taking true branch
363 remove(p);
32
Value assigned to 'aPtr'
33
Null pointer value stored to 'aPtr.mSlot.mKeyHash'
34
Calling 'HashMap::remove'
364 }
365 }
366
367 // Remove a previously found key/value (assuming aPtr.found()). The map must
368 // not have been mutated in the interim.
369 void remove(Ptr aPtr) { mImpl.remove(aPtr); }
35
Null pointer value stored to 'aPtr.mSlot.mKeyHash'
36
Calling 'HashTable::remove'
370
371 // Remove all keys/values without changing the capacity.
372 void clear() { mImpl.clear(); }
373
374 // Like clear() followed by compact().
375 void clearAndCompact() { mImpl.clearAndCompact(); }
376
377 // -- Rekeying -------------------------------------------------------------
378
379 // Infallibly rekey one entry, if necessary. Requires that template
380 // parameters Key and HashPolicy::Lookup are the same type.
381 void rekeyIfMoved(const Key& aOldKey, const Key& aNewKey) {
382 if (aOldKey != aNewKey) {
383 rekeyAs(aOldKey, aNewKey, aNewKey);
384 }
385 }
386
387 // Infallibly rekey one entry if present, and return whether that happened.
388 bool rekeyAs(const Lookup& aOldLookup, const Lookup& aNewLookup,
389 const Key& aNewKey) {
390 if (Ptr p = lookup(aOldLookup)) {
391 mImpl.rekeyAndMaybeRehash(p, aNewLookup, aNewKey);
392 return true;
393 }
394 return false;
395 }
396
397 // -- Iteration ------------------------------------------------------------
398
399 // |iter()| returns an Iterator:
400 //
401 // HashMap<int, char> h;
402 // for (auto iter = h.iter(); !iter.done(); iter.next()) {
403 // char c = iter.get().value();
404 // }
405 //
406 using Iterator = typename Impl::Iterator;
407 Iterator iter() const { return mImpl.iter(); }
408
409 // |modIter()| returns a ModIterator:
410 //
411 // HashMap<int, char> h;
412 // for (auto iter = h.modIter(); !iter.done(); iter.next()) {
413 // if (iter.get().value() == 'l') {
414 // iter.remove();
415 // }
416 // }
417 //
418 // Table resize may occur in ModIterator's destructor.
419 using ModIterator = typename Impl::ModIterator;
420 ModIterator modIter() { return mImpl.modIter(); }
421
422 // These are similar to Iterator/ModIterator/iter(), but use different
423 // terminology.
424 using Range = typename Impl::Range;
425 using Enum = typename Impl::Enum;
426 Range all() const { return mImpl.all(); }
427};
428
429//---------------------------------------------------------------------------
430// HashSet
431//---------------------------------------------------------------------------
432
433// HashSet is a fast hash-based set of values.
434//
435// Template parameter requirements:
436// - T: movable, destructible, assignable.
437// - HashPolicy: see the "Hash Policy" section below.
438// - AllocPolicy: see AllocPolicy.h
439//
440// Note:
441// - HashSet is not reentrant: T/HashPolicy/AllocPolicy members called by
442// HashSet must not call back into the same HashSet object.
443//
444template <class T, class HashPolicy = DefaultHasher<T>,
445 class AllocPolicy = MallocAllocPolicy>
446class HashSet {
447 // -- Implementation details -----------------------------------------------
448
449 // HashSet is not copyable or assignable.
450 HashSet(const HashSet& hs) = delete;
451 HashSet& operator=(const HashSet& hs) = delete;
452
453 struct SetHashPolicy : HashPolicy {
454 using Base = HashPolicy;
455 using KeyType = T;
456
457 static const KeyType& getKey(const T& aT) { return aT; }
458
459 static void setKey(T& aT, KeyType& aKey) { HashPolicy::rekey(aT, aKey); }
460 };
461
462 using Impl = detail::HashTable<const T, SetHashPolicy, AllocPolicy>;
463 Impl mImpl;
464
465 friend class Impl::Enum;
466
467 public:
468 using Lookup = typename HashPolicy::Lookup;
469 using Entry = T;
470
471 // -- Initialization -------------------------------------------------------
472
473 explicit HashSet(AllocPolicy aAllocPolicy = AllocPolicy(),
474 uint32_t aLen = Impl::sDefaultLen)
475 : mImpl(std::move(aAllocPolicy), aLen) {}
476
477 explicit HashSet(uint32_t aLen) : mImpl(AllocPolicy(), aLen) {}
478
479 // HashSet is movable.
480 HashSet(HashSet&& aRhs) = default;
481 HashSet& operator=(HashSet&& aRhs) = default;
482
483 // Swap the contents of this hash set with another.
484 void swap(HashSet& aOther) { mImpl.swap(aOther.mImpl); }
485
486 // -- Status and sizing ----------------------------------------------------
487
488 // The set's current generation.
489 Generation generation() const { return mImpl.generation(); }
490
491 // Is the set empty?
492 bool empty() const { return mImpl.empty(); }
493
494 // Number of elements in the set.
495 uint32_t count() const { return mImpl.count(); }
496
497 // Number of element slots in the set. Note: resize will happen well before
498 // count() == capacity().
499 uint32_t capacity() const { return mImpl.capacity(); }
500
501 // The size of the set's entry storage, in bytes. If the elements contain
502 // pointers to other heap blocks, you must iterate over the set and measure
503 // them separately; hence the "shallow" prefix.
504 size_t shallowSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
505 return mImpl.shallowSizeOfExcludingThis(aMallocSizeOf);
506 }
507 size_t shallowSizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
508 return aMallocSizeOf(this) +
509 mImpl.shallowSizeOfExcludingThis(aMallocSizeOf);
510 }
511
512 // Attempt to minimize the capacity(). If the table is empty, this will free
513 // the empty storage and upon regrowth it will be given the minimum capacity.
514 void compact() { mImpl.compact(); }
515
516 // Attempt to reserve enough space to fit at least |aLen| elements. This is
517 // total capacity, including elements already present. Does nothing if the
518 // map already has sufficient capacity.
519 [[nodiscard]] bool reserve(uint32_t aLen) { return mImpl.reserve(aLen); }
520
521 // -- Lookups --------------------------------------------------------------
522
523 // Does the set contain an element matching |aLookup|?
524 bool has(const Lookup& aLookup) const {
525 return mImpl.lookup(aLookup).found();
526 }
527
528 // Return a Ptr indicating whether an element matching |aLookup| is present
529 // in the set. E.g.:
530 //
531 // using HS = HashSet<int>;
532 // HS h;
533 // if (HS::Ptr p = h.lookup(3)) {
534 // assert(*p == 3); // p acts like a pointer to int
535 // }
536 //
537 using Ptr = typename Impl::Ptr;
538 MOZ_ALWAYS_INLINEinline Ptr lookup(const Lookup& aLookup) const {
539 return mImpl.lookup(aLookup);
540 }
541
542 // Like lookup(), but does not assert if two threads call it at the same
543 // time. Only use this method when none of the threads will modify the set.
544 MOZ_ALWAYS_INLINEinline Ptr readonlyThreadsafeLookup(const Lookup& aLookup) const {
545 return mImpl.readonlyThreadsafeLookup(aLookup);
546 }
547
548 // -- Insertions -----------------------------------------------------------
549
550 // Add |aU| if it is not present already. Returns false on OOM.
551 template <typename U>
552 [[nodiscard]] bool put(U&& aU) {
553 AddPtr p = lookupForAdd(aU);
554 return p ? true : add(p, std::forward<U>(aU));
555 }
556
557 // Like put(), but slightly faster. Must only be used when the given element
558 // is not already present. (In debug builds, assertions check this.)
559 template <typename U>
560 [[nodiscard]] bool putNew(U&& aU) {
561 return mImpl.putNew(aU, std::forward<U>(aU));
562 }
563
564 // Like the other putNew(), but for when |Lookup| is different to |T|.
565 template <typename U>
566 [[nodiscard]] bool putNew(const Lookup& aLookup, U&& aU) {
567 return mImpl.putNew(aLookup, std::forward<U>(aU));
568 }
569
570 // Like putNew(), but should be only used when the table is known to be big
571 // enough for the insertion, and hashing cannot fail. Typically this is used
572 // to populate an empty set with known-unique elements after reserving space
573 // with reserve(), e.g.
574 //
575 // using HS = HashMap<int>;
576 // HS h;
577 // if (!h.reserve(3)) {
578 // MOZ_CRASH("OOM");
579 // }
580 // h.putNewInfallible(1); // unique element
581 // h.putNewInfallible(2); // unique element
582 // h.putNewInfallible(3); // unique element
583 //
584 template <typename U>
585 void putNewInfallible(const Lookup& aLookup, U&& aU) {
586 mImpl.putNewInfallible(aLookup, std::forward<U>(aU));
587 }
588
589 // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient
590 // insertion of T value |t| (where |HashPolicy::match(t,l) == true|) using
591 // |add(p,t)|. After |add(p,t)|, |p| points to the new element. E.g.:
592 //
593 // using HS = HashSet<int>;
594 // HS h;
595 // HS::AddPtr p = h.lookupForAdd(3);
596 // if (!p) {
597 // if (!h.add(p, 3)) {
598 // return false;
599 // }
600 // }
601 // assert(*p == 3); // p acts like a pointer to int
602 //
603 // N.B. The caller must ensure that no mutating hash table operations occur
604 // between a pair of lookupForAdd() and add() calls. To avoid looking up the
605 // key a second time, the caller may use the more efficient relookupOrAdd()
606 // method. This method reuses part of the hashing computation to more
607 // efficiently insert the key if it has not been added. For example, a
608 // mutation-handling version of the previous example:
609 //
610 // HS::AddPtr p = h.lookupForAdd(3);
611 // if (!p) {
612 // call_that_may_mutate_h();
613 // if (!h.relookupOrAdd(p, 3, 3)) {
614 // return false;
615 // }
616 // }
617 // assert(*p == 3);
618 //
619 // Note that relookupOrAdd(p,l,t) performs Lookup using |l| and adds the
620 // entry |t|, where the caller ensures match(l,t).
621 using AddPtr = typename Impl::AddPtr;
622 MOZ_ALWAYS_INLINEinline AddPtr lookupForAdd(const Lookup& aLookup) {
623 return mImpl.lookupForAdd(aLookup);
624 }
625
626 // Add an element. Returns false on OOM.
627 template <typename U>
628 [[nodiscard]] bool add(AddPtr& aPtr, U&& aU) {
629 return mImpl.add(aPtr, std::forward<U>(aU));
630 }
631
632 // See the comment above lookupForAdd() for details.
633 template <typename U>
634 [[nodiscard]] bool relookupOrAdd(AddPtr& aPtr, const Lookup& aLookup,
635 U&& aU) {
636 return mImpl.relookupOrAdd(aPtr, aLookup, std::forward<U>(aU));
637 }
638
639 // -- Removal --------------------------------------------------------------
640
641 // Lookup and remove the element matching |aLookup|, if present.
642 void remove(const Lookup& aLookup) {
643 if (Ptr p = lookup(aLookup)) {
644 remove(p);
645 }
646 }
647
648 // Remove a previously found element (assuming aPtr.found()). The set must
649 // not have been mutated in the interim.
650 void remove(Ptr aPtr) { mImpl.remove(aPtr); }
651
652 // Remove all keys/values without changing the capacity.
653 void clear() { mImpl.clear(); }
654
655 // Like clear() followed by compact().
656 void clearAndCompact() { mImpl.clearAndCompact(); }
657
658 // -- Rekeying -------------------------------------------------------------
659
660 // Infallibly rekey one entry, if present. Requires that template parameters
661 // T and HashPolicy::Lookup are the same type.
662 void rekeyIfMoved(const Lookup& aOldValue, const T& aNewValue) {
663 if (aOldValue != aNewValue) {
664 rekeyAs(aOldValue, aNewValue, aNewValue);
665 }
666 }
667
668 // Infallibly rekey one entry if present, and return whether that happened.
669 bool rekeyAs(const Lookup& aOldLookup, const Lookup& aNewLookup,
670 const T& aNewValue) {
671 if (Ptr p = lookup(aOldLookup)) {
672 mImpl.rekeyAndMaybeRehash(p, aNewLookup, aNewValue);
673 return true;
674 }
675 return false;
676 }
677
678 // Infallibly replace the current key at |aPtr| with an equivalent key.
679 // Specifically, both HashPolicy::hash and HashPolicy::match must return
680 // identical results for the new and old key when applied against all
681 // possible matching values.
682 void replaceKey(Ptr aPtr, const Lookup& aLookup, const T& aNewValue) {
683 MOZ_ASSERT(aPtr.found())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPtr.found())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPtr.found()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPtr.found()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 683); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.found()"
")"); do { *((volatile int*)__null) = 683; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
684 MOZ_ASSERT(*aPtr != aNewValue)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aPtr != aNewValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aPtr != aNewValue))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("*aPtr != aNewValue"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aPtr != aNewValue"
")"); do { *((volatile int*)__null) = 684; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
685 MOZ_ASSERT(HashPolicy::match(*aPtr, aLookup))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(HashPolicy::match(*aPtr, aLookup))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(HashPolicy::match(*aPtr, aLookup
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("HashPolicy::match(*aPtr, aLookup)", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 685); AnnotateMozCrashReason("MOZ_ASSERT" "(" "HashPolicy::match(*aPtr, aLookup)"
")"); do { *((volatile int*)__null) = 685; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
686 MOZ_ASSERT(HashPolicy::match(aNewValue, aLookup))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(HashPolicy::match(aNewValue, aLookup))>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(HashPolicy::match(aNewValue, aLookup)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("HashPolicy::match(aNewValue, aLookup)"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "HashPolicy::match(aNewValue, aLookup)"
")"); do { *((volatile int*)__null) = 686; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
687 const_cast<T&>(*aPtr) = aNewValue;
688 MOZ_ASSERT(*lookup(aLookup) == aNewValue)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*lookup(aLookup) == aNewValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*lookup(aLookup) == aNewValue
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"*lookup(aLookup) == aNewValue", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 688); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*lookup(aLookup) == aNewValue"
")"); do { *((volatile int*)__null) = 688; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
689 }
690 void replaceKey(Ptr aPtr, const T& aNewValue) {
691 replaceKey(aPtr, aNewValue, aNewValue);
692 }
693
694 // -- Iteration ------------------------------------------------------------
695
696 // |iter()| returns an Iterator:
697 //
698 // HashSet<int> h;
699 // for (auto iter = h.iter(); !iter.done(); iter.next()) {
700 // int i = iter.get();
701 // }
702 //
703 using Iterator = typename Impl::Iterator;
704 Iterator iter() const { return mImpl.iter(); }
705
706 // |modIter()| returns a ModIterator:
707 //
708 // HashSet<int> h;
709 // for (auto iter = h.modIter(); !iter.done(); iter.next()) {
710 // if (iter.get() == 42) {
711 // iter.remove();
712 // }
713 // }
714 //
715 // Table resize may occur in ModIterator's destructor.
716 using ModIterator = typename Impl::ModIterator;
717 ModIterator modIter() { return mImpl.modIter(); }
718
719 // These are similar to Iterator/ModIterator/iter(), but use different
720 // terminology.
721 using Range = typename Impl::Range;
722 using Enum = typename Impl::Enum;
723 Range all() const { return mImpl.all(); }
724};
725
726//---------------------------------------------------------------------------
727// Hash Policy
728//---------------------------------------------------------------------------
729
730// A hash policy |HP| for a hash table with key-type |Key| must provide:
731//
732// - a type |HP::Lookup| to use to lookup table entries;
733//
734// - a static member function |HP::hash| that hashes lookup values:
735//
736// static mozilla::HashNumber hash(const Lookup&);
737//
738// - a static member function |HP::match| that tests equality of key and
739// lookup values:
740//
741// static bool match(const Key& aKey, const Lookup& aLookup);
742//
743// |aKey| and |aLookup| can have different hash numbers, only when a
744// collision happens with |prepareHash| operation, which is less frequent.
745// Thus, |HP::match| shouldn't assume the hash equality in the comparison,
746// even if the hash numbers are almost always same between them.
747//
748// Normally, Lookup = Key. In general, though, different values and types of
749// values can be used to lookup and store. If a Lookup value |l| is not equal
750// to the added Key value |k|, the user must ensure that |HP::match(k,l)| is
751// true. E.g.:
752//
753// mozilla::HashSet<Key, HP>::AddPtr p = h.lookup(l);
754// if (!p) {
755// assert(HP::match(k, l)); // must hold
756// h.add(p, k);
757// }
758
759// A pointer hashing policy that uses HashGeneric() to create good hashes for
760// pointers. Note that we don't shift out the lowest k bits because we don't
761// want to assume anything about the alignment of the pointers.
762template <typename Key>
763struct PointerHasher {
764 using Lookup = Key;
765
766 static HashNumber hash(const Lookup& aLookup) { return HashGeneric(aLookup); }
767
768 static bool match(const Key& aKey, const Lookup& aLookup) {
769 return aKey == aLookup;
770 }
771
772 static void rekey(Key& aKey, const Key& aNewKey) { aKey = aNewKey; }
773};
774
775// The default hash policy, which only works with integers.
776template <class Key, typename>
777struct DefaultHasher {
778 using Lookup = Key;
779
780 static HashNumber hash(const Lookup& aLookup) {
781 // Just convert the integer to a HashNumber and use that as is. (This
782 // discards the high 32-bits of 64-bit integers!) ScrambleHashCode() is
783 // subsequently called on the value to improve the distribution.
784 return aLookup;
785 }
786
787 static bool match(const Key& aKey, const Lookup& aLookup) {
788 // Use builtin or overloaded operator==.
789 return aKey == aLookup;
790 }
791
792 static void rekey(Key& aKey, const Key& aNewKey) { aKey = aNewKey; }
793};
794
795// A DefaultHasher specialization for enums.
796template <class T>
797struct DefaultHasher<T, std::enable_if_t<std::is_enum_v<T>>> {
798 using Key = T;
799 using Lookup = Key;
800
801 static HashNumber hash(const Lookup& aLookup) { return HashGeneric(aLookup); }
802
803 static bool match(const Key& aKey, const Lookup& aLookup) {
804 // Use builtin or overloaded operator==.
805 return aKey == static_cast<Key>(aLookup);
806 }
807
808 static void rekey(Key& aKey, const Key& aNewKey) { aKey = aNewKey; }
809};
810
811// A DefaultHasher specialization for pointers.
812template <class T>
813struct DefaultHasher<T*> : PointerHasher<T*> {};
814
815// A DefaultHasher specialization for mozilla::UniquePtr.
816template <class T, class D>
817struct DefaultHasher<UniquePtr<T, D>> {
818 using Key = UniquePtr<T, D>;
819 using Lookup = Key;
820 using PtrHasher = PointerHasher<T*>;
821
822 static HashNumber hash(const Lookup& aLookup) {
823 return PtrHasher::hash(aLookup.get());
824 }
825
826 static bool match(const Key& aKey, const Lookup& aLookup) {
827 return PtrHasher::match(aKey.get(), aLookup.get());
828 }
829
830 static void rekey(UniquePtr<T, D>& aKey, UniquePtr<T, D>&& aNewKey) {
831 aKey = std::move(aNewKey);
832 }
833};
834
835// A DefaultHasher specialization for doubles.
836template <>
837struct DefaultHasher<double> {
838 using Key = double;
839 using Lookup = Key;
840
841 static HashNumber hash(const Lookup& aLookup) {
842 // Just xor the high bits with the low bits, and then treat the bits of the
843 // result as a uint32_t.
844 static_assert(sizeof(HashNumber) == 4,
845 "subsequent code assumes a four-byte hash");
846 uint64_t u = BitwiseCast<uint64_t>(aLookup);
847 return HashNumber(u ^ (u >> 32));
848 }
849
850 static bool match(const Key& aKey, const Lookup& aLookup) {
851 return BitwiseCast<uint64_t>(aKey) == BitwiseCast<uint64_t>(aLookup);
852 }
853};
854
855// A DefaultHasher specialization for floats.
856template <>
857struct DefaultHasher<float> {
858 using Key = float;
859 using Lookup = Key;
860
861 static HashNumber hash(const Lookup& aLookup) {
862 // Just use the value as if its bits form an integer. ScrambleHashCode() is
863 // subsequently called on the value to improve the distribution.
864 static_assert(sizeof(HashNumber) == 4,
865 "subsequent code assumes a four-byte hash");
866 return HashNumber(BitwiseCast<uint32_t>(aLookup));
867 }
868
869 static bool match(const Key& aKey, const Lookup& aLookup) {
870 return BitwiseCast<uint32_t>(aKey) == BitwiseCast<uint32_t>(aLookup);
871 }
872};
873
874// A hash policy for C strings.
875struct CStringHasher {
876 using Key = const char*;
877 using Lookup = const char*;
878
879 static HashNumber hash(const Lookup& aLookup) { return HashString(aLookup); }
880
881 static bool match(const Key& aKey, const Lookup& aLookup) {
882 return strcmp(aKey, aLookup) == 0;
883 }
884};
885
886//---------------------------------------------------------------------------
887// Fallible Hashing Interface
888//---------------------------------------------------------------------------
889
890// Most of the time generating a hash code is infallible, but sometimes it is
891// necessary to generate hash codes on demand in a way that can fail. Specialize
892// this class for your own hash policy to provide fallible hashing.
893//
894// This is used by MovableCellHasher to handle the fact that generating a unique
895// ID for cell pointer may fail due to OOM.
896//
897// The default implementations of these methods delegate to the usual HashPolicy
898// implementation and always succeed.
899template <typename HashPolicy>
900struct FallibleHashMethods {
901 // Return true if a hashcode is already available for its argument, and
902 // sets |aHashOut|. Once this succeeds for a specific argument it
903 // must continue to do so.
904 //
905 // Return false if a hashcode is not already available. This implies that any
906 // lookup must fail, as the hash code would have to have been successfully
907 // created on insertion.
908 template <typename Lookup>
909 static bool maybeGetHash(Lookup&& aLookup, HashNumber* aHashOut) {
910 *aHashOut = HashPolicy::hash(aLookup);
911 return true;
912 }
913
914 // Fallible method to ensure a hashcode exists for its argument and create one
915 // if not. Sets |aHashOut| to the hashcode and retuns true on success. Returns
916 // false on error, e.g. out of memory.
917 template <typename Lookup>
918 static bool ensureHash(Lookup&& aLookup, HashNumber* aHashOut) {
919 *aHashOut = HashPolicy::hash(aLookup);
920 return true;
921 }
922};
923
924template <typename HashPolicy, typename Lookup>
925static bool MaybeGetHash(Lookup&& aLookup, HashNumber* aHashOut) {
926 return FallibleHashMethods<typename HashPolicy::Base>::maybeGetHash(
927 std::forward<Lookup>(aLookup), aHashOut);
928}
929
930template <typename HashPolicy, typename Lookup>
931static bool EnsureHash(Lookup&& aLookup, HashNumber* aHashOut) {
932 return FallibleHashMethods<typename HashPolicy::Base>::ensureHash(
933 std::forward<Lookup>(aLookup), aHashOut);
934}
935
936//---------------------------------------------------------------------------
937// Implementation Details (HashMapEntry, HashTableEntry, HashTable)
938//---------------------------------------------------------------------------
939
940// Both HashMap and HashSet are implemented by a single HashTable that is even
941// more heavily parameterized than the other two. This leaves HashTable gnarly
942// and extremely coupled to HashMap and HashSet; thus code should not use
943// HashTable directly.
944
945template <class Key, class Value>
946class HashMapEntry {
947 Key key_;
948 Value value_;
949
950 template <class, class, class>
951 friend class detail::HashTable;
952 template <class>
953 friend class detail::HashTableEntry;
954 template <class, class, class, class>
955 friend class HashMap;
956
957 public:
958 template <typename KeyInput, typename ValueInput>
959 HashMapEntry(KeyInput&& aKey, ValueInput&& aValue)
960 : key_(std::forward<KeyInput>(aKey)),
961 value_(std::forward<ValueInput>(aValue)) {}
962
963 HashMapEntry(HashMapEntry&& aRhs) = default;
964 HashMapEntry& operator=(HashMapEntry&& aRhs) = default;
965
966 using KeyType = Key;
967 using ValueType = Value;
968
969 const Key& key() const { return key_; }
970
971 // Use this method with caution! If the key is changed such that its hash
972 // value also changes, the map will be left in an invalid state.
973 Key& mutableKey() { return key_; }
974
975 const Value& value() const { return value_; }
976 Value& value() { return value_; }
977
978 private:
979 HashMapEntry(const HashMapEntry&) = delete;
980 void operator=(const HashMapEntry&) = delete;
981};
982
983namespace detail {
984
985template <class T, class HashPolicy, class AllocPolicy>
986class HashTable;
987
988template <typename T>
989class EntrySlot;
990
991template <typename T>
992class HashTableEntry {
993 private:
994 using NonConstT = std::remove_const_t<T>;
995
996 // Instead of having a hash table entry store that looks like this:
997 //
998 // +--------+--------+--------+--------+
999 // | entry0 | entry1 | .... | entryN |
1000 // +--------+--------+--------+--------+
1001 //
1002 // where the entries contained their cached hash code, we're going to lay out
1003 // the entry store thusly:
1004 //
1005 // +-------+-------+-------+-------+--------+--------+--------+--------+
1006 // | hash0 | hash1 | ... | hashN | entry0 | entry1 | .... | entryN |
1007 // +-------+-------+-------+-------+--------+--------+--------+--------+
1008 //
1009 // with all the cached hashes prior to the actual entries themselves.
1010 //
1011 // We do this because implementing the first strategy requires us to make
1012 // HashTableEntry look roughly like:
1013 //
1014 // template <typename T>
1015 // class HashTableEntry {
1016 // HashNumber mKeyHash;
1017 // T mValue;
1018 // };
1019 //
1020 // The problem with this setup is that, depending on the layout of `T`, there
1021 // may be platform ABI-mandated padding between `mKeyHash` and the first
1022 // member of `T`. This ABI-mandated padding is wasted space, and can be
1023 // surprisingly common, e.g. when `T` is a single pointer on 64-bit platforms.
1024 // In such cases, we're throwing away a quarter of our entry store on padding,
1025 // which is undesirable.
1026 //
1027 // The second layout above, namely:
1028 //
1029 // +-------+-------+-------+-------+--------+--------+--------+--------+
1030 // | hash0 | hash1 | ... | hashN | entry0 | entry1 | .... | entryN |
1031 // +-------+-------+-------+-------+--------+--------+--------+--------+
1032 //
1033 // means there is no wasted space between the hashes themselves, and no wasted
1034 // space between the entries themselves. However, we would also like there to
1035 // be no gap between the last hash and the first entry. The memory allocator
1036 // guarantees the alignment of the start of the hashes. The use of a
1037 // power-of-two capacity of at least 4 guarantees that the alignment of the
1038 // *end* of the hash array is no less than the alignment of the start.
1039 // Finally, the static_asserts here guarantee that the entries themselves
1040 // don't need to be any more aligned than the alignment of the entry store
1041 // itself.
1042 //
1043 // This assertion is safe for 32-bit builds because on both Windows and Linux
1044 // (including Android), the minimum alignment for allocations larger than 8
1045 // bytes is 8 bytes, and the actual data for entries in our entry store is
1046 // guaranteed to have that alignment as well, thanks to the power-of-two
1047 // number of cached hash values stored prior to the entry data.
1048
1049 // The allocation policy must allocate a table with at least this much
1050 // alignment.
1051 static constexpr size_t kMinimumAlignment = 8;
1052
1053 static_assert(alignof(HashNumber) <= kMinimumAlignment,
1054 "[N*2 hashes, N*2 T values] allocation's alignment must be "
1055 "enough to align each hash");
1056 static_assert(alignof(NonConstT) <= 2 * sizeof(HashNumber),
1057 "subsequent N*2 T values must not require more than an even "
1058 "number of HashNumbers provides");
1059
1060 static const HashNumber sFreeKey = 0;
1061 static const HashNumber sRemovedKey = 1;
1062 static const HashNumber sCollisionBit = 1;
1063
1064 alignas(NonConstT) unsigned char mValueData[sizeof(NonConstT)];
1065
1066 private:
1067 template <class, class, class>
1068 friend class HashTable;
1069 template <typename>
1070 friend class EntrySlot;
1071
1072 // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
1073 // -Werror compile error) to reinterpret_cast<> |mValueData| to |T*|, even
1074 // through |void*|. Placing the latter cast in these separate functions
1075 // breaks the chain such that affected GCC versions no longer warn/error.
1076 void* rawValuePtr() { return mValueData; }
1077
1078 static bool isLiveHash(HashNumber hash) { return hash > sRemovedKey; }
1079
1080 HashTableEntry(const HashTableEntry&) = delete;
1081 void operator=(const HashTableEntry&) = delete;
1082
1083 NonConstT* valuePtr() { return reinterpret_cast<NonConstT*>(rawValuePtr()); }
1084
1085 void destroyStoredT() {
1086 NonConstT* ptr = valuePtr();
1087 ptr->~T();
1088 MOZ_MAKE_MEM_UNDEFINED(ptr, sizeof(*ptr))do { } while (0);
1089 }
1090
1091 public:
1092 HashTableEntry() = default;
1093
1094 ~HashTableEntry() { MOZ_MAKE_MEM_UNDEFINED(this, sizeof(*this))do { } while (0); }
1095
1096 void destroy() { destroyStoredT(); }
1097
1098 void swap(HashTableEntry* aOther, bool aIsLive) {
1099 // This allows types to use Argument-Dependent-Lookup, and thus use a custom
1100 // std::swap, which is needed by types like JS::Heap and such.
1101 using std::swap;
1102
1103 if (this == aOther) {
1104 return;
1105 }
1106 if (aIsLive) {
1107 swap(*valuePtr(), *aOther->valuePtr());
1108 } else {
1109 *aOther->valuePtr() = std::move(*valuePtr());
1110 destroy();
1111 }
1112 }
1113
1114 T& get() { return *valuePtr(); }
1115
1116 NonConstT& getMutable() { return *valuePtr(); }
1117};
1118
1119// A slot represents a cached hash value and its associated entry stored
1120// in the hash table. These two things are not stored in contiguous memory.
1121template <class T>
1122class EntrySlot {
1123 using NonConstT = std::remove_const_t<T>;
1124
1125 using Entry = HashTableEntry<T>;
1126
1127 Entry* mEntry;
1128 HashNumber* mKeyHash;
1129
1130 template <class, class, class>
1131 friend class HashTable;
1132
1133 EntrySlot(Entry* aEntry, HashNumber* aKeyHash)
1134 : mEntry(aEntry), mKeyHash(aKeyHash) {}
23
Null pointer value stored to 'p.mSlot.mKeyHash'
1135
1136 public:
1137 static bool isLiveHash(HashNumber hash) { return hash > Entry::sRemovedKey; }
1138
1139 EntrySlot(const EntrySlot&) = default;
1140 EntrySlot(EntrySlot&& aOther) = default;
1141
1142 EntrySlot& operator=(const EntrySlot&) = default;
1143 EntrySlot& operator=(EntrySlot&&) = default;
1144
1145 bool operator==(const EntrySlot& aRhs) const { return mEntry == aRhs.mEntry; }
1146
1147 bool operator<(const EntrySlot& aRhs) const { return mEntry < aRhs.mEntry; }
1148
1149 EntrySlot& operator++() {
1150 ++mEntry;
1151 ++mKeyHash;
1152 return *this;
1153 }
1154
1155 void destroy() { mEntry->destroy(); }
1156
1157 void swap(EntrySlot& aOther) {
1158 mEntry->swap(aOther.mEntry, aOther.isLive());
1159 std::swap(*mKeyHash, *aOther.mKeyHash);
1160 }
1161
1162 T& get() const { return mEntry->get(); }
1163
1164 NonConstT& getMutable() { return mEntry->getMutable(); }
1165
1166 bool isFree() const { return *mKeyHash == Entry::sFreeKey; }
1167
1168 void clearLive() {
1169 MOZ_ASSERT(isLive())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isLive())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isLive()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isLive()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1169); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLive()" ")"
); do { *((volatile int*)__null) = 1169; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1170 *mKeyHash = Entry::sFreeKey;
1171 mEntry->destroyStoredT();
1172 }
1173
1174 void clear() {
1175 if (isLive()) {
1176 mEntry->destroyStoredT();
1177 }
1178 MOZ_MAKE_MEM_UNDEFINED(mEntry, sizeof(*mEntry))do { } while (0);
1179 *mKeyHash = Entry::sFreeKey;
1180 }
1181
1182 bool isRemoved() const { return *mKeyHash == Entry::sRemovedKey; }
1183
1184 void removeLive() {
1185 MOZ_ASSERT(isLive())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isLive())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isLive()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isLive()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1185); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLive()" ")"
); do { *((volatile int*)__null) = 1185; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1186 *mKeyHash = Entry::sRemovedKey;
1187 mEntry->destroyStoredT();
1188 }
1189
1190 bool isLive() const { return isLiveHash(*mKeyHash); }
1191
1192 void setCollision() {
1193 MOZ_ASSERT(isLive())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isLive())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isLive()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isLive()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1193); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLive()" ")"
); do { *((volatile int*)__null) = 1193; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1194 *mKeyHash |= Entry::sCollisionBit;
1195 }
1196 void unsetCollision() { *mKeyHash &= ~Entry::sCollisionBit; }
1197 bool hasCollision() const { return *mKeyHash & Entry::sCollisionBit; }
49
Dereference of null pointer (loaded from field 'mKeyHash')
1198 bool matchHash(HashNumber hn) {
1199 return (*mKeyHash & ~Entry::sCollisionBit) == hn;
1200 }
1201 HashNumber getKeyHash() const { return *mKeyHash & ~Entry::sCollisionBit; }
1202
1203 template <typename... Args>
1204 void setLive(HashNumber aHashNumber, Args&&... aArgs) {
1205 MOZ_ASSERT(!isLive())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isLive())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!isLive()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!isLive()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1205); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isLive()" ")"
); do { *((volatile int*)__null) = 1205; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1206 *mKeyHash = aHashNumber;
1207 new (KnownNotNull, mEntry->valuePtr()) T(std::forward<Args>(aArgs)...);
1208 MOZ_ASSERT(isLive())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isLive())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isLive()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isLive()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1208); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLive()" ")"
); do { *((volatile int*)__null) = 1208; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1209 }
1210
1211 Entry* toEntry() const { return mEntry; }
1212};
1213
1214template <class T, class HashPolicy, class AllocPolicy>
1215class HashTable : private AllocPolicy {
1216 friend class mozilla::ReentrancyGuard;
1217
1218 using NonConstT = std::remove_const_t<T>;
1219 using Key = typename HashPolicy::KeyType;
1220 using Lookup = typename HashPolicy::Lookup;
1221
1222 public:
1223 using Entry = HashTableEntry<T>;
1224 using Slot = EntrySlot<T>;
1225
1226 template <typename F>
1227 static void forEachSlot(char* aTable, uint32_t aCapacity, F&& f) {
1228 auto hashes = reinterpret_cast<HashNumber*>(aTable);
1229 auto entries = reinterpret_cast<Entry*>(&hashes[aCapacity]);
1230 Slot slot(entries, hashes);
1231 for (size_t i = 0; i < size_t(aCapacity); ++i) {
1232 f(slot);
1233 ++slot;
1234 }
1235 }
1236
1237 // A nullable pointer to a hash table element. A Ptr |p| can be tested
1238 // either explicitly |if (p.found()) p->...| or using boolean conversion
1239 // |if (p) p->...|. Ptr objects must not be used after any mutating hash
1240 // table operations unless |generation()| is tested.
1241 class Ptr {
1242 friend class HashTable;
1243
1244 Slot mSlot;
1245#ifdef DEBUG1
1246 const HashTable* mTable;
1247 Generation mGeneration;
1248#endif
1249
1250 protected:
1251 Ptr(Slot aSlot, const HashTable& aTable)
1252 : mSlot(aSlot)
1253#ifdef DEBUG1
1254 ,
1255 mTable(&aTable),
1256 mGeneration(aTable.generation())
1257#endif
1258 {
1259 }
1260
1261 // This constructor is used only by AddPtr() within lookupForAdd().
1262 explicit Ptr(const HashTable& aTable)
1263 : mSlot(nullptr, nullptr)
1264#ifdef DEBUG1
1265 ,
1266 mTable(&aTable),
1267 mGeneration(aTable.generation())
1268#endif
1269 {
1270 }
1271
1272 bool isValid() const { return !!mSlot.toEntry(); }
1273
1274 public:
1275 Ptr()
1276 : mSlot(nullptr, nullptr)
21
Passing null pointer value via 2nd parameter 'aKeyHash'
22
Calling constructor for 'EntrySlot<mozilla::HashMapEntry<nsTString<char>, nsTString<char>>>'
24
Returning from constructor for 'EntrySlot<mozilla::HashMapEntry<nsTString<char>, nsTString<char>>>'
1277#ifdef DEBUG1
1278 ,
1279 mTable(nullptr),
1280 mGeneration(0)
1281#endif
1282 {
1283 }
1284
1285 bool found() const {
1286 if (!isValid()) {
1287 return false;
1288 }
1289#ifdef DEBUG1
1290 MOZ_ASSERT(mGeneration == mTable->generation())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGeneration == mTable->generation())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mGeneration == mTable->generation()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mGeneration == mTable->generation()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1290); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable->generation()"
")"); do { *((volatile int*)__null) = 1290; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1291#endif
1292 return mSlot.isLive();
1293 }
1294
1295 explicit operator bool() const { return found(); }
1296
1297 bool operator==(const Ptr& aRhs) const {
1298 MOZ_ASSERT(found() && aRhs.found())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(found() && aRhs.found())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(found() && aRhs.found
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("found() && aRhs.found()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1298); AnnotateMozCrashReason("MOZ_ASSERT" "(" "found() && aRhs.found()"
")"); do { *((volatile int*)__null) = 1298; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1299 return mSlot == aRhs.mSlot;
1300 }
1301
1302 bool operator!=(const Ptr& aRhs) const {
1303#ifdef DEBUG1
1304 MOZ_ASSERT(mGeneration == mTable->generation())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGeneration == mTable->generation())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mGeneration == mTable->generation()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mGeneration == mTable->generation()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1304); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable->generation()"
")"); do { *((volatile int*)__null) = 1304; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1305#endif
1306 return !(*this == aRhs);
1307 }
1308
1309 T& operator*() const {
1310#ifdef DEBUG1
1311 MOZ_ASSERT(found())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(found())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(found()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("found()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1311); AnnotateMozCrashReason("MOZ_ASSERT" "(" "found()" ")"
); do { *((volatile int*)__null) = 1311; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1312 MOZ_ASSERT(mGeneration == mTable->generation())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGeneration == mTable->generation())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mGeneration == mTable->generation()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mGeneration == mTable->generation()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1312); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable->generation()"
")"); do { *((volatile int*)__null) = 1312; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1313#endif
1314 return mSlot.get();
1315 }
1316
1317 T* operator->() const {
1318#ifdef DEBUG1
1319 MOZ_ASSERT(found())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(found())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(found()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("found()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "found()" ")"
); do { *((volatile int*)__null) = 1319; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1320 MOZ_ASSERT(mGeneration == mTable->generation())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGeneration == mTable->generation())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mGeneration == mTable->generation()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mGeneration == mTable->generation()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1320); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable->generation()"
")"); do { *((volatile int*)__null) = 1320; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1321#endif
1322 return &mSlot.get();
1323 }
1324 };
1325
1326 // A Ptr that can be used to add a key after a failed lookup.
1327 class AddPtr : public Ptr {
1328 friend class HashTable;
1329
1330 HashNumber mKeyHash;
1331#ifdef DEBUG1
1332 uint64_t mMutationCount;
1333#endif
1334
1335 AddPtr(Slot aSlot, const HashTable& aTable, HashNumber aHashNumber)
1336 : Ptr(aSlot, aTable),
1337 mKeyHash(aHashNumber)
1338#ifdef DEBUG1
1339 ,
1340 mMutationCount(aTable.mMutationCount)
1341#endif
1342 {
1343 }
1344
1345 // This constructor is used when lookupForAdd() is performed on a table
1346 // lacking entry storage; it leaves mSlot null but initializes everything
1347 // else.
1348 AddPtr(const HashTable& aTable, HashNumber aHashNumber)
1349 : Ptr(aTable),
1350 mKeyHash(aHashNumber)
1351#ifdef DEBUG1
1352 ,
1353 mMutationCount(aTable.mMutationCount)
1354#endif
1355 {
1356 MOZ_ASSERT(isLive())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isLive())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isLive()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isLive()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1356); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLive()" ")"
); do { *((volatile int*)__null) = 1356; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1357 }
1358
1359 bool isLive() const { return isLiveHash(mKeyHash); }
1360
1361 public:
1362 AddPtr() : mKeyHash(0) {}
1363 };
1364
1365 // A hash table iterator that (mostly) doesn't allow table modifications.
1366 // As with Ptr/AddPtr, Iterator objects must not be used after any mutating
1367 // hash table operation unless the |generation()| is tested.
1368 class Iterator {
1369 void moveToNextLiveEntry() {
1370 while (++mCur < mEnd && !mCur.isLive()) {
1371 continue;
1372 }
1373 }
1374
1375 protected:
1376 friend class HashTable;
1377
1378 explicit Iterator(const HashTable& aTable)
1379 : mCur(aTable.slotForIndex(0)),
1380 mEnd(aTable.slotForIndex(aTable.capacity()))
1381#ifdef DEBUG1
1382 ,
1383 mTable(aTable),
1384 mMutationCount(aTable.mMutationCount),
1385 mGeneration(aTable.generation()),
1386 mValidEntry(true)
1387#endif
1388 {
1389 if (!done() && !mCur.isLive()) {
1390 moveToNextLiveEntry();
1391 }
1392 }
1393
1394 Slot mCur;
1395 Slot mEnd;
1396#ifdef DEBUG1
1397 const HashTable& mTable;
1398 uint64_t mMutationCount;
1399 Generation mGeneration;
1400 bool mValidEntry;
1401#endif
1402
1403 public:
1404 bool done() const {
1405 MOZ_ASSERT(mGeneration == mTable.generation())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGeneration == mTable.generation())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mGeneration == mTable.generation
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mGeneration == mTable.generation()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1405); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable.generation()"
")"); do { *((volatile int*)__null) = 1405; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1406 MOZ_ASSERT(mMutationCount == mTable.mMutationCount)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMutationCount == mTable.mMutationCount)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mMutationCount == mTable.mMutationCount))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mMutationCount == mTable.mMutationCount"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1406); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMutationCount == mTable.mMutationCount"
")"); do { *((volatile int*)__null) = 1406; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1407 return mCur == mEnd;
1408 }
1409
1410 T& get() const {
1411 MOZ_ASSERT(!done())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!done())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!done()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!done()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1411); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!done()" ")"
); do { *((volatile int*)__null) = 1411; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1412 MOZ_ASSERT(mValidEntry)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mValidEntry)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mValidEntry))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mValidEntry", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1412); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mValidEntry"
")"); do { *((volatile int*)__null) = 1412; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1413 MOZ_ASSERT(mGeneration == mTable.generation())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGeneration == mTable.generation())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mGeneration == mTable.generation
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mGeneration == mTable.generation()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1413); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable.generation()"
")"); do { *((volatile int*)__null) = 1413; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1414 MOZ_ASSERT(mMutationCount == mTable.mMutationCount)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMutationCount == mTable.mMutationCount)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mMutationCount == mTable.mMutationCount))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mMutationCount == mTable.mMutationCount"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1414); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMutationCount == mTable.mMutationCount"
")"); do { *((volatile int*)__null) = 1414; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1415 return mCur.get();
1416 }
1417
1418 void next() {
1419 MOZ_ASSERT(!done())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!done())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!done()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!done()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1419); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!done()" ")"
); do { *((volatile int*)__null) = 1419; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1420 MOZ_ASSERT(mGeneration == mTable.generation())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGeneration == mTable.generation())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mGeneration == mTable.generation
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mGeneration == mTable.generation()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1420); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable.generation()"
")"); do { *((volatile int*)__null) = 1420; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1421 MOZ_ASSERT(mMutationCount == mTable.mMutationCount)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMutationCount == mTable.mMutationCount)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mMutationCount == mTable.mMutationCount))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mMutationCount == mTable.mMutationCount"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1421); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMutationCount == mTable.mMutationCount"
")"); do { *((volatile int*)__null) = 1421; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1422 moveToNextLiveEntry();
1423#ifdef DEBUG1
1424 mValidEntry = true;
1425#endif
1426 }
1427 };
1428
1429 // A hash table iterator that permits modification, removal and rekeying.
1430 // Since rehashing when elements were removed during enumeration would be
1431 // bad, it is postponed until the ModIterator is destructed. Since the
1432 // ModIterator's destructor touches the hash table, the user must ensure
1433 // that the hash table is still alive when the destructor runs.
1434 class ModIterator : public Iterator {
1435 friend class HashTable;
1436
1437 HashTable& mTable;
1438 bool mRekeyed;
1439 bool mRemoved;
1440
1441 // ModIterator is movable but not copyable.
1442 ModIterator(const ModIterator&) = delete;
1443 void operator=(const ModIterator&) = delete;
1444
1445 protected:
1446 explicit ModIterator(HashTable& aTable)
1447 : Iterator(aTable), mTable(aTable), mRekeyed(false), mRemoved(false) {}
1448
1449 public:
1450 MOZ_IMPLICIT ModIterator(ModIterator&& aOther)
1451 : Iterator(aOther),
1452 mTable(aOther.mTable),
1453 mRekeyed(aOther.mRekeyed),
1454 mRemoved(aOther.mRemoved) {
1455 aOther.mRekeyed = false;
1456 aOther.mRemoved = false;
1457 }
1458
1459 // Removes the current element from the table, leaving |get()|
1460 // invalid until the next call to |next()|.
1461 void remove() {
1462 mTable.remove(this->mCur);
1463 mRemoved = true;
1464#ifdef DEBUG1
1465 this->mValidEntry = false;
1466 this->mMutationCount = mTable.mMutationCount;
1467#endif
1468 }
1469
1470 NonConstT& getMutable() {
1471 MOZ_ASSERT(!this->done())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!this->done())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!this->done()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!this->done()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1471); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!this->done()"
")"); do { *((volatile int*)__null) = 1471; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1472 MOZ_ASSERT(this->mValidEntry)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(this->mValidEntry)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(this->mValidEntry))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("this->mValidEntry"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1472); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this->mValidEntry"
")"); do { *((volatile int*)__null) = 1472; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1473 MOZ_ASSERT(this->mGeneration == this->Iterator::mTable.generation())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(this->mGeneration == this->Iterator::mTable.generation
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(this->mGeneration == this->Iterator::mTable.generation
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("this->mGeneration == this->Iterator::mTable.generation()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this->mGeneration == this->Iterator::mTable.generation()"
")"); do { *((volatile int*)__null) = 1473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1474 MOZ_ASSERT(this->mMutationCount == this->Iterator::mTable.mMutationCount)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(this->mMutationCount == this->Iterator::mTable
.mMutationCount)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(this->mMutationCount == this
->Iterator::mTable.mMutationCount))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("this->mMutationCount == this->Iterator::mTable.mMutationCount"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1474); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this->mMutationCount == this->Iterator::mTable.mMutationCount"
")"); do { *((volatile int*)__null) = 1474; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1475 return this->mCur.getMutable();
1476 }
1477
1478 // Removes the current element and re-inserts it into the table with
1479 // a new key at the new Lookup position. |get()| is invalid after
1480 // this operation until the next call to |next()|.
1481 void rekey(const Lookup& l, const Key& k) {
1482 MOZ_ASSERT(&k != &HashPolicy::getKey(this->mCur.get()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(&k != &HashPolicy::getKey(this->mCur.get(
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(&k != &HashPolicy::getKey(this->mCur.get(
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("&k != &HashPolicy::getKey(this->mCur.get())", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1482); AnnotateMozCrashReason("MOZ_ASSERT" "(" "&k != &HashPolicy::getKey(this->mCur.get())"
")"); do { *((volatile int*)__null) = 1482; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1483 Ptr p(this->mCur, mTable);
1484 mTable.rekeyWithoutRehash(p, l, k);
1485 mRekeyed = true;
1486#ifdef DEBUG1
1487 this->mValidEntry = false;
1488 this->mMutationCount = mTable.mMutationCount;
1489#endif
1490 }
1491
1492 void rekey(const Key& k) { rekey(k, k); }
1493
1494 // Potentially rehashes the table.
1495 ~ModIterator() {
1496 if (mRekeyed) {
1497 mTable.mGen++;
1498 mTable.infallibleRehashIfOverloaded();
1499 }
1500
1501 if (mRemoved) {
1502 mTable.compact();
1503 }
1504 }
1505 };
1506
1507 // Range is similar to Iterator, but uses different terminology.
1508 class Range {
1509 friend class HashTable;
1510
1511 Iterator mIter;
1512
1513 protected:
1514 explicit Range(const HashTable& table) : mIter(table) {}
1515
1516 public:
1517 bool empty() const { return mIter.done(); }
1518
1519 T& front() const { return mIter.get(); }
1520
1521 void popFront() { return mIter.next(); }
1522 };
1523
1524 // Enum is similar to ModIterator, but uses different terminology.
1525 class Enum {
1526 ModIterator mIter;
1527
1528 // Enum is movable but not copyable.
1529 Enum(const Enum&) = delete;
1530 void operator=(const Enum&) = delete;
1531
1532 public:
1533 template <class Map>
1534 explicit Enum(Map& map) : mIter(map.mImpl) {}
1535
1536 MOZ_IMPLICIT Enum(Enum&& other) : mIter(std::move(other.mIter)) {}
1537
1538 bool empty() const { return mIter.done(); }
1539
1540 T& front() const { return mIter.get(); }
1541
1542 void popFront() { return mIter.next(); }
1543
1544 void removeFront() { mIter.remove(); }
1545
1546 NonConstT& mutableFront() { return mIter.getMutable(); }
1547
1548 void rekeyFront(const Lookup& aLookup, const Key& aKey) {
1549 mIter.rekey(aLookup, aKey);
1550 }
1551
1552 void rekeyFront(const Key& aKey) { mIter.rekey(aKey); }
1553 };
1554
1555 // HashTable is movable
1556 HashTable(HashTable&& aRhs) : AllocPolicy(std::move(aRhs)) { moveFrom(aRhs); }
1557 HashTable& operator=(HashTable&& aRhs) {
1558 MOZ_ASSERT(this != &aRhs, "self-move assignment is prohibited")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(this != &aRhs)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(this != &aRhs))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("this != &aRhs"
" (" "self-move assignment is prohibited" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1558); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this != &aRhs"
") (" "self-move assignment is prohibited" ")"); do { *((volatile
int*)__null) = 1558; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1559 if (mTable) {
1560 destroyTable(*this, mTable, capacity());
1561 }
1562 AllocPolicy::operator=(std::move(aRhs));
1563 moveFrom(aRhs);
1564 return *this;
1565 }
1566
1567 void swap(HashTable& aOther) {
1568 ReentrancyGuard g1(*this);
1569 ReentrancyGuard g2(aOther);
1570
1571 // Manual swap of generation because it's a bitfield
1572 uint64_t generation = mGen;
1573 mGen = aOther.mGen;
1574 aOther.mGen = generation;
1575
1576 // Manual swap of hashShift because it's a bitfield
1577 uint64_t hashShift = mHashShift;
1578 mHashShift = aOther.mHashShift;
1579 aOther.mHashShift = hashShift;
1580
1581 std::swap(mTable, aOther.mTable);
1582 std::swap(mEntryCount, aOther.mEntryCount);
1583 std::swap(mRemovedCount, aOther.mRemovedCount);
1584#ifdef DEBUG1
1585 std::swap(mMutationCount, aOther.mMutationCount);
1586 std::swap(mEntered, aOther.mEntered);
1587#endif
1588 }
1589
1590 private:
1591 void moveFrom(HashTable& aRhs) {
1592 mGen = aRhs.mGen;
1593 mHashShift = aRhs.mHashShift;
1594 mTable = aRhs.mTable;
1595 mEntryCount = aRhs.mEntryCount;
1596 mRemovedCount = aRhs.mRemovedCount;
1597#ifdef DEBUG1
1598 mMutationCount = aRhs.mMutationCount;
1599 mEntered = aRhs.mEntered;
1600#endif
1601 aRhs.mTable = nullptr;
1602 aRhs.clearAndCompact();
1603 }
1604
1605 // HashTable is not copyable or assignable
1606 HashTable(const HashTable&) = delete;
1607 void operator=(const HashTable&) = delete;
1608
1609 static const uint32_t CAP_BITS = 30;
1610
1611 public:
1612 uint64_t mGen : 56; // entry storage generation number
1613 uint64_t mHashShift : 8; // multiplicative hash shift
1614 char* mTable; // entry storage
1615 uint32_t mEntryCount; // number of entries in mTable
1616 uint32_t mRemovedCount; // removed entry sentinels in mTable
1617
1618#ifdef DEBUG1
1619 uint64_t mMutationCount;
1620 mutable bool mEntered;
1621#endif
1622
1623 // The default initial capacity is 32 (enough to hold 16 elements), but it
1624 // can be as low as 4.
1625 static const uint32_t sDefaultLen = 16;
1626 static const uint32_t sMinCapacity = 4;
1627 // See the comments in HashTableEntry about this value.
1628 static_assert(sMinCapacity >= 4, "too-small sMinCapacity breaks assumptions");
1629 static const uint32_t sMaxInit = 1u << (CAP_BITS - 1);
1630 static const uint32_t sMaxCapacity = 1u << CAP_BITS;
1631
1632 // Hash-table alpha is conceptually a fraction, but to avoid floating-point
1633 // math we implement it as a ratio of integers.
1634 static const uint8_t sAlphaDenominator = 4;
1635 static const uint8_t sMinAlphaNumerator = 1; // min alpha: 1/4
1636 static const uint8_t sMaxAlphaNumerator = 3; // max alpha: 3/4
1637
1638 static const HashNumber sFreeKey = Entry::sFreeKey;
1639 static const HashNumber sRemovedKey = Entry::sRemovedKey;
1640 static const HashNumber sCollisionBit = Entry::sCollisionBit;
1641
1642 static uint32_t bestCapacity(uint32_t aLen) {
1643 static_assert(
1644 (sMaxInit * sAlphaDenominator) / sAlphaDenominator == sMaxInit,
1645 "multiplication in numerator below could overflow");
1646 static_assert(
1647 sMaxInit * sAlphaDenominator <= UINT32_MAX(4294967295U) - sMaxAlphaNumerator,
1648 "numerator calculation below could potentially overflow");
1649
1650 // Callers should ensure this is true.
1651 MOZ_ASSERT(aLen <= sMaxInit)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLen <= sMaxInit)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLen <= sMaxInit))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("aLen <= sMaxInit"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1651); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLen <= sMaxInit"
")"); do { *((volatile int*)__null) = 1651; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1652
1653 // Compute the smallest capacity allowing |aLen| elements to be
1654 // inserted without rehashing: ceil(aLen / max-alpha). (Ceiling
1655 // integral division: <http://stackoverflow.com/a/2745086>.)
1656 uint32_t capacity = (aLen * sAlphaDenominator + sMaxAlphaNumerator - 1) /
1657 sMaxAlphaNumerator;
1658 capacity = (capacity < sMinCapacity) ? sMinCapacity : RoundUpPow2(capacity);
1659
1660 MOZ_ASSERT(capacity >= aLen)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(capacity >= aLen)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(capacity >= aLen))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("capacity >= aLen"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "capacity >= aLen"
")"); do { *((volatile int*)__null) = 1660; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1661 MOZ_ASSERT(capacity <= sMaxCapacity)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(capacity <= sMaxCapacity)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(capacity <= sMaxCapacity)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("capacity <= sMaxCapacity"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1661); AnnotateMozCrashReason("MOZ_ASSERT" "(" "capacity <= sMaxCapacity"
")"); do { *((volatile int*)__null) = 1661; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1662
1663 return capacity;
1664 }
1665
1666 static uint32_t hashShift(uint32_t aLen) {
1667 // Reject all lengths whose initial computed capacity would exceed
1668 // sMaxCapacity. Round that maximum aLen down to the nearest power of two
1669 // for speedier code.
1670 if (MOZ_UNLIKELY(aLen > sMaxInit)(__builtin_expect(!!(aLen > sMaxInit), 0))) {
1671 MOZ_CRASH("initial length is too large")do { do { } while (false); MOZ_ReportCrash("" "initial length is too large"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1671); AnnotateMozCrashReason("MOZ_CRASH(" "initial length is too large"
")"); do { *((volatile int*)__null) = 1671; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1672 }
1673
1674 return kHashNumberBits - mozilla::CeilingLog2(bestCapacity(aLen));
1675 }
1676
1677 static bool isLiveHash(HashNumber aHash) { return Entry::isLiveHash(aHash); }
1678
1679 static HashNumber prepareHash(HashNumber aInputHash) {
1680 HashNumber keyHash = ScrambleHashCode(aInputHash);
1681
1682 // Avoid reserved hash codes.
1683 if (!isLiveHash(keyHash)) {
1684 keyHash -= (sRemovedKey + 1);
1685 }
1686 return keyHash & ~sCollisionBit;
1687 }
1688
1689 enum FailureBehavior { DontReportFailure = false, ReportFailure = true };
1690
1691 // Fake a struct that we're going to alloc. See the comments in
1692 // HashTableEntry about how the table is laid out, and why it's safe.
1693 struct FakeSlot {
1694 unsigned char c[sizeof(HashNumber) + sizeof(typename Entry::NonConstT)];
1695 };
1696
1697 static char* createTable(AllocPolicy& aAllocPolicy, uint32_t aCapacity,
1698 FailureBehavior aReportFailure = ReportFailure) {
1699 FakeSlot* fake =
1700 aReportFailure
1701 ? aAllocPolicy.template pod_malloc<FakeSlot>(aCapacity)
1702 : aAllocPolicy.template maybe_pod_malloc<FakeSlot>(aCapacity);
1703
1704 MOZ_ASSERT((reinterpret_cast<uintptr_t>(fake) % Entry::kMinimumAlignment) ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype((reinterpret_cast<uintptr_t>(fake) % Entry::kMinimumAlignment
) == 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((reinterpret_cast<uintptr_t>(fake) % Entry::kMinimumAlignment
) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(reinterpret_cast<uintptr_t>(fake) % Entry::kMinimumAlignment) == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1705); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(reinterpret_cast<uintptr_t>(fake) % Entry::kMinimumAlignment) == 0"
")"); do { *((volatile int*)__null) = 1705; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1705 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((reinterpret_cast<uintptr_t>(fake) % Entry::kMinimumAlignment
) == 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((reinterpret_cast<uintptr_t>(fake) % Entry::kMinimumAlignment
) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(reinterpret_cast<uintptr_t>(fake) % Entry::kMinimumAlignment) == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1705); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(reinterpret_cast<uintptr_t>(fake) % Entry::kMinimumAlignment) == 0"
")"); do { *((volatile int*)__null) = 1705; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1706
1707 char* table = reinterpret_cast<char*>(fake);
1708 if (table) {
1709 forEachSlot(table, aCapacity, [&](Slot& slot) {
1710 *slot.mKeyHash = sFreeKey;
1711 new (KnownNotNull, slot.toEntry()) Entry();
1712 });
1713 }
1714 return table;
1715 }
1716
1717 static void destroyTable(AllocPolicy& aAllocPolicy, char* aOldTable,
1718 uint32_t aCapacity) {
1719 forEachSlot(aOldTable, aCapacity, [&](const Slot& slot) {
1720 if (slot.isLive()) {
1721 slot.toEntry()->destroyStoredT();
1722 }
1723 });
1724 freeTable(aAllocPolicy, aOldTable, aCapacity);
1725 }
1726
1727 static void freeTable(AllocPolicy& aAllocPolicy, char* aOldTable,
1728 uint32_t aCapacity) {
1729 FakeSlot* fake = reinterpret_cast<FakeSlot*>(aOldTable);
1730 aAllocPolicy.free_(fake, aCapacity);
1731 }
1732
1733 public:
1734 HashTable(AllocPolicy aAllocPolicy, uint32_t aLen)
1735 : AllocPolicy(std::move(aAllocPolicy)),
1736 mGen(0),
1737 mHashShift(hashShift(aLen)),
1738 mTable(nullptr),
1739 mEntryCount(0),
1740 mRemovedCount(0)
1741#ifdef DEBUG1
1742 ,
1743 mMutationCount(0),
1744 mEntered(false)
1745#endif
1746 {
1747 }
1748
1749 explicit HashTable(AllocPolicy aAllocPolicy)
1750 : HashTable(aAllocPolicy, sDefaultLen) {}
1751
1752 ~HashTable() {
1753 if (mTable) {
1754 destroyTable(*this, mTable, capacity());
1755 }
1756 }
1757
1758 private:
1759 HashNumber hash1(HashNumber aHash0) const { return aHash0 >> mHashShift; }
1760
1761 struct DoubleHash {
1762 HashNumber mHash2;
1763 HashNumber mSizeMask;
1764 };
1765
1766 DoubleHash hash2(HashNumber aCurKeyHash) const {
1767 uint32_t sizeLog2 = kHashNumberBits - mHashShift;
1768 DoubleHash dh = {((aCurKeyHash << sizeLog2) >> mHashShift) | 1,
1769 (HashNumber(1) << sizeLog2) - 1};
1770 return dh;
1771 }
1772
1773 static HashNumber applyDoubleHash(HashNumber aHash1,
1774 const DoubleHash& aDoubleHash) {
1775 return WrappingSubtract(aHash1, aDoubleHash.mHash2) & aDoubleHash.mSizeMask;
1776 }
1777
1778 static MOZ_ALWAYS_INLINEinline bool match(T& aEntry, const Lookup& aLookup) {
1779 return HashPolicy::match(HashPolicy::getKey(aEntry), aLookup);
1780 }
1781
1782 enum LookupReason { ForNonAdd, ForAdd };
1783
1784 Slot slotForIndex(HashNumber aIndex) const {
1785 auto hashes = reinterpret_cast<HashNumber*>(mTable);
1786 auto entries = reinterpret_cast<Entry*>(&hashes[capacity()]);
1787 return Slot(&entries[aIndex], &hashes[aIndex]);
1788 }
1789
1790 // Warning: in order for readonlyThreadsafeLookup() to be safe this
1791 // function must not modify the table in any way when Reason==ForNonAdd.
1792 template <LookupReason Reason>
1793 MOZ_ALWAYS_INLINEinline Slot lookup(const Lookup& aLookup,
1794 HashNumber aKeyHash) const {
1795 MOZ_ASSERT(isLiveHash(aKeyHash))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isLiveHash(aKeyHash))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isLiveHash(aKeyHash)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("isLiveHash(aKeyHash)"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1795); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLiveHash(aKeyHash)"
")"); do { *((volatile int*)__null) = 1795; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1796 MOZ_ASSERT(!(aKeyHash & sCollisionBit))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aKeyHash & sCollisionBit))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aKeyHash & sCollisionBit
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aKeyHash & sCollisionBit)", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1796); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(aKeyHash & sCollisionBit)"
")"); do { *((volatile int*)__null) = 1796; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1797 MOZ_ASSERT(mTable)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTable)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(mTable))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTable", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1797); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 1797; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1798
1799 // Compute the primary hash address.
1800 HashNumber h1 = hash1(aKeyHash);
1801 Slot slot = slotForIndex(h1);
1802
1803 // Miss: return space for a new entry.
1804 if (slot.isFree()) {
1805 return slot;
1806 }
1807
1808 // Hit: return entry.
1809 if (slot.matchHash(aKeyHash) && match(slot.get(), aLookup)) {
1810 return slot;
1811 }
1812
1813 // Collision: double hash.
1814 DoubleHash dh = hash2(aKeyHash);
1815
1816 // Save the first removed entry pointer so we can recycle later.
1817 Maybe<Slot> firstRemoved;
1818
1819 while (true) {
1820 if (Reason == ForAdd && !firstRemoved) {
1821 if (MOZ_UNLIKELY(slot.isRemoved())(__builtin_expect(!!(slot.isRemoved()), 0))) {
1822 firstRemoved.emplace(slot);
1823 } else {
1824 slot.setCollision();
1825 }
1826 }
1827
1828 h1 = applyDoubleHash(h1, dh);
1829
1830 slot = slotForIndex(h1);
1831 if (slot.isFree()) {
1832 return firstRemoved.refOr(slot);
1833 }
1834
1835 if (slot.matchHash(aKeyHash) && match(slot.get(), aLookup)) {
1836 return slot;
1837 }
1838 }
1839 }
1840
1841 // This is a copy of lookup() hardcoded to the assumptions:
1842 // 1. the lookup is for an add;
1843 // 2. the key, whose |keyHash| has been passed, is not in the table.
1844 Slot findNonLiveSlot(HashNumber aKeyHash) {
1845 MOZ_ASSERT(!(aKeyHash & sCollisionBit))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aKeyHash & sCollisionBit))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aKeyHash & sCollisionBit
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aKeyHash & sCollisionBit)", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1845); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(aKeyHash & sCollisionBit)"
")"); do { *((volatile int*)__null) = 1845; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1846 MOZ_ASSERT(mTable)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTable)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(mTable))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTable", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1846); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 1846; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1847
1848 // We assume 'aKeyHash' has already been distributed.
1849
1850 // Compute the primary hash address.
1851 HashNumber h1 = hash1(aKeyHash);
1852 Slot slot = slotForIndex(h1);
1853
1854 // Miss: return space for a new entry.
1855 if (!slot.isLive()) {
1856 return slot;
1857 }
1858
1859 // Collision: double hash.
1860 DoubleHash dh = hash2(aKeyHash);
1861
1862 while (true) {
1863 slot.setCollision();
1864
1865 h1 = applyDoubleHash(h1, dh);
1866
1867 slot = slotForIndex(h1);
1868 if (!slot.isLive()) {
1869 return slot;
1870 }
1871 }
1872 }
1873
1874 enum RebuildStatus { NotOverloaded, Rehashed, RehashFailed };
1875
1876 RebuildStatus changeTableSize(
1877 uint32_t newCapacity, FailureBehavior aReportFailure = ReportFailure) {
1878 MOZ_ASSERT(IsPowerOfTwo(newCapacity))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsPowerOfTwo(newCapacity))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsPowerOfTwo(newCapacity))))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsPowerOfTwo(newCapacity)"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsPowerOfTwo(newCapacity)"
")"); do { *((volatile int*)__null) = 1878; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1879 MOZ_ASSERT(!!mTable == !!capacity())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!!mTable == !!capacity())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!!mTable == !!capacity()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!!mTable == !!capacity()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1879); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!!mTable == !!capacity()"
")"); do { *((volatile int*)__null) = 1879; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1880
1881 // Look, but don't touch, until we succeed in getting new entry store.
1882 char* oldTable = mTable;
1883 uint32_t oldCapacity = capacity();
1884 uint32_t newLog2 = mozilla::CeilingLog2(newCapacity);
1885
1886 if (MOZ_UNLIKELY(newCapacity > sMaxCapacity)(__builtin_expect(!!(newCapacity > sMaxCapacity), 0))) {
1887 if (aReportFailure) {
1888 this->reportAllocOverflow();
1889 }
1890 return RehashFailed;
1891 }
1892
1893 char* newTable = createTable(*this, newCapacity, aReportFailure);
1894 if (!newTable) {
1895 return RehashFailed;
1896 }
1897
1898 // We can't fail from here on, so update table parameters.
1899 mHashShift = kHashNumberBits - newLog2;
1900 mRemovedCount = 0;
1901 mGen++;
1902 mTable = newTable;
1903
1904 // Copy only live entries, leaving removed ones behind.
1905 forEachSlot(oldTable, oldCapacity, [&](Slot& slot) {
1906 if (slot.isLive()) {
1907 HashNumber hn = slot.getKeyHash();
1908 findNonLiveSlot(hn).setLive(
1909 hn, std::move(const_cast<typename Entry::NonConstT&>(slot.get())));
1910 }
1911
1912 slot.clear();
1913 });
1914
1915 // All entries have been destroyed, no need to destroyTable.
1916 freeTable(*this, oldTable, oldCapacity);
1917 return Rehashed;
1918 }
1919
1920 RebuildStatus rehashIfOverloaded(
1921 FailureBehavior aReportFailure = ReportFailure) {
1922 static_assert(sMaxCapacity <= UINT32_MAX(4294967295U) / sMaxAlphaNumerator,
1923 "multiplication below could overflow");
1924
1925 // Note: if capacity() is zero, this will always succeed, which is
1926 // what we want.
1927 bool overloaded = mEntryCount + mRemovedCount >=
1928 capacity() * sMaxAlphaNumerator / sAlphaDenominator;
1929
1930 if (!overloaded) {
1931 return NotOverloaded;
1932 }
1933
1934 // Succeed if a quarter or more of all entries are removed. Note that this
1935 // always succeeds if capacity() == 0 (i.e. entry storage has not been
1936 // allocated), which is what we want, because it means changeTableSize()
1937 // will allocate the requested capacity rather than doubling it.
1938 bool manyRemoved = mRemovedCount >= (capacity() >> 2);
1939 uint32_t newCapacity = manyRemoved ? rawCapacity() : rawCapacity() * 2;
1940 return changeTableSize(newCapacity, aReportFailure);
1941 }
1942
1943 void infallibleRehashIfOverloaded() {
1944 if (rehashIfOverloaded(DontReportFailure) == RehashFailed) {
1945 rehashTableInPlace();
1946 }
1947 }
1948
1949 void remove(Slot& aSlot) {
1950 MOZ_ASSERT(mTable)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTable)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(mTable))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTable", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 1950); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 1950; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
46
Taking false branch
47
Loop condition is false. Exiting loop
1951
1952 if (aSlot.hasCollision()) {
48
Calling 'EntrySlot::hasCollision'
1953 aSlot.removeLive();
1954 mRemovedCount++;
1955 } else {
1956 aSlot.clearLive();
1957 }
1958 mEntryCount--;
1959#ifdef DEBUG1
1960 mMutationCount++;
1961#endif
1962 }
1963
1964 void shrinkIfUnderloaded() {
1965 static_assert(sMaxCapacity <= UINT32_MAX(4294967295U) / sMinAlphaNumerator,
1966 "multiplication below could overflow");
1967 bool underloaded =
1968 capacity() > sMinCapacity &&
1969 mEntryCount <= capacity() * sMinAlphaNumerator / sAlphaDenominator;
1970
1971 if (underloaded) {
1972 (void)changeTableSize(capacity() / 2, DontReportFailure);
1973 }
1974 }
1975
1976 // This is identical to changeTableSize(currentSize), but without requiring
1977 // a second table. We do this by recycling the collision bits to tell us if
1978 // the element is already inserted or still waiting to be inserted. Since
1979 // already-inserted elements win any conflicts, we get the same table as we
1980 // would have gotten through random insertion order.
1981 void rehashTableInPlace() {
1982 mRemovedCount = 0;
1983 mGen++;
1984 forEachSlot(mTable, capacity(), [&](Slot& slot) { slot.unsetCollision(); });
1985 for (uint32_t i = 0; i < capacity();) {
1986 Slot src = slotForIndex(i);
1987
1988 if (!src.isLive() || src.hasCollision()) {
1989 ++i;
1990 continue;
1991 }
1992
1993 HashNumber keyHash = src.getKeyHash();
1994 HashNumber h1 = hash1(keyHash);
1995 DoubleHash dh = hash2(keyHash);
1996 Slot tgt = slotForIndex(h1);
1997 while (true) {
1998 if (!tgt.hasCollision()) {
1999 src.swap(tgt);
2000 tgt.setCollision();
2001 break;
2002 }
2003
2004 h1 = applyDoubleHash(h1, dh);
2005 tgt = slotForIndex(h1);
2006 }
2007 }
2008
2009 // TODO: this algorithm leaves collision bits on *all* elements, even if
2010 // they are on no collision path. We have the option of setting the
2011 // collision bits correctly on a subsequent pass or skipping the rehash
2012 // unless we are totally filled with tombstones: benchmark to find out
2013 // which approach is best.
2014 }
2015
2016 // Prefer to use putNewInfallible; this function does not check
2017 // invariants.
2018 template <typename... Args>
2019 void putNewInfallibleInternal(HashNumber aKeyHash, Args&&... aArgs) {
2020 MOZ_ASSERT(mTable)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTable)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(mTable))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTable", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 2020; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2021
2022 Slot slot = findNonLiveSlot(aKeyHash);
2023
2024 if (slot.isRemoved()) {
2025 mRemovedCount--;
2026 aKeyHash |= sCollisionBit;
2027 }
2028
2029 slot.setLive(aKeyHash, std::forward<Args>(aArgs)...);
2030 mEntryCount++;
2031#ifdef DEBUG1
2032 mMutationCount++;
2033#endif
2034 }
2035
2036 public:
2037 void clear() {
2038 forEachSlot(mTable, capacity(), [&](Slot& slot) { slot.clear(); });
2039 mRemovedCount = 0;
2040 mEntryCount = 0;
2041#ifdef DEBUG1
2042 mMutationCount++;
2043#endif
2044 }
2045
2046 // Resize the table down to the smallest capacity that doesn't overload the
2047 // table. Since we call shrinkIfUnderloaded() on every remove, you only need
2048 // to call this after a bulk removal of items done without calling remove().
2049 void compact() {
2050 if (empty()) {
2051 // Free the entry storage.
2052 freeTable(*this, mTable, capacity());
2053 mGen++;
2054 mHashShift = hashShift(0); // gives minimum capacity on regrowth
2055 mTable = nullptr;
2056 mRemovedCount = 0;
2057 return;
2058 }
2059
2060 uint32_t bestCapacity = this->bestCapacity(mEntryCount);
2061 MOZ_ASSERT(bestCapacity <= capacity())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bestCapacity <= capacity())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bestCapacity <= capacity(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("bestCapacity <= capacity()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2061); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bestCapacity <= capacity()"
")"); do { *((volatile int*)__null) = 2061; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2062
2063 if (bestCapacity < capacity()) {
2064 (void)changeTableSize(bestCapacity, DontReportFailure);
2065 }
2066 }
2067
2068 void clearAndCompact() {
2069 clear();
2070 compact();
2071 }
2072
2073 [[nodiscard]] bool reserve(uint32_t aLen) {
2074 if (aLen == 0) {
2075 return true;
2076 }
2077
2078 if (MOZ_UNLIKELY(aLen > sMaxInit)(__builtin_expect(!!(aLen > sMaxInit), 0))) {
2079 this->reportAllocOverflow();
2080 return false;
2081 }
2082
2083 uint32_t bestCapacity = this->bestCapacity(aLen);
2084 if (bestCapacity <= capacity()) {
2085 return true; // Capacity is already sufficient.
2086 }
2087
2088 RebuildStatus status = changeTableSize(bestCapacity, ReportFailure);
2089 MOZ_ASSERT(status != NotOverloaded)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(status != NotOverloaded)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(status != NotOverloaded))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("status != NotOverloaded"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2089); AnnotateMozCrashReason("MOZ_ASSERT" "(" "status != NotOverloaded"
")"); do { *((volatile int*)__null) = 2089; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2090 return status != RehashFailed;
2091 }
2092
2093 Iterator iter() const { return Iterator(*this); }
2094
2095 ModIterator modIter() { return ModIterator(*this); }
2096
2097 Range all() const { return Range(*this); }
2098
2099 bool empty() const { return mEntryCount == 0; }
2100
2101 uint32_t count() const { return mEntryCount; }
2102
2103 uint32_t rawCapacity() const { return 1u << (kHashNumberBits - mHashShift); }
2104
2105 uint32_t capacity() const { return mTable ? rawCapacity() : 0; }
2106
2107 Generation generation() const { return Generation(mGen); }
2108
2109 size_t shallowSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
2110 return aMallocSizeOf(mTable);
2111 }
2112
2113 size_t shallowSizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
2114 return aMallocSizeOf(this) + shallowSizeOfExcludingThis(aMallocSizeOf);
2115 }
2116
2117 MOZ_ALWAYS_INLINEinline Ptr readonlyThreadsafeLookup(const Lookup& aLookup) const {
2118 if (empty()) {
19
Taking true branch
2119 return Ptr();
20
Calling default constructor for 'Ptr'
25
Returning from default constructor for 'Ptr'
2120 }
2121
2122 HashNumber inputHash;
2123 if (!MaybeGetHash<HashPolicy>(aLookup, &inputHash)) {
2124 return Ptr();
2125 }
2126
2127 HashNumber keyHash = prepareHash(inputHash);
2128 return Ptr(lookup<ForNonAdd>(aLookup, keyHash), *this);
2129 }
2130
2131 MOZ_ALWAYS_INLINEinline Ptr lookup(const Lookup& aLookup) const {
2132 ReentrancyGuard g(*this);
2133 return readonlyThreadsafeLookup(aLookup);
18
Calling 'HashTable::readonlyThreadsafeLookup'
26
Returning from 'HashTable::readonlyThreadsafeLookup'
2134 }
2135
2136 MOZ_ALWAYS_INLINEinline AddPtr lookupForAdd(const Lookup& aLookup) {
2137 ReentrancyGuard g(*this);
2138
2139 HashNumber inputHash;
2140 if (!EnsureHash<HashPolicy>(aLookup, &inputHash)) {
2141 return AddPtr();
2142 }
2143
2144 HashNumber keyHash = prepareHash(inputHash);
2145
2146 if (!mTable) {
2147 return AddPtr(*this, keyHash);
2148 }
2149
2150 // Directly call the constructor in the return statement to avoid
2151 // excess copying when building with Visual Studio 2017.
2152 // See bug 1385181.
2153 return AddPtr(lookup<ForAdd>(aLookup, keyHash), *this, keyHash);
2154 }
2155
2156 template <typename... Args>
2157 [[nodiscard]] bool add(AddPtr& aPtr, Args&&... aArgs) {
2158 ReentrancyGuard g(*this);
2159 MOZ_ASSERT_IF(aPtr.isValid(), mTable)do { if (aPtr.isValid()) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(mTable)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTable))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTable", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2159); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 2159; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2160 MOZ_ASSERT_IF(aPtr.isValid(), aPtr.mTable == this)do { if (aPtr.isValid()) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(aPtr.mTable == this)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aPtr.mTable == this))), 0))) { do { } while (false);
MOZ_ReportAssertionFailure("aPtr.mTable == this", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2160); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.mTable == this"
")"); do { *((volatile int*)__null) = 2160; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2161 MOZ_ASSERT(!aPtr.found())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aPtr.found())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aPtr.found()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aPtr.found()",
"/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPtr.found()"
")"); do { *((volatile int*)__null) = 2161; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2162 MOZ_ASSERT(!(aPtr.mKeyHash & sCollisionBit))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aPtr.mKeyHash & sCollisionBit))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aPtr.mKeyHash & sCollisionBit
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aPtr.mKeyHash & sCollisionBit)", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(aPtr.mKeyHash & sCollisionBit)"
")"); do { *((volatile int*)__null) = 2162; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2163
2164 // Check for error from ensureHash() here.
2165 if (!aPtr.isLive()) {
2166 return false;
2167 }
2168
2169 MOZ_ASSERT(aPtr.mGeneration == generation())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPtr.mGeneration == generation())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPtr.mGeneration == generation
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPtr.mGeneration == generation()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2169); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.mGeneration == generation()"
")"); do { *((volatile int*)__null) = 2169; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2170#ifdef DEBUG1
2171 MOZ_ASSERT(aPtr.mMutationCount == mMutationCount)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPtr.mMutationCount == mMutationCount)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(aPtr.mMutationCount == mMutationCount))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aPtr.mMutationCount == mMutationCount"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2171); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.mMutationCount == mMutationCount"
")"); do { *((volatile int*)__null) = 2171; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2172#endif
2173
2174 if (!aPtr.isValid()) {
2175 MOZ_ASSERT(!mTable && mEntryCount == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mTable && mEntryCount == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mTable && mEntryCount
== 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mTable && mEntryCount == 0", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mTable && mEntryCount == 0"
")"); do { *((volatile int*)__null) = 2175; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2176 uint32_t newCapacity = rawCapacity();
2177 RebuildStatus status = changeTableSize(newCapacity, ReportFailure);
2178 MOZ_ASSERT(status != NotOverloaded)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(status != NotOverloaded)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(status != NotOverloaded))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("status != NotOverloaded"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "status != NotOverloaded"
")"); do { *((volatile int*)__null) = 2178; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2179 if (status == RehashFailed) {
2180 return false;
2181 }
2182 aPtr.mSlot = findNonLiveSlot(aPtr.mKeyHash);
2183
2184 } else if (aPtr.mSlot.isRemoved()) {
2185 // Changing an entry from removed to live does not affect whether we are
2186 // overloaded and can be handled separately.
2187 if (!this->checkSimulatedOOM()) {
2188 return false;
2189 }
2190 mRemovedCount--;
2191 aPtr.mKeyHash |= sCollisionBit;
2192
2193 } else {
2194 // Preserve the validity of |aPtr.mSlot|.
2195 RebuildStatus status = rehashIfOverloaded();
2196 if (status == RehashFailed) {
2197 return false;
2198 }
2199 if (status == NotOverloaded && !this->checkSimulatedOOM()) {
2200 return false;
2201 }
2202 if (status == Rehashed) {
2203 aPtr.mSlot = findNonLiveSlot(aPtr.mKeyHash);
2204 }
2205 }
2206
2207 aPtr.mSlot.setLive(aPtr.mKeyHash, std::forward<Args>(aArgs)...);
2208 mEntryCount++;
2209#ifdef DEBUG1
2210 mMutationCount++;
2211 aPtr.mGeneration = generation();
2212 aPtr.mMutationCount = mMutationCount;
2213#endif
2214 return true;
2215 }
2216
2217 // Note: |aLookup| may reference pieces of arguments in |aArgs|, so this
2218 // function must take care not to use |aLookup| after moving |aArgs|.
2219 template <typename... Args>
2220 void putNewInfallible(const Lookup& aLookup, Args&&... aArgs) {
2221 MOZ_ASSERT(!lookup(aLookup).found())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!lookup(aLookup).found())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!lookup(aLookup).found()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!lookup(aLookup).found()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!lookup(aLookup).found()"
")"); do { *((volatile int*)__null) = 2221; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2222 ReentrancyGuard g(*this);
2223 HashNumber keyHash = prepareHash(HashPolicy::hash(aLookup));
2224 putNewInfallibleInternal(keyHash, std::forward<Args>(aArgs)...);
2225 }
2226
2227 // Note: |aLookup| may alias arguments in |aArgs|, so this function must take
2228 // care not to use |aLookup| after moving |aArgs|.
2229 template <typename... Args>
2230 [[nodiscard]] bool putNew(const Lookup& aLookup, Args&&... aArgs) {
2231 MOZ_ASSERT(!lookup(aLookup).found())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!lookup(aLookup).found())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!lookup(aLookup).found()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!lookup(aLookup).found()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2231); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!lookup(aLookup).found()"
")"); do { *((volatile int*)__null) = 2231; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2232 ReentrancyGuard g(*this);
2233 if (!this->checkSimulatedOOM()) {
2234 return false;
2235 }
2236 HashNumber inputHash;
2237 if (!EnsureHash<HashPolicy>(aLookup, &inputHash)) {
2238 return false;
2239 }
2240 HashNumber keyHash = prepareHash(inputHash);
2241 if (rehashIfOverloaded() == RehashFailed) {
2242 return false;
2243 }
2244 putNewInfallibleInternal(keyHash, std::forward<Args>(aArgs)...);
2245 return true;
2246 }
2247
2248 // Note: |aLookup| may be a reference pieces of arguments in |aArgs|, so this
2249 // function must take care not to use |aLookup| after moving |aArgs|.
2250 template <typename... Args>
2251 [[nodiscard]] bool relookupOrAdd(AddPtr& aPtr, const Lookup& aLookup,
2252 Args&&... aArgs) {
2253 // Check for error from ensureHash() here.
2254 if (!aPtr.isLive()) {
2255 return false;
2256 }
2257#ifdef DEBUG1
2258 aPtr.mGeneration = generation();
2259 aPtr.mMutationCount = mMutationCount;
2260#endif
2261 if (mTable) {
2262 ReentrancyGuard g(*this);
2263 // Check that aLookup has not been destroyed.
2264 MOZ_ASSERT(prepareHash(HashPolicy::hash(aLookup)) == aPtr.mKeyHash)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prepareHash(HashPolicy::hash(aLookup)) == aPtr.mKeyHash
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(prepareHash(HashPolicy::hash(aLookup)) == aPtr.mKeyHash
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"prepareHash(HashPolicy::hash(aLookup)) == aPtr.mKeyHash", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2264); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prepareHash(HashPolicy::hash(aLookup)) == aPtr.mKeyHash"
")"); do { *((volatile int*)__null) = 2264; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2265 aPtr.mSlot = lookup<ForAdd>(aLookup, aPtr.mKeyHash);
2266 if (aPtr.found()) {
2267 return true;
2268 }
2269 } else {
2270 // Clear aPtr so it's invalid; add() will allocate storage and redo the
2271 // lookup.
2272 aPtr.mSlot = Slot(nullptr, nullptr);
2273 }
2274 return add(aPtr, std::forward<Args>(aArgs)...);
2275 }
2276
2277 void remove(Ptr aPtr) {
2278 MOZ_ASSERT(mTable)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTable)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(mTable))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTable", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2278); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 2278; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
37
Assuming field 'mTable' is non-null
38
Taking false branch
39
Loop condition is false. Exiting loop
2279 ReentrancyGuard g(*this);
2280 MOZ_ASSERT(aPtr.found())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPtr.found())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPtr.found()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPtr.found()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2280); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.found()"
")"); do { *((volatile int*)__null) = 2280; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
40
Assuming the condition is false
41
Taking false branch
42
Loop condition is false. Exiting loop
2281 MOZ_ASSERT(aPtr.mGeneration == generation())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPtr.mGeneration == generation())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPtr.mGeneration == generation
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPtr.mGeneration == generation()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2281); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.mGeneration == generation()"
")"); do { *((volatile int*)__null) = 2281; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
43
Taking false branch
44
Loop condition is false. Exiting loop
2282 remove(aPtr.mSlot);
45
Calling 'HashTable::remove'
2283 shrinkIfUnderloaded();
2284 }
2285
2286 void rekeyWithoutRehash(Ptr aPtr, const Lookup& aLookup, const Key& aKey) {
2287 MOZ_ASSERT(mTable)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTable)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(mTable))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTable", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2287); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 2287; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2288 ReentrancyGuard g(*this);
2289 MOZ_ASSERT(aPtr.found())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPtr.found())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPtr.found()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPtr.found()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2289); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.found()"
")"); do { *((volatile int*)__null) = 2289; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2290 MOZ_ASSERT(aPtr.mGeneration == generation())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPtr.mGeneration == generation())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPtr.mGeneration == generation
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPtr.mGeneration == generation()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h"
, 2290); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.mGeneration == generation()"
")"); do { *((volatile int*)__null) = 2290; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2291 typename HashTableEntry<T>::NonConstT t(std::move(*aPtr));
2292 HashPolicy::setKey(t, const_cast<Key&>(aKey));
2293 remove(aPtr.mSlot);
2294 HashNumber keyHash = prepareHash(HashPolicy::hash(aLookup));
2295 putNewInfallibleInternal(keyHash, std::move(t));
2296 }
2297
2298 void rekeyAndMaybeRehash(Ptr aPtr, const Lookup& aLookup, const Key& aKey) {
2299 rekeyWithoutRehash(aPtr, aLookup, aKey);
2300 infallibleRehashIfOverloaded();
2301 }
2302};
2303
2304} // namespace detail
2305} // namespace mozilla
2306
2307#endif /* mozilla_HashTable_h */