Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/HashTable.h
Warning:line 1191, 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-18/lib/clang/18 -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 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-18/lib/clang/18/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 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -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-2024-07-30-004816-4182763-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 "WindowNamedPropertiesHandler.h"
70#include "nsFrameSelection.h"
71#include "nsNetUtil.h"
72#include "nsVariant.h"
73#include "nsPrintfCString.h"
74#include "mozilla/intl/LocaleService.h"
75#include "WindowDestroyedEvent.h"
76#include "nsDocShellLoadState.h"
77#include "mozilla/dom/WindowGlobalChild.h"
78
79// Helper Classes
80#include "nsJSUtils.h"
81#include "jsapi.h"
82#include "jsfriendapi.h"
83#include "js/CallAndConstruct.h" // JS::Call
84#include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
85#include "js/friend/WindowProxy.h" // js::IsWindowProxy, js::SetWindowProxy
86#include "js/PropertyAndElement.h" // JS_DefineObject, JS_GetProperty
87#include "js/PropertySpec.h"
88#include "js/RealmIterators.h"
89#include "js/Wrapper.h"
90#include "nsLayoutUtils.h"
91#include "nsReadableUtils.h"
92#include "nsJSEnvironment.h"
93#include "mozilla/dom/ScriptSettings.h"
94#include "mozilla/Preferences.h"
95#include "mozilla/Likely.h"
96#include "mozilla/SchedulerGroup.h"
97#include "mozilla/SpinEventLoopUntil.h"
98#include "mozilla/Sprintf.h"
99#include "mozilla/Unused.h"
100
101// Other Classes
102#include "mozilla/dom/BarProps.h"
103#include "nsLayoutStatics.h"
104#include "nsCCUncollectableMarker.h"
105#include "mozilla/dom/WorkerCommon.h"
106#include "mozilla/dom/ToJSValue.h"
107#include "nsJSPrincipals.h"
108#include "mozilla/Attributes.h"
109#include "mozilla/Components.h"
110#include "mozilla/Debug.h"
111#include "mozilla/EventListenerManager.h"
112#include "mozilla/MouseEvents.h"
113#include "mozilla/PresShell.h"
114#include "mozilla/ProcessHangMonitor.h"
115#include "mozilla/StaticPrefs_dom.h"
116#include "mozilla/StaticPrefs_full_screen_api.h"
117#include "mozilla/StaticPrefs_print.h"
118#include "mozilla/StaticPrefs_fission.h"
119#include "mozilla/ThrottledEventQueue.h"
120#include "AudioChannelService.h"
121#include "nsAboutProtocolUtils.h"
122#include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE
123#include "PostMessageEvent.h"
124#include "mozilla/dom/DocGroup.h"
125#include "mozilla/net/CookieJarSettings.h"
126
127// Interfaces Needed
128#include "nsIFrame.h"
129#include "nsCanvasFrame.h"
130#include "nsIWidget.h"
131#include "nsIWidgetListener.h"
132#include "nsIBaseWindow.h"
133#include "nsIDeviceSensors.h"
134#include "nsIContent.h"
135#include "nsIDocShell.h"
136#include "mozilla/dom/Document.h"
137#include "Crypto.h"
138#include "nsDOMString.h"
139#include "nsThreadUtils.h"
140#include "nsILoadContext.h"
141#include "nsView.h"
142#include "nsViewManager.h"
143#include "nsIPrompt.h"
144#include "nsIPromptService.h"
145#include "nsIPromptFactory.h"
146#include "nsIWritablePropertyBag2.h"
147#include "nsIWebNavigation.h"
148#include "nsIWebBrowserChrome.h"
149#include "nsIWebBrowserFind.h" // For window.find()
150#include "nsComputedDOMStyle.h"
151#include "nsDOMCID.h"
152#include "nsDOMWindowUtils.h"
153#include "nsIWindowWatcher.h"
154#include "nsPIWindowWatcher.h"
155#include "nsIDocumentViewer.h"
156#include "nsIScriptError.h"
157#include "nsISHistory.h"
158#include "nsIControllers.h"
159#include "nsGlobalWindowCommands.h"
160#include "nsQueryObject.h"
161#include "nsContentUtils.h"
162#include "nsCSSProps.h"
163#include "nsIURIFixup.h"
164#include "nsIURIMutator.h"
165#include "mozilla/EventDispatcher.h"
166#include "mozilla/EventStateManager.h"
167#include "mozilla/ScrollContainerFrame.h"
168#include "nsIObserverService.h"
169#include "nsFocusManager.h"
170#include "nsIAppWindow.h"
171#include "nsServiceManagerUtils.h"
172#include "mozilla/dom/CustomEvent.h"
173#include "nsIScreenManager.h"
174#include "nsIClassifiedChannel.h"
175#include "nsIXULRuntime.h"
176#include "xpcprivate.h"
177
178#ifdef NS_PRINTING1
179# include "nsIPrintSettings.h"
180# include "nsIPrintSettingsService.h"
181# include "nsIWebBrowserPrint.h"
182#endif
183
184#include "nsWindowRoot.h"
185#include "nsNetCID.h"
186#include "nsIArray.h"
187
188#include "nsIDOMXULCommandDispatcher.h"
189
190#include "mozilla/GlobalKeyListener.h"
191
192#include "nsIDragService.h"
193#include "mozilla/dom/Element.h"
194#include "mozilla/dom/Selection.h"
195#include "nsFrameLoader.h"
196#include "nsFrameLoaderOwner.h"
197#include "nsXPCOMCID.h"
198#include "mozilla/Logging.h"
199#include "mozilla/ProfilerMarkers.h"
200#include "prenv.h"
201
202#include "mozilla/dom/IDBFactory.h"
203#include "mozilla/dom/MessageChannel.h"
204#include "mozilla/dom/Promise.h"
205
206#include "mozilla/dom/Gamepad.h"
207#include "mozilla/dom/GamepadManager.h"
208
209#include "gfxVR.h"
210#include "VRShMem.h"
211#include "FxRWindowManager.h"
212#include "mozilla/dom/VRDisplay.h"
213#include "mozilla/dom/VRDisplayEvent.h"
214#include "mozilla/dom/VRDisplayEventBinding.h"
215#include "mozilla/dom/VREventObserver.h"
216
217#include "nsRefreshDriver.h"
218
219#include "mozilla/extensions/WebExtensionPolicy.h"
220
221#include "mozilla/BasePrincipal.h"
222#include "mozilla/Services.h"
223#include "mozilla/Telemetry.h"
224#include "mozilla/dom/Location.h"
225#include "nsHTMLDocument.h"
226#include "nsWrapperCacheInlines.h"
227#include "mozilla/DOMEventTargetHelper.h"
228#include "prrng.h"
229#include "nsSandboxFlags.h"
230#include "nsXULControllers.h"
231#include "mozilla/dom/AudioContext.h"
232#include "mozilla/dom/BrowserElementDictionariesBinding.h"
233#include "mozilla/dom/BrowsingContextGroup.h"
234#include "mozilla/dom/cache/CacheStorage.h"
235#include "mozilla/dom/Console.h"
236#include "mozilla/dom/Fetch.h"
237#include "mozilla/dom/FunctionBinding.h"
238#include "mozilla/dom/HashChangeEvent.h"
239#include "mozilla/dom/IntlUtils.h"
240#include "mozilla/dom/PopStateEvent.h"
241#include "mozilla/dom/PopupBlockedEvent.h"
242#include "mozilla/dom/PrimitiveConversions.h"
243#include "mozilla/dom/WindowBinding.h"
244#include "nsIBrowserChild.h"
245#include "mozilla/dom/MediaQueryList.h"
246#include "mozilla/dom/NavigatorBinding.h"
247#include "mozilla/dom/ImageBitmap.h"
248#include "mozilla/dom/ImageBitmapBinding.h"
249#include "mozilla/dom/ServiceWorkerRegistration.h"
250#include "mozilla/dom/WebIDLGlobalNameHash.h"
251#include "mozilla/dom/Worklet.h"
252#include "AccessCheck.h"
253
254#ifdef MOZ_WEBSPEECH1
255# include "mozilla/dom/SpeechSynthesis.h"
256#endif
257
258#ifdef ANDROID
259# include <android/log.h>
260#endif
261
262#ifdef XP_WIN
263# include <process.h>
264# define getpid _getpid
265#else
266# include <unistd.h> // for getpid()
267#endif
268
269using namespace mozilla;
270using namespace mozilla::dom;
271using namespace mozilla::dom::ipc;
272using mozilla::BasePrincipal;
273using mozilla::OriginAttributes;
274using mozilla::TimeStamp;
275using mozilla::layout::RemotePrintJobChild;
276
277static inline nsGlobalWindowInner* GetCurrentInnerWindowInternal(
278 const nsGlobalWindowOuter* aOuter) {
279 return nsGlobalWindowInner::Cast(aOuter->GetCurrentInnerWindow());
280}
281
282#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"
, 282); return err_rval; } return GetCurrentInnerWindowInternal
(this)->method args; } while (0)
\
283 PR_BEGIN_MACROdo { \
284 if (!mInnerWindow) { \
285 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"
, 285)
; \
286 return err_rval; \
287 } \
288 return GetCurrentInnerWindowInternal(this)->method args; \
289 PR_END_MACRO} while (0)
290
291#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"
, 291); return; } GetCurrentInnerWindowInternal(this)->method
args; return; } while (0)
\
292 PR_BEGIN_MACROdo { \
293 if (!mInnerWindow) { \
294 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"
, 294)
; \
295 return; \
296 } \
297 GetCurrentInnerWindowInternal(this)->method args; \
298 return; \
299 PR_END_MACRO} while (0)
300
301// Same as FORWARD_TO_INNER, but this will create a fresh inner if an
302// inner doesn't already exists.
303#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)
\
304 PR_BEGIN_MACROdo { \
305 if (!mInnerWindow) { \
306 if (mIsClosed) { \
307 return err_rval; \
308 } \
309 nsCOMPtr<Document> kungFuDeathGrip = GetDoc(); \
310 ::mozilla::Unused << kungFuDeathGrip; \
311 if (!mInnerWindow) { \
312 return err_rval; \
313 } \
314 } \
315 return GetCurrentInnerWindowInternal(this)->method args; \
316 PR_END_MACRO} while (0)
317
318static LazyLogModule gDOMLeakPRLogOuter("DOMLeakOuter");
319extern LazyLogModule gPageCacheLog;
320
321#ifdef DEBUG1
322static LazyLogModule gDocShellAndDOMWindowLeakLogging(
323 "DocShellAndDOMWindowLeak");
324#endif
325
326nsGlobalWindowOuter::OuterWindowByIdTable*
327 nsGlobalWindowOuter::sOuterWindowsById = nullptr;
328
329/* static */
330nsPIDOMWindowOuter* nsPIDOMWindowOuter::GetFromCurrentInner(
331 nsPIDOMWindowInner* aInner) {
332 if (!aInner) {
333 return nullptr;
334 }
335
336 nsPIDOMWindowOuter* outer = aInner->GetOuterWindow();
337 if (!outer || outer->GetCurrentInnerWindow() != aInner) {
338 return nullptr;
339 }
340
341 return outer;
342}
343
344//*****************************************************************************
345// nsOuterWindowProxy: Outer Window Proxy
346//*****************************************************************************
347
348// Give OuterWindowProxyClass 2 reserved slots, like the other wrappers, so
349// JSObject::swap can swap it with CrossCompartmentWrappers without requiring
350// malloc.
351//
352// We store the nsGlobalWindowOuter* in our first slot.
353//
354// We store our holder weakmap in the second slot.
355const 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}
356 "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 */
357
358static const size_t OUTER_WINDOW_SLOT = 0;
359static const size_t HOLDER_WEAKMAP_SLOT = 1;
360
361class nsOuterWindowProxy : public MaybeCrossOriginObject<js::Wrapper> {
362 using Base = MaybeCrossOriginObject<js::Wrapper>;
363
364 public:
365 constexpr nsOuterWindowProxy() : Base(0) {}
366
367 bool finalizeInBackground(const JS::Value& priv) const override {
368 return false;
369 }
370
371 // Standard internal methods
372 /**
373 * Implementation of [[GetOwnProperty]] as defined at
374 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty
375 *
376 * "proxy" is the WindowProxy object involved. It may not be same-compartment
377 * with cx.
378 */
379 bool getOwnPropertyDescriptor(
380 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
381 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const override;
382
383 /*
384 * Implementation of the same-origin case of
385 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty>.
386 */
387 bool definePropertySameOrigin(JSContext* cx, JS::Handle<JSObject*> proxy,
388 JS::Handle<jsid> id,
389 JS::Handle<JS::PropertyDescriptor> desc,
390 JS::ObjectOpResult& result) const override;
391
392 /**
393 * Implementation of [[OwnPropertyKeys]] as defined at
394 *
395 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys
396 *
397 * "proxy" is the WindowProxy object involved. It may not be same-compartment
398 * with cx.
399 */
400 bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
401 JS::MutableHandleVector<jsid> props) const override;
402 /**
403 * Implementation of [[Delete]] as defined at
404 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-delete
405 *
406 * "proxy" is the WindowProxy object involved. It may not be same-compartment
407 * with cx.
408 */
409 bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
410 JS::ObjectOpResult& result) const override;
411
412 /**
413 * Implementaton of hook for superclass getPrototype() method.
414 */
415 JSObject* getSameOriginPrototype(JSContext* cx) const override;
416
417 /**
418 * Implementation of [[HasProperty]] internal method as defined at
419 * https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p
420 *
421 * "proxy" is the WindowProxy object involved. It may not be same-compartment
422 * with cx.
423 *
424 * Note that the HTML spec does not define an override for this internal
425 * method, so we just want the "normal object" behavior. We have to override
426 * it, because js::Wrapper also overrides, with "not normal" behavior.
427 */
428 bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
429 bool* bp) const override;
430
431 /**
432 * Implementation of [[Get]] internal method as defined at
433 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-get>.
434 *
435 * "proxy" is the WindowProxy object involved. It may or may not be
436 * same-compartment with "cx".
437 *
438 * "receiver" is the receiver ("this") for the get. It will be
439 * same-compartment with "cx".
440 *
441 * "vp" is the return value. It will be same-compartment with "cx".
442 */
443 bool get(JSContext* cx, JS::Handle<JSObject*> proxy,
444 JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
445 JS::MutableHandle<JS::Value> vp) const override;
446
447 /**
448 * Implementation of [[Set]] internal method as defined at
449 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-set>.
450 *
451 * "proxy" is the WindowProxy object involved. It may or may not be
452 * same-compartment with "cx".
453 *
454 * "v" is the value being set. It will be same-compartment with "cx".
455 *
456 * "receiver" is the receiver ("this") for the set. It will be
457 * same-compartment with "cx".
458 */
459 bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
460 JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
461 JS::ObjectOpResult& result) const override;
462
463 // SpiderMonkey extensions
464 /**
465 * Implementation of SpiderMonkey extension which just checks whether this
466 * object has the property. Basically Object.getOwnPropertyDescriptor(obj,
467 * prop) !== undefined. but does not require reifying the descriptor.
468 *
469 * We have to override this because js::Wrapper overrides it, but we want
470 * different behavior from js::Wrapper.
471 *
472 * "proxy" is the WindowProxy object involved. It may not be same-compartment
473 * with cx.
474 */
475 bool hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
476 bool* bp) const override;
477
478 /**
479 * Implementation of SpiderMonkey extension which is used as a fast path for
480 * enumerating.
481 *
482 * We have to override this because js::Wrapper overrides it, but we want
483 * different behavior from js::Wrapper.
484 *
485 * "proxy" is the WindowProxy object involved. It may not be same-compartment
486 * with cx.
487 */
488 bool getOwnEnumerablePropertyKeys(
489 JSContext* cx, JS::Handle<JSObject*> proxy,
490 JS::MutableHandleVector<jsid> props) const override;
491
492 /**
493 * Hook used by SpiderMonkey to implement Object.prototype.toString.
494 */
495 const char* className(JSContext* cx,
496 JS::Handle<JSObject*> wrapper) const override;
497
498 void finalize(JS::GCContext* gcx, JSObject* proxy) const override;
499 size_t objectMoved(JSObject* proxy, JSObject* old) const override;
500
501 bool isCallable(JSObject* obj) const override { return false; }
502 bool isConstructor(JSObject* obj) const override { return false; }
503
504 static const nsOuterWindowProxy singleton;
505
506 static nsGlobalWindowOuter* GetOuterWindow(JSObject* proxy) {
507 nsGlobalWindowOuter* outerWindow =
508 nsGlobalWindowOuter::FromSupports(static_cast<nsISupports*>(
509 js::GetProxyReservedSlot(proxy, OUTER_WINDOW_SLOT).toPrivate()));
510 return outerWindow;
511 }
512
513 protected:
514 // False return value means we threw an exception. True return value
515 // but false "found" means we didn't have a subframe at that index.
516 bool GetSubframeWindow(JSContext* cx, JS::Handle<JSObject*> proxy,
517 JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp,
518 bool& found) const;
519
520 // Returns a non-null window only if id is an index and we have a
521 // window at that index.
522 Nullable<WindowProxyHolder> GetSubframeWindow(JSContext* cx,
523 JS::Handle<JSObject*> proxy,
524 JS::Handle<jsid> id) const;
525
526 bool AppendIndexedPropertyNames(JSObject* proxy,
527 JS::MutableHandleVector<jsid> props) const;
528
529 using MaybeCrossOriginObjectMixins::EnsureHolder;
530 bool EnsureHolder(JSContext* cx, JS::Handle<JSObject*> proxy,
531 JS::MutableHandle<JSObject*> holder) const override;
532
533 // Helper method for creating a special "print" method that allows printing
534 // our PDF-viewer documents even if you're not same-origin with them.
535 //
536 // aProxy must be our nsOuterWindowProxy. It will not be same-compartment
537 // with aCx, since we only use this on the different-origin codepath!
538 //
539 // Can return true without filling in aDesc, which corresponds to not exposing
540 // a "print" method.
541 static bool MaybeGetPDFJSPrintMethod(
542 JSContext* cx, JS::Handle<JSObject*> proxy,
543 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc);
544
545 // The actual "print" method we use for the PDFJS case.
546 static bool PDFJSPrintMethod(JSContext* cx, unsigned argc, JS::Value* vp);
547
548 // Helper method to get the pre-PDF-viewer-messing-with-it principal from an
549 // inner window. Will return null if this is not a PDF-viewer inner or if the
550 // principal could not be found for some reason.
551 static already_AddRefed<nsIPrincipal> GetNoPDFJSPrincipal(
552 nsGlobalWindowInner* inner);
553};
554
555const char* nsOuterWindowProxy::className(JSContext* cx,
556 JS::Handle<JSObject*> proxy) const {
557 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"
, 557); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsProxy(proxy)"
")"); do { *((volatile int*)__null) = 557; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
558
559 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
560 return "Object";
561 }
562
563 return "Window";
564}
565
566void nsOuterWindowProxy::finalize(JS::GCContext* gcx, JSObject* proxy) const {
567 nsGlobalWindowOuter* outerWindow = GetOuterWindow(proxy);
568 if (outerWindow) {
569 outerWindow->ClearWrapper(proxy);
570 BrowsingContext* bc = outerWindow->GetBrowsingContext();
571 if (bc) {
572 bc->ClearWindowProxy();
573 }
574
575 // Ideally we would use OnFinalize here, but it's possible that
576 // EnsureScriptEnvironment will later be called on the window, and we don't
577 // want to create a new script object in that case. Therefore, we need to
578 // write a non-null value that will reliably crash when dereferenced.
579 outerWindow->PoisonOuterWindowProxy(proxy);
580 }
581}
582
583bool nsOuterWindowProxy::getOwnPropertyDescriptor(
584 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
585 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const {
586 // First check for indexed access. This is
587 // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty
588 // step 2, mostly.
589 JS::Rooted<JS::Value> subframe(cx);
590 bool found;
591 if (!GetSubframeWindow(cx, proxy, id, &subframe, found)) {
592 return false;
593 }
594 if (found) {
595 // Step 2.4.
596
597 desc.set(Some(JS::PropertyDescriptor::Data(
598 subframe, {
599 JS::PropertyAttribute::Configurable,
600 JS::PropertyAttribute::Enumerable,
601 })));
602 return true;
603 }
604
605 bool isSameOrigin = IsPlatformObjectSameOrigin(cx, proxy);
606
607 // If we did not find a subframe, we could still have an indexed property
608 // access. In that case we should throw a SecurityError in the cross-origin
609 // case.
610 if (!isSameOrigin && IsArrayIndex(GetArrayIndexFromId(id))) {
611 // Step 2.5.2.
612 return ReportCrossOriginDenial(cx, id, "access"_ns);
613 }
614
615 // Step 2.5.1 is handled via the forwarding to js::Wrapper; it saves us an
616 // IsArrayIndex(GetArrayIndexFromId(id)) here. We'll never have a property on
617 // the Window whose name is an index, because our defineProperty doesn't pass
618 // those on to the Window.
619
620 // Step 3.
621 if (isSameOrigin) {
622 if (StaticPrefs::dom_missing_prop_counters_enabled() && id.isAtom()) {
623 Window_Binding::CountMaybeMissingProperty(proxy, id);
624 }
625
626 // Fall through to js::Wrapper.
627 { // Scope for JSAutoRealm while we are dealing with js::Wrapper.
628 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
629 // for now. That's what js::Wrapper expects, and since we're same-origin
630 // anyway this is not changing any security behavior.
631 JSAutoRealm ar(cx, proxy);
632 JS_MarkCrossZoneId(cx, id);
633 bool ok = js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
634 if (!ok) {
635 return false;
636 }
637
638#if 0
639 // See https://github.com/tc39/ecma262/issues/672 for more information.
640 if (desc.isSome() &&
641 !IsNonConfigurableReadonlyPrimitiveGlobalProp(cx, id)) {
642 (*desc).setConfigurable(true);
643 }
644#endif
645 }
646
647 // Now wrap our descriptor back into the Realm that asked for it.
648 return JS_WrapPropertyDescriptor(cx, desc);
649 }
650
651 // Step 4.
652 if (!CrossOriginGetOwnPropertyHelper(cx, proxy, id, desc)) {
653 return false;
654 }
655
656 // Step 5
657 if (desc.isSome()) {
658 return true;
659 }
660
661 // Non-spec step for the PDF viewer's window.print(). This comes before we
662 // check for named subframes, because in the same-origin case print() would
663 // shadow those.
664 if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_PRINT)) {
665 if (!MaybeGetPDFJSPrintMethod(cx, proxy, desc)) {
666 return false;
667 }
668
669 if (desc.isSome()) {
670 return true;
671 }
672 }
673
674 // Step 6 -- check for named subframes.
675 if (id.isString()) {
676 nsAutoJSString name;
677 if (!name.init(cx, id.toString())) {
678 return false;
679 }
680 nsGlobalWindowOuter* win = GetOuterWindow(proxy);
681 if (RefPtr<BrowsingContext> childDOMWin = win->GetChildWindow(name)) {
682 JS::Rooted<JS::Value> childValue(cx);
683 if (!ToJSValue(cx, WindowProxyHolder(childDOMWin), &childValue)) {
684 return false;
685 }
686 desc.set(Some(JS::PropertyDescriptor::Data(
687 childValue, {JS::PropertyAttribute::Configurable})));
688 return true;
689 }
690 }
691
692 // And step 7.
693 return CrossOriginPropertyFallback(cx, proxy, id, desc);
694}
695
696bool nsOuterWindowProxy::definePropertySameOrigin(
697 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
698 JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result) const {
699 if (IsArrayIndex(GetArrayIndexFromId(id))) {
700 // Spec says to Reject whether this is a supported index or not,
701 // since we have no indexed setter or indexed creator. It is up
702 // to the caller to decide whether to throw a TypeError.
703 return result.failCantDefineWindowElement();
704 }
705
706 JS::ObjectOpResult ourResult;
707 bool ok = js::Wrapper::defineProperty(cx, proxy, id, desc, ourResult);
708 if (!ok) {
709 return false;
710 }
711
712 if (!ourResult.ok()) {
713 // It's possible that this failed because the page got the existing
714 // descriptor (which we force to claim to be configurable) and then tried to
715 // redefine the property with the descriptor it got but a different value.
716 // We want to allow this case to succeed, so check for it and if we're in
717 // that case try again but now with an attempt to define a non-configurable
718 // property.
719 if (!desc.hasConfigurable() || !desc.configurable()) {
720 // The incoming descriptor was not explicitly marked "configurable: true",
721 // so it failed for some other reason. Just propagate that reason out.
722 result = ourResult;
723 return true;
724 }
725
726 JS::Rooted<Maybe<JS::PropertyDescriptor>> existingDesc(cx);
727 ok = js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, &existingDesc);
728 if (!ok) {
729 return false;
730 }
731 if (existingDesc.isNothing() || existingDesc->configurable()) {
732 // We have no existing property, or its descriptor is already configurable
733 // (on the Window itself, where things really can be non-configurable).
734 // So we failed for some other reason, which we should propagate out.
735 result = ourResult;
736 return true;
737 }
738
739 JS::Rooted<JS::PropertyDescriptor> updatedDesc(cx, desc);
740 updatedDesc.setConfigurable(false);
741
742 JS::ObjectOpResult ourNewResult;
743 ok = js::Wrapper::defineProperty(cx, proxy, id, updatedDesc, ourNewResult);
744 if (!ok) {
745 return false;
746 }
747
748 if (!ourNewResult.ok()) {
749 // Twiddling the configurable flag didn't help. Just return this failure
750 // out to the caller.
751 result = ourNewResult;
752 return true;
753 }
754 }
755
756#if 0
757 // See https://github.com/tc39/ecma262/issues/672 for more information.
758 if (desc.hasConfigurable() && !desc.configurable() &&
759 !IsNonConfigurableReadonlyPrimitiveGlobalProp(cx, id)) {
760 // Give callers a way to detect that they failed to "really" define a
761 // non-configurable property.
762 result.failCantDefineWindowNonConfigurable();
763 return true;
764 }
765#endif
766
767 result.succeed();
768 return true;
769}
770
771bool nsOuterWindowProxy::ownPropertyKeys(
772 JSContext* cx, JS::Handle<JSObject*> proxy,
773 JS::MutableHandleVector<jsid> props) const {
774 // Just our indexed stuff followed by our "normal" own property names.
775 if (!AppendIndexedPropertyNames(proxy, props)) {
776 return false;
777 }
778
779 if (IsPlatformObjectSameOrigin(cx, proxy)) {
780 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
781 // for now. That's what js::Wrapper expects, and since we're same-origin
782 // anyway this is not changing any security behavior.
783 JS::RootedVector<jsid> innerProps(cx);
784 { // Scope for JSAutoRealm so we can mark the ids once we exit it
785 JSAutoRealm ar(cx, proxy);
786 if (!js::Wrapper::ownPropertyKeys(cx, proxy, &innerProps)) {
787 return false;
788 }
789 }
790 for (auto& id : innerProps) {
791 JS_MarkCrossZoneId(cx, id);
792 }
793 return js::AppendUnique(cx, props, innerProps);
794 }
795
796 // In the cross-origin case we purposefully exclude subframe names from the
797 // list of property names we report here.
798 JS::Rooted<JSObject*> holder(cx);
799 if (!EnsureHolder(cx, proxy, &holder)) {
800 return false;
801 }
802
803 JS::RootedVector<jsid> crossOriginProps(cx);
804 if (!js::GetPropertyKeys(cx, holder,
805 JSITER_OWNONLY0x8 | JSITER_HIDDEN0x10 | JSITER_SYMBOLS0x20,
806 &crossOriginProps) ||
807 !js::AppendUnique(cx, props, crossOriginProps)) {
808 return false;
809 }
810
811 // Add the "print" property if needed.
812 nsGlobalWindowOuter* outer = GetOuterWindow(proxy);
813 nsGlobalWindowInner* inner =
814 nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow());
815 if (inner) {
816 nsCOMPtr<nsIPrincipal> targetPrincipal = GetNoPDFJSPrincipal(inner);
817 if (targetPrincipal &&
818 nsContentUtils::SubjectPrincipal(cx)->Equals(targetPrincipal)) {
819 JS::RootedVector<jsid> printProp(cx);
820 if (!printProp.append(GetJSIDByIndex(cx, XPCJSContext::IDX_PRINT)) ||
821 !js::AppendUnique(cx, props, printProp)) {
822 return false;
823 }
824 }
825 }
826
827 return xpc::AppendCrossOriginWhitelistedPropNames(cx, props);
828}
829
830bool nsOuterWindowProxy::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
831 JS::Handle<jsid> id,
832 JS::ObjectOpResult& result) const {
833 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
834 return ReportCrossOriginDenial(cx, id, "delete"_ns);
835 }
836
837 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
838 // Fail (which means throw if strict, else return false).
839 return result.failCantDeleteWindowElement();
840 }
841
842 if (IsArrayIndex(GetArrayIndexFromId(id))) {
843 // Indexed, but not supported. Spec says return true.
844 return result.succeed();
845 }
846
847 // We're same-origin, so it should be safe to enter the Realm of "proxy".
848 // Let's do that, just in case, to avoid cross-compartment issues in our
849 // js::Wrapper caller..
850 JSAutoRealm ar(cx, proxy);
851 JS_MarkCrossZoneId(cx, id);
852 return js::Wrapper::delete_(cx, proxy, id, result);
853}
854
855JSObject* nsOuterWindowProxy::getSameOriginPrototype(JSContext* cx) const {
856 return Window_Binding::GetProtoObjectHandle(cx);
857}
858
859bool nsOuterWindowProxy::has(JSContext* cx, JS::Handle<JSObject*> proxy,
860 JS::Handle<jsid> id, bool* bp) const {
861 // We could just directly forward this method to js::BaseProxyHandler, but
862 // that involves reifying the actual property descriptor, which might be more
863 // work than we have to do for has() on the Window.
864
865 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
866 // In the cross-origin case we only have own properties. Just call hasOwn
867 // directly.
868 return hasOwn(cx, proxy, id, bp);
869 }
870
871 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
872 *bp = true;
873 return true;
874 }
875
876 // Just to be safe in terms of compartment asserts, enter the Realm of
877 // "proxy". We're same-origin with it, so this should be safe.
878 JSAutoRealm ar(cx, proxy);
879 JS_MarkCrossZoneId(cx, id);
880 return js::Wrapper::has(cx, proxy, id, bp);
881}
882
883bool nsOuterWindowProxy::hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy,
884 JS::Handle<jsid> id, bool* bp) const {
885 // We could just directly forward this method to js::BaseProxyHandler, but
886 // that involves reifying the actual property descriptor, which might be more
887 // work than we have to do for hasOwn() on the Window.
888
889 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
890 // Avoiding reifying the property descriptor here would require duplicating
891 // a bunch of "is this property exposed cross-origin" logic, which is
892 // probably not worth it. Just forward this along to the base
893 // implementation.
894 //
895 // It's very important to not forward this to js::Wrapper, because that will
896 // not do the right security and cross-origin checks and will pass through
897 // the call to the Window.
898 //
899 // The BaseProxyHandler code is OK with this happening without entering the
900 // compartment of "proxy".
901 return js::BaseProxyHandler::hasOwn(cx, proxy, id, bp);
902 }
903
904 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
905 *bp = true;
906 return true;
907 }
908
909 // Just to be safe in terms of compartment asserts, enter the Realm of
910 // "proxy". We're same-origin with it, so this should be safe.
911 JSAutoRealm ar(cx, proxy);
912 JS_MarkCrossZoneId(cx, id);
913 return js::Wrapper::hasOwn(cx, proxy, id, bp);
914}
915
916bool nsOuterWindowProxy::get(JSContext* cx, JS::Handle<JSObject*> proxy,
917 JS::Handle<JS::Value> receiver,
918 JS::Handle<jsid> id,
919 JS::MutableHandle<JS::Value> vp) const {
920 if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_WRAPPED_JSOBJECT) &&
921 xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
922 vp.set(JS::ObjectValue(*proxy));
923 return MaybeWrapValue(cx, vp);
924 }
925
926 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
927 return CrossOriginGet(cx, proxy, receiver, id, vp);
928 }
929
930 bool found;
931 if (!GetSubframeWindow(cx, proxy, id, vp, found)) {
932 return false;
933 }
934
935 if (found) {
936 return true;
937 }
938
939 if (StaticPrefs::dom_missing_prop_counters_enabled() && id.isAtom()) {
940 Window_Binding::CountMaybeMissingProperty(proxy, id);
941 }
942
943 { // Scope for JSAutoRealm
944 // Enter "proxy"'s Realm. We're in the same-origin case, so this should be
945 // safe.
946 JSAutoRealm ar(cx, proxy);
947
948 JS_MarkCrossZoneId(cx, id);
949
950 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
951 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
952 return false;
953 }
954
955 // Fall through to js::Wrapper.
956 if (!js::Wrapper::get(cx, proxy, wrappedReceiver, id, vp)) {
957 return false;
958 }
959 }
960
961 // Make sure our return value is in the caller compartment.
962 return MaybeWrapValue(cx, vp);
963}
964
965bool nsOuterWindowProxy::set(JSContext* cx, JS::Handle<JSObject*> proxy,
966 JS::Handle<jsid> id, JS::Handle<JS::Value> v,
967 JS::Handle<JS::Value> receiver,
968 JS::ObjectOpResult& result) const {
969 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
970 return CrossOriginSet(cx, proxy, id, v, receiver, result);
971 }
972
973 if (IsArrayIndex(GetArrayIndexFromId(id))) {
974 // Reject the set. It's up to the caller to decide whether to throw a
975 // TypeError. If the caller is strict mode JS code, it'll throw.
976 return result.failReadOnly();
977 }
978
979 // Do the rest in the Realm of "proxy", since we're in the same-origin case.
980 JSAutoRealm ar(cx, proxy);
981 JS::Rooted<JS::Value> wrappedArg(cx, v);
982 if (!MaybeWrapValue(cx, &wrappedArg)) {
983 return false;
984 }
985 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
986 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
987 return false;
988 }
989
990 JS_MarkCrossZoneId(cx, id);
991
992 return js::Wrapper::set(cx, proxy, id, wrappedArg, wrappedReceiver, result);
993}
994
995bool nsOuterWindowProxy::getOwnEnumerablePropertyKeys(
996 JSContext* cx, JS::Handle<JSObject*> proxy,
997 JS::MutableHandleVector<jsid> props) const {
998 // We could just stop overring getOwnEnumerablePropertyKeys and let our
999 // superclasses deal (by falling back on the BaseProxyHandler implementation
1000 // that uses a combination of ownPropertyKeys and getOwnPropertyDescriptor to
1001 // only return the enumerable ones. But maybe there's value in having
1002 // somewhat faster for-in iteration on Window objects...
1003
1004 // Like ownPropertyKeys, our indexed stuff followed by our "normal" enumerable
1005 // own property names.
1006 if (!AppendIndexedPropertyNames(proxy, props)) {
1007 return false;
1008 }
1009
1010 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
1011 // All the cross-origin properties other than the indexed props are
1012 // non-enumerable, so we're done here.
1013 return true;
1014 }
1015
1016 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
1017 // for now. That's what js::Wrapper expects, and since we're same-origin
1018 // anyway this is not changing any security behavior.
1019 JS::RootedVector<jsid> innerProps(cx);
1020 { // Scope for JSAutoRealm so we can mark the ids once we exit it.
1021 JSAutoRealm ar(cx, proxy);
1022 if (!js::Wrapper::getOwnEnumerablePropertyKeys(cx, proxy, &innerProps)) {
1023 return false;
1024 }
1025 }
1026
1027 for (auto& id : innerProps) {
1028 JS_MarkCrossZoneId(cx, id);
1029 }
1030
1031 return js::AppendUnique(cx, props, innerProps);
1032}
1033
1034bool nsOuterWindowProxy::GetSubframeWindow(JSContext* cx,
1035 JS::Handle<JSObject*> proxy,
1036 JS::Handle<jsid> id,
1037 JS::MutableHandle<JS::Value> vp,
1038 bool& found) const {
1039 Nullable<WindowProxyHolder> frame = GetSubframeWindow(cx, proxy, id);
1040 if (frame.IsNull()) {
1041 found = false;
1042 return true;
1043 }
1044
1045 found = true;
1046 return WrapObject(cx, frame.Value(), vp);
1047}
1048
1049Nullable<WindowProxyHolder> nsOuterWindowProxy::GetSubframeWindow(
1050 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const {
1051 uint32_t index = GetArrayIndexFromId(id);
1052 if (!IsArrayIndex(index)) {
1053 return nullptr;
1054 }
1055
1056 nsGlobalWindowOuter* win = GetOuterWindow(proxy);
1057 return win->IndexedGetterOuter(index);
1058}
1059
1060bool nsOuterWindowProxy::AppendIndexedPropertyNames(
1061 JSObject* proxy, JS::MutableHandleVector<jsid> props) const {
1062 uint32_t length = GetOuterWindow(proxy)->Length();
1063 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"
, 1063); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(length) >= 0"
")"); do { *((volatile int*)__null) = 1063; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1064 if (!props.reserve(props.length() + length)) {
1065 return false;
1066 }
1067 for (int32_t i = 0; i < int32_t(length); ++i) {
1068 if (!props.append(JS::PropertyKey::Int(i))) {
1069 return false;
1070 }
1071 }
1072
1073 return true;
1074}
1075
1076bool nsOuterWindowProxy::EnsureHolder(
1077 JSContext* cx, JS::Handle<JSObject*> proxy,
1078 JS::MutableHandle<JSObject*> holder) const {
1079 return EnsureHolder(cx, proxy, HOLDER_WEAKMAP_SLOT,
1080 Window_Binding::sCrossOriginProperties, holder);
1081}
1082
1083size_t nsOuterWindowProxy::objectMoved(JSObject* obj, JSObject* old) const {
1084 nsGlobalWindowOuter* outerWindow = GetOuterWindow(obj);
1085 if (outerWindow) {
1086 outerWindow->UpdateWrapper(obj, old);
1087 BrowsingContext* bc = outerWindow->GetBrowsingContext();
1088 if (bc) {
1089 bc->UpdateWindowProxy(obj, old);
1090 }
1091 }
1092 return 0;
1093}
1094
1095enum { PDFJS_SLOT_CALLEE = 0 };
1096
1097// static
1098bool nsOuterWindowProxy::MaybeGetPDFJSPrintMethod(
1099 JSContext* cx, JS::Handle<JSObject*> proxy,
1100 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) {
1101 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"
, 1101); AnnotateMozCrashReason("MOZ_ASSERT" "(" "proxy" ")")
; do { *((volatile int*)__null) = 1101; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1102 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"
, 1102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!desc.isSome()"
")"); do { *((volatile int*)__null) = 1102; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1103
1104 nsGlobalWindowOuter* outer = GetOuterWindow(proxy);
1105 nsGlobalWindowInner* inner =
1106 nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow());
1107 if (!inner) {
1108 // No print method to expose.
1109 return true;
1110 }
1111
1112 nsCOMPtr<nsIPrincipal> targetPrincipal = GetNoPDFJSPrincipal(inner);
1113 if (!targetPrincipal) {
1114 // Nothing special to be done.
1115 return true;
1116 }
1117
1118 if (!nsContentUtils::SubjectPrincipal(cx)->Equals(targetPrincipal)) {
1119 // Not our origin's PDF document.
1120 return true;
1121 }
1122
1123 // Get the function we plan to actually call.
1124 JS::Rooted<JSObject*> innerObj(cx, inner->GetGlobalJSObject());
1125 if (!innerObj) {
1126 // Really should not happen, but ok, let's just return.
1127 return true;
1128 }
1129
1130 JS::Rooted<JS::Value> targetFunc(cx);
1131 {
1132 JSAutoRealm ar(cx, innerObj);
1133 if (!JS_GetProperty(cx, innerObj, "print", &targetFunc)) {
1134 return false;
1135 }
1136 }
1137
1138 if (!targetFunc.isObject()) {
1139 // Who knows what's going on. Just return.
1140 return true;
1141 }
1142
1143 // The Realm of cx is the realm our caller is in and the realm we
1144 // should create our function in. Note that we can't use the
1145 // standard XPConnect function forwarder machinery because our
1146 // "this" is cross-origin, so we have to do thus by hand.
1147
1148 // Make sure targetFunc is wrapped into the right compartment.
1149 if (!MaybeWrapValue(cx, &targetFunc)) {
1150 return false;
1151 }
1152
1153 JSFunction* fun =
1154 js::NewFunctionWithReserved(cx, PDFJSPrintMethod, 0, 0, "print");
1155 if (!fun) {
1156 return false;
1157 }
1158
1159 JS::Rooted<JSObject*> funObj(cx, JS_GetFunctionObject(fun));
1160 js::SetFunctionNativeReserved(funObj, PDFJS_SLOT_CALLEE, targetFunc);
1161
1162 // { value: <print>, writable: true, enumerable: true, configurable: true }
1163 // because that's what it would have been in the same-origin case without
1164 // the PDF viewer messing with things.
1165 desc.set(Some(JS::PropertyDescriptor::Data(
1166 JS::ObjectValue(*funObj),
1167 {JS::PropertyAttribute::Configurable, JS::PropertyAttribute::Enumerable,
1168 JS::PropertyAttribute::Writable})));
1169 return true;
1170}
1171
1172// static
1173bool nsOuterWindowProxy::PDFJSPrintMethod(JSContext* cx, unsigned argc,
1174 JS::Value* vp) {
1175 JS::CallArgs args = CallArgsFromVp(argc, vp);
1176
1177 JS::Rooted<JSObject*> realCallee(
1178 cx, &js::GetFunctionNativeReserved(&args.callee(), PDFJS_SLOT_CALLEE)
1179 .toObject());
1180 // Unchecked unwrap, because we want to extract the thing we really had
1181 // before.
1182 realCallee = js::UncheckedUnwrap(realCallee);
1183
1184 JS::Rooted<JS::Value> thisv(cx, args.thisv());
1185 if (thisv.isNullOrUndefined()) {
1186 // Replace it with the global of our stashed callee, simulating the
1187 // global-assuming behavior of DOM methods.
1188 JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(realCallee));
1189 if (!MaybeWrapObject(cx, &global)) {
1190 return false;
1191 }
1192 thisv.setObject(*global);
1193 } else if (!thisv.isObject()) {
1194 return ThrowInvalidThis(cx, args, false, prototypes::id::Window);
1195 }
1196
1197 // We want to do an UncheckedUnwrap here, because we're going to directly
1198 // examine the principal of the inner window, if we have an inner window.
1199 JS::Rooted<JSObject*> unwrappedObj(cx,
1200 js::UncheckedUnwrap(&thisv.toObject()));
1201 nsGlobalWindowInner* inner = nullptr;
1202 {
1203 // Do the unwrap in the Realm of the object we're looking at.
1204 JSAutoRealm ar(cx, unwrappedObj);
1205 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)
;
1206 }
1207 if (!inner) {
1208 return ThrowInvalidThis(cx, args, false, prototypes::id::Window);
1209 }
1210
1211 nsIPrincipal* callerPrincipal = nsContentUtils::SubjectPrincipal(cx);
1212 if (!callerPrincipal->SubsumesConsideringDomain(inner->GetPrincipal())) {
1213 // Check whether it's a PDF viewer from our origin.
1214 nsCOMPtr<nsIPrincipal> pdfPrincipal = GetNoPDFJSPrincipal(inner);
1215 if (!pdfPrincipal || !callerPrincipal->Equals(pdfPrincipal)) {
1216 // Security error.
1217 return ThrowInvalidThis(cx, args, true, prototypes::id::Window);
1218 }
1219 }
1220
1221 // Go ahead and enter the Realm of our real callee to call it. We'll pass it
1222 // our "thisv", just in case someone grabs a "print" method off one PDF
1223 // document and .call()s it on another one.
1224 {
1225 JSAutoRealm ar(cx, realCallee);
1226 if (!MaybeWrapValue(cx, &thisv)) {
1227 return false;
1228 }
1229
1230 // Don't bother passing through the args; they will get ignored anyway.
1231
1232 if (!JS::Call(cx, thisv, realCallee, JS::HandleValueArray::empty(),
1233 args.rval())) {
1234 return false;
1235 }
1236 }
1237
1238 // Wrap the return value (not that there should be any!) into the right
1239 // compartment.
1240 return MaybeWrapValue(cx, args.rval());
1241}
1242
1243// static
1244already_AddRefed<nsIPrincipal> nsOuterWindowProxy::GetNoPDFJSPrincipal(
1245 nsGlobalWindowInner* inner) {
1246 if (!nsContentUtils::IsPDFJS(inner->GetPrincipal())) {
1247 return nullptr;
1248 }
1249
1250 if (Document* doc = inner->GetExtantDoc()) {
1251 if (nsCOMPtr<nsIPropertyBag2> propBag =
1252 do_QueryInterface(doc->GetChannel())) {
1253 nsCOMPtr<nsIPrincipal> principal(
1254 do_GetProperty(propBag, u"noPDFJSPrincipal"_ns));
1255 return principal.forget();
1256 }
1257 }
1258 return nullptr;
1259}
1260
1261const nsOuterWindowProxy nsOuterWindowProxy::singleton;
1262
1263class nsChromeOuterWindowProxy : public nsOuterWindowProxy {
1264 public:
1265 constexpr nsChromeOuterWindowProxy() = default;
1266
1267 const char* className(JSContext* cx,
1268 JS::Handle<JSObject*> wrapper) const override;
1269
1270 static const nsChromeOuterWindowProxy singleton;
1271};
1272
1273const char* nsChromeOuterWindowProxy::className(
1274 JSContext* cx, JS::Handle<JSObject*> proxy) const {
1275 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"
, 1275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsProxy(proxy)"
")"); do { *((volatile int*)__null) = 1275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1276
1277 return "ChromeWindow";
1278}
1279
1280const nsChromeOuterWindowProxy nsChromeOuterWindowProxy::singleton;
1281
1282static JSObject* NewOuterWindowProxy(JSContext* cx,
1283 JS::Handle<JSObject*> global,
1284 bool isChrome) {
1285 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"
, 1285); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JS_IsGlobalObject(global)"
")"); do { *((volatile int*)__null) = 1285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1286
1287 JSAutoRealm ar(cx, global);
1288
1289 js::WrapperOptions options;
1290 options.setClass(&OuterWindowProxyClass);
1291 JSObject* obj =
1292 js::Wrapper::New(cx, global,
1293 isChrome ? &nsChromeOuterWindowProxy::singleton
1294 : &nsOuterWindowProxy::singleton,
1295 options);
1296 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"
, 1296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(obj)"
")"); do { *((volatile int*)__null) = 1296; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1297 return obj;
1298}
1299
1300//*****************************************************************************
1301//*** nsGlobalWindowOuter: Object Management
1302//*****************************************************************************
1303
1304nsGlobalWindowOuter::nsGlobalWindowOuter(uint64_t aWindowID)
1305 : nsPIDOMWindowOuter(aWindowID),
1306 mFullscreenHasChangedDuringProcessing(false),
1307 mForceFullScreenInWidget(false),
1308 mIsClosed(false),
1309 mInClose(false),
1310 mHavePendingClose(false),
1311 mBlockScriptedClosingFlag(false),
1312 mWasOffline(false),
1313 mCreatingInnerWindow(false),
1314 mIsChrome(false),
1315 mAllowScriptsToClose(false),
1316 mTopLevelOuterContentWindow(false),
1317 mDelayedPrintUntilAfterLoad(false),
1318 mDelayedCloseForPrinting(false),
1319 mShouldDelayPrintUntilAfterLoad(false),
1320#ifdef DEBUG1
1321 mSerial(0),
1322 mSetOpenerWindowCalled(false),
1323#endif
1324 mCleanedUp(false),
1325 mCanSkipCCGeneration(0),
1326 mAutoActivateVRDisplayID(0) {
1327 AssertIsOnMainThread();
1328 SetIsOnMainThread();
1329 nsLayoutStatics::AddRef();
1330
1331 // Initialize the PRCList (this).
1332 PR_INIT_CLIST(this)do { (this)->next = (this); (this)->prev = (this); } while
(0)
;
1333
1334 // |this| is an outer window. Outer windows start out frozen and
1335 // remain frozen until they get an inner window.
1336 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"
, 1336); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFrozen()"
")"); do { *((volatile int*)__null) = 1336; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1337
1338 // We could have failed the first time through trying
1339 // to create the entropy collector, so we should
1340 // try to get one until we succeed.
1341
1342#ifdef DEBUG1
1343 mSerial = nsContentUtils::InnerOrOuterWindowCreated();
1344
1345 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)
1346 ("++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)
1347 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)
1348 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)
1349 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)
;
1350#endif
1351
1352 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)
1353 ("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)
;
1354
1355 // Add ourselves to the outer windows list.
1356 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"
, 1356); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sOuterWindowsById"
") (" "Outer Windows hash table must be created!" ")"); do {
*((volatile int*)__null) = 1356; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1357
1358 // |this| is an outer window, add to the outer windows list.
1359 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"
, 1360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sOuterWindowsById->Contains(mWindowID)"
") (" "This window shouldn't be in the hash table yet!" ")")
; do { *((volatile int*)__null) = 1360; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1360 "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"
, 1360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sOuterWindowsById->Contains(mWindowID)"
") (" "This window shouldn't be in the hash table yet!" ")")
; do { *((volatile int*)__null) = 1360; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1361 // We seem to see crashes in release builds because of null
1362 // |sOuterWindowsById|.
1363 if (sOuterWindowsById) {
1364 sOuterWindowsById->InsertOrUpdate(mWindowID, this);
1365 }
1366}
1367
1368#ifdef DEBUG1
1369
1370/* static */
1371void nsGlobalWindowOuter::AssertIsOnMainThread() {
1372 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"
, 1372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 1372; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1373}
1374
1375#endif // DEBUG
1376
1377/* static */
1378void nsGlobalWindowOuter::Init() {
1379 AssertIsOnMainThread();
1380
1381 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"
, 1382); MOZ_PretendNoReturn(); } } while (0)
1382 "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"
, 1382); MOZ_PretendNoReturn(); } } while (0)
;
1383
1384 sOuterWindowsById = new OuterWindowByIdTable();
1385}
1386
1387nsGlobalWindowOuter::~nsGlobalWindowOuter() {
1388 AssertIsOnMainThread();
1389
1390 if (sOuterWindowsById) {
1391 sOuterWindowsById->Remove(mWindowID);
1392 }
1393
1394 nsContentUtils::InnerOrOuterWindowDestroyed();
1395
1396#ifdef DEBUG1
1397 if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)(__builtin_expect(!!(mozilla::detail::log_test(gDocShellAndDOMWindowLeakLogging
, LogLevel::Info)), 0))
) {
1398 nsAutoCString url;
1399 if (mLastOpenedURI) {
1400 url = mLastOpenedURI->GetSpecOrDefault();
1401
1402 // Data URLs can be very long, so truncate to avoid flooding the log.
1403 const uint32_t maxURLLength = 1000;
1404 if (url.Length() > maxURLLength) {
1405 url.Truncate(maxURLLength);
1406 }
1407 }
1408
1409 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)
1410 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)
1411 ("--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)
1412 "%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)
1413 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)
1414 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)
1415 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)
;
1416 }
1417#endif
1418
1419 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)
1420 ("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)
;
1421
1422 JSObject* proxy = GetWrapperMaybeDead();
1423 if (proxy) {
1424 if (mBrowsingContext && mBrowsingContext->GetUnbarrieredWindowProxy()) {
1425 nsGlobalWindowOuter* outer = nsOuterWindowProxy::GetOuterWindow(
1426 mBrowsingContext->GetUnbarrieredWindowProxy());
1427 // Check that the current WindowProxy object corresponds to this
1428 // nsGlobalWindowOuter, because we don't want to clear the WindowProxy if
1429 // we've replaced it with a cross-process WindowProxy.
1430 if (outer == this) {
1431 mBrowsingContext->ClearWindowProxy();
1432 }
1433 }
1434 js::SetProxyReservedSlot(proxy, OUTER_WINDOW_SLOT,
1435 JS::PrivateValue(nullptr));
1436 }
1437
1438 // An outer window is destroyed with inner windows still possibly
1439 // alive, iterate through the inner windows and null out their
1440 // back pointer to this outer, and pull them out of the list of
1441 // inner windows.
1442 //
1443 // Our linked list of inner windows both contains (an nsGlobalWindowOuter),
1444 // and our inner windows (nsGlobalWindowInners). This means that we need to
1445 // use PRCList*. We can then compare that PRCList* to `this` to see if its an
1446 // inner or outer window.
1447 PRCList* w;
1448 while ((w = PR_LIST_HEAD(this)(this)->next) != this) {
1449 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)
;
1450 }
1451
1452 DropOuterWindowDocs();
1453
1454 // Outer windows are always supposed to call CleanUp before letting themselves
1455 // be destroyed.
1456 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"
, 1456); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCleanedUp"
")"); do { *((volatile int*)__null) = 1456; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1457
1458 nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID"@mozilla.org/devicesensors;1");
1459 if (ac) ac->RemoveWindowAsListener(this);
1460
1461 nsLayoutStatics::Release();
1462}
1463
1464// static
1465void nsGlobalWindowOuter::ShutDown() {
1466 AssertIsOnMainThread();
1467
1468 delete sOuterWindowsById;
1469 sOuterWindowsById = nullptr;
1470}
1471
1472void nsGlobalWindowOuter::DropOuterWindowDocs() {
1473 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"
, 1473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDoc->EventHandlingSuppressed()"
")"); do { *((volatile int*)__null) = 1473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1474 mDoc = nullptr;
1475 mSuspendedDocs.Clear();
1476}
1477
1478void nsGlobalWindowOuter::CleanUp() {
1479 // Guarantee idempotence.
1480 if (mCleanedUp) return;
1481 mCleanedUp = true;
1482
1483 StartDying();
1484
1485 mWindowUtils = nullptr;
1486
1487 ClearControllers();
1488
1489 mContext = nullptr; // Forces Release
1490 mChromeEventHandler = nullptr; // Forces Release
1491 mParentTarget = nullptr;
1492 mMessageManager = nullptr;
1493
1494 mArguments = nullptr;
1495}
1496
1497void nsGlobalWindowOuter::ClearControllers() {
1498 if (mControllers) {
1499 uint32_t count;
1500 mControllers->GetControllerCount(&count);
1501
1502 while (count--) {
1503 nsCOMPtr<nsIController> controller;
1504 mControllers->GetControllerAt(count, getter_AddRefs(controller));
1505
1506 nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
1507 if (context) context->SetCommandContext(nullptr);
1508 }
1509
1510 mControllers = nullptr;
1511 }
1512}
1513
1514//*****************************************************************************
1515// nsGlobalWindowOuter::nsISupports
1516//*****************************************************************************
1517
1518// QueryInterface implementation for nsGlobalWindowOuter
1519NS_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"
, 1519); 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
1520 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRYif (aIID.Equals((nsWrapperCache::COMTypeInfo<nsWrapperCache
, void>::kIID))) { *aInstancePtr = static_cast<nsWrapperCache
*>(this); return NS_OK; } else
1521 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
1522 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIDOMWindow>)) foundInterface = static_cast
<nsIDOMWindow*>(this); else
1523 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIGlobalObject>)) foundInterface
= static_cast<nsIGlobalObject*>(this); else
1524 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIScriptGlobalObject>)) foundInterface
= static_cast<nsIScriptGlobalObject*>(this); else
1525 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIScriptObjectPrincipal>)) foundInterface
= static_cast<nsIScriptObjectPrincipal*>(this); else
1526 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
1527 NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowOuter)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsPIDOMWindowOuter>)) foundInterface
= static_cast<nsPIDOMWindowOuter*>(this); else
1528 NS_INTERFACE_MAP_ENTRY(mozIDOMWindowProxy)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, mozIDOMWindowProxy>)) foundInterface
= static_cast<mozIDOMWindowProxy*>(this); else
1529 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
1530 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIInterfaceRequestor>)) foundInterface
= static_cast<nsIInterfaceRequestor*>(this); else
1531NS_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"
, 1531); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 1531; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
1532
1533NS_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"
, 1533); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1533; __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; }
1534NS_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"
, 1534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); 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.decr
(base); NS_LogRelease((this), (count), ("nsGlobalWindowOuter"
)); return count; } void nsGlobalWindowOuter::DeleteCycleCollectable
(void) { delete (this); }
1535
1536NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipReal(void* p
, bool aRemovingAllowed) { nsGlobalWindowOuter* tmp = DowncastCCParticipant
<nsGlobalWindowOuter>(p);
1537 if (tmp->IsBlackForCC(false)) {
1538 if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
1539 return true;
1540 }
1541 tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
1542 if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
1543 elm->MarkForCC();
1544 }
1545 return true;
1546 }
1547NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END(void)tmp; return false; }
1548
1549NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipInCCReal(void
* p) { nsGlobalWindowOuter* tmp = DowncastCCParticipant<nsGlobalWindowOuter
>(p);
1550 return tmp->IsBlackForCC(true);
1551NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END(void)tmp; return false; }
1552
1553NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipThisReal(void
* p) { nsGlobalWindowOuter* tmp = DowncastCCParticipant<nsGlobalWindowOuter
>(p);
1554 return tmp->IsBlackForCC(false);
1555NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END(void)tmp; return false; }
1556
1557NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowOuter)nsGlobalWindowOuter::cycleCollection nsGlobalWindowOuter::_cycleCollectorGlobal
;
1558
1559NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowOuter)nsresult nsGlobalWindowOuter::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1560 if (MOZ_UNLIKELY(cb.WantDebugInfo())(__builtin_expect(!!(cb.WantDebugInfo()), 0))) {
1561 char name[512];
1562 nsAutoCString uri;
1563 if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
1564 uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
1565 }
1566 SprintfLiteral(name, "nsGlobalWindowOuter # %" PRIu64"l" "u" " outer %s",
1567 tmp->mWindowID, uri.get());
1568 cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
1569 } else {
1570 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowOuter, tmp->mRefCnt.get())cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "nsGlobalWindowOuter"
);
1571 }
1572
1573 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)ImplCycleCollectionTraverse(cb, tmp->mContext, "mContext",
0);
1574
1575 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)ImplCycleCollectionTraverse(cb, tmp->mControllers, "mControllers"
, 0);
1576 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)ImplCycleCollectionTraverse(cb, tmp->mArguments, "mArguments"
, 0);
1577
1578 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)ImplCycleCollectionTraverse(cb, tmp->mLocalStorage, "mLocalStorage"
, 0);
1579 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDocs)ImplCycleCollectionTraverse(cb, tmp->mSuspendedDocs, "mSuspendedDocs"
, 0);
1580 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentPrincipal, "mDocumentPrincipal"
, 0);
1581 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCookiePrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentCookiePrincipal
, "mDocumentCookiePrincipal", 0);
1582 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentStoragePrincipal
, "mDocumentStoragePrincipal", 0);
1583 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPartitionedPrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentPartitionedPrincipal
, "mDocumentPartitionedPrincipal", 0);
1584 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)ImplCycleCollectionTraverse(cb, tmp->mDoc, "mDoc", 0);
1585
1586 // Traverse stuff from nsPIDOMWindow
1587 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)ImplCycleCollectionTraverse(cb, tmp->mChromeEventHandler, "mChromeEventHandler"
, 0);
1588 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)ImplCycleCollectionTraverse(cb, tmp->mParentTarget, "mParentTarget"
, 0);
1589 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)ImplCycleCollectionTraverse(cb, tmp->mMessageManager, "mMessageManager"
, 0);
1590 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)ImplCycleCollectionTraverse(cb, tmp->mFrameElement, "mFrameElement"
, 0);
1591
1592 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell)ImplCycleCollectionTraverse(cb, tmp->mDocShell, "mDocShell"
, 0);
1593 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)ImplCycleCollectionTraverse(cb, tmp->mBrowsingContext, "mBrowsingContext"
, 0);
1594
1595 tmp->TraverseObjectsInGlobal(cb);
1596
1597 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mBrowserDOMWindow)ImplCycleCollectionTraverse(cb, tmp->mChromeFields.mBrowserDOMWindow
, "mChromeFields.mBrowserDOMWindow", 0);
1598NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END(void)tmp; return NS_OK; }
1599
1600NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowOuter)void nsGlobalWindowOuter::cycleCollection::Unlink(void* p) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1601 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCEtmp->ClearWeakReferences();
1602 if (sOuterWindowsById) {
1603 sOuterWindowsById->Remove(tmp->mWindowID);
1604 }
1605
1606 NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)ImplCycleCollectionUnlink(tmp->mContext);
1607
1608 NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)ImplCycleCollectionUnlink(tmp->mControllers);
1609 NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)ImplCycleCollectionUnlink(tmp->mArguments);
1610
1611 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)ImplCycleCollectionUnlink(tmp->mLocalStorage);
1612 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDocs)ImplCycleCollectionUnlink(tmp->mSuspendedDocs);
1613 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)ImplCycleCollectionUnlink(tmp->mDocumentPrincipal);
1614 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCookiePrincipal)ImplCycleCollectionUnlink(tmp->mDocumentCookiePrincipal);
1615 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)ImplCycleCollectionUnlink(tmp->mDocumentStoragePrincipal);
1616 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPartitionedPrincipal)ImplCycleCollectionUnlink(tmp->mDocumentPartitionedPrincipal
);
1617 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)ImplCycleCollectionUnlink(tmp->mDoc);
1618
1619 // Unlink stuff from nsPIDOMWindow
1620 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)ImplCycleCollectionUnlink(tmp->mChromeEventHandler);
1621 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)ImplCycleCollectionUnlink(tmp->mParentTarget);
1622 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)ImplCycleCollectionUnlink(tmp->mMessageManager);
1623 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)ImplCycleCollectionUnlink(tmp->mFrameElement);
1624
1625 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)ImplCycleCollectionUnlink(tmp->mDocShell);
1626 if (tmp->mBrowsingContext) {
1627 if (tmp->mBrowsingContext->GetUnbarrieredWindowProxy()) {
1628 nsGlobalWindowOuter* outer = nsOuterWindowProxy::GetOuterWindow(
1629 tmp->mBrowsingContext->GetUnbarrieredWindowProxy());
1630 // Check that the current WindowProxy object corresponds to this
1631 // nsGlobalWindowOuter, because we don't want to clear the WindowProxy if
1632 // we've replaced it with a cross-process WindowProxy.
1633 if (outer == tmp) {
1634 tmp->mBrowsingContext->ClearWindowProxy();
1635 }
1636 }
1637 tmp->mBrowsingContext = nullptr;
1638 }
1639
1640 tmp->UnlinkObjectsInGlobal();
1641
1642 if (tmp->IsChromeWindow()) {
1643 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mBrowserDOMWindow)ImplCycleCollectionUnlink(tmp->mChromeFields.mBrowserDOMWindow
);
1644 }
1645
1646 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPERtmp->ReleaseWrapper(p);
1647NS_IMPL_CYCLE_COLLECTION_UNLINK_END(void)tmp; }
1648
1649NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowOuter)void nsGlobalWindowOuter::cycleCollection::Trace( void* p, const
TraceCallbacks& aCallbacks, void* aClosure) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1650 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPERtmp->TraceWrapper(aCallbacks, aClosure);
1651NS_IMPL_CYCLE_COLLECTION_TRACE_END(void)tmp; }
1652
1653bool nsGlobalWindowOuter::IsBlackForCC(bool aTracingNeeded) {
1654 if (!nsCCUncollectableMarker::sGeneration) {
1655 return false;
1656 }
1657
1658 // Unlike most wrappers, the outer window wrapper is not a wrapper for
1659 // the outer window. Instead, the outer window wrapper holds the inner
1660 // window binding object, which in turn holds the nsGlobalWindowInner, which
1661 // has a strong reference to the nsGlobalWindowOuter. We're using the
1662 // mInnerWindow pointer as a flag for that whole chain.
1663 return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
1664 (mInnerWindow && HasKnownLiveWrapper())) &&
1665 (!aTracingNeeded || HasNothingToTrace(ToSupports(this)));
1666}
1667
1668//*****************************************************************************
1669// nsGlobalWindowOuter::nsIScriptGlobalObject
1670//*****************************************************************************
1671
1672bool nsGlobalWindowOuter::ShouldResistFingerprinting(RFPTarget aTarget) const {
1673 if (mDoc) {
1674 return mDoc->ShouldResistFingerprinting(aTarget);
1675 }
1676 return nsContentUtils::ShouldResistFingerprinting(
1677 "If we do not have a document then we do not have any context"
1678 "to make an informed RFP choice, so we fall back to the global pref",
1679 aTarget);
1680}
1681
1682OriginTrials nsGlobalWindowOuter::Trials() const {
1683 return mInnerWindow ? nsGlobalWindowInner::Cast(mInnerWindow)->Trials()
1684 : OriginTrials();
1685}
1686
1687FontFaceSet* nsGlobalWindowOuter::GetFonts() {
1688 if (mDoc) {
1689 return mDoc->Fonts();
1690 }
1691 return nullptr;
1692}
1693
1694nsresult nsGlobalWindowOuter::EnsureScriptEnvironment() {
1695 if (GetWrapperPreserveColor()) {
1696 return NS_OK;
1697 }
1698
1699 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"
, 1699); return NS_ERROR_UNEXPECTED; } } while (false)
;
1700
1701 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"
, 1702); MOZ_PretendNoReturn(); } } while (0)
1702 "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"
, 1702); MOZ_PretendNoReturn(); } } while (0)
;
1703 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"
, 1703); MOZ_PretendNoReturn(); } } while (0)
;
1704
1705 // If this window is an [i]frame, don't bother GC'ing when the frame's context
1706 // is destroyed since a GC will happen when the frameset or host document is
1707 // destroyed anyway.
1708 mContext = new nsJSContext(mBrowsingContext->IsTop(), this);
1709 return NS_OK;
1710}
1711
1712nsIScriptContext* nsGlobalWindowOuter::GetScriptContext() { return mContext; }
1713
1714bool nsGlobalWindowOuter::WouldReuseInnerWindow(Document* aNewDocument) {
1715 // We reuse the inner window when:
1716 // a. We are currently at our original document.
1717 // b. At least one of the following conditions are true:
1718 // -- The new document is the same as the old document. This means that we're
1719 // getting called from document.open().
1720 // -- The new document has the same origin as what we have loaded right now.
1721
1722 if (!mDoc || !aNewDocument) {
1723 return false;
1724 }
1725
1726 if (!mDoc->IsInitialDocument()) {
1727 return false;
1728 }
1729
1730#ifdef DEBUG1
1731 {
1732 nsCOMPtr<nsIURI> uri;
1733 NS_GetURIWithoutRef(mDoc->GetDocumentURI(), getter_AddRefs(uri));
1734 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"
, 1734); MOZ_PretendNoReturn(); } } while (0)
;
1735 }
1736#endif
1737
1738 // Great, we're the original document, check for one of the other
1739 // conditions.
1740
1741 if (mDoc == aNewDocument) {
1742 return true;
1743 }
1744
1745 if (aNewDocument->IsStaticDocument()) {
1746 return false;
1747 }
1748
1749 if (BasePrincipal::Cast(mDoc->NodePrincipal())
1750 ->FastEqualsConsideringDomain(aNewDocument->NodePrincipal())) {
1751 // The origin is the same.
1752 return true;
1753 }
1754
1755 return false;
1756}
1757
1758void nsGlobalWindowOuter::SetInitialPrincipal(
1759 nsIPrincipal* aNewWindowPrincipal, nsIContentSecurityPolicy* aCSP,
1760 const Maybe<nsILoadInfo::CrossOriginEmbedderPolicy>& aCOEP) {
1761 // We should never create windows with an expanded principal.
1762 // If we have a system principal, make sure we're not using it for a content
1763 // docshell.
1764 // NOTE: Please keep this logic in sync with
1765 // nsAppShellService::JustCreateTopWindow
1766 if (nsContentUtils::IsExpandedPrincipal(aNewWindowPrincipal) ||
1767 (aNewWindowPrincipal->IsSystemPrincipal() &&
1768 GetBrowsingContext()->IsContent())) {
1769 aNewWindowPrincipal = nullptr;
1770 }
1771
1772 // If there's an existing document, bail if it either:
1773 if (mDoc) {
1774 // (a) is not an initial about:blank document, or
1775 if (!mDoc->IsInitialDocument()) return;
1776 // (b) already has the correct principal.
1777 if (mDoc->NodePrincipal() == aNewWindowPrincipal) return;
1778
1779#ifdef DEBUG1
1780 // If we have a document loaded at this point, it had better be about:blank.
1781 // Otherwise, something is really weird. An about:blank page has a
1782 // NullPrincipal.
1783 bool isNullPrincipal;
1784 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"
, 1786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1786; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1785 &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"
, 1786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1786; __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"
, 1786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1786; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1787#endif
1788 }
1789
1790 // Use the subject (or system) principal as the storage principal too until
1791 // the new window finishes navigating and gets a real storage principal.
1792 nsDocShell::Cast(GetDocShell())
1793 ->CreateAboutBlankDocumentViewer(aNewWindowPrincipal, aNewWindowPrincipal,
1794 aCSP, nullptr,
1795 /* aIsInitialDocument */ true, aCOEP);
1796
1797 if (mDoc) {
1798 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"
, 1799); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc->IsInitialDocument()"
") (" "document should be initial document" ")"); do { *((volatile
int*)__null) = 1799; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
1799 "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"
, 1799); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc->IsInitialDocument()"
") (" "document should be initial document" ")"); do { *((volatile
int*)__null) = 1799; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1800 }
1801
1802 RefPtr<PresShell> presShell = GetDocShell()->GetPresShell();
1803 if (presShell && !presShell->DidInitialize()) {
1804 // Ensure that if someone plays with this document they will get
1805 // layout happening.
1806 presShell->Initialize();
1807 }
1808}
1809
1810#define WINDOWSTATEHOLDER_IID{ 0x0b917c3e, 0xbd50, 0x4683, { 0xaf, 0xc9, 0xc7, 0x81, 0x07,
0xae, 0x33, 0x26 } }
\
1811 { \
1812 0x0b917c3e, 0xbd50, 0x4683, { \
1813 0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26 \
1814 } \
1815 }
1816
1817class WindowStateHolder final : public nsISupports {
1818 public:
1819 NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)template <typename T, typename U> struct COMTypeInfo;
1820 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:
1821
1822 explicit WindowStateHolder(nsGlobalWindowInner* aWindow);
1823
1824 nsGlobalWindowInner* GetInnerWindow() { return mInnerWindow; }
1825
1826 void DidRestoreWindow() {
1827 mInnerWindow = nullptr;
1828 mInnerWindowReflector = nullptr;
1829 }
1830
1831 protected:
1832 ~WindowStateHolder();
1833
1834 nsGlobalWindowInner* mInnerWindow;
1835 // We hold onto this to make sure the inner window doesn't go away. The outer
1836 // window ends up recalculating it anyway.
1837 JS::PersistentRooted<JSObject*> mInnerWindowReflector;
1838};
1839
1840NS_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 } };
1841
1842WindowStateHolder::WindowStateHolder(nsGlobalWindowInner* aWindow)
1843 : mInnerWindow(aWindow),
1844 mInnerWindowReflector(RootingCx(), aWindow->GetWrapper()) {
1845 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"
, 1845); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ") ("
"null window" ")"); do { *((volatile int*)__null) = 1845; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
1846
1847 aWindow->Suspend();
1848
1849 // When a global goes into the bfcache, we disable script.
1850 xpc::Scriptability::Get(mInnerWindowReflector).SetWindowAllowsScript(false);
1851}
1852
1853WindowStateHolder::~WindowStateHolder() {
1854 if (mInnerWindow) {
1855 // This window was left in the bfcache and is now going away. We need to
1856 // free it up.
1857 // Note that FreeInnerObjects may already have been called on the
1858 // inner window if its outer has already had SetDocShell(null)
1859 // called.
1860 mInnerWindow->FreeInnerObjects();
1861 }
1862}
1863
1864NS_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"
, 1864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1864; __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"
, 1864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WindowStateHolder\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1864; __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"
, 1864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 1864
; __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"
, 1864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WindowStateHolder\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1864; __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"
, 1864); 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((sizeof(table) / sizeof(table[0])) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
1865
1866bool nsGlobalWindowOuter::ComputeIsSecureContext(Document* aDocument,
1867 SecureContextFlags aFlags) {
1868 nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
1869 if (principal->IsSystemPrincipal()) {
1870 return true;
1871 }
1872
1873 // Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object
1874 // With some modifications to allow for aFlags.
1875
1876 bool hadNonSecureContextCreator = false;
1877
1878 if (WindowContext* parentWindow =
1879 GetBrowsingContext()->GetParentWindowContext()) {
1880 hadNonSecureContextCreator = !parentWindow->GetIsSecureContext();
1881 }
1882
1883 if (hadNonSecureContextCreator) {
1884 return false;
1885 }
1886
1887 if (nsContentUtils::HttpsStateIsModern(aDocument)) {
1888 return true;
1889 }
1890
1891 if (principal->GetIsNullPrincipal()) {
1892 // If the NullPrincipal has a valid precursor URI we want to use it to
1893 // construct the principal otherwise we fall back to the original document
1894 // URI.
1895 nsCOMPtr<nsIPrincipal> precursorPrin = principal->GetPrecursorPrincipal();
1896 nsCOMPtr<nsIURI> uri = precursorPrin ? precursorPrin->GetURI() : nullptr;
1897 if (!uri) {
1898 uri = aDocument->GetOriginalURI();
1899 }
1900 // IsOriginPotentiallyTrustworthy doesn't care about origin attributes so
1901 // it doesn't actually matter what we use here, but reusing the document
1902 // principal's attributes is convenient.
1903 const OriginAttributes& attrs = principal->OriginAttributesRef();
1904 // CreateContentPrincipal correctly gets a useful principal for blob: and
1905 // other URI_INHERITS_SECURITY_CONTEXT URIs.
1906 principal = BasePrincipal::CreateContentPrincipal(uri, attrs);
1907 if (NS_WARN_IF(!principal)NS_warn_if_impl(!principal, "!principal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1907)
) {
1908 return false;
1909 }
1910 }
1911
1912 return principal->GetIsOriginPotentiallyTrustworthy();
1913}
1914
1915static bool InitializeLegacyNetscapeObject(JSContext* aCx,
1916 JS::Handle<JSObject*> aGlobal) {
1917 JSAutoRealm ar(aCx, aGlobal);
1918
1919 // Note: MathJax depends on window.netscape being exposed. See bug 791526.
1920 JS::Rooted<JSObject*> obj(aCx);
1921 obj = JS_DefineObject(aCx, aGlobal, "netscape", nullptr);
1922 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"
, 1922); return false; } } while (false)
;
1923
1924 obj = JS_DefineObject(aCx, obj, "security", nullptr);
1925 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"
, 1925); return false; } } while (false)
;
1926
1927 return true;
1928}
1929
1930struct MOZ_STACK_CLASS CompartmentFinderState {
1931 explicit CompartmentFinderState(nsIPrincipal* aPrincipal)
1932 : principal(aPrincipal), compartment(nullptr) {}
1933
1934 // Input: we look for a compartment which is same-origin with the
1935 // given principal.
1936 nsIPrincipal* principal;
1937
1938 // Output: We set this member if we find a compartment.
1939 JS::Compartment* compartment;
1940};
1941
1942static JS::CompartmentIterResult FindSameOriginCompartment(
1943 JSContext* aCx, void* aData, JS::Compartment* aCompartment) {
1944 auto* data = static_cast<CompartmentFinderState*>(aData);
1945 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"
, 1945); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!data->compartment"
") (" "Why are we getting called?" ")"); do { *((volatile int
*)__null) = 1945; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1946
1947 // If this compartment is not safe to share across globals, don't do
1948 // anything with it; in particular we should not be getting a
1949 // CompartmentPrivate from such a compartment, because it may be in
1950 // the middle of being collected and its CompartmentPrivate may no
1951 // longer be valid.
1952 if (!js::IsSharableCompartment(aCompartment)) {
1953 return JS::CompartmentIterResult::KeepGoing;
1954 }
1955
1956 auto* compartmentPrivate = xpc::CompartmentPrivate::Get(aCompartment);
1957 if (!compartmentPrivate->CanShareCompartmentWith(data->principal)) {
1958 // Can't reuse this one, keep going.
1959 return JS::CompartmentIterResult::KeepGoing;
1960 }
1961
1962 // We have a winner!
1963 data->compartment = aCompartment;
1964 return JS::CompartmentIterResult::Stop;
1965}
1966
1967static JS::RealmCreationOptions& SelectZone(
1968 JSContext* aCx, nsIPrincipal* aPrincipal, nsGlobalWindowInner* aNewInner,
1969 JS::RealmCreationOptions& aOptions) {
1970 // Use the shared system compartment for chrome windows.
1971 if (aPrincipal->IsSystemPrincipal()) {
1972 return aOptions.setExistingCompartment(xpc::PrivilegedJunkScope());
1973 }
1974
1975 BrowsingContext* bc = aNewInner->GetBrowsingContext();
1976 if (bc->IsTop()) {
1977 // We're a toplevel load. Use a new zone. This way, when we do
1978 // zone-based compartment sharing we won't share compartments
1979 // across navigations.
1980 return aOptions.setNewCompartmentAndZone();
1981 }
1982
1983 // Find the in-process ancestor highest in the hierarchy.
1984 nsGlobalWindowInner* ancestor = nullptr;
1985 for (WindowContext* wc = bc->GetParentWindowContext(); wc;
1986 wc = wc->GetParentWindowContext()) {
1987 if (nsGlobalWindowInner* win = wc->GetInnerWindow()) {
1988 ancestor = win;
1989 }
1990 }
1991
1992 // If we have an ancestor window, use its zone.
1993 if (ancestor && ancestor->GetGlobalJSObject()) {
1994 JS::Zone* zone = JS::GetObjectZone(ancestor->GetGlobalJSObject());
1995 // Now try to find an existing compartment that's same-origin
1996 // with our principal.
1997 CompartmentFinderState data(aPrincipal);
1998 JS_IterateCompartmentsInZone(aCx, zone, &data, FindSameOriginCompartment);
1999 if (data.compartment) {
2000 return aOptions.setExistingCompartment(data.compartment);
2001 }
2002 return aOptions.setNewCompartmentInExistingZone(
2003 ancestor->GetGlobalJSObject());
2004 }
2005
2006 return aOptions.setNewCompartmentAndZone();
2007}
2008
2009/**
2010 * Create a new global object that will be used for an inner window.
2011 * Return the native global and an nsISupports 'holder' that can be used
2012 * to manage the lifetime of it.
2013 */
2014static nsresult CreateNativeGlobalForInner(
2015 JSContext* aCx, nsGlobalWindowInner* aNewInner, Document* aDocument,
2016 JS::MutableHandle<JSObject*> aGlobal, bool aIsSecureContext,
2017 bool aDefineSharedArrayBufferConstructor) {
2018 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"
, 2018); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCx" ")"); do
{ *((volatile int*)__null) = 2018; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2019 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"
, 2019); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewInner" ")"
); do { *((volatile int*)__null) = 2019; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2020
2021 nsCOMPtr<nsIURI> uri = aDocument->GetDocumentURI();
2022 nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
2023 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"
, 2023); AnnotateMozCrashReason("MOZ_ASSERT" "(" "principal" ")"
); do { *((volatile int*)__null) = 2023; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2024
2025 // DOMWindow with nsEP is not supported, we have to make sure
2026 // no one creates one accidentally.
2027 nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(principal);
2028 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"
, 2028); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!nsEP"
") (" "DOMWindow with nsEP is not supported" ")"); do { *((volatile
int*)__null) = 2028; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2029
2030 JS::RealmOptions options;
2031 JS::RealmCreationOptions& creationOptions = options.creationOptions();
2032
2033 SelectZone(aCx, principal, aNewInner, creationOptions);
2034
2035 // Define the SharedArrayBuffer global constructor property only if shared
2036 // memory may be used and structured-cloned (e.g. through postMessage).
2037 //
2038 // When the global constructor property isn't defined, the SharedArrayBuffer
2039 // constructor can still be reached through Web Assembly. Omitting the global
2040 // property just prevents feature-tests from being misled. See bug 1624266.
2041 creationOptions.setDefineSharedArrayBufferConstructor(
2042 aDefineSharedArrayBufferConstructor);
2043
2044 xpc::InitGlobalObjectOptions(
2045 options, principal->IsSystemPrincipal(), aIsSecureContext,
2046 aDocument->ShouldResistFingerprinting(RFPTarget::JSDateTimeUTC),
2047 aDocument->ShouldResistFingerprinting(RFPTarget::JSMathFdlibm),
2048 aDocument->ShouldResistFingerprinting(RFPTarget::JSLocale));
2049
2050 // Determine if we need the Components object.
2051 bool needComponents = principal->IsSystemPrincipal();
2052 uint32_t flags = needComponents ? 0 : xpc::OMIT_COMPONENTS_OBJECT;
2053 flags |= xpc::DONT_FIRE_ONNEWGLOBALHOOK;
2054
2055 if (!Window_Binding::Wrap(aCx, aNewInner, aNewInner, options,
2056 nsJSPrincipals::get(principal), aGlobal) ||
2057 !xpc::InitGlobalObject(aCx, aGlobal, flags)) {
2058 return NS_ERROR_FAILURE;
2059 }
2060
2061 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"
, 2061); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewInner->GetWrapperPreserveColor() == aGlobal"
")"); do { *((volatile int*)__null) = 2061; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2062
2063 // Set the location information for the new global, so that tools like
2064 // about:memory may use that information
2065 xpc::SetLocationForGlobal(aGlobal, uri);
2066
2067 if (!InitializeLegacyNetscapeObject(aCx, aGlobal)) {
2068 return NS_ERROR_FAILURE;
2069 }
2070
2071 return NS_OK;
2072}
2073
2074nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
2075 nsISupports* aState,
2076 bool aForceReuseInnerWindow,
2077 WindowGlobalChild* aActor) {
2078 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"
, 2079); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPrincipal == nullptr"
") (" "mDocumentPrincipal prematurely set!" ")"); do { *((volatile
int*)__null) = 2079; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
2079 "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"
, 2079); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPrincipal == nullptr"
") (" "mDocumentPrincipal prematurely set!" ")"); do { *((volatile
int*)__null) = 2079; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2080 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"
, 2081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentCookiePrincipal == nullptr"
") (" "mDocumentCookiePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2081; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2081 "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"
, 2081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentCookiePrincipal == nullptr"
") (" "mDocumentCookiePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2081; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2082 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"
, 2083); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentStoragePrincipal == nullptr"
") (" "mDocumentStoragePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2083; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2083 "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"
, 2083); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentStoragePrincipal == nullptr"
") (" "mDocumentStoragePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2083; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2084 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"
, 2085); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPartitionedPrincipal == nullptr"
") (" "mDocumentPartitionedPrincipal prematurely set!" ")");
do { *((volatile int*)__null) = 2085; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2085 "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"
, 2085); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPartitionedPrincipal == nullptr"
") (" "mDocumentPartitionedPrincipal prematurely set!" ")");
do { *((volatile int*)__null) = 2085; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2086 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"
, 2086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")"
); do { *((volatile int*)__null) = 2086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2087
2088 // Bail out early if we're in process of closing down the window.
2089 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"
, 2089); return NS_ERROR_UNEXPECTED; } } while (false)
;
2090
2091 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"
, 2094); MOZ_PretendNoReturn(); } } while (0)
2092 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"
, 2094); MOZ_PretendNoReturn(); } } while (0)
2093 "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"
, 2094); MOZ_PretendNoReturn(); } } while (0)
2094 "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"
, 2094); MOZ_PretendNoReturn(); } } while (0)
;
2095 bool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
2096 if (aForceReuseInnerWindow && !wouldReuseInnerWindow && mDoc &&
2097 mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
2098 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"
, 2098); MOZ_PretendNoReturn(); } while (0)
;
2099 return NS_ERROR_UNEXPECTED;
2100 }
2101
2102 if (!mBrowsingContext->AncestorsAreCurrent()) {
2103 return NS_ERROR_NOT_AVAILABLE;
2104 }
2105
2106 RefPtr<Document> oldDoc = mDoc;
2107 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"
, 2107); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "oldDoc != aDocument"
")"); do { *((volatile int*)__null) = 2107; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2108
2109 AutoJSAPI jsapi;
2110 jsapi.Init();
2111 JSContext* cx = jsapi.cx();
2112
2113 // Check if we're anywhere near the stack limit before we reach the
2114 // transplanting code, since it has no good way to handle errors. This uses
2115 // the untrusted script limit, which is not strictly necessary since no
2116 // actual script should run.
2117 js::AutoCheckRecursionLimit recursion(cx);
2118 if (!recursion.checkConservativeDontReport(cx)) {
2119 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"
, 2119)
;
2120 return NS_ERROR_FAILURE;
2121 }
2122
2123 if (!mDoc) {
2124 // First document load.
2125
2126 // Get our private root. If it is equal to us, then we need to
2127 // attach our global key bindings that handles browser scrolling
2128 // and other browser commands.
2129 nsPIDOMWindowOuter* privateRoot = GetPrivateRoot();
2130
2131 if (privateRoot == this) {
2132 RootWindowGlobalKeyListener::AttachKeyHandler(mChromeEventHandler);
2133 }
2134 }
2135
2136 MaybeResetWindowName(aDocument);
2137
2138 /* No mDocShell means we're already been partially closed down. When that
2139 happens, setting status isn't a big requirement, so don't. (Doesn't happen
2140 under normal circumstances, but bug 49615 describes a case.) */
2141
2142 nsContentUtils::AddScriptRunner(
2143 NewRunnableMethod("nsGlobalWindowOuter::ClearStatus", this,
2144 &nsGlobalWindowOuter::ClearStatus));
2145
2146 // Sometimes, WouldReuseInnerWindow() returns true even if there's no inner
2147 // window (see bug 776497). Be safe.
2148 bool reUseInnerWindow = (aForceReuseInnerWindow || wouldReuseInnerWindow) &&
2149 GetCurrentInnerWindowInternal(this);
2150
2151 nsresult rv;
2152
2153 // We set mDoc even though this is an outer window to avoid
2154 // having to *always* reach into the inner window to find the
2155 // document.
2156 mDoc = aDocument;
2157
2158 nsDocShell::Cast(mDocShell)->MaybeRestoreWindowName();
2159
2160 // We drop the print request for the old document on the floor, it never made
2161 // it. We don't close the window here either even if we were asked to.
2162 mShouldDelayPrintUntilAfterLoad = true;
2163 mDelayedCloseForPrinting = false;
2164 mDelayedPrintUntilAfterLoad = false;
2165
2166 // Take this opportunity to clear mSuspendedDocs. Our old inner window is now
2167 // responsible for unsuspending it.
2168 mSuspendedDocs.Clear();
2169
2170#ifdef DEBUG1
2171 mLastOpenedURI = aDocument->GetDocumentURI();
2172#endif
2173
2174 RefPtr<nsGlobalWindowInner> currentInner =
2175 GetCurrentInnerWindowInternal(this);
2176
2177 if (currentInner && currentInner->mNavigator) {
2178 currentInner->mNavigator->OnNavigation();
2179 }
2180
2181 RefPtr<nsGlobalWindowInner> newInnerWindow;
2182 bool createdInnerWindow = false;
2183
2184 bool thisChrome = IsChromeWindow();
2185
2186 nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
2187 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"
, 2188); MOZ_PretendNoReturn(); } } while (0)
2188 "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"
, 2188); MOZ_PretendNoReturn(); } } while (0)
;
2189
2190 bool doomCurrentInner = false;
2191
2192 // Only non-gray (i.e. exposed to JS) objects should be assigned to
2193 // newInnerGlobal.
2194 JS::Rooted<JSObject*> newInnerGlobal(cx);
2195 if (reUseInnerWindow) {
2196 // We're reusing the current inner window.
2197 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"
, 2198); MOZ_PretendNoReturn(); } } while (0)
2198 "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"
, 2198); MOZ_PretendNoReturn(); } } while (0)
;
2199 newInnerWindow = currentInner;
2200 newInnerGlobal = currentInner->GetWrapper();
2201
2202 // We're reusing the inner window, but this still counts as a navigation,
2203 // so all expandos and such defined on the outer window should go away.
2204 // Force all Xray wrappers to be recomputed.
2205 JS::Rooted<JSObject*> rootedObject(cx, GetWrapper());
2206 if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) {
2207 return NS_ERROR_FAILURE;
2208 }
2209
2210 // Inner windows are only reused for same-origin principals, but the
2211 // principals don't necessarily match exactly. Update the principal on the
2212 // realm to match the new document. NB: We don't just call
2213 // currentInner->RefreshRealmPrincipals() here because we haven't yet set
2214 // its mDoc to aDocument.
2215 JS::Realm* realm = js::GetNonCCWObjectRealm(newInnerGlobal);
2216#ifdef DEBUG1
2217 bool sameOrigin = false;
2218 nsIPrincipal* existing = nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
2219 aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
2220 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"
, 2220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sameOrigin"
")"); do { *((volatile int*)__null) = 2220; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2221#endif
2222 JS::SetRealmPrincipals(realm,
2223 nsJSPrincipals::get(aDocument->NodePrincipal()));
2224 } else {
2225 if (aState) {
2226 newInnerWindow = wsh->GetInnerWindow();
2227 newInnerGlobal = newInnerWindow->GetWrapper();
2228 } else {
2229 newInnerWindow = nsGlobalWindowInner::Create(this, thisChrome, aActor);
2230 if (StaticPrefs::dom_timeout_defer_during_load()) {
2231 // ensure the initial loading state is known
2232 newInnerWindow->SetActiveLoadingState(
2233 aDocument->GetReadyStateEnum() ==
2234 Document::ReadyState::READYSTATE_LOADING);
2235 }
2236
2237 // The outer window is automatically treated as frozen when we
2238 // null out the inner window. As a result, initializing classes
2239 // on the new inner won't end up reaching into the old inner
2240 // window for classes etc.
2241 //
2242 // [This happens with Object.prototype when XPConnect creates
2243 // a temporary global while initializing classes; the reason
2244 // being that xpconnect creates the temp global w/o a parent
2245 // and proto, which makes the JS engine look up classes in
2246 // cx->globalObject, i.e. this outer window].
2247
2248 mInnerWindow = nullptr;
2249
2250 mCreatingInnerWindow = true;
2251
2252 // The SharedArrayBuffer global constructor property should not be present
2253 // in a fresh global object when shared memory objects aren't allowed
2254 // (because COOP/COEP support isn't enabled, or because COOP/COEP don't
2255 // act to isolate this page to a separate process).
2256
2257 // Every script context we are initialized with must create a
2258 // new global.
2259 rv = CreateNativeGlobalForInner(
2260 cx, newInnerWindow, aDocument, &newInnerGlobal,
2261 ComputeIsSecureContext(aDocument),
2262 newInnerWindow->IsSharedMemoryAllowedInternal(
2263 aDocument->NodePrincipal()));
2264 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"
, 2267); MOZ_PretendNoReturn(); } } while (0)
2265 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"
, 2267); MOZ_PretendNoReturn(); } } while (0)
2266 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"
, 2267); MOZ_PretendNoReturn(); } } while (0)
2267 "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"
, 2267); MOZ_PretendNoReturn(); } } while (0)
;
2268
2269 mCreatingInnerWindow = false;
2270 createdInnerWindow = true;
2271
2272 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"
, 2272); return rv; } } while (false)
;
2273 }
2274
2275 if (currentInner && currentInner->GetWrapperPreserveColor()) {
2276 // Don't free objects on our current inner window if it's going to be
2277 // held in the bfcache.
2278 if (!currentInner->IsFrozen()) {
2279 doomCurrentInner = true;
2280 }
2281 }
2282
2283 mInnerWindow = newInnerWindow;
2284 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"
, 2284); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mInnerWindow"
")"); do { *((volatile int*)__null) = 2284; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2285 mInnerWindow->TryToCacheTopInnerWindow();
2286
2287 if (!GetWrapperPreserveColor()) {
2288 JS::Rooted<JSObject*> outer(
2289 cx, NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
2290 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"
, 2290); return NS_ERROR_FAILURE; } } while (false)
;
2291
2292 mBrowsingContext->CleanUpDanglingRemoteOuterWindowProxies(cx, &outer);
2293 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"
, 2293); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(outer)"
")"); do { *((volatile int*)__null) = 2293; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2294
2295 js::SetProxyReservedSlot(outer, OUTER_WINDOW_SLOT,
2296 JS::PrivateValue(ToSupports(this)));
2297
2298 // Inform the nsJSContext, which is the canonical holder of the outer.
2299 mContext->SetWindowProxy(outer);
2300
2301 SetWrapper(mContext->GetWindowProxy());
2302 } else {
2303 JS::Rooted<JSObject*> outerObject(
2304 cx, NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
2305 if (!outerObject) {
2306 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"
, 2306); MOZ_PretendNoReturn(); } while (0)
;
2307 return NS_ERROR_FAILURE;
2308 }
2309
2310 JS::Rooted<JSObject*> obj(cx, GetWrapper());
2311
2312 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"
, 2312); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(obj)"
")"); do { *((volatile int*)__null) = 2312; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2313
2314 js::SetProxyReservedSlot(obj, OUTER_WINDOW_SLOT,
2315 JS::PrivateValue(nullptr));
2316 js::SetProxyReservedSlot(outerObject, OUTER_WINDOW_SLOT,
2317 JS::PrivateValue(nullptr));
2318 js::SetProxyReservedSlot(obj, HOLDER_WEAKMAP_SLOT, JS::UndefinedValue());
2319
2320 outerObject = xpc::TransplantObjectNukingXrayWaiver(cx, obj, outerObject);
2321
2322 if (!outerObject) {
2323 mBrowsingContext->ClearWindowProxy();
2324 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"
, 2324); MOZ_PretendNoReturn(); } while (0)
;
2325 return NS_ERROR_FAILURE;
2326 }
2327
2328 js::SetProxyReservedSlot(outerObject, OUTER_WINDOW_SLOT,
2329 JS::PrivateValue(ToSupports(this)));
2330
2331 SetWrapper(outerObject);
2332
2333 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"
, 2333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal"
")"); do { *((volatile int*)__null) = 2333; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2334
2335 // Inform the nsJSContext, which is the canonical holder of the outer.
2336 mContext->SetWindowProxy(outerObject);
2337 }
2338
2339 // Enter the new global's realm.
2340 JSAutoRealm ar(cx, GetWrapperPreserveColor());
2341
2342 {
2343 JS::Rooted<JSObject*> outer(cx, GetWrapperPreserveColor());
2344 js::SetWindowProxy(cx, newInnerGlobal, outer);
2345 mBrowsingContext->SetWindowProxy(outer);
2346 }
2347
2348 // Set scriptability based on the state of the WindowContext.
2349 WindowContext* wc = mInnerWindow->GetWindowContext();
2350 bool allow =
2351 wc ? wc->CanExecuteScripts() : mBrowsingContext->CanExecuteScripts();
2352 xpc::Scriptability::Get(GetWrapperPreserveColor())
2353 .SetWindowAllowsScript(allow);
2354
2355 if (!aState) {
2356 // Get the "window" property once so it will be cached on our inner. We
2357 // have to do this here, not in binding code, because this has to happen
2358 // after we've created the outer window proxy and stashed it in the outer
2359 // nsGlobalWindowOuter, so GetWrapperPreserveColor() on that outer
2360 // nsGlobalWindowOuter doesn't return null and
2361 // nsGlobalWindowOuter::OuterObject works correctly.
2362 JS::Rooted<JS::Value> unused(cx);
2363 if (!JS_GetProperty(cx, newInnerGlobal, "window", &unused)) {
2364 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"
, 2364); MOZ_PretendNoReturn(); } while (0)
;
2365 return NS_ERROR_FAILURE;
2366 }
2367
2368 // And same thing for the "self" property.
2369 if (!JS_GetProperty(cx, newInnerGlobal, "self", &unused)) {
2370 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"
, 2370); MOZ_PretendNoReturn(); } while (0)
;
2371 return NS_ERROR_FAILURE;
2372 }
2373 }
2374 }
2375
2376 JSAutoRealm ar(cx, GetWrapperPreserveColor());
2377
2378 if (!aState && !reUseInnerWindow) {
2379 // Loading a new page and creating a new inner window, *not*
2380 // restoring from session history.
2381
2382 // Now that both the the inner and outer windows are initialized
2383 // let the script context do its magic to hook them together.
2384 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"
, 2384); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mContext->GetWindowProxy() == GetWrapperPreserveColor()"
")"); do { *((volatile int*)__null) = 2384; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2385#ifdef DEBUG1
2386 JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
2387 JS::Rooted<JSObject*> proto1(cx), proto2(cx);
2388 JS_GetPrototype(cx, rootedJSObject, &proto1);
2389 JS_GetPrototype(cx, newInnerGlobal, &proto2);
2390 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"
, 2391); MOZ_PretendNoReturn(); } } while (0)
2391 "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"
, 2391); MOZ_PretendNoReturn(); } } while (0)
;
2392#endif
2393
2394 mInnerWindow->SyncStateFromParentWindow();
2395 }
2396
2397 // Add an extra ref in case we release mContext during GC.
2398 nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
2399
2400 // Make sure the inner's document is set correctly before we call
2401 // SetScriptGlobalObject, because that might try to examine document-dependent
2402 // state. Unfortunately, we can't do some of the other clearing/resetting
2403 // work we do below until after SetScriptGlobalObject(), because it might
2404 // depend on the document having the right scope object.
2405 if (aState) {
2406 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"
, 2406); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc == aDocument"
")"); do { *((volatile int*)__null) = 2406; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2407 } else {
2408 if (reUseInnerWindow) {
2409 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"
, 2409); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc != aDocument"
")"); do { *((volatile int*)__null) = 2409; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2410 }
2411 newInnerWindow->mDoc = aDocument;
2412 }
2413
2414 aDocument->SetScriptGlobalObject(newInnerWindow);
2415
2416 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"
, 2416); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc == aDocument"
")"); do { *((volatile int*)__null) = 2416; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2417
2418 if (mBrowsingContext->IsTopContent()) {
2419 net::CookieJarSettings::Cast(aDocument->CookieJarSettings())
2420 ->SetTopLevelWindowContextId(aDocument->InnerWindowID());
2421 }
2422
2423 newInnerWindow->RefreshReduceTimerPrecisionCallerType();
2424
2425 if (!aState) {
2426 if (reUseInnerWindow) {
2427 // The StorageAccess state may have changed. Invalidate the cached
2428 // StorageAllowed field, so that the next call to StorageAllowedForWindow
2429 // recomputes it.
2430 newInnerWindow->ClearStorageAllowedCache();
2431
2432 // The storage objects contain the URL of the window. We have to
2433 // recreate them when the innerWindow is reused.
2434 newInnerWindow->mLocalStorage = nullptr;
2435 newInnerWindow->mSessionStorage = nullptr;
2436 newInnerWindow->mPerformance = nullptr;
2437
2438 // This must be called after nullifying the internal objects because
2439 // here we could recreate them, calling the getter methods, and store
2440 // them into the JS slots. If we nullify them after, the slot values and
2441 // the objects will be out of sync.
2442 newInnerWindow->ClearDocumentDependentSlots(cx);
2443 } else {
2444 newInnerWindow->InitDocumentDependentState(cx);
2445
2446 // Initialize DOM classes etc on the inner window.
2447 JS::Rooted<JSObject*> obj(cx, newInnerGlobal);
2448 rv = kungFuDeathGrip->InitClasses(obj);
2449 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"
, 2449); return rv; } } while (false)
;
2450 }
2451
2452 // When replacing an initial about:blank document we call
2453 // ExecutionReady again to update the client creation URL.
2454 rv = newInnerWindow->ExecutionReady();
2455 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"
, 2455); return rv; } } while (false)
;
2456
2457 if (mArguments) {
2458 newInnerWindow->DefineArgumentsProperty(mArguments);
2459 mArguments = nullptr;
2460 }
2461
2462 // Give the new inner window our chrome event handler (since it
2463 // doesn't have one).
2464 newInnerWindow->mChromeEventHandler = mChromeEventHandler;
2465 }
2466
2467 if (!aState && reUseInnerWindow) {
2468 // Notify our WindowGlobalChild that it has a new document. If `aState` was
2469 // passed, we're restoring the window from the BFCache, so the document
2470 // hasn't changed.
2471 // If we didn't have a window global child before, then initializing
2472 // it will have set all the required state, so we don't need to do
2473 // it again.
2474 mInnerWindow->GetWindowGlobalChild()->OnNewDocument(aDocument);
2475 }
2476
2477 // Update the current window for our BrowsingContext.
2478 RefPtr<BrowsingContext> bc = GetBrowsingContext();
2479
2480 if (bc->IsOwnedByProcess()) {
2481 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 { static_assert( mozilla::detail
::AssertionConditionType<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2481); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))"
")"); do { *((volatile int*)__null) = 2481; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2482 }
2483
2484 // We no longer need the old inner window. Start its destruction if
2485 // its not being reused and clear our reference.
2486 if (doomCurrentInner) {
2487 currentInner->FreeInnerObjects();
2488 }
2489 currentInner = nullptr;
2490
2491 // We wait to fire the debugger hook until the window is all set up and hooked
2492 // up with the outer. See bug 969156.
2493 if (createdInnerWindow) {
2494 nsContentUtils::AddScriptRunner(NewRunnableMethod(
2495 "nsGlobalWindowInner::FireOnNewGlobalObject", newInnerWindow,
2496 &nsGlobalWindowInner::FireOnNewGlobalObject));
2497 }
2498
2499 if (!newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
2500 // We should probably notify. However if this is the, arguably bad,
2501 // situation when we're creating a temporary non-chrome-about-blank
2502 // document in a chrome docshell, don't notify just yet. Instead wait
2503 // until we have a real chrome doc.
2504 const bool isContentAboutBlankInChromeDocshell = [&] {
2505 if (!mDocShell) {
2506 return false;
2507 }
2508
2509 RefPtr<BrowsingContext> bc = mDocShell->GetBrowsingContext();
2510 if (!bc || bc->GetType() != BrowsingContext::Type::Chrome) {
2511 return false;
2512 }
2513
2514 return !mDoc->NodePrincipal()->IsSystemPrincipal();
2515 }();
2516
2517 if (!isContentAboutBlankInChromeDocshell) {
2518 newInnerWindow->mHasNotifiedGlobalCreated = true;
2519 nsContentUtils::AddScriptRunner(NewRunnableMethod(
2520 "nsGlobalWindowOuter::DispatchDOMWindowCreated", this,
2521 &nsGlobalWindowOuter::DispatchDOMWindowCreated));
2522 }
2523 }
2524
2525 PreloadLocalStorage();
2526
2527 // Do this here rather than in say the Document constructor, since
2528 // we need a WindowContext available.
2529 mDoc->InitUseCounters();
2530
2531 return NS_OK;
2532}
2533
2534/* static */
2535void nsGlobalWindowOuter::PrepareForProcessChange(JSObject* aProxy) {
2536 JS::Rooted<JSObject*> localProxy(RootingCx(), aProxy);
2537 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"
, 2537); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(localProxy)"
")"); do { *((volatile int*)__null) = 2537; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2538
2539 RefPtr<nsGlobalWindowOuter> outerWindow =
2540 nsOuterWindowProxy::GetOuterWindow(localProxy);
2541 if (!outerWindow) {
2542 return;
2543 }
2544
2545 AutoJSAPI jsapi;
2546 jsapi.Init();
2547 JSContext* cx = jsapi.cx();
2548
2549 JSAutoRealm ar(cx, localProxy);
2550
2551 // Clear out existing references from the browsing context and outer window to
2552 // the proxy, and from the proxy to the outer window. These references will
2553 // become invalid once the proxy is transplanted. Clearing the window proxy
2554 // from the browsing context is also necessary to indicate that it is for an
2555 // out of process window.
2556 outerWindow->ClearWrapper(localProxy);
2557 RefPtr<BrowsingContext> bc = outerWindow->GetBrowsingContext();
2558 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"
, 2558); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc" ")"); do
{ *((volatile int*)__null) = 2558; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2559 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"
, 2559); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc->GetWindowProxy() == localProxy"
")"); do { *((volatile int*)__null) = 2559; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2560 bc->ClearWindowProxy();
2561 js::SetProxyReservedSlot(localProxy, OUTER_WINDOW_SLOT,
2562 JS::PrivateValue(nullptr));
2563 js::SetProxyReservedSlot(localProxy, HOLDER_WEAKMAP_SLOT,
2564 JS::UndefinedValue());
2565
2566 // Create a new remote outer window proxy, and transplant to it.
2567 JS::Rooted<JSObject*> remoteProxy(cx);
2568
2569 if (!mozilla::dom::GetRemoteOuterWindowProxy(cx, bc, localProxy,
2570 &remoteProxy)) {
2571 MOZ_CRASH("PrepareForProcessChange GetRemoteOuterWindowProxy")do { do { } while (false); MOZ_ReportCrash("" "PrepareForProcessChange GetRemoteOuterWindowProxy"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2571); AnnotateMozCrashReason("MOZ_CRASH(" "PrepareForProcessChange GetRemoteOuterWindowProxy"
")"); do { *((volatile int*)__null) = 2571; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2572 }
2573
2574 if (!xpc::TransplantObjectNukingXrayWaiver(cx, localProxy, remoteProxy)) {
2575 MOZ_CRASH("PrepareForProcessChange TransplantObject")do { do { } while (false); MOZ_ReportCrash("" "PrepareForProcessChange TransplantObject"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2575); AnnotateMozCrashReason("MOZ_CRASH(" "PrepareForProcessChange TransplantObject"
")"); do { *((volatile int*)__null) = 2575; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2576 }
2577}
2578
2579void nsGlobalWindowOuter::PreloadLocalStorage() {
2580 if (!Storage::StoragePrefIsEnabled()) {
2581 return;
2582 }
2583
2584 if (IsChromeWindow()) {
2585 return;
2586 }
2587
2588 nsIPrincipal* principal = GetPrincipal();
2589 nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
2590 if (!principal || !storagePrincipal) {
2591 return;
2592 }
2593
2594 nsresult rv;
2595
2596 nsCOMPtr<nsIDOMStorageManager> storageManager =
2597 do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
2598 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2599 return;
2600 }
2601
2602 // private browsing windows do not persist local storage to disk so we should
2603 // only try to precache storage when we're not a private browsing window.
2604 if (!principal->GetIsInPrivateBrowsing()) {
2605 RefPtr<Storage> storage;
2606 rv = storageManager->PrecacheStorage(principal, storagePrincipal,
2607 getter_AddRefs(storage));
2608 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2609 mLocalStorage = storage;
2610 }
2611 }
2612}
2613
2614void nsGlobalWindowOuter::DispatchDOMWindowCreated() {
2615 if (!mDoc) {
2616 return;
2617 }
2618
2619 // Fire DOMWindowCreated at chrome event listeners
2620 nsContentUtils::DispatchChromeEvent(mDoc, mDoc, u"DOMWindowCreated"_ns,
2621 CanBubble::eYes, Cancelable::eNo);
2622
2623 nsCOMPtr<nsIObserverService> observerService =
2624 mozilla::services::GetObserverService();
2625
2626 // The event dispatching could possibly cause docshell destory, and
2627 // consequently cause mDoc to be set to nullptr by DropOuterWindowDocs(),
2628 // so check it again here.
2629 if (observerService && mDoc) {
2630 nsAutoString origin;
2631 nsIPrincipal* principal = mDoc->NodePrincipal();
2632 nsContentUtils::GetWebExposedOriginSerialization(principal, origin);
2633 observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
2634 principal->IsSystemPrincipal()
2635 ? "chrome-document-global-created"
2636 : "content-document-global-created",
2637 origin.get());
2638 }
2639}
2640
2641void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); }
2642
2643void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) {
2644 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"
, 2644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocShell" ")"
); do { *((volatile int*)__null) = 2644; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2645
2646 if (aDocShell == mDocShell) {
2647 return;
2648 }
2649
2650 mDocShell = aDocShell;
2651 mBrowsingContext = aDocShell->GetBrowsingContext();
2652
2653 RefPtr<BrowsingContext> parentContext = mBrowsingContext->GetParent();
2654
2655 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"
, 2656); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
")"); do { *((volatile int*)__null) = 2656; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2656 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"
, 2656); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
")"); do { *((volatile int*)__null) = 2656; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2657
2658 mTopLevelOuterContentWindow = mBrowsingContext->IsTopContent();
2659
2660 // Get our enclosing chrome shell and retrieve its global window impl, so
2661 // that we can do some forwarding to the chrome document.
2662 RefPtr<EventTarget> chromeEventHandler;
2663 mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
2664 mChromeEventHandler = chromeEventHandler;
2665 if (!mChromeEventHandler) {
2666 // We have no chrome event handler. If we have a parent,
2667 // get our chrome event handler from the parent. If
2668 // we don't have a parent, then we need to make a new
2669 // window root object that will function as a chrome event
2670 // handler and receive all events that occur anywhere inside
2671 // our window.
2672 nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetInProcessParent();
2673 if (parentWindow.get() != this) {
2674 mChromeEventHandler = parentWindow->GetChromeEventHandler();
2675 } else {
2676 mChromeEventHandler = NS_NewWindowRoot(this);
2677 mIsRootOuterWindow = true;
2678 }
2679 }
2680
2681 SetIsBackgroundInternal(!mBrowsingContext->IsActive());
2682}
2683
2684void nsGlobalWindowOuter::DetachFromDocShell(bool aIsBeingDiscarded) {
2685 // DetachFromDocShell means the window is being torn down. Drop our
2686 // reference to the script context, allowing it to be deleted
2687 // later. Meanwhile, keep our weak reference to the script object
2688 // so that it can be retrieved later (until it is finalized by the JS GC).
2689
2690 // Call FreeInnerObjects on all inner windows, not just the current
2691 // one, since some could be held by WindowStateHolder objects that
2692 // are GC-owned.
2693 RefPtr<nsGlobalWindowInner> inner;
2694 for (PRCList* node = PR_LIST_HEAD(this)(this)->next; node != this;
2695 node = PR_NEXT_LINK(inner)((inner)->next)) {
2696 // This cast is safe because `node != this`. Non-this nodes are inner
2697 // windows.
2698 inner = static_cast<nsGlobalWindowInner*>(node);
2699 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"
, 2699); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inner->mOuterWindow || inner->mOuterWindow == this"
")"); do { *((volatile int*)__null) = 2699; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2700 inner->FreeInnerObjects();
2701 }
2702
2703 // Don't report that we were detached to the nsWindowMemoryReporter, as it
2704 // only tracks inner windows.
2705
2706 NotifyWindowIDDestroyed("outer-window-destroyed");
2707
2708 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(this);
2709
2710 if (currentInner) {
2711 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"
, 2711); MOZ_PretendNoReturn(); } } while (0)
;
2712
2713 // Remember the document's principal and URI.
2714 mDocumentPrincipal = mDoc->NodePrincipal();
2715 mDocumentCookiePrincipal = mDoc->EffectiveCookiePrincipal();
2716 mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
2717 mDocumentPartitionedPrincipal = mDoc->PartitionedPrincipal();
2718 mDocumentURI = mDoc->GetDocumentURI();
2719
2720 // Release our document reference
2721 DropOuterWindowDocs();
2722 }
2723
2724 ClearControllers();
2725
2726 mChromeEventHandler = nullptr; // force release now
2727
2728 if (mContext) {
2729 // When we're about to destroy a top level content window
2730 // (for example a tab), we trigger a full GC by passing null as the last
2731 // param. We also trigger a full GC for chrome windows.
2732 nsJSContext::PokeGC(JS::GCReason::SET_DOC_SHELL,
2733 (mTopLevelOuterContentWindow || mIsChrome)
2734 ? nullptr
2735 : GetWrapperPreserveColor());
2736 mContext = nullptr;
2737 }
2738
2739 if (aIsBeingDiscarded) {
2740 // If our BrowsingContext is being discarded, make a note that our current
2741 // inner window was active at the time it went away.
2742 if (nsGlobalWindowInner* currentInner =
2743 GetCurrentInnerWindowInternal(this)) {
2744 currentInner->SetWasCurrentInnerWindow();
2745 }
2746 }
2747
2748 mDocShell = nullptr;
2749 mBrowsingContext->ClearDocShell();
2750
2751 CleanUp();
2752}
2753
2754void nsGlobalWindowOuter::UpdateParentTarget() {
2755 // NOTE: This method is nearly identical to
2756 // nsGlobalWindowInner::UpdateParentTarget(). IF YOU UPDATE THIS METHOD,
2757 // UPDATE THE OTHER ONE TOO! The one difference is that this method updates
2758 // mMessageManager as well, which inner windows don't have.
2759
2760 // Try to get our frame element's tab child global (its in-process message
2761 // manager). If that fails, fall back to the chrome event handler's tab
2762 // child global, and if it doesn't have one, just use the chrome event
2763 // handler itself.
2764
2765 nsCOMPtr<Element> frameElement = GetFrameElementInternal();
2766 mMessageManager = nsContentUtils::TryGetBrowserChildGlobal(frameElement);
2767
2768 if (!mMessageManager) {
2769 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
2770 if (topWin) {
2771 frameElement = topWin->GetFrameElementInternal();
2772 mMessageManager = nsContentUtils::TryGetBrowserChildGlobal(frameElement);
2773 }
2774 }
2775
2776 if (!mMessageManager) {
2777 mMessageManager =
2778 nsContentUtils::TryGetBrowserChildGlobal(mChromeEventHandler);
2779 }
2780
2781 if (mMessageManager) {
2782 mParentTarget = mMessageManager;
2783 } else {
2784 mParentTarget = mChromeEventHandler;
2785 }
2786}
2787
2788EventTarget* nsGlobalWindowOuter::GetTargetForEventTargetChain() {
2789 return GetCurrentInnerWindowInternal(this);
2790}
2791
2792void nsGlobalWindowOuter::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
2793 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"
, 2793); AnnotateMozCrashReason("MOZ_CRASH(" "The outer window should not be part of an event path"
")"); do { *((volatile int*)__null) = 2793; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2794}
2795
2796bool nsGlobalWindowOuter::ShouldPromptToBlockDialogs() {
2797 if (!nsContentUtils::GetCurrentJSContext()) {
2798 return false; // non-scripted caller.
2799 }
2800
2801 BrowsingContextGroup* group = GetBrowsingContextGroup();
2802 if (!group) {
2803 return true;
2804 }
2805
2806 return group->DialogsAreBeingAbused();
2807}
2808
2809bool nsGlobalWindowOuter::AreDialogsEnabled() {
2810 BrowsingContextGroup* group = mBrowsingContext->Group();
2811 if (!group) {
2812 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"
, 2812); MOZ_PretendNoReturn(); } while (0)
;
2813 return false;
2814 }
2815
2816 // Dialogs are blocked if the content viewer is hidden
2817 if (mDocShell) {
2818 nsCOMPtr<nsIDocumentViewer> viewer;
2819 mDocShell->GetDocViewer(getter_AddRefs(viewer));
2820
2821 bool isHidden;
2822 viewer->GetIsHidden(&isHidden);
2823 if (isHidden) {
2824 return false;
2825 }
2826 }
2827
2828 // Dialogs are also blocked if the document is sandboxed with SANDBOXED_MODALS
2829 // (or if we have no document, of course). Which document? Who knows; the
2830 // spec is daft. See <https://github.com/whatwg/html/issues/1206>. For now
2831 // just go ahead and check mDoc, since in everything except edge cases in
2832 // which a frame is allow-same-origin but not allow-scripts and is being poked
2833 // at by some other window this should be the right thing anyway.
2834 if (!mDoc || (mDoc->GetSandboxFlags() & SANDBOXED_MODALS)) {
2835 return false;
2836 }
2837
2838 return group->GetAreDialogsEnabled();
2839}
2840
2841bool nsGlobalWindowOuter::ConfirmDialogIfNeeded() {
2842 NS_ENSURE_TRUE(mDocShell, false)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"
, 2842); return false; } } while (false)
;
2843 nsCOMPtr<nsIPromptService> promptSvc =
2844 do_GetService("@mozilla.org/prompter;1");
2845
2846 if (!promptSvc) {
2847 return true;
2848 }
2849
2850 // Reset popup state while opening a modal dialog, and firing events
2851 // about the dialog, to prevent the current state from being active
2852 // the whole time a modal dialog is open.
2853 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
2854
2855 bool disableDialog = false;
2856 nsAutoString label, title;
2857 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2858 "ScriptDialogLabel", label);
2859 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2860 "ScriptDialogPreventTitle", title);
2861 promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
2862 if (disableDialog) {
2863 DisableDialogs();
2864 return false;
2865 }
2866
2867 return true;
2868}
2869
2870void nsGlobalWindowOuter::DisableDialogs() {
2871 BrowsingContextGroup* group = mBrowsingContext->Group();
2872 if (!group) {
2873 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"
, 2873); MOZ_PretendNoReturn(); } while (0)
;
2874 return;
2875 }
2876
2877 if (group) {
2878 group->SetAreDialogsEnabled(false);
2879 }
2880}
2881
2882void nsGlobalWindowOuter::EnableDialogs() {
2883 BrowsingContextGroup* group = mBrowsingContext->Group();
2884 if (!group) {
2885 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"
, 2885); MOZ_PretendNoReturn(); } while (0)
;
2886 return;
2887 }
2888
2889 if (group) {
2890 group->SetAreDialogsEnabled(true);
2891 }
2892}
2893
2894nsresult nsGlobalWindowOuter::PostHandleEvent(EventChainPostVisitor& aVisitor) {
2895 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"
, 2895); AnnotateMozCrashReason("MOZ_CRASH(" "The outer window should not be part of an event path"
")"); do { *((volatile int*)__null) = 2895; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2896}
2897
2898void nsGlobalWindowOuter::PoisonOuterWindowProxy(JSObject* aObject) {
2899 if (aObject == GetWrapperMaybeDead()) {
2900 PoisonWrapper();
2901 }
2902}
2903
2904nsresult nsGlobalWindowOuter::SetArguments(nsIArray* aArguments) {
2905 nsresult rv;
2906
2907 // We've now mostly separated them, but the difference is still opaque to
2908 // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
2909 // embedding waltz we do here).
2910 //
2911 // So we need to demultiplex the two cases here.
2912 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(this);
2913
2914 mArguments = aArguments;
2915 rv = currentInner->DefineArgumentsProperty(aArguments);
2916 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"
, 2916); return rv; } } while (false)
;
2917
2918 return NS_OK;
2919}
2920
2921//*****************************************************************************
2922// nsGlobalWindowOuter::nsIScriptObjectPrincipal
2923//*****************************************************************************
2924
2925nsIPrincipal* nsGlobalWindowOuter::GetPrincipal() {
2926 if (mDoc) {
2927 // If we have a document, get the principal from the document
2928 return mDoc->NodePrincipal();
2929 }
2930
2931 if (mDocumentPrincipal) {
2932 return mDocumentPrincipal;
2933 }
2934
2935 // If we don't have a principal and we don't have a document we
2936 // ask the parent window for the principal. This can happen when
2937 // loading a frameset that has a <frame src="javascript:xxx">, in
2938 // that case the global window is used in JS before we've loaded
2939 // a document into the window.
2940
2941 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2942 do_QueryInterface(GetInProcessParentInternal());
2943
2944 if (objPrincipal) {
2945 return objPrincipal->GetPrincipal();
2946 }
2947
2948 return nullptr;
2949}
2950
2951nsIPrincipal* nsGlobalWindowOuter::GetEffectiveCookiePrincipal() {
2952 if (mDoc) {
2953 // If we have a document, get the principal from the document
2954 return mDoc->EffectiveCookiePrincipal();
2955 }
2956
2957 if (mDocumentCookiePrincipal) {
2958 return mDocumentCookiePrincipal;
2959 }
2960
2961 // If we don't have a cookie principal and we don't have a document we ask
2962 // the parent window for the cookie principal.
2963
2964 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2965 do_QueryInterface(GetInProcessParentInternal());
2966
2967 if (objPrincipal) {
2968 return objPrincipal->GetEffectiveCookiePrincipal();
2969 }
2970
2971 return nullptr;
2972}
2973
2974nsIPrincipal* nsGlobalWindowOuter::GetEffectiveStoragePrincipal() {
2975 if (mDoc) {
2976 // If we have a document, get the principal from the document
2977 return mDoc->EffectiveStoragePrincipal();
2978 }
2979
2980 if (mDocumentStoragePrincipal) {
2981 return mDocumentStoragePrincipal;
2982 }
2983
2984 // If we don't have a storage principal and we don't have a document we ask
2985 // the parent window for the storage principal.
2986
2987 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2988 do_QueryInterface(GetInProcessParentInternal());
2989
2990 if (objPrincipal) {
2991 return objPrincipal->GetEffectiveStoragePrincipal();
2992 }
2993
2994 return nullptr;
2995}
2996
2997nsIPrincipal* nsGlobalWindowOuter::PartitionedPrincipal() {
2998 if (mDoc) {
2999 // If we have a document, get the principal from the document
3000 return mDoc->PartitionedPrincipal();
3001 }
3002
3003 if (mDocumentPartitionedPrincipal) {
3004 return mDocumentPartitionedPrincipal;
3005 }
3006
3007 // If we don't have a partitioned principal and we don't have a document we
3008 // ask the parent window for the partitioned principal.
3009
3010 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
3011 do_QueryInterface(GetInProcessParentInternal());
3012
3013 if (objPrincipal) {
3014 return objPrincipal->PartitionedPrincipal();
3015 }
3016
3017 return nullptr;
3018}
3019
3020//*****************************************************************************
3021// nsGlobalWindowOuter::nsIDOMWindow
3022//*****************************************************************************
3023
3024Element* nsPIDOMWindowOuter::GetFrameElementInternal() const {
3025 return mFrameElement;
3026}
3027
3028void nsPIDOMWindowOuter::SetFrameElementInternal(Element* aFrameElement) {
3029 mFrameElement = aFrameElement;
3030}
3031
3032Navigator* nsGlobalWindowOuter::GetNavigator() {
3033 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"
, 3033); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Navigator (); } while (0)
;
3034}
3035
3036nsScreen* nsGlobalWindowOuter::GetScreen() {
3037 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"
, 3037); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Screen (); } while (0)
;
3038}
3039
3040void nsPIDOMWindowOuter::ActivateMediaComponents() {
3041 if (!ShouldDelayMediaFromStart()) {
3042 return;
3043 }
3044 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)
3045 ("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)
3046 "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)
3047 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)
;
3048 if (BrowsingContext* bc = GetBrowsingContext()) {
3049 Unused << bc->Top()->SetShouldDelayMediaFromStart(false);
3050 }
3051 NotifyResumingDelayedMedia();
3052}
3053
3054bool nsPIDOMWindowOuter::ShouldDelayMediaFromStart() const {
3055 BrowsingContext* bc = GetBrowsingContext();
3056 return bc && bc->Top()->GetShouldDelayMediaFromStart();
3057}
3058
3059void nsPIDOMWindowOuter::NotifyResumingDelayedMedia() {
3060 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
3061 if (service) {
3062 service->NotifyResumingDelayedMedia(this);
3063 }
3064}
3065
3066bool nsPIDOMWindowOuter::GetAudioMuted() const {
3067 BrowsingContext* bc = GetBrowsingContext();
3068 return bc && bc->Top()->GetMuted();
3069}
3070
3071void nsPIDOMWindowOuter::RefreshMediaElementsVolume() {
3072 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
3073 if (service) {
3074 // TODO: RefreshAgentsVolume can probably be simplified further.
3075 service->RefreshAgentsVolume(this, 1.0f, GetAudioMuted());
3076 }
3077}
3078
3079mozilla::dom::BrowsingContextGroup*
3080nsPIDOMWindowOuter::GetBrowsingContextGroup() const {
3081 return mBrowsingContext ? mBrowsingContext->Group() : nullptr;
3082}
3083
3084Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetParentOuter() {
3085 BrowsingContext* bc = GetBrowsingContext();
3086 return bc ? bc->GetParent(IgnoreErrors()) : nullptr;
3087}
3088
3089/**
3090 * GetInProcessScriptableParent used to be called when a script read
3091 * window.parent. Under Fission, that is now handled by
3092 * BrowsingContext::GetParent, and the result is a WindowProxyHolder rather than
3093 * an actual global window. This method still exists for legacy callers which
3094 * relied on the old logic, and require in-process windows. However, it only
3095 * works correctly when no out-of-process frames exist between this window and
3096 * the top-level window, so it should not be used in new code.
3097 *
3098 * In contrast to GetRealParent, GetInProcessScriptableParent respects <iframe
3099 * mozbrowser> boundaries, so if |this| is contained by an <iframe
3100 * mozbrowser>, we will return |this| as its own parent.
3101 */
3102nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableParent() {
3103 if (!mDocShell) {
3104 return nullptr;
3105 }
3106
3107 if (BrowsingContext* parentBC = GetBrowsingContext()->GetParent()) {
3108 if (nsCOMPtr<nsPIDOMWindowOuter> parent = parentBC->GetDOMWindow()) {
3109 return parent;
3110 }
3111 }
3112 return this;
3113}
3114
3115/**
3116 * Behavies identically to GetInProcessScriptableParent extept that it returns
3117 * null if GetInProcessScriptableParent would return this window.
3118 */
3119nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableParentOrNull() {
3120 nsPIDOMWindowOuter* parent = GetInProcessScriptableParent();
3121 return (nsGlobalWindowOuter::Cast(parent) == this) ? nullptr : parent;
3122}
3123
3124already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetInProcessParent() {
3125 if (!mDocShell) {
3126 return nullptr;
3127 }
3128
3129 if (auto* parentBC = GetBrowsingContext()->GetParent()) {
3130 if (auto* parent = parentBC->GetDOMWindow()) {
3131 return do_AddRef(parent);
3132 }
3133 }
3134 return do_AddRef(this);
3135}
3136
3137static nsresult GetTopImpl(nsGlobalWindowOuter* aWin, nsIURI* aURIBeingLoaded,
3138 nsPIDOMWindowOuter** aTop, bool aScriptable,
3139 bool aExcludingExtensionAccessibleContentFrames) {
3140 *aTop = nullptr;
3141
3142 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"
, 3142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aScriptable"
")"); do { *((volatile int*)__null) = 3142; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3143
3144 // Walk up the parent chain.
3145
3146 nsCOMPtr<nsPIDOMWindowOuter> prevParent = aWin;
3147 nsCOMPtr<nsPIDOMWindowOuter> parent = aWin;
3148 do {
3149 if (!parent) {
3150 break;
3151 }
3152
3153 prevParent = parent;
3154
3155 if (aScriptable) {
3156 parent = parent->GetInProcessScriptableParent();
3157 } else {
3158 parent = parent->GetInProcessParent();
3159 }
3160
3161 if (aExcludingExtensionAccessibleContentFrames) {
3162 if (auto* p = nsGlobalWindowOuter::Cast(parent)) {
3163 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(p);
3164 nsIURI* uri = prevParent->GetDocumentURI();
3165 if (!uri) {
3166 // If our parent doesn't have a URI yet, we have a document that is in
3167 // the process of being loaded. In that case, our caller is
3168 // responsible for passing in the URI for the document that is being
3169 // loaded, so we fall back to using that URI here.
3170 uri = aURIBeingLoaded;
3171 }
3172
3173 if (currentInner && uri) {
3174 // If we find an inner window, we better find the uri for the current
3175 // window we're looking at. If we can't find it directly, it is the
3176 // responsibility of our caller to provide it to us.
3177 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"
, 3177); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "uri"
")"); do { *((volatile int*)__null) = 3177; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3178
3179 // If the new parent has permission to load the current page, we're
3180 // at a moz-extension:// frame which has a host permission that allows
3181 // it to load the document that we've loaded. In that case, stop at
3182 // this frame and consider it the top-level frame.
3183 //
3184 // Note that it's possible for the set of URIs accepted by
3185 // AddonAllowsLoad() to change at runtime, but we don't need to cache
3186 // the result of this check, since the important consumer of this code
3187 // (which is nsIHttpChannelInternal.topWindowURI) already caches the
3188 // result after computing it the first time.
3189 if (BasePrincipal::Cast(p->GetPrincipal())
3190 ->AddonAllowsLoad(uri, true)) {
3191 parent = prevParent;
3192 break;
3193 }
3194 }
3195 }
3196 }
3197
3198 } while (parent != prevParent);
3199
3200 if (parent) {
3201 parent.swap(*aTop);
3202 }
3203
3204 return NS_OK;
3205}
3206
3207/**
3208 * GetInProcessScriptableTop used to be called when a script read window.top.
3209 * Under Fission, that is now handled by BrowsingContext::Top, and the result is
3210 * a WindowProxyHolder rather than an actual global window. This method still
3211 * exists for legacy callers which relied on the old logic, and require
3212 * in-process windows. However, it only works correctly when no out-of-process
3213 * frames exist between this window and the top-level window, so it should not
3214 * be used in new code.
3215 *
3216 * In contrast to GetRealTop, GetInProcessScriptableTop respects <iframe
3217 * mozbrowser> boundaries. If we encounter a window owned by an <iframe
3218 * mozbrowser> while walking up the window hierarchy, we'll stop and return that
3219 * window.
3220 */
3221nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableTop() {
3222 nsCOMPtr<nsPIDOMWindowOuter> window;
3223 GetTopImpl(this, /* aURIBeingLoaded = */ nullptr, getter_AddRefs(window),
3224 /* aScriptable = */ true,
3225 /* aExcludingExtensionAccessibleContentFrames = */ false);
3226 return window.get();
3227}
3228
3229already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetInProcessTop() {
3230 nsCOMPtr<nsPIDOMWindowOuter> window;
3231 GetTopImpl(this, /* aURIBeingLoaded = */ nullptr, getter_AddRefs(window),
3232 /* aScriptable = */ false,
3233 /* aExcludingExtensionAccessibleContentFrames = */ false);
3234 return window.forget();
3235}
3236
3237already_AddRefed<nsPIDOMWindowOuter>
3238nsGlobalWindowOuter::GetTopExcludingExtensionAccessibleContentFrames(
3239 nsIURI* aURIBeingLoaded) {
3240 // There is a parent-process equivalent of this in DocumentLoadListener.cpp
3241 // GetTopWindowExcludingExtensionAccessibleContentFrames
3242 nsCOMPtr<nsPIDOMWindowOuter> window;
3243 GetTopImpl(this, aURIBeingLoaded, getter_AddRefs(window),
3244 /* aScriptable = */ false,
3245 /* aExcludingExtensionAccessibleContentFrames = */ true);
3246 return window.forget();
3247}
3248
3249void nsGlobalWindowOuter::GetContentOuter(JSContext* aCx,
3250 JS::MutableHandle<JSObject*> aRetval,
3251 CallerType aCallerType,
3252 ErrorResult& aError) {
3253 RefPtr<BrowsingContext> content = GetContentInternal(aCallerType, aError);
3254 if (aError.Failed()) {
3255 return;
3256 }
3257
3258 if (!content) {
3259 aRetval.set(nullptr);
3260 return;
3261 }
3262
3263 JS::Rooted<JS::Value> val(aCx);
3264 if (!ToJSValue(aCx, WindowProxyHolder{content}, &val)) {
3265 aError.Throw(NS_ERROR_UNEXPECTED);
3266 return;
3267 }
3268
3269 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"
, 3269); AnnotateMozCrashReason("MOZ_ASSERT" "(" "val.isObjectOrNull()"
")"); do { *((volatile int*)__null) = 3269; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3270 aRetval.set(val.toObjectOrNull());
3271}
3272
3273already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetContentInternal(
3274 CallerType aCallerType, ErrorResult& aError) {
3275 // First check for a named frame named "content"
3276 if (RefPtr<BrowsingContext> named = GetChildWindow(u"content"_ns)) {
3277 return named.forget();
3278 }
3279
3280 // If we're in the parent process, and being called by system code, `content`
3281 // should return the current primary content frame (if it's in-process).
3282 //
3283 // We return `nullptr` if the current primary content frame is out-of-process,
3284 // rather than a remote window proxy, as that is the existing behaviour as of
3285 // bug 1597437.
3286 if (XRE_IsParentProcess() && aCallerType == CallerType::System) {
3287 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
3288 if (!treeOwner) {
3289 aError.Throw(NS_ERROR_FAILURE);
3290 return nullptr;
3291 }
3292
3293 nsCOMPtr<nsIDocShellTreeItem> primaryContent;
3294 treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
3295 if (!primaryContent) {
3296 return nullptr;
3297 }
3298
3299 return do_AddRef(primaryContent->GetBrowsingContext());
3300 }
3301
3302 // For legacy untrusted callers we always return the same value as
3303 // `window.top`
3304 if (mDoc && aCallerType != CallerType::System) {
3305 mDoc->WarnOnceAbout(DeprecatedOperations::eWindowContentUntrusted);
3306 }
3307
3308 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"
, 3308); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mBrowsingContext->IsContent()"
")"); do { *((volatile int*)__null) = 3308; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3309 return do_AddRef(mBrowsingContext->Top());
3310}
3311
3312nsresult nsGlobalWindowOuter::GetPrompter(nsIPrompt** aPrompt) {
3313 if (!mDocShell) return NS_ERROR_FAILURE;
3314
3315 nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
3316 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"
, 3316); return NS_ERROR_NO_INTERFACE; } } while (false)
;
3317
3318 prompter.forget(aPrompt);
3319 return NS_OK;
3320}
3321
3322bool nsGlobalWindowOuter::GetClosedOuter() {
3323 // If someone called close(), or if we don't have a docshell, we're closed.
3324 return mIsClosed || !mDocShell;
3325}
3326
3327bool nsGlobalWindowOuter::Closed() { return GetClosedOuter(); }
3328
3329Nullable<WindowProxyHolder> nsGlobalWindowOuter::IndexedGetterOuter(
3330 uint32_t aIndex) {
3331 BrowsingContext* bc = GetBrowsingContext();
3332 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"
, 3332); return nullptr; } } while (false)
;
3333
3334 Span<RefPtr<BrowsingContext>> children = bc->NonSyntheticChildren();
3335
3336 if (aIndex < children.Length()) {
3337 return WindowProxyHolder(children[aIndex]);
3338 }
3339 return nullptr;
3340}
3341
3342nsIControllers* nsGlobalWindowOuter::GetControllersOuter(ErrorResult& aError) {
3343 if (!mControllers) {
3344 mControllers = new nsXULControllers();
3345 if (!mControllers) {
3346 aError.Throw(NS_ERROR_FAILURE);
3347 return nullptr;
3348 }
3349
3350 // Add in the default controller
3351 RefPtr<nsBaseCommandController> commandController =
3352 nsBaseCommandController::CreateWindowController();
3353 if (!commandController) {
3354 aError.Throw(NS_ERROR_FAILURE);
3355 return nullptr;
3356 }
3357
3358 mControllers->InsertControllerAt(0, commandController);
3359 commandController->SetCommandContext(static_cast<nsIDOMWindow*>(this));
3360 }
3361
3362 return mControllers;
3363}
3364
3365nsresult nsGlobalWindowOuter::GetControllers(nsIControllers** aResult) {
3366 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"
, 3366); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetControllers (aResult); } while (0)
;
3367}
3368
3369already_AddRefed<BrowsingContext>
3370nsGlobalWindowOuter::GetOpenerBrowsingContext() {
3371 RefPtr<BrowsingContext> opener = GetBrowsingContext()->GetOpener();
3372 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"
, 3373); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!opener || opener->Group() == GetBrowsingContext()->Group()"
")"); do { *((volatile int*)__null) = 3373; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3373 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"
, 3373); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!opener || opener->Group() == GetBrowsingContext()->Group()"
")"); do { *((volatile int*)__null) = 3373; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3374 if (!opener || opener->Group() != GetBrowsingContext()->Group()) {
3375 return nullptr;
3376 }
3377
3378 // Catch the case where we're chrome but the opener is not...
3379 if (nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
3380 GetPrincipal() == nsContentUtils::GetSystemPrincipal()) {
3381 auto* openerWin = nsGlobalWindowOuter::Cast(opener->GetDOMWindow());
3382 if (!openerWin ||
3383 openerWin->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
3384 return nullptr;
3385 }
3386 }
3387
3388 return opener.forget();
3389}
3390
3391nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSameProcessOpener() {
3392 if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
3393 return opener->GetDOMWindow();
3394 }
3395 return nullptr;
3396}
3397
3398Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpenerWindowOuter() {
3399 if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
3400 return WindowProxyHolder(std::move(opener));
3401 }
3402 return nullptr;
3403}
3404
3405Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpener() {
3406 return GetOpenerWindowOuter();
3407}
3408
3409void nsGlobalWindowOuter::GetStatusOuter(nsAString& aStatus) {
3410 aStatus = mStatus;
3411}
3412
3413void nsGlobalWindowOuter::SetStatusOuter(const nsAString& aStatus) {
3414 mStatus = aStatus;
3415
3416 // We don't support displaying window.status in the UI, so there's nothing
3417 // left to do here.
3418}
3419
3420void nsGlobalWindowOuter::GetNameOuter(nsAString& aName) {
3421 if (mDocShell) {
3422 mDocShell->GetName(aName);
3423 }
3424}
3425
3426void nsGlobalWindowOuter::SetNameOuter(const nsAString& aName,
3427 mozilla::ErrorResult& aError) {
3428 if (mDocShell) {
3429 aError = mDocShell->SetName(aName);
3430 }
3431}
3432
3433// NOTE: The idea of this function is that it should return the same as
3434// nsPresContext::CSSToDeviceScale() if it was in aWindow synchronously. For
3435// that, we use the UnscaledDevicePixelsPerCSSPixel() (which contains the device
3436// scale and the OS zoom scale) and then account for the browsing context full
3437// zoom. See the declaration of this function for context about why this is
3438// needed.
3439CSSToLayoutDeviceScale nsGlobalWindowOuter::CSSToDevScaleForBaseWindow(
3440 nsIBaseWindow* aWindow) {
3441 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"
, 3441); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")"
); do { *((volatile int*)__null) = 3441; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3442 auto scale = aWindow->UnscaledDevicePixelsPerCSSPixel();
3443 if (mBrowsingContext) {
3444 scale.scale *= mBrowsingContext->FullZoom();
3445 }
3446 return scale;
3447}
3448
3449nsresult nsGlobalWindowOuter::GetInnerSize(CSSSize& aSize) {
3450 EnsureSizeAndPositionUpToDate();
3451
3452 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"
, 3452); return NS_ERROR_UNEXPECTED; } } while (false)
;
3453
3454 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3455 PresShell* presShell = mDocShell->GetPresShell();
3456
3457 if (!presContext || !presShell) {
3458 aSize = {};
3459 return NS_OK;
3460 }
3461
3462 // Whether or not the css viewport has been overridden, we can get the
3463 // correct value by looking at the visible area of the presContext.
3464 if (RefPtr<nsViewManager> viewManager = presShell->GetViewManager()) {
3465 viewManager->FlushDelayedResize();
3466 }
3467
3468 // FIXME: Bug 1598487 - Return the layout viewport instead of the ICB.
3469 nsSize viewportSize = presContext->GetVisibleArea().Size();
3470 if (presContext->GetDynamicToolbarState() == DynamicToolbarState::Collapsed) {
3471 viewportSize =
3472 nsLayoutUtils::ExpandHeightForViewportUnits(presContext, viewportSize);
3473 }
3474
3475 aSize = CSSPixel::FromAppUnits(viewportSize);
3476
3477 switch (StaticPrefs::dom_innerSize_rounding()) {
3478 case 1:
3479 aSize.width = std::roundf(aSize.width);
3480 aSize.height = std::roundf(aSize.height);
3481 break;
3482 case 2:
3483 aSize.width = std::truncf(aSize.width);
3484 aSize.height = std::truncf(aSize.height);
3485 break;
3486 default:
3487 break;
3488 }
3489
3490 return NS_OK;
3491}
3492
3493double nsGlobalWindowOuter::GetInnerWidthOuter(ErrorResult& aError) {
3494 CSSSize size;
3495 aError = GetInnerSize(size);
3496 return size.width;
3497}
3498
3499nsresult nsGlobalWindowOuter::GetInnerWidth(double* aInnerWidth) {
3500 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"
, 3500); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetInnerWidth (aInnerWidth); } while (0)
;
3501}
3502
3503double nsGlobalWindowOuter::GetInnerHeightOuter(ErrorResult& aError) {
3504 CSSSize size;
3505 aError = GetInnerSize(size);
3506 return size.height;
3507}
3508
3509nsresult nsGlobalWindowOuter::GetInnerHeight(double* aInnerHeight) {
3510 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"
, 3510); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetInnerHeight (aInnerHeight); } while (0)
;
3511}
3512
3513CSSIntSize nsGlobalWindowOuter::GetOuterSize(CallerType aCallerType,
3514 ErrorResult& aError) {
3515 if (nsIGlobalObject::ShouldResistFingerprinting(aCallerType,
3516 RFPTarget::WindowOuterSize)) {
3517 CSSSize size;
3518 aError = GetInnerSize(size);
3519 return RoundedToInt(size);
3520 }
3521
3522 // Windows showing documents in RDM panes and any subframes within them
3523 // return the simulated device size.
3524 if (mDoc) {
3525 Maybe<CSSIntSize> deviceSize = GetRDMDeviceSize(*mDoc);
3526 if (deviceSize.isSome()) {
3527 return *deviceSize;
3528 }
3529 }
3530
3531 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3532 if (!treeOwnerAsWin) {
3533 aError.Throw(NS_ERROR_FAILURE);
3534 return {};
3535 }
3536
3537 return RoundedToInt(treeOwnerAsWin->GetSize() /
3538 CSSToDevScaleForBaseWindow(treeOwnerAsWin));
3539}
3540
3541int32_t nsGlobalWindowOuter::GetOuterWidthOuter(CallerType aCallerType,
3542 ErrorResult& aError) {
3543 return GetOuterSize(aCallerType, aError).width;
3544}
3545
3546int32_t nsGlobalWindowOuter::GetOuterHeightOuter(CallerType aCallerType,
3547 ErrorResult& aError) {
3548 return GetOuterSize(aCallerType, aError).height;
3549}
3550
3551CSSPoint nsGlobalWindowOuter::ScreenEdgeSlop() {
3552 if (NS_WARN_IF(!mDocShell)NS_warn_if_impl(!mDocShell, "!mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3552)
) {
3553 return {};
3554 }
3555 RefPtr<nsPresContext> pc = mDocShell->GetPresContext();
3556 if (NS_WARN_IF(!pc)NS_warn_if_impl(!pc, "!pc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3556)
) {
3557 return {};
3558 }
3559 nsCOMPtr<nsIWidget> widget = GetMainWidget();
3560 if (NS_WARN_IF(!widget)NS_warn_if_impl(!widget, "!widget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3560)
) {
3561 return {};
3562 }
3563 LayoutDeviceIntPoint pt = widget->GetScreenEdgeSlop();
3564 auto auPoint =
3565 LayoutDeviceIntPoint::ToAppUnits(pt, pc->AppUnitsPerDevPixel());
3566 return CSSPoint::FromAppUnits(auPoint);
3567}
3568
3569CSSIntPoint nsGlobalWindowOuter::GetScreenXY(CallerType aCallerType,
3570 ErrorResult& aError) {
3571 // When resisting fingerprinting, always return (0,0)
3572 if (nsIGlobalObject::ShouldResistFingerprinting(aCallerType,
3573 RFPTarget::WindowScreenXY)) {
3574 return CSSIntPoint(0, 0);
3575 }
3576
3577 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3578 if (!treeOwnerAsWin) {
3579 aError.Throw(NS_ERROR_FAILURE);
3580 return CSSIntPoint(0, 0);
3581 }
3582
3583 LayoutDeviceIntPoint windowPos;
3584 aError = treeOwnerAsWin->GetPosition(&windowPos.x.value, &windowPos.y.value);
3585
3586 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3587 if (!presContext) {
3588 // XXX Fishy LayoutDevice to CSS conversion?
3589 return CSSIntPoint(windowPos.x, windowPos.y);
3590 }
3591
3592 nsDeviceContext* context = presContext->DeviceContext();
3593 auto windowPosAppUnits = LayoutDeviceIntPoint::ToAppUnits(
3594 windowPos, context->AppUnitsPerDevPixel());
3595 return CSSIntPoint::FromAppUnitsRounded(windowPosAppUnits);
3596}
3597
3598int32_t nsGlobalWindowOuter::GetScreenXOuter(CallerType aCallerType,
3599 ErrorResult& aError) {
3600 return GetScreenXY(aCallerType, aError).x;
3601}
3602
3603nsRect nsGlobalWindowOuter::GetInnerScreenRect() {
3604 if (!mDocShell) {
3605 return nsRect();
3606 }
3607
3608 EnsureSizeAndPositionUpToDate();
3609
3610 if (!mDocShell) {
3611 return nsRect();
3612 }
3613
3614 PresShell* presShell = mDocShell->GetPresShell();
3615 if (!presShell) {
3616 return nsRect();
3617 }
3618 nsIFrame* rootFrame = presShell->GetRootFrame();
3619 if (!rootFrame) {
3620 return nsRect();
3621 }
3622
3623 return rootFrame->GetScreenRectInAppUnits();
3624}
3625
3626Maybe<CSSIntSize> nsGlobalWindowOuter::GetRDMDeviceSize(
3627 const Document& aDocument) {
3628 // RDM device size should reflect the simulated device resolution, and
3629 // be independent of any full zoom or resolution zoom applied to the
3630 // content. To get this value, we get the "unscaled" browser child size,
3631 // and divide by the full zoom. "Unscaled" in this case means unscaled
3632 // from device to screen but it has been affected (multiplied) by the
3633 // full zoom and we need to compensate for that.
3634 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"
, 3634); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3634; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3635
3636 // Bug 1576256: This does not work for cross-process subframes.
3637 const Document* topInProcessContentDoc =
3638 aDocument.GetTopLevelContentDocumentIfSameProcess();
3639 BrowsingContext* bc = topInProcessContentDoc
3640 ? topInProcessContentDoc->GetBrowsingContext()
3641 : nullptr;
3642 if (bc && bc->InRDMPane()) {
3643 nsIDocShell* docShell = topInProcessContentDoc->GetDocShell();
3644 if (docShell) {
3645 nsPresContext* presContext = docShell->GetPresContext();
3646 if (presContext) {
3647 nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild();
3648 if (child) {
3649 // We intentionally use GetFullZoom here instead of
3650 // GetDeviceFullZoom, because the unscaledInnerSize is based
3651 // on the full zoom and not the device full zoom (which is
3652 // rounded to result in integer device pixels).
3653 float zoom = presContext->GetFullZoom();
3654 BrowserChild* bc = static_cast<BrowserChild*>(child.get());
3655 CSSSize unscaledSize = bc->GetUnscaledInnerSize();
3656 return Some(CSSIntSize(gfx::RoundedToInt(unscaledSize / zoom)));
3657 }
3658 }
3659 }
3660 }
3661 return Nothing();
3662}
3663
3664float nsGlobalWindowOuter::GetMozInnerScreenXOuter(CallerType aCallerType) {
3665 // When resisting fingerprinting, always return 0.
3666 if (nsIGlobalObject::ShouldResistFingerprinting(
3667 aCallerType, RFPTarget::WindowInnerScreenXY)) {
3668 return 0.0;
3669 }
3670
3671 nsRect r = GetInnerScreenRect();
3672 return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
3673}
3674
3675float nsGlobalWindowOuter::GetMozInnerScreenYOuter(CallerType aCallerType) {
3676 // Return 0 to prevent fingerprinting.
3677 if (nsIGlobalObject::ShouldResistFingerprinting(
3678 aCallerType, RFPTarget::WindowInnerScreenXY)) {
3679 return 0.0;
3680 }
3681
3682 nsRect r = GetInnerScreenRect();
3683 return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
3684}
3685
3686int32_t nsGlobalWindowOuter::GetScreenYOuter(CallerType aCallerType,
3687 ErrorResult& aError) {
3688 return GetScreenXY(aCallerType, aError).y;
3689}
3690
3691// NOTE: Arguments to this function should have values scaled to
3692// CSS pixels, not device pixels.
3693void nsGlobalWindowOuter::CheckSecurityWidthAndHeight(int32_t* aWidth,
3694 int32_t* aHeight,
3695 CallerType aCallerType) {
3696 if (aCallerType != CallerType::System) {
3697 // if attempting to resize the window, hide any open popups
3698 nsContentUtils::HidePopupsInDocument(mDoc);
3699 }
3700
3701 // This one is easy. Just ensure the variable is greater than 100;
3702 if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
3703 // Check security state for use in determing window dimensions
3704
3705 if (aCallerType != CallerType::System) {
3706 // sec check failed
3707 if (aWidth && *aWidth < 100) {
3708 *aWidth = 100;
3709 }
3710 if (aHeight && *aHeight < 100) {
3711 *aHeight = 100;
3712 }
3713 }
3714 }
3715}
3716
3717// NOTE: Arguments to this function should have values in app units
3718void nsGlobalWindowOuter::SetCSSViewportWidthAndHeight(nscoord aInnerWidth,
3719 nscoord aInnerHeight) {
3720 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3721
3722 nsRect shellArea = presContext->GetVisibleArea();
3723 shellArea.SetHeight(aInnerHeight);
3724 shellArea.SetWidth(aInnerWidth);
3725
3726 // FIXME(emilio): This doesn't seem to be ok, this doesn't reflow or
3727 // anything... Should go through PresShell::ResizeReflow.
3728 //
3729 // But I don't think this can be reached by content, as we don't allow to set
3730 // inner{Width,Height}.
3731 presContext->SetVisibleArea(shellArea);
3732}
3733
3734// NOTE: Arguments to this function should have values scaled to
3735// CSS pixels, not device pixels.
3736void nsGlobalWindowOuter::CheckSecurityLeftAndTop(int32_t* aLeft, int32_t* aTop,
3737 CallerType aCallerType) {
3738 // This one is harder. We have to get the screen size and window dimensions.
3739
3740 // Check security state for use in determing window dimensions
3741
3742 if (aCallerType != CallerType::System) {
3743 // if attempting to move the window, hide any open popups
3744 nsContentUtils::HidePopupsInDocument(mDoc);
3745
3746 if (nsGlobalWindowOuter* rootWindow =
3747 nsGlobalWindowOuter::Cast(GetPrivateRoot())) {
3748 rootWindow->FlushPendingNotifications(FlushType::Layout);
3749 }
3750
3751 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3752
3753 RefPtr<nsScreen> screen = GetScreen();
3754
3755 if (treeOwnerAsWin && screen) {
3756 CSSToLayoutDeviceScale scale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
3757 CSSIntRect winRect =
3758 CSSIntRect::Round(treeOwnerAsWin->GetPositionAndSize() / scale);
3759
3760 // Get the screen dimensions
3761 // XXX This should use nsIScreenManager once it's fully fleshed out.
3762 int32_t screenLeft = screen->AvailLeft();
3763 int32_t screenWidth = screen->AvailWidth();
3764 int32_t screenHeight = screen->AvailHeight();
3765#if defined(XP_MACOSX)
3766 /* The mac's coordinate system is different from the assumed Windows'
3767 system. It offsets by the height of the menubar so that a window
3768 placed at (0,0) will be entirely visible. Unfortunately that
3769 correction is made elsewhere (in Widget) and the meaning of
3770 the Avail... coordinates is overloaded. Here we allow a window
3771 to be placed at (0,0) because it does make sense to do so.
3772 */
3773 int32_t screenTop = screen->Top();
3774#else
3775 int32_t screenTop = screen->AvailTop();
3776#endif
3777
3778 if (aLeft) {
3779 if (screenLeft + screenWidth < *aLeft + winRect.width)
3780 *aLeft = screenLeft + screenWidth - winRect.width;
3781 if (screenLeft > *aLeft) *aLeft = screenLeft;
3782 }
3783 if (aTop) {
3784 if (screenTop + screenHeight < *aTop + winRect.height)
3785 *aTop = screenTop + screenHeight - winRect.height;
3786 if (screenTop > *aTop) *aTop = screenTop;
3787 }
3788 } else {
3789 if (aLeft) *aLeft = 0;
3790 if (aTop) *aTop = 0;
3791 }
3792 }
3793}
3794
3795int32_t nsGlobalWindowOuter::GetScrollBoundaryOuter(Side aSide) {
3796 FlushPendingNotifications(FlushType::Layout);
3797 if (ScrollContainerFrame* sf = GetScrollContainerFrame()) {
3798 return nsPresContext::AppUnitsToIntCSSPixels(
3799 sf->GetScrollRange().Edge(aSide));
3800 }
3801 return 0;
3802}
3803
3804CSSPoint nsGlobalWindowOuter::GetScrollXY(bool aDoFlush) {
3805 if (aDoFlush) {
3806 FlushPendingNotifications(FlushType::Layout);
3807 } else {
3808 EnsureSizeAndPositionUpToDate();
3809 }
3810
3811 ScrollContainerFrame* sf = GetScrollContainerFrame();
3812 if (!sf) {
3813 return CSSIntPoint(0, 0);
3814 }
3815
3816 nsPoint scrollPos = sf->GetScrollPosition();
3817 if (scrollPos != nsPoint(0, 0) && !aDoFlush) {
3818 // Oh, well. This is the expensive case -- the window is scrolled and we
3819 // didn't actually flush yet. Repeat, but with a flush, since the content
3820 // may get shorter and hence our scroll position may decrease.
3821 return GetScrollXY(true);
3822 }
3823
3824 return CSSPoint::FromAppUnits(scrollPos);
3825}
3826
3827double nsGlobalWindowOuter::GetScrollXOuter() { return GetScrollXY(false).x; }
3828
3829double nsGlobalWindowOuter::GetScrollYOuter() { return GetScrollXY(false).y; }
3830
3831uint32_t nsGlobalWindowOuter::Length() {
3832 BrowsingContext* bc = GetBrowsingContext();
3833 return bc ? bc->NonSyntheticChildren().Length() : 0;
3834}
3835
3836Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetTopOuter() {
3837 BrowsingContext* bc = GetBrowsingContext();
3838 return bc ? bc->GetTop(IgnoreErrors()) : nullptr;
3839}
3840
3841already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetChildWindow(
3842 const nsAString& aName) {
3843 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"
, 3843); return nullptr; } } while (false)
;
3844 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"
, 3844); return nullptr; } } while (false)
;
3845 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"
, 3845); return nullptr; } } while (false)
;
3846
3847 return do_AddRef(mBrowsingContext->FindChildWithName(
3848 aName, *mInnerWindow->GetWindowGlobalChild()));
3849}
3850
3851bool nsGlobalWindowOuter::DispatchCustomEvent(
3852 const nsAString& aEventName, ChromeOnlyDispatch aChromeOnlyDispatch) {
3853 bool defaultActionEnabled = true;
3854
3855 if (aChromeOnlyDispatch == ChromeOnlyDispatch::eYes) {
3856 nsContentUtils::DispatchEventOnlyToChrome(mDoc, this, aEventName,
3857 CanBubble::eYes, Cancelable::eYes,
3858 &defaultActionEnabled);
3859 } else {
3860 nsContentUtils::DispatchTrustedEvent(mDoc, this, aEventName,
3861 CanBubble::eYes, Cancelable::eYes,
3862 &defaultActionEnabled);
3863 }
3864
3865 return defaultActionEnabled;
3866}
3867
3868bool nsGlobalWindowOuter::DispatchResizeEvent(const CSSIntSize& aSize) {
3869 ErrorResult res;
3870 RefPtr<Event> domEvent =
3871 mDoc->CreateEvent(u"CustomEvent"_ns, CallerType::System, res);
3872 if (res.Failed()) {
3873 return false;
3874 }
3875
3876 // We don't init the AutoJSAPI with ourselves because we don't want it
3877 // reporting errors to our onerror handlers.
3878 AutoJSAPI jsapi;
3879 jsapi.Init();
3880 JSContext* cx = jsapi.cx();
3881 JSAutoRealm ar(cx, GetWrapperPreserveColor());
3882
3883 DOMWindowResizeEventDetail detail;
3884 detail.mWidth = aSize.width;
3885 detail.mHeight = aSize.height;
3886 JS::Rooted<JS::Value> detailValue(cx);
3887 if (!ToJSValue(cx, detail, &detailValue)) {
3888 return false;
3889 }
3890
3891 CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
3892 customEvent->InitCustomEvent(cx, u"DOMWindowResize"_ns,
3893 /* aCanBubble = */ true,
3894 /* aCancelable = */ true, detailValue);
3895
3896 domEvent->SetTrusted(true);
3897 domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
3898
3899 nsCOMPtr<EventTarget> target = this;
3900 domEvent->SetTarget(target);
3901
3902 return target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
3903}
3904
3905bool nsGlobalWindowOuter::WindowExists(const nsAString& aName,
3906 bool aForceNoOpener,
3907 bool aLookForCallerOnJSStack) {
3908 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"
, 3908); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocShell" ") ("
"Must have docshell" ")"); do { *((volatile int*)__null) = 3908
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3909
3910 if (aForceNoOpener) {
3911 return aName.LowerCaseEqualsLiteral("_self") ||
3912 aName.LowerCaseEqualsLiteral("_top") ||
3913 aName.LowerCaseEqualsLiteral("_parent");
3914 }
3915
3916 if (WindowGlobalChild* wgc = mInnerWindow->GetWindowGlobalChild()) {
3917 return wgc->FindBrowsingContextWithName(aName, aLookForCallerOnJSStack);
3918 }
3919 return false;
3920}
3921
3922already_AddRefed<nsIWidget> nsGlobalWindowOuter::GetMainWidget() {
3923 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3924
3925 nsCOMPtr<nsIWidget> widget;
3926
3927 if (treeOwnerAsWin) {
3928 treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
3929 }
3930
3931 return widget.forget();
3932}
3933
3934nsIWidget* nsGlobalWindowOuter::GetNearestWidget() const {
3935 nsIDocShell* docShell = GetDocShell();
3936 if (!docShell) {
3937 return nullptr;
3938 }
3939 PresShell* presShell = docShell->GetPresShell();
3940 if (!presShell) {
3941 return nullptr;
3942 }
3943 nsIFrame* rootFrame = presShell->GetRootFrame();
3944 if (!rootFrame) {
3945 return nullptr;
3946 }
3947 return rootFrame->GetView()->GetNearestWidget(nullptr);
3948}
3949
3950void nsGlobalWindowOuter::SetFullscreenOuter(bool aFullscreen,
3951 mozilla::ErrorResult& aError) {
3952 aError =
3953 SetFullscreenInternal(FullscreenReason::ForFullscreenMode, aFullscreen);
3954}
3955
3956nsresult nsGlobalWindowOuter::SetFullScreen(bool aFullscreen) {
3957 return SetFullscreenInternal(FullscreenReason::ForFullscreenMode,
3958 aFullscreen);
3959}
3960
3961static void FinishDOMFullscreenChange(Document* aDoc, bool aInDOMFullscreen) {
3962 if (aInDOMFullscreen) {
3963 // Ask the document to handle any pending DOM fullscreen change.
3964 if (!Document::HandlePendingFullscreenRequests(aDoc)) {
3965 // If we don't end up having anything in fullscreen,
3966 // async request exiting fullscreen.
3967 Document::AsyncExitFullscreen(aDoc);
3968 }
3969 } else {
3970 // If the window is leaving fullscreen state, also ask the document
3971 // to exit from DOM Fullscreen.
3972 Document::ExitFullscreenInDocTree(aDoc);
3973 }
3974}
3975
3976struct FullscreenTransitionDuration {
3977 // The unit of the durations is millisecond
3978 uint16_t mFadeIn = 0;
3979 uint16_t mFadeOut = 0;
3980 bool IsSuppressed() const { return mFadeIn == 0 && mFadeOut == 0; }
3981};
3982
3983static void GetFullscreenTransitionDuration(
3984 bool aEnterFullscreen, FullscreenTransitionDuration* aDuration) {
3985 const char* pref = aEnterFullscreen
3986 ? "full-screen-api.transition-duration.enter"
3987 : "full-screen-api.transition-duration.leave";
3988 nsAutoCString prefValue;
3989 Preferences::GetCString(pref, prefValue);
3990 if (!prefValue.IsEmpty()) {
3991 sscanf(prefValue.get(), "%hu%hu", &aDuration->mFadeIn,
3992 &aDuration->mFadeOut);
3993 }
3994}
3995
3996class FullscreenTransitionTask : public Runnable {
3997 public:
3998 FullscreenTransitionTask(const FullscreenTransitionDuration& aDuration,
3999 nsGlobalWindowOuter* aWindow, bool aFullscreen,
4000 nsIWidget* aWidget, nsISupports* aTransitionData)
4001 : mozilla::Runnable("FullscreenTransitionTask"),
4002 mWindow(aWindow),
4003 mWidget(aWidget),
4004 mTransitionData(aTransitionData),
4005 mDuration(aDuration),
4006 mStage(eBeforeToggle),
4007 mFullscreen(aFullscreen) {}
4008
4009 NS_IMETHODvirtual nsresult Run() override;
4010
4011 private:
4012 ~FullscreenTransitionTask() override = default;
4013
4014 /**
4015 * The flow of fullscreen transition:
4016 *
4017 * parent process | child process
4018 * ----------------------------------------------------------------
4019 *
4020 * | request/exit fullscreen
4021 * <-----|
4022 * BeforeToggle stage |
4023 * |
4024 * ToggleFullscreen stage *1 |----->
4025 * | HandleFullscreenRequests
4026 * |
4027 * <-----| MozAfterPaint event
4028 * AfterToggle stage *2 |
4029 * |
4030 * End stage |
4031 *
4032 * Note we also start a timer at *1 so that if we don't get MozAfterPaint
4033 * from the child process in time, we continue going to *2.
4034 */
4035 enum Stage {
4036 // BeforeToggle stage happens before we enter or leave fullscreen
4037 // state. In this stage, the task triggers the pre-toggle fullscreen
4038 // transition on the widget.
4039 eBeforeToggle,
4040 // ToggleFullscreen stage actually executes the fullscreen toggle,
4041 // and wait for the next paint on the content to continue.
4042 eToggleFullscreen,
4043 // AfterToggle stage happens after we toggle the fullscreen state.
4044 // In this stage, the task triggers the post-toggle fullscreen
4045 // transition on the widget.
4046 eAfterToggle,
4047 // End stage is triggered after the final transition finishes.
4048 eEnd
4049 };
4050
4051 class Observer final : public nsIObserver, public nsINamed {
4052 public:
4053 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:
4054 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
4055 NS_DECL_NSINAMEDvirtual nsresult GetName(nsACString& aName) override;
4056
4057 explicit Observer(FullscreenTransitionTask* aTask) : mTask(aTask) {}
4058
4059 private:
4060 ~Observer() = default;
4061
4062 RefPtr<FullscreenTransitionTask> mTask;
4063 };
4064
4065 static const char* const kPaintedTopic;
4066
4067 RefPtr<nsGlobalWindowOuter> mWindow;
4068 nsCOMPtr<nsIWidget> mWidget;
4069 nsCOMPtr<nsITimer> mTimer;
4070 nsCOMPtr<nsISupports> mTransitionData;
4071
4072 TimeStamp mFullscreenChangeStartTime;
4073 FullscreenTransitionDuration mDuration;
4074 Stage mStage;
4075 bool mFullscreen;
4076};
4077
4078const char* const FullscreenTransitionTask::kPaintedTopic =
4079 "fullscreen-painted";
4080
4081NS_IMETHODIMPnsresult
4082FullscreenTransitionTask::Run() {
4083 Stage stage = mStage;
4084 mStage = Stage(mStage + 1);
4085 if (MOZ_UNLIKELY(mWidget->Destroyed())(__builtin_expect(!!(mWidget->Destroyed()), 0))) {
4086 // If the widget has been destroyed before we get here, don't try to
4087 // do anything more. Just let it go and release ourselves.
4088 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"
, 4088)
;
4089 mWindow->mIsInFullScreenTransition = false;
4090 return NS_OK;
4091 }
4092 if (stage == eBeforeToggle) {
4093 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)
;
4094
4095 mWindow->mIsInFullScreenTransition = true;
4096
4097 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4098 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"
, 4098); return NS_ERROR_FAILURE; } } while (false)
;
4099 obs->NotifyObservers(nullptr, "fullscreen-transition-start", nullptr);
4100
4101 mWidget->PerformFullscreenTransition(nsIWidget::eBeforeFullscreenToggle,
4102 mDuration.mFadeIn, mTransitionData,
4103 this);
4104 } else if (stage == eToggleFullscreen) {
4105 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)
;
4106 mFullscreenChangeStartTime = TimeStamp::Now();
4107 // Toggle the fullscreen state on the widget
4108 if (!mWindow->SetWidgetFullscreen(FullscreenReason::ForFullscreenAPI,
4109 mFullscreen, mWidget)) {
4110 // Fail to setup the widget, call FinishFullscreenChange to
4111 // complete fullscreen change directly.
4112 mWindow->FinishFullscreenChange(mFullscreen);
4113 }
4114 // Set observer for the next content paint.
4115 nsCOMPtr<nsIObserver> observer = new Observer(this);
4116 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4117 obs->AddObserver(observer, kPaintedTopic, false);
4118 // There are several edge cases where we may never get the paint
4119 // notification, including:
4120 // 1. the window/tab is closed before the next paint;
4121 // 2. the user has switched to another tab before we get here.
4122 // Completely fixing those cases seems to be tricky, and since they
4123 // should rarely happen, it probably isn't worth to fix. Hence we
4124 // simply add a timeout here to ensure we never hang forever.
4125 // In addition, if the page is complicated or the machine is less
4126 // powerful, layout could take a long time, in which case, staying
4127 // in black screen for that long could hurt user experience even
4128 // more than exposing an intermediate state.
4129 uint32_t timeout =
4130 Preferences::GetUint("full-screen-api.transition.timeout", 1000);
4131 NS_NewTimerWithObserver(getter_AddRefs(mTimer), observer, timeout,
4132 nsITimer::TYPE_ONE_SHOT);
4133 } else if (stage == eAfterToggle) {
4134 Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS,
4135 mFullscreenChangeStartTime);
4136 mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,
4137 mDuration.mFadeOut, mTransitionData,
4138 this);
4139 } else if (stage == eEnd) {
4140 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)
;
4141
4142 mWindow->mIsInFullScreenTransition = false;
4143
4144 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4145 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"
, 4145); return NS_ERROR_FAILURE; } } while (false)
;
4146 obs->NotifyObservers(nullptr, "fullscreen-transition-end", nullptr);
4147
4148 mWidget->CleanupFullscreenTransition();
4149 }
4150 return NS_OK;
4151}
4152
4153NS_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"
, 4153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
4153; __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"
, 4153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionTask::Observer\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 4153; __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"
, 4153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 4153
; __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"
, 4153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionTask::Observer\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 4153; __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"
, 4153); 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((sizeof
(table) / sizeof(table[0])) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
4154
4155NS_IMETHODIMPnsresult
4156FullscreenTransitionTask::Observer::Observe(nsISupports* aSubject,
4157 const char* aTopic,
4158 const char16_t* aData) {
4159 bool shouldContinue = false;
4160 if (strcmp(aTopic, FullscreenTransitionTask::kPaintedTopic) == 0) {
4161 nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aSubject));
4162 nsCOMPtr<nsIWidget> widget =
4163 win ? nsGlobalWindowInner::Cast(win)->GetMainWidget() : nullptr;
4164 if (widget == mTask->mWidget) {
4165 // The paint notification arrives first. Cancel the timer.
4166 mTask->mTimer->Cancel();
4167 shouldContinue = true;
4168 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)
;
4169 }
4170 } else {
4171#ifdef DEBUG1
4172 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"
, 4173); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(aTopic, \"timer-callback\") == 0"
") (" "Should only get fullscreen-painted or timer-callback"
")"); do { *((volatile int*)__null) = 4173; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4173 "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"
, 4173); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(aTopic, \"timer-callback\") == 0"
") (" "Should only get fullscreen-painted or timer-callback"
")"); do { *((volatile int*)__null) = 4173; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4174 nsCOMPtr<nsITimer> timer(do_QueryInterface(aSubject));
4175 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"
, 4176); AnnotateMozCrashReason("MOZ_ASSERT" "(" "timer && timer == mTask->mTimer"
") (" "Should only trigger this with the timer the task created"
")"); do { *((volatile int*)__null) = 4176; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4176 "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"
, 4176); AnnotateMozCrashReason("MOZ_ASSERT" "(" "timer && timer == mTask->mTimer"
") (" "Should only trigger this with the timer the task created"
")"); do { *((volatile int*)__null) = 4176; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4177#endif
4178 shouldContinue = true;
4179 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)
;
4180 }
4181 if (shouldContinue) {
4182 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4183 obs->RemoveObserver(this, kPaintedTopic);
4184 mTask->mTimer = nullptr;
4185 mTask->Run();
4186 }
4187 return NS_OK;
4188}
4189
4190NS_IMETHODIMPnsresult
4191FullscreenTransitionTask::Observer::GetName(nsACString& aName) {
4192 aName.AssignLiteral("FullscreenTransitionTask");
4193 return NS_OK;
4194}
4195
4196static bool MakeWidgetFullscreen(nsGlobalWindowOuter* aWindow,
4197 FullscreenReason aReason, bool aFullscreen) {
4198 nsCOMPtr<nsIWidget> widget = aWindow->GetMainWidget();
4199 if (!widget) {
4200 return false;
4201 }
4202
4203 FullscreenTransitionDuration duration;
4204 bool performTransition = false;
4205 nsCOMPtr<nsISupports> transitionData;
4206 if (aReason == FullscreenReason::ForFullscreenAPI) {
4207 GetFullscreenTransitionDuration(aFullscreen, &duration);
4208 if (!duration.IsSuppressed()) {
4209 performTransition = widget->PrepareForFullscreenTransition(
4210 getter_AddRefs(transitionData));
4211 }
4212 }
4213
4214 if (!performTransition) {
4215 return aWindow->SetWidgetFullscreen(aReason, aFullscreen, widget);
4216 }
4217
4218 nsCOMPtr<nsIRunnable> task = new FullscreenTransitionTask(
4219 duration, aWindow, aFullscreen, widget, transitionData);
4220 task->Run();
4221 return true;
4222}
4223
4224nsresult nsGlobalWindowOuter::ProcessWidgetFullscreenRequest(
4225 FullscreenReason aReason, bool aFullscreen) {
4226 mInProcessFullscreenRequest.emplace(aReason, aFullscreen);
4227
4228 // Prevent chrome documents which are still loading from resizing
4229 // the window after we set fullscreen mode.
4230 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4231 nsCOMPtr<nsIAppWindow> appWin(do_GetInterface(treeOwnerAsWin));
4232 if (aFullscreen && appWin) {
4233 appWin->SetIntrinsicallySized(false);
4234 }
4235
4236 // Sometimes we don't want the top-level widget to actually go fullscreen:
4237 // - in the B2G desktop client, we don't want the emulated screen dimensions
4238 // to appear to increase when entering fullscreen mode; we just want the
4239 // content to fill the entire client area of the emulator window.
4240 // - in FxR Desktop, we don't want fullscreen to take over the monitor, but
4241 // instead we want fullscreen to fill the FxR window in the the headset.
4242 if (!StaticPrefs::full_screen_api_ignore_widgets() &&
4243 !mForceFullScreenInWidget) {
4244 if (MakeWidgetFullscreen(this, aReason, aFullscreen)) {
4245 // The rest of code for switching fullscreen is in nsGlobalWindowOuter::
4246 // FinishFullscreenChange() which will be called after sizemodechange
4247 // event is dispatched.
4248 return NS_OK;
4249 }
4250 }
4251
4252#if defined(NIGHTLY_BUILD1) && defined(XP_WIN)
4253 if (FxRWindowManager::GetInstance()->IsFxRWindow(mWindowID)) {
4254 mozilla::gfx::VRShMem shmem(nullptr, true /*aRequiresMutex*/);
4255 shmem.SendFullscreenState(mWindowID, aFullscreen);
4256 }
4257#endif // NIGHTLY_BUILD && XP_WIN
4258 FinishFullscreenChange(aFullscreen);
4259 return NS_OK;
4260}
4261
4262nsresult nsGlobalWindowOuter::SetFullscreenInternal(FullscreenReason aReason,
4263 bool aFullscreen) {
4264 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"
, 4266); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4266; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4265 "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"
, 4266); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4266; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4266 "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"
, 4266); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4266; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4267
4268 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"
, 4268); return NS_ERROR_FAILURE; } } while (false)
;
4269
4270 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"
, 4273); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4273; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4271 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"
, 4273); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4273; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4272 "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"
, 4273); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4273; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4273 "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"
, 4273); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4273; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4274
4275 // Only chrome can change our fullscreen mode. Otherwise, the state
4276 // can only be changed for DOM fullscreen.
4277 if (aReason == FullscreenReason::ForFullscreenMode &&
4278 !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
4279 return NS_OK;
4280 }
4281
4282 // SetFullscreen needs to be called on the root window, so get that
4283 // via the DocShell tree, and if we are not already the root,
4284 // call SetFullscreen on that window instead.
4285 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4286 mDocShell->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
4287 nsCOMPtr<nsPIDOMWindowOuter> window =
4288 rootItem ? rootItem->GetWindow() : nullptr;
4289 if (!window) return NS_ERROR_FAILURE;
4290 if (rootItem != mDocShell)
4291 return window->SetFullscreenInternal(aReason, aFullscreen);
4292
4293 // make sure we don't try to set full screen on a non-chrome window,
4294 // which might happen in embedding world
4295 if (mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome)
4296 return NS_ERROR_FAILURE;
4297
4298 // FullscreenReason::ForForceExitFullscreen can only be used with exiting
4299 // fullscreen
4300 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"
, 4302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4302; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4301 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"
, 4302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4302; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4302 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"
, 4302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4302; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4303
4304 // If we are already in full screen mode, just return, we don't care about the
4305 // reason here, because,
4306 // - If we are in fullscreen mode due to browser fullscreen mode, requesting
4307 // DOM fullscreen does not change anything.
4308 // - If we are in fullscreen mode due to DOM fullscreen, requesting browser
4309 // fullscreen should not change anything, either. Note that we should not
4310 // update reason to ForFullscreenMode, otherwise the subsequent DOM
4311 // fullscreen exit will be ignored and user will be confused. And ideally
4312 // this should never happen as `window.fullscreen` returns `true` for DOM
4313 // fullscreen as well.
4314 if (mFullscreen.isSome() == aFullscreen) {
4315 // How come we get browser fullscreen request while we are already in DOM
4316 // fullscreen?
4317 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"
, 4318); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForFullscreenAPI"
")"); do { *((volatile int*)__null) = 4318; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4318 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"
, 4318); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForFullscreenAPI"
")"); do { *((volatile int*)__null) = 4318; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4319 return NS_OK;
4320 }
4321
4322 // Note that although entering DOM fullscreen could also cause
4323 // consequential calls to this method, those calls will be skipped
4324 // at the condition above.
4325 if (aReason == FullscreenReason::ForFullscreenMode) {
4326 if (!aFullscreen && mFullscreen &&
4327 mFullscreen.value() == FullscreenReason::ForFullscreenAPI) {
4328 // If we are exiting fullscreen mode, but we actually didn't
4329 // entered browser fullscreen mode, the fullscreen state was only for
4330 // the Fullscreen API. Change the reason here so that we can
4331 // perform transition for it.
4332 aReason = FullscreenReason::ForFullscreenAPI;
4333 }
4334 } else {
4335 // If we are exiting from DOM fullscreen while we initially make
4336 // the window fullscreen because of browser fullscreen mode, don't restore
4337 // the window. But we still need to exit the DOM fullscreen state.
4338 if (!aFullscreen && mFullscreen &&
4339 mFullscreen.value() == FullscreenReason::ForFullscreenMode) {
4340 // If there is a in-process fullscreen request, FinishDOMFullscreenChange
4341 // will be called when the request is finished.
4342 if (!mInProcessFullscreenRequest.isSome()) {
4343 FinishDOMFullscreenChange(mDoc, false);
4344 }
4345 return NS_OK;
4346 }
4347 }
4348
4349 // Set this before so if widget sends an event indicating its
4350 // gone full screen, the state trap above works.
4351 if (aFullscreen) {
4352 mFullscreen.emplace(aReason);
4353 } else {
4354 mFullscreen.reset();
4355 }
4356
4357 // If we are in process of fullscreen request, only keep the latest fullscreen
4358 // state, we will sync up later while the processing request is finished.
4359 if (mInProcessFullscreenRequest.isSome()) {
4360 mFullscreenHasChangedDuringProcessing = true;
4361 return NS_OK;
4362 }
4363
4364 return ProcessWidgetFullscreenRequest(aReason, aFullscreen);
4365}
4366
4367// Support a per-window, dynamic equivalent of enabling
4368// full-screen-api.ignore-widgets
4369void nsGlobalWindowOuter::ForceFullScreenInWidget() {
4370 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"
, 4370); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4370; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4371
4372 mForceFullScreenInWidget = true;
4373}
4374
4375bool nsGlobalWindowOuter::SetWidgetFullscreen(FullscreenReason aReason,
4376 bool aIsFullscreen,
4377 nsIWidget* aWidget) {
4378 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"
, 4379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this == GetInProcessTopInternal()"
") (" "Only topmost window should call this" ")"); do { *((volatile
int*)__null) = 4379; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
4379 "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"
, 4379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this == GetInProcessTopInternal()"
") (" "Only topmost window should call this" ")"); do { *((volatile
int*)__null) = 4379; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4380 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"
, 4380); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetFrameElementInternal()"
") (" "Content window should not call this" ")"); do { *((volatile
int*)__null) = 4380; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4381 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"
, 4381); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_GetProcessType() == GeckoProcessType_Default"
")"); do { *((volatile int*)__null) = 4381; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4382
4383 if (!NS_WARN_IF(!IsChromeWindow())NS_warn_if_impl(!IsChromeWindow(), "!IsChromeWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4383)
) {
4384 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"
, 4384)
) {
4385 if (PresShell* presShell = mDocShell->GetPresShell()) {
4386 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
4387 mChromeFields.mFullscreenPresShell = do_GetWeakReference(presShell);
4388 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"
, 4388); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChromeFields.mFullscreenPresShell"
")"); do { *((volatile int*)__null) = 4388; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4389 rd->SetIsResizeSuppressed();
4390 rd->Freeze();
4391 }
4392 }
4393 }
4394 }
4395 nsresult rv = aReason == FullscreenReason::ForFullscreenMode
4396 ?
4397 // If we enter fullscreen for fullscreen mode, we want
4398 // the native system behavior.
4399 aWidget->MakeFullScreenWithNativeTransition(aIsFullscreen)
4400 : aWidget->MakeFullScreen(aIsFullscreen);
4401 return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
4402}
4403
4404/* virtual */
4405void nsGlobalWindowOuter::FullscreenWillChange(bool aIsFullscreen) {
4406 if (!mInProcessFullscreenRequest.isSome()) {
4407 // If there is no in-process fullscreen request, the fullscreen state change
4408 // is triggered from the OS directly, e.g. user use built-in window button
4409 // to enter/exit fullscreen on macOS.
4410 mInProcessFullscreenRequest.emplace(FullscreenReason::ForFullscreenMode,
4411 aIsFullscreen);
4412 if (mFullscreen.isSome() != aIsFullscreen) {
4413 if (aIsFullscreen) {
4414 mFullscreen.emplace(FullscreenReason::ForFullscreenMode);
4415 } else {
4416 mFullscreen.reset();
4417 }
4418 } else {
4419 // It is possible that FullscreenWillChange is notified with current
4420 // fullscreen state, e.g. browser goes into fullscreen when widget
4421 // fullscreen is prevented, and then user triggers fullscreen from the OS
4422 // directly again.
4423 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"
, 4425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4424 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"
, 4425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4425 "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"
, 4425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4426 }
4427 }
4428 if (aIsFullscreen) {
4429 DispatchCustomEvent(u"willenterfullscreen"_ns, ChromeOnlyDispatch::eYes);
4430 } else {
4431 DispatchCustomEvent(u"willexitfullscreen"_ns, ChromeOnlyDispatch::eYes);
4432 }
4433}
4434
4435/* virtual */
4436void nsGlobalWindowOuter::FinishFullscreenChange(bool aIsFullscreen) {
4437 mozilla::Maybe<FullscreenRequest> currentInProcessRequest =
4438 std::move(mInProcessFullscreenRequest);
4439 if (!mFullscreenHasChangedDuringProcessing &&
4440 aIsFullscreen != mFullscreen.isSome()) {
4441 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"
, 4441)
;
4442 // We failed to make the widget enter fullscreen.
4443 // Stop further changes and restore the state.
4444 if (!aIsFullscreen) {
4445 mFullscreen.reset();
4446 } else {
4447#ifndef XP_MACOSX
4448 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"
, 4448); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Failed to exit fullscreen?" ")")
; do { *((volatile int*)__null) = 4448; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4449#endif
4450 // Restore fullscreen state with FullscreenReason::ForFullscreenAPI reason
4451 // in order to make subsequent DOM fullscreen exit request can exit
4452 // browser fullscreen mode.
4453 mFullscreen.emplace(FullscreenReason::ForFullscreenAPI);
4454 }
4455 return;
4456 }
4457
4458 // Note that we must call this to toggle the DOM fullscreen state
4459 // of the document before dispatching the "fullscreen" event, so
4460 // that the chrome can distinguish between browser fullscreen mode
4461 // and DOM fullscreen.
4462 FinishDOMFullscreenChange(mDoc, aIsFullscreen);
4463
4464 // dispatch a "fullscreen" DOM event so that XUL apps can
4465 // respond visually if we are kicked into full screen mode
4466 DispatchCustomEvent(u"fullscreen"_ns, ChromeOnlyDispatch::eYes);
4467
4468 if (!NS_WARN_IF(!IsChromeWindow())NS_warn_if_impl(!IsChromeWindow(), "!IsChromeWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4468)
) {
4469 if (RefPtr<PresShell> presShell =
4470 do_QueryReferent(mChromeFields.mFullscreenPresShell)) {
4471 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
4472 rd->Thaw();
4473 }
4474 mChromeFields.mFullscreenPresShell = nullptr;
4475 }
4476 }
4477
4478 // If fullscreen state has changed during processing fullscreen request, we
4479 // need to ensure widget matches our latest fullscreen state here.
4480 if (mFullscreenHasChangedDuringProcessing) {
4481 mFullscreenHasChangedDuringProcessing = false;
4482 // Widget doesn't care about the reason that makes it entering/exiting
4483 // fullscreen, so here we just need to ensure the fullscreen state is
4484 // matched.
4485 if (aIsFullscreen != mFullscreen.isSome()) {
4486 // If we end up need to exit fullscreen, use the same reason that brings
4487 // us into fullscreen mode, so that we will perform the same fullscreen
4488 // transistion effect for exiting.
4489 ProcessWidgetFullscreenRequest(
4490 mFullscreen.isSome() ? mFullscreen.value()
4491 : currentInProcessRequest.value().mReason,
4492 mFullscreen.isSome());
4493 }
4494 }
4495}
4496
4497/* virtual */
4498void nsGlobalWindowOuter::MacFullscreenMenubarOverlapChanged(
4499 mozilla::DesktopCoord aOverlapAmount) {
4500 ErrorResult res;
4501 RefPtr<Event> domEvent =
4502 mDoc->CreateEvent(u"CustomEvent"_ns, CallerType::System, res);
4503 if (res.Failed()) {
4504 return;
4505 }
4506
4507 AutoJSAPI jsapi;
4508 jsapi.Init();
4509 JSContext* cx = jsapi.cx();
4510 JSAutoRealm ar(cx, GetWrapperPreserveColor());
4511
4512 JS::Rooted<JS::Value> detailValue(cx);
4513 if (!ToJSValue(cx, aOverlapAmount, &detailValue)) {
4514 return;
4515 }
4516
4517 CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
4518 customEvent->InitCustomEvent(cx, u"MacFullscreenMenubarRevealUpdate"_ns,
4519 /* aCanBubble = */ true,
4520 /* aCancelable = */ true, detailValue);
4521 domEvent->SetTrusted(true);
4522 domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
4523
4524 nsCOMPtr<EventTarget> target = this;
4525 domEvent->SetTarget(target);
4526
4527 target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
4528}
4529
4530bool nsGlobalWindowOuter::Fullscreen() const {
4531 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"
, 4531); return mFullscreen.isSome(); } } while (false)
;
4532
4533 // Get the fullscreen value of the root window, to always have the value
4534 // accurate, even when called from content.
4535 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4536 mDocShell->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
4537 if (rootItem == mDocShell) {
4538 if (!XRE_IsContentProcess()) {
4539 // We are the root window. Return our internal value.
4540 return mFullscreen.isSome();
4541 }
4542 if (nsCOMPtr<nsIWidget> widget = GetNearestWidget()) {
4543 // We are in content process, figure out the value from
4544 // the sizemode of the puppet widget.
4545 return widget->SizeMode() == nsSizeMode_Fullscreen;
4546 }
4547 return false;
4548 }
4549
4550 nsCOMPtr<nsPIDOMWindowOuter> window = rootItem->GetWindow();
4551 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"
, 4551); return mFullscreen.isSome(); } } while (false)
;
4552
4553 return nsGlobalWindowOuter::Cast(window)->Fullscreen();
4554}
4555
4556bool nsGlobalWindowOuter::GetFullscreenOuter() { return Fullscreen(); }
4557
4558bool nsGlobalWindowOuter::GetFullScreen() {
4559 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"
, 4559); return false; } return GetCurrentInnerWindowInternal
(this)->GetFullScreen (); } while (0)
;
4560}
4561
4562void nsGlobalWindowOuter::EnsureReflowFlushAndPaint() {
4563 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"
, 4565); MOZ_PretendNoReturn(); } } while (0)
4564 "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"
, 4565); MOZ_PretendNoReturn(); } } while (0)
4565 "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"
, 4565); MOZ_PretendNoReturn(); } } while (0)
;
4566
4567 if (!mDocShell) return;
4568
4569 RefPtr<PresShell> presShell = mDocShell->GetPresShell();
4570 if (!presShell) {
4571 return;
4572 }
4573
4574 // Flush pending reflows.
4575 if (mDoc) {
4576 mDoc->FlushPendingNotifications(FlushType::Layout);
4577 }
4578
4579 // Unsuppress painting.
4580 presShell->UnsuppressPainting();
4581}
4582
4583// static
4584void nsGlobalWindowOuter::MakeMessageWithPrincipal(
4585 nsAString& aOutMessage, nsIPrincipal* aSubjectPrincipal, bool aUseHostPort,
4586 const char* aNullMessage, const char* aContentMessage,
4587 const char* aFallbackMessage) {
4588 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"
, 4588); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubjectPrincipal"
")"); do { *((volatile int*)__null) = 4588; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4589
4590 aOutMessage.Truncate();
4591
4592 // Try to get a host from the running principal -- this will do the
4593 // right thing for javascript: and data: documents.
4594
4595 nsAutoCString contentDesc;
4596
4597 if (aSubjectPrincipal->GetIsNullPrincipal()) {
4598 nsContentUtils::GetLocalizedString(
4599 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, aNullMessage, aOutMessage);
4600 } else {
4601 auto* addonPolicy = BasePrincipal::Cast(aSubjectPrincipal)->AddonPolicy();
4602 if (addonPolicy) {
4603 nsContentUtils::FormatLocalizedString(
4604 aOutMessage, nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4605 aContentMessage, addonPolicy->Name());
4606 } else {
4607 nsresult rv = NS_ERROR_FAILURE;
4608 if (aUseHostPort) {
4609 nsCOMPtr<nsIURI> uri = aSubjectPrincipal->GetURI();
4610 if (uri) {
4611 rv = uri->GetDisplayHostPort(contentDesc);
4612 }
4613 }
4614 if (!aUseHostPort || NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4615 rv = aSubjectPrincipal->GetExposablePrePath(contentDesc);
4616 }
4617 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !contentDesc.IsEmpty()) {
4618 NS_ConvertUTF8toUTF16 ucsPrePath(contentDesc);
4619 nsContentUtils::FormatLocalizedString(
4620 aOutMessage, nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4621 aContentMessage, ucsPrePath);
4622 }
4623 }
4624 }
4625
4626 if (aOutMessage.IsEmpty()) {
4627 // We didn't find a host so use the generic heading
4628 nsContentUtils::GetLocalizedString(
4629 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, aFallbackMessage,
4630 aOutMessage);
4631 }
4632
4633 // Just in case
4634 if (aOutMessage.IsEmpty()) {
4635 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"
, 4636)
4636 "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"
, 4636)
;
4637 aOutMessage.AssignLiteral("[Script]");
4638 }
4639}
4640
4641bool nsGlobalWindowOuter::CanMoveResizeWindows(CallerType aCallerType) {
4642 // When called from chrome, we can avoid the following checks.
4643 if (aCallerType != CallerType::System) {
4644 // Don't allow scripts to move or resize windows that were not opened by a
4645 // script.
4646 if (!mBrowsingContext->GetTopLevelCreatedByWebContent()) {
4647 return false;
4648 }
4649
4650 if (!CanSetProperty("dom.disable_window_move_resize")) {
4651 return false;
4652 }
4653
4654 // Ignore the request if we have more than one tab in the window.
4655 if (mBrowsingContext->Top()->HasSiblings()) {
4656 return false;
4657 }
4658 }
4659
4660 if (mDocShell) {
4661 bool allow;
4662 nsresult rv = mDocShell->GetAllowWindowControl(&allow);
4663 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !allow) return false;
4664 }
4665
4666 if (nsGlobalWindowInner::sMouseDown &&
4667 !nsGlobalWindowInner::sDragServiceDisabled) {
4668 nsCOMPtr<nsIDragService> ds =
4669 do_GetService("@mozilla.org/widget/dragservice;1");
4670 if (ds) {
4671 nsGlobalWindowInner::sDragServiceDisabled = true;
4672 ds->Suppress();
4673 }
4674 }
4675 return true;
4676}
4677
4678bool nsGlobalWindowOuter::AlertOrConfirm(bool aAlert, const nsAString& aMessage,
4679 nsIPrincipal& aSubjectPrincipal,
4680 ErrorResult& aError) {
4681 // XXX This method is very similar to nsGlobalWindowOuter::Prompt, make
4682 // sure any modifications here don't need to happen over there!
4683 if (!AreDialogsEnabled()) {
4684 // Just silently return. In the case of alert(), the return value is
4685 // ignored. In the case of confirm(), returning false is the same thing as
4686 // would happen if the user cancels.
4687 return false;
4688 }
4689
4690 // Reset popup state while opening a modal dialog, and firing events
4691 // about the dialog, to prevent the current state from being active
4692 // the whole time a modal dialog is open.
4693 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
4694
4695 // Before bringing up the window, unsuppress painting and flush
4696 // pending reflows.
4697 EnsureReflowFlushAndPaint();
4698
4699 nsAutoString title;
4700 MakeMessageWithPrincipal(title, &aSubjectPrincipal, false,
4701 "ScriptDlgNullPrincipalHeading", "ScriptDlgHeading",
4702 "ScriptDlgGenericHeading");
4703
4704 // Remove non-terminating null characters from the
4705 // string. See bug #310037.
4706 nsAutoString final;
4707 nsContentUtils::StripNullChars(aMessage, final);
4708 nsContentUtils::PlatformToDOMLineBreaks(final);
4709
4710 nsresult rv;
4711 nsCOMPtr<nsIPromptFactory> promptFac =
4712 do_GetService("@mozilla.org/prompter;1", &rv);
4713 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4714 aError.Throw(rv);
4715 return false;
4716 }
4717
4718 nsCOMPtr<nsIPrompt> prompt;
4719 aError =
4720 promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt)(nsIPrompt::COMTypeInfo<nsIPrompt, void>::kIID), getter_AddRefs(prompt));
4721 if (aError.Failed()) {
4722 return false;
4723 }
4724
4725 // Always allow content modal prompts for alert and confirm.
4726 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4727 promptBag->SetPropertyAsUint32(u"modalType"_ns,
4728 nsIPrompt::MODAL_TYPE_CONTENT);
4729 }
4730
4731 bool result = false;
4732 nsAutoSyncOperation sync(mDoc, SyncOperationBehavior::eSuspendInput);
4733 if (ShouldPromptToBlockDialogs()) {
4734 bool disallowDialog = false;
4735 nsAutoString label;
4736 MakeMessageWithPrincipal(
4737 label, &aSubjectPrincipal, true, "ScriptDialogLabelNullPrincipal",
4738 "ScriptDialogLabelContentPrincipal", "ScriptDialogLabelNullPrincipal");
4739
4740 aError = aAlert
4741 ? prompt->AlertCheck(title.get(), final.get(), label.get(),
4742 &disallowDialog)
4743 : prompt->ConfirmCheck(title.get(), final.get(), label.get(),
4744 &disallowDialog, &result);
4745
4746 if (disallowDialog) {
4747 DisableDialogs();
4748 }
4749 } else {
4750 aError = aAlert ? prompt->Alert(title.get(), final.get())
4751 : prompt->Confirm(title.get(), final.get(), &result);
4752 }
4753
4754 return result;
4755}
4756
4757void nsGlobalWindowOuter::AlertOuter(const nsAString& aMessage,
4758 nsIPrincipal& aSubjectPrincipal,
4759 ErrorResult& aError) {
4760 AlertOrConfirm(/* aAlert = */ true, aMessage, aSubjectPrincipal, aError);
4761}
4762
4763bool nsGlobalWindowOuter::ConfirmOuter(const nsAString& aMessage,
4764 nsIPrincipal& aSubjectPrincipal,
4765 ErrorResult& aError) {
4766 return AlertOrConfirm(/* aAlert = */ false, aMessage, aSubjectPrincipal,
4767 aError);
4768}
4769
4770void nsGlobalWindowOuter::PromptOuter(const nsAString& aMessage,
4771 const nsAString& aInitial,
4772 nsAString& aReturn,
4773 nsIPrincipal& aSubjectPrincipal,
4774 ErrorResult& aError) {
4775 // XXX This method is very similar to nsGlobalWindowOuter::AlertOrConfirm,
4776 // make sure any modifications here don't need to happen over there!
4777 SetDOMStringToNull(aReturn);
4778
4779 if (!AreDialogsEnabled()) {
4780 // Return null, as if the user just canceled the prompt.
4781 return;
4782 }
4783
4784 // Reset popup state while opening a modal dialog, and firing events
4785 // about the dialog, to prevent the current state from being active
4786 // the whole time a modal dialog is open.
4787 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
4788
4789 // Before bringing up the window, unsuppress painting and flush
4790 // pending reflows.
4791 EnsureReflowFlushAndPaint();
4792
4793 nsAutoString title;
4794 MakeMessageWithPrincipal(title, &aSubjectPrincipal, false,
4795 "ScriptDlgNullPrincipalHeading", "ScriptDlgHeading",
4796 "ScriptDlgGenericHeading");
4797
4798 // Remove non-terminating null characters from the
4799 // string. See bug #310037.
4800 nsAutoString fixedMessage, fixedInitial;
4801 nsContentUtils::StripNullChars(aMessage, fixedMessage);
4802 nsContentUtils::PlatformToDOMLineBreaks(fixedMessage);
4803 nsContentUtils::StripNullChars(aInitial, fixedInitial);
4804
4805 nsresult rv;
4806 nsCOMPtr<nsIPromptFactory> promptFac =
4807 do_GetService("@mozilla.org/prompter;1", &rv);
4808 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4809 aError.Throw(rv);
4810 return;
4811 }
4812
4813 nsCOMPtr<nsIPrompt> prompt;
4814 aError =
4815 promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt)(nsIPrompt::COMTypeInfo<nsIPrompt, void>::kIID), getter_AddRefs(prompt));
4816 if (aError.Failed()) {
4817 return;
4818 }
4819
4820 // Always allow content modal prompts for prompt.
4821 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4822 promptBag->SetPropertyAsUint32(u"modalType"_ns,
4823 nsIPrompt::MODAL_TYPE_CONTENT);
4824 }
4825
4826 // Pass in the default value, if any.
4827 char16_t* inoutValue = ToNewUnicode(fixedInitial);
4828 bool disallowDialog = false;
4829
4830 nsAutoString label;
4831 label.SetIsVoid(true);
4832 if (ShouldPromptToBlockDialogs()) {
4833 nsContentUtils::GetLocalizedString(
4834 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, "ScriptDialogLabel", label);
4835 }
4836
4837 nsAutoSyncOperation sync(mDoc, SyncOperationBehavior::eSuspendInput);
4838 bool ok;
4839 aError = prompt->Prompt(title.get(), fixedMessage.get(), &inoutValue,
4840 label.IsVoid() ? nullptr : label.get(),
4841 &disallowDialog, &ok);
4842
4843 if (disallowDialog) {
4844 DisableDialogs();
4845 }
4846
4847 // XXX Doesn't this leak inoutValue?
4848 if (aError.Failed()) {
4849 return;
4850 }
4851
4852 nsString outValue;
4853 outValue.Adopt(inoutValue);
4854 if (ok && inoutValue) {
4855 aReturn = std::move(outValue);
4856 }
4857}
4858
4859void nsGlobalWindowOuter::FocusOuter(CallerType aCallerType,
4860 bool aFromOtherProcess,
4861 uint64_t aActionId) {
4862 RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
4863 if (MOZ_UNLIKELY(!fm)(__builtin_expect(!!(!fm), 0))) {
4864 return;
4865 }
4866
4867 auto [canFocus, isActive] = GetBrowsingContext()->CanFocusCheck(aCallerType);
4868 if (aFromOtherProcess) {
4869 // We trust that the check passed in a process that's, in principle,
4870 // untrusted, because we don't have the required caller context available
4871 // here. Also, the worst that the other process can do in this case is to
4872 // raise a window it's not supposed to be allowed to raise.
4873 // https://bugzilla.mozilla.org/show_bug.cgi?id=1677899
4874 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"
, 4875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "Parent should not trust other processes." ")"); do { *
((volatile int*)__null) = 4875; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
4875 "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"
, 4875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "Parent should not trust other processes." ")"); do { *
((volatile int*)__null) = 4875; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4876 canFocus = true;
4877 }
4878
4879 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4880 if (treeOwnerAsWin && (canFocus || isActive)) {
4881 bool isEnabled = true;
4882 if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled))((bool)(__builtin_expect(!!(!NS_FAILED_impl(treeOwnerAsWin->
GetEnabled(&isEnabled))), 1)))
&& !isEnabled) {
4883 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"
, 4883)
;
4884 return;
4885 }
4886 }
4887
4888 if (!mDocShell) {
4889 return;
4890 }
4891
4892 // If the window has a child frame focused, clear the focus. This
4893 // ensures that focus will be in this frame and not in a child.
4894 if (nsIContent* content = GetFocusedElement()) {
4895 if (HTMLIFrameElement::FromNode(content)) {
4896 fm->ClearFocus(this);
4897 }
4898 }
4899
4900 RefPtr<BrowsingContext> parent;
4901 BrowsingContext* bc = GetBrowsingContext();
4902 if (bc) {
4903 parent = bc->GetParent();
4904 if (!parent && XRE_IsParentProcess()) {
4905 parent = bc->Canonical()->GetParentCrossChromeBoundary();
4906 }
4907 }
4908 if (parent) {
4909 if (!parent->IsInProcess()) {
4910 if (isActive) {
4911 OwningNonNull<nsGlobalWindowOuter> kungFuDeathGrip(*this);
4912 fm->WindowRaised(kungFuDeathGrip, aActionId);
4913 } else {
4914 ContentChild* contentChild = ContentChild::GetSingleton();
4915 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"
, 4915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 4915; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4916 contentChild->SendFinalizeFocusOuter(bc, canFocus, aCallerType);
4917 }
4918 return;
4919 }
4920
4921 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"
, 4921); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc" ") ("
"Call chain should have ensured document creation." ")"); do
{ *((volatile int*)__null) = 4921; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4922 if (mDoc) {
4923 if (Element* frame = mDoc->GetEmbedderElement()) {
4924 nsContentUtils::RequestFrameFocus(*frame, canFocus, aCallerType);
4925 }
4926 }
4927 return;
4928 }
4929
4930 if (canFocus) {
4931 // if there is no parent, this must be a toplevel window, so raise the
4932 // window if canFocus is true. If this is a child process, the raise
4933 // window request will get forwarded to the parent by the puppet widget.
4934 OwningNonNull<nsGlobalWindowOuter> kungFuDeathGrip(*this);
4935 fm->RaiseWindow(kungFuDeathGrip, aCallerType, aActionId);
4936 }
4937}
4938
4939nsresult nsGlobalWindowOuter::Focus(CallerType aCallerType) {
4940 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"
, 4940); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->Focus (aCallerType); } while (0)
;
4941}
4942
4943void nsGlobalWindowOuter::BlurOuter(CallerType aCallerType) {
4944 if (!GetBrowsingContext()->CanBlurCheck(aCallerType)) {
4945 return;
4946 }
4947
4948 nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
4949 if (chrome) {
4950 chrome->Blur();
4951 }
4952}
4953
4954void nsGlobalWindowOuter::StopOuter(ErrorResult& aError) {
4955 // IsNavigationAllowed checks are usually done in nsDocShell directly,
4956 // however nsDocShell::Stop has a bunch of internal users that would fail
4957 // the IsNavigationAllowed check.
4958 if (!mDocShell || !nsDocShell::Cast(mDocShell)->IsNavigationAllowed()) {
4959 return;
4960 }
4961
4962 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4963 if (webNav) {
4964 aError = webNav->Stop(nsIWebNavigation::STOP_ALL);
4965 }
4966}
4967
4968void nsGlobalWindowOuter::PrintOuter(ErrorResult& aError) {
4969 if (!AreDialogsEnabled()) {
4970 // Per spec, silently return. https://github.com/whatwg/html/commit/21a1de1
4971 return;
4972 }
4973
4974 // Printing is disabled, silently return.
4975 if (!StaticPrefs::print_enabled()) {
4976 return;
4977 }
4978
4979 // If we're loading, queue the print for later. This is a special-case that
4980 // only applies to the window.print() call, for compat with other engines and
4981 // pre-existing behavior.
4982 if (mShouldDelayPrintUntilAfterLoad) {
4983 if (nsIDocShell* docShell = GetDocShell()) {
4984 if (docShell->GetBusyFlags() & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) {
4985 mDelayedPrintUntilAfterLoad = true;
4986 return;
4987 }
4988 }
4989 }
4990
4991#ifdef NS_PRINTING1
4992 RefPtr<BrowsingContext> top =
4993 mBrowsingContext ? mBrowsingContext->Top() : nullptr;
4994 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"
, 4994)
) {
4995 return;
4996 }
4997
4998 if (top) {
4999 Unused << top->SetIsPrinting(true);
5000 }
5001
5002 auto unset = MakeScopeExit([&] {
5003 if (top) {
5004 Unused << top->SetIsPrinting(false);
5005 }
5006 });
5007
5008 const bool forPreview = !StaticPrefs::print_always_print_silent();
5009 Print(nullptr, nullptr, nullptr, nullptr, IsPreview(forPreview),
5010 IsForWindowDotPrint::Yes, nullptr, nullptr, aError);
5011#endif
5012}
5013
5014class MOZ_RAII AutoModalState {
5015 public:
5016 explicit AutoModalState(nsGlobalWindowOuter& aWin)
5017 : mModalStateWin(aWin.EnterModalState()) {}
5018
5019 ~AutoModalState() {
5020 if (mModalStateWin) {
5021 mModalStateWin->LeaveModalState();
5022 }
5023 }
5024
5025 RefPtr<nsGlobalWindowOuter> mModalStateWin;
5026};
5027
5028Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
5029 nsIPrintSettings* aPrintSettings, RemotePrintJobChild* aRemotePrintJob,
5030 nsIWebProgressListener* aListener, nsIDocShell* aDocShellToCloneInto,
5031 IsPreview aIsPreview, IsForWindowDotPrint aForWindowDotPrint,
5032 PrintPreviewResolver&& aPrintPreviewCallback,
5033 RefPtr<BrowsingContext>* aCachedBrowsingContext, ErrorResult& aError) {
5034#ifdef NS_PRINTING1
5035 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
5036 do_GetService("@mozilla.org/gfx/printsettings-service;1");
5037 if (!printSettingsService) {
5038 // we currently return here in headless mode - should we?
5039 aError.ThrowNotSupportedError("No print settings service");
5040 return nullptr;
5041 }
5042
5043 nsCOMPtr<nsIPrintSettings> ps = aPrintSettings;
5044 if (!ps) {
5045 // We shouldn't need this once bug 1776169 is fixed.
5046 printSettingsService->GetDefaultPrintSettingsForPrinting(
5047 getter_AddRefs(ps));
5048 }
5049
5050 RefPtr<Document> docToPrint = mDoc;
5051 if (NS_WARN_IF(!docToPrint)NS_warn_if_impl(!docToPrint, "!docToPrint", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5051)
) {
5052 aError.ThrowNotSupportedError("Document is gone");
5053 return nullptr;
5054 }
5055
5056 RefPtr<BrowsingContext> sourceBC = docToPrint->GetBrowsingContext();
5057 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"
, 5057); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "sourceBC"
")"); do { *((volatile int*)__null) = 5057; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5058 if (!sourceBC) {
5059 aError.ThrowNotSupportedError("No browsing context for source document");
5060 return nullptr;
5061 }
5062
5063 nsAutoSyncOperation sync(docToPrint, SyncOperationBehavior::eAllowInput);
5064 AutoModalState modalState(*this);
5065
5066 nsCOMPtr<nsIDocumentViewer> viewer;
5067 RefPtr<BrowsingContext> bc;
5068 bool hasPrintCallbacks = false;
5069 bool wasStaticDocument = docToPrint->IsStaticDocument();
5070 bool usingCachedBrowsingContext = false;
5071 if (aCachedBrowsingContext && *aCachedBrowsingContext) {
5072 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"
, 5074); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5074; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
5073 "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"
, 5074); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5074; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
5074 "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"
, 5074); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5074; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
5075 if (!wasStaticDocument) {
5076 // The passed in document is not a static clone and the caller passed in a
5077 // static clone to reuse, so swap it in.
5078 docToPrint = (*aCachedBrowsingContext)->GetDocument();
5079 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"
, 5079); AnnotateMozCrashReason("MOZ_ASSERT" "(" "docToPrint"
")"); do { *((volatile int*)__null) = 5079; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5080 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"
, 5080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "docToPrint->IsStaticDocument()"
")"); do { *((volatile int*)__null) = 5080; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5081 wasStaticDocument = true;
5082 usingCachedBrowsingContext = true;
5083 }
5084 }
5085 if (wasStaticDocument) {
5086 if (aForWindowDotPrint == IsForWindowDotPrint::Yes) {
5087 aError.ThrowNotSupportedError(
5088 "Calling print() from a print preview is unsupported, did you intend "
5089 "to call printPreview() instead?");
5090 return nullptr;
5091 }
5092 if (usingCachedBrowsingContext) {
5093 bc = docToPrint->GetBrowsingContext();
5094 } else {
5095 // We're already a print preview window, just reuse our browsing context /
5096 // content viewer.
5097 bc = sourceBC;
5098 }
5099 nsCOMPtr<nsIDocShell> docShell = bc->GetDocShell();
5100 if (!docShell) {
5101 aError.ThrowNotSupportedError("No docshell");
5102 return nullptr;
5103 }
5104 // We could handle this if needed.
5105 if (aDocShellToCloneInto && aDocShellToCloneInto != docShell) {
5106 aError.ThrowNotSupportedError(
5107 "We don't handle cloning a print preview doc into a different "
5108 "docshell");
5109 return nullptr;
5110 }
5111 docShell->GetDocViewer(getter_AddRefs(viewer));
5112 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"
, 5112); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "viewer"
")"); do { *((volatile int*)__null) = 5112; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5113 } else {
5114 if (aDocShellToCloneInto) {
5115 // Ensure the content viewer is created if needed.
5116 Unused << aDocShellToCloneInto->GetDocument();
5117 bc = aDocShellToCloneInto->GetBrowsingContext();
5118 } else {
5119 AutoNoJSAPI nojsapi;
5120 auto printKind = aForWindowDotPrint == IsForWindowDotPrint::Yes
5121 ? PrintKind::WindowDotPrint
5122 : PrintKind::InternalPrint;
5123 // For PrintKind::WindowDotPrint, this call will not only make the parent
5124 // process create a CanonicalBrowsingContext for the returned `bc`, but
5125 // it will also make the parent process initiate the print/print preview.
5126 // See the handling of OPEN_PRINT_BROWSER in browser.js.
5127 aError = OpenInternal(u""_ns, u""_ns, u""_ns,
5128 false, // aDialog
5129 false, // aContentModal
5130 true, // aCalledNoScript
5131 false, // aDoJSFixups
5132 true, // aNavigate
5133 nullptr, nullptr, // No args
5134 nullptr, // aLoadState
5135 false, // aForceNoOpener
5136 printKind, getter_AddRefs(bc));
5137 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"
, 5137)
) {
5138 return nullptr;
5139 }
5140 if (aCachedBrowsingContext) {
5141 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"
, 5141); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!*aCachedBrowsingContext"
")"); do { *((volatile int*)__null) = 5141; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5142 *aCachedBrowsingContext = bc;
5143 }
5144 }
5145 if (!bc) {
5146 aError.ThrowNotAllowedError("No browsing context");
5147 return nullptr;
5148 }
5149
5150 Unused << bc->Top()->SetIsPrinting(true);
5151 nsCOMPtr<nsIDocShell> cloneDocShell = bc->GetDocShell();
5152 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"
, 5152); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "cloneDocShell"
")"); do { *((volatile int*)__null) = 5152; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5153 cloneDocShell->GetDocViewer(getter_AddRefs(viewer));
5154 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"
, 5154); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "viewer"
")"); do { *((volatile int*)__null) = 5154; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5155 if (!viewer) {
5156 aError.ThrowNotSupportedError("Didn't end up with a content viewer");
5157 return nullptr;
5158 }
5159
5160 if (bc != sourceBC) {
5161 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"
, 5161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc->IsTopContent()"
")"); do { *((volatile int*)__null) = 5161; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5162 // If we are cloning from a document in a different BrowsingContext, we
5163 // need to make sure to copy over our opener policy information from that
5164 // BrowsingContext. In the case where the source is an iframe, this
5165 // information needs to be copied from the toplevel source
5166 // BrowsingContext, as we may be making a static clone of a single
5167 // subframe.
5168 MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy
()))), 1)))), 1))) { } else { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5169); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")"); do { *((volatile int*)__null) = 5169; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5169 bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy
()))), 1)))), 1))) { } else { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5169); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")"); do { *((volatile int*)__null) = 5169; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
5170 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"
, 5170); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "bc->Group() == sourceBC->Group()"
")"); do { *((volatile int*)__null) = 5170; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5171 }
5172
5173 if (RefPtr<Document> doc = viewer->GetDocument()) {
5174 if (doc->IsShowing()) {
5175 // We're going to drop this document on the floor, in the SetDocument
5176 // call below. Make sure to run OnPageHide() to keep state consistent
5177 // and avoids assertions in the document destructor.
5178 doc->OnPageHide(false, nullptr);
5179 }
5180 }
5181
5182 AutoPrintEventDispatcher dispatcher(*docToPrint);
5183
5184 nsAutoScriptBlocker blockScripts;
5185 RefPtr<Document> clone = docToPrint->CreateStaticClone(
5186 cloneDocShell, viewer, ps, &hasPrintCallbacks);
5187 if (!clone) {
5188 aError.ThrowNotSupportedError("Clone operation for printing failed");
5189 return nullptr;
5190 }
5191 }
5192
5193 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint = do_QueryInterface(viewer);
5194 if (!webBrowserPrint) {
5195 aError.ThrowNotSupportedError(
5196 "Content viewer didn't implement nsIWebBrowserPrint");
5197 return nullptr;
5198 }
5199 bool closeWindowAfterPrint;
5200 if (wasStaticDocument) {
5201 // Here the document was a static clone to begin with that this code did not
5202 // create, so we should not clean it up.
5203 // The exception is if we're using the passed-in aCachedBrowsingContext, in
5204 // which case this is the second print with this static document clone that
5205 // we created the first time through, and we are responsible for cleaning it
5206 // up.
5207 closeWindowAfterPrint = usingCachedBrowsingContext;
5208 } else {
5209 // In this case the document was not a static clone, so we made a static
5210 // clone for printing purposes and must clean it up after the print is done.
5211 // The exception is if aCachedBrowsingContext is non-NULL, meaning the
5212 // caller is intending to print this document again, so we need to defer the
5213 // cleanup until after the second print.
5214 closeWindowAfterPrint = !aCachedBrowsingContext;
5215 }
5216 webBrowserPrint->SetCloseWindowAfterPrint(closeWindowAfterPrint);
5217
5218 // For window.print(), we postpone making these calls until the round-trip to
5219 // the parent process (triggered by the OpenInternal call above) calls us
5220 // again. Only a call from the parent can provide a valid nsPrintSettings
5221 // object and RemotePrintJobChild object.
5222 if (aForWindowDotPrint == IsForWindowDotPrint::No) {
5223 if (aIsPreview == IsPreview::Yes) {
5224 aError = webBrowserPrint->PrintPreview(ps, aListener,
5225 std::move(aPrintPreviewCallback));
5226 if (aError.Failed()) {
5227 return nullptr;
5228 }
5229 } else {
5230 // Historically we've eaten this error.
5231 webBrowserPrint->Print(ps, aRemotePrintJob, aListener);
5232 }
5233 }
5234
5235 // When using window.print() with the new UI, we usually want to block until
5236 // the print dialog is hidden. But we can't really do that if we have print
5237 // callbacks, because we are inside a sync operation, and we want to run
5238 // microtasks / etc that the print callbacks may create. It is really awkward
5239 // to have this subtle behavior difference...
5240 //
5241 // We also want to do this for fuzzing, so that they can test window.print().
5242 const bool shouldBlock = [&] {
5243 if (aForWindowDotPrint == IsForWindowDotPrint::No) {
5244 return false;
5245 }
5246 if (aIsPreview == IsPreview::Yes) {
5247 return !hasPrintCallbacks;
5248 }
5249 return StaticPrefs::dom_window_print_fuzzing_block_while_printing();
5250 }();
5251
5252 if (shouldBlock) {
5253 SpinEventLoopUntil("nsGlobalWindowOuter::Print"_ns,
5254 [&] { return bc->IsDiscarded(); });
5255 }
5256
5257 return WindowProxyHolder(std::move(bc));
5258#else
5259 return nullptr;
5260#endif // NS_PRINTING
5261}
5262
5263void nsGlobalWindowOuter::MoveToOuter(int32_t aXPos, int32_t aYPos,
5264 CallerType aCallerType,
5265 ErrorResult& aError) {
5266 /*
5267 * If caller is not chrome and the user has not explicitly exempted the site,
5268 * prevent window.moveTo() by exiting early
5269 */
5270
5271 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5272 return;
5273 }
5274
5275 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5276 if (!treeOwnerAsWin) {
5277 aError.Throw(NS_ERROR_FAILURE);
5278 return;
5279 }
5280
5281 // We need to do the same transformation GetScreenXY does.
5282 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
5283 if (!presContext) {
5284 return;
5285 }
5286
5287 CSSIntPoint cssPos(aXPos, aYPos);
5288 CheckSecurityLeftAndTop(&cssPos.x.value, &cssPos.y.value, aCallerType);
5289
5290 nsDeviceContext* context = presContext->DeviceContext();
5291
5292 auto devPos = LayoutDeviceIntPoint::FromAppUnitsRounded(
5293 CSSIntPoint::ToAppUnits(cssPos), context->AppUnitsPerDevPixel());
5294
5295 aError = treeOwnerAsWin->SetPosition(devPos.x, devPos.y);
5296 CheckForDPIChange();
5297}
5298
5299void nsGlobalWindowOuter::MoveByOuter(int32_t aXDif, int32_t aYDif,
5300 CallerType aCallerType,
5301 ErrorResult& aError) {
5302 /*
5303 * If caller is not chrome and the user has not explicitly exempted the site,
5304 * prevent window.moveBy() by exiting early
5305 */
5306
5307 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5308 return;
5309 }
5310
5311 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5312 if (!treeOwnerAsWin) {
5313 aError.Throw(NS_ERROR_FAILURE);
5314 return;
5315 }
5316
5317 // To do this correctly we have to convert what we get from GetPosition
5318 // into CSS pixels, add the arguments, do the security check, and
5319 // then convert back to device pixels for the call to SetPosition.
5320
5321 int32_t x, y;
5322 aError = treeOwnerAsWin->GetPosition(&x, &y);
5323 if (aError.Failed()) {
5324 return;
5325 }
5326
5327 auto cssScale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
5328 CSSIntPoint cssPos = RoundedToInt(treeOwnerAsWin->GetPosition() / cssScale);
5329
5330 cssPos.x += aXDif;
5331 cssPos.y += aYDif;
5332
5333 CheckSecurityLeftAndTop(&cssPos.x.value, &cssPos.y.value, aCallerType);
5334
5335 LayoutDeviceIntPoint newDevPos = RoundedToInt(cssPos * cssScale);
5336 aError = treeOwnerAsWin->SetPosition(newDevPos.x, newDevPos.y);
5337
5338 CheckForDPIChange();
5339}
5340
5341nsresult nsGlobalWindowOuter::MoveBy(int32_t aXDif, int32_t aYDif) {
5342 ErrorResult rv;
5343 MoveByOuter(aXDif, aYDif, CallerType::System, rv);
5344
5345 return rv.StealNSResult();
5346}
5347
5348void nsGlobalWindowOuter::ResizeToOuter(int32_t aWidth, int32_t aHeight,
5349 CallerType aCallerType,
5350 ErrorResult& aError) {
5351 /*
5352 * If caller is not chrome and the user has not explicitly exempted the site,
5353 * prevent window.resizeTo() by exiting early
5354 */
5355
5356 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5357 return;
5358 }
5359
5360 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5361 if (!treeOwnerAsWin) {
5362 aError.Throw(NS_ERROR_FAILURE);
5363 return;
5364 }
5365
5366 CSSIntSize cssSize(aWidth, aHeight);
5367 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5368
5369 LayoutDeviceIntSize devSize =
5370 RoundedToInt(cssSize * CSSToDevScaleForBaseWindow(treeOwnerAsWin));
5371 aError = treeOwnerAsWin->SetSize(devSize.width, devSize.height, true);
5372
5373 CheckForDPIChange();
5374}
5375
5376void nsGlobalWindowOuter::ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif,
5377 CallerType aCallerType,
5378 ErrorResult& aError) {
5379 /*
5380 * If caller is not chrome and the user has not explicitly exempted the site,
5381 * prevent window.resizeBy() by exiting early
5382 */
5383
5384 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5385 return;
5386 }
5387
5388 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5389 if (!treeOwnerAsWin) {
5390 aError.Throw(NS_ERROR_FAILURE);
5391 return;
5392 }
5393
5394 LayoutDeviceIntSize size = treeOwnerAsWin->GetSize();
5395
5396 // To do this correctly we have to convert what we got from GetSize
5397 // into CSS pixels, add the arguments, do the security check, and
5398 // then convert back to device pixels for the call to SetSize.
5399
5400 auto scale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
5401 CSSIntSize cssSize = RoundedToInt(size / scale);
5402
5403 cssSize.width += aWidthDif;
5404 cssSize.height += aHeightDif;
5405
5406 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5407
5408 LayoutDeviceIntSize newDevSize = RoundedToInt(cssSize * scale);
5409
5410 aError = treeOwnerAsWin->SetSize(newDevSize.width, newDevSize.height, true);
5411
5412 CheckForDPIChange();
5413}
5414
5415void nsGlobalWindowOuter::SizeToContentOuter(
5416 CallerType aCallerType, const SizeToContentConstraints& aConstraints,
5417 ErrorResult& aError) {
5418 if (!mDocShell) {
5419 return;
5420 }
5421
5422 /*
5423 * If caller is not chrome and the user has not explicitly exempted the site,
5424 * prevent window.sizeToContent() by exiting early
5425 */
5426
5427 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5428 return;
5429 }
5430
5431 // The content viewer does a check to make sure that it's a content
5432 // viewer for a toplevel docshell.
5433 nsCOMPtr<nsIDocumentViewer> viewer;
5434 mDocShell->GetDocViewer(getter_AddRefs(viewer));
5435 if (!viewer) {
5436 return aError.Throw(NS_ERROR_FAILURE);
5437 }
5438
5439 auto contentSize = viewer->GetContentSize(
5440 aConstraints.mMaxWidth, aConstraints.mMaxHeight, aConstraints.mPrefWidth);
5441 if (!contentSize) {
5442 return aError.Throw(NS_ERROR_FAILURE);
5443 }
5444
5445 // Make sure the new size is following the CheckSecurityWidthAndHeight
5446 // rules.
5447 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
5448 if (!treeOwner) {
5449 return aError.Throw(NS_ERROR_FAILURE);
5450 }
5451
5452 // Don't use DevToCSSIntPixelsForBaseWindow() nor
5453 // CSSToDevIntPixelsForBaseWindow() here because contentSize is comes from
5454 // nsIDocumentViewer::GetContentSize() and it's computed with nsPresContext so
5455 // that we need to work with nsPresContext here too.
5456 RefPtr<nsPresContext> presContext = viewer->GetPresContext();
5457 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"
, 5459); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5459; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5458 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"
, 5459); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5459; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5459 "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"
, 5459); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5459; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5460 CSSIntSize cssSize = *contentSize;
5461 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5462
5463 LayoutDeviceIntSize newDevSize(
5464 presContext->CSSPixelsToDevPixels(cssSize.width),
5465 presContext->CSSPixelsToDevPixels(cssSize.height));
5466
5467 nsCOMPtr<nsIDocShell> docShell = mDocShell;
5468 aError =
5469 treeOwner->SizeShellTo(docShell, newDevSize.width, newDevSize.height);
5470}
5471
5472already_AddRefed<nsPIWindowRoot> nsGlobalWindowOuter::GetTopWindowRoot() {
5473 nsPIDOMWindowOuter* piWin = GetPrivateRoot();
5474 if (!piWin) {
5475 return nullptr;
5476 }
5477
5478 nsCOMPtr<nsPIWindowRoot> window =
5479 do_QueryInterface(piWin->GetChromeEventHandler());
5480 return window.forget();
5481}
5482
5483void nsGlobalWindowOuter::FirePopupBlockedEvent(
5484 Document* aDoc, nsIURI* aPopupURI, const nsAString& aPopupWindowName,
5485 const nsAString& aPopupWindowFeatures) {
5486 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"
, 5486); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDoc" ")");
do { *((volatile int*)__null) = 5486; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5487
5488 // Fire a "DOMPopupBlocked" event so that the UI can hear about
5489 // blocked popups.
5490 PopupBlockedEventInit init;
5491 init.mBubbles = true;
5492 init.mCancelable = true;
5493 // XXX: This is a different object, but webidl requires an inner window here
5494 // now.
5495 init.mRequestingWindow = GetCurrentInnerWindowInternal(this);
5496 init.mPopupWindowURI = aPopupURI;
5497 init.mPopupWindowName = aPopupWindowName;
5498 init.mPopupWindowFeatures = aPopupWindowFeatures;
5499
5500 RefPtr<PopupBlockedEvent> event =
5501 PopupBlockedEvent::Constructor(aDoc, u"DOMPopupBlocked"_ns, init);
5502
5503 event->SetTrusted(true);
5504
5505 aDoc->DispatchEvent(*event);
5506}
5507
5508// static
5509bool nsGlobalWindowOuter::CanSetProperty(const char* aPrefName) {
5510 // Chrome can set any property.
5511 if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
5512 return true;
5513 }
5514
5515 // If the pref is set to true, we can not set the property
5516 // and vice versa.
5517 return !Preferences::GetBool(aPrefName, true);
5518}
5519
5520/* If a window open is blocked, fire the appropriate DOM events. */
5521void nsGlobalWindowOuter::FireAbuseEvents(
5522 const nsAString& aPopupURL, const nsAString& aPopupWindowName,
5523 const nsAString& aPopupWindowFeatures) {
5524 // fetch the URI of the window requesting the opened window
5525 nsCOMPtr<Document> currentDoc = GetDoc();
5526 nsCOMPtr<nsIURI> popupURI;
5527
5528 // build the URI of the would-have-been popup window
5529 // (see nsWindowWatcher::URIfromURL)
5530
5531 // first, fetch the opener's base URI
5532
5533 nsIURI* baseURL = nullptr;
5534
5535 nsCOMPtr<Document> doc = GetEntryDocument();
5536 if (doc) baseURL = doc->GetDocBaseURI();
5537
5538 // use the base URI to build what would have been the popup's URI
5539 nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID"@mozilla.org/network/io-service;1"));
5540 if (ios)
5541 ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), nullptr, baseURL,
5542 getter_AddRefs(popupURI));
5543
5544 // fire an event block full of informative URIs
5545 FirePopupBlockedEvent(currentDoc, popupURI, aPopupWindowName,
5546 aPopupWindowFeatures);
5547}
5548
5549Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenOuter(
5550 const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
5551 ErrorResult& aError) {
5552 RefPtr<BrowsingContext> bc;
5553 nsresult rv = OpenJS(aUrl, aName, aOptions, getter_AddRefs(bc));
5554 if (rv == NS_ERROR_MALFORMED_URI) {
5555 aError.ThrowSyntaxError("Unable to open a window with invalid URL '"_ns +
5556 NS_ConvertUTF16toUTF8(aUrl) + "'."_ns);
5557 return nullptr;
5558 }
5559
5560 // XXX Is it possible that some internal errors are thrown here?
5561 aError = rv;
5562
5563 if (!bc) {
5564 return nullptr;
5565 }
5566 return WindowProxyHolder(std::move(bc));
5567}
5568
5569nsresult nsGlobalWindowOuter::Open(const nsAString& aUrl,
5570 const nsAString& aName,
5571 const nsAString& aOptions,
5572 nsDocShellLoadState* aLoadState,
5573 bool aForceNoOpener,
5574 BrowsingContext** _retval) {
5575 return OpenInternal(aUrl, aName, aOptions,
5576 false, // aDialog
5577 false, // aContentModal
5578 true, // aCalledNoScript
5579 false, // aDoJSFixups
5580 true, // aNavigate
5581 nullptr, nullptr, // No args
5582 aLoadState, aForceNoOpener, PrintKind::None, _retval);
5583}
5584
5585nsresult nsGlobalWindowOuter::OpenJS(const nsAString& aUrl,
5586 const nsAString& aName,
5587 const nsAString& aOptions,
5588 BrowsingContext** _retval) {
5589 return OpenInternal(aUrl, aName, aOptions,
5590 false, // aDialog
5591 false, // aContentModal
5592 false, // aCalledNoScript
5593 true, // aDoJSFixups
5594 true, // aNavigate
5595 nullptr, nullptr, // No args
5596 nullptr, // aLoadState
5597 false, // aForceNoOpener
5598 PrintKind::None, _retval);
5599}
5600
5601// like Open, but attaches to the new window any extra parameters past
5602// [features] as a JS property named "arguments"
5603nsresult nsGlobalWindowOuter::OpenDialog(const nsAString& aUrl,
5604 const nsAString& aName,
5605 const nsAString& aOptions,
5606 nsISupports* aExtraArgument,
5607 BrowsingContext** _retval) {
5608 return OpenInternal(aUrl, aName, aOptions,
5609 true, // aDialog
5610 false, // aContentModal
5611 true, // aCalledNoScript
5612 false, // aDoJSFixups
5613 true, // aNavigate
5614 nullptr, aExtraArgument, // Arguments
5615 nullptr, // aLoadState
5616 false, // aForceNoOpener
5617 PrintKind::None, _retval);
5618}
5619
5620// Like Open, but passes aNavigate=false.
5621/* virtual */
5622nsresult nsGlobalWindowOuter::OpenNoNavigate(const nsAString& aUrl,
5623 const nsAString& aName,
5624 const nsAString& aOptions,
5625 BrowsingContext** _retval) {
5626 return OpenInternal(aUrl, aName, aOptions,
5627 false, // aDialog
5628 false, // aContentModal
5629 true, // aCalledNoScript
5630 false, // aDoJSFixups
5631 false, // aNavigate
5632 nullptr, nullptr, // No args
5633 nullptr, // aLoadState
5634 false, // aForceNoOpener
5635 PrintKind::None, _retval);
5636}
5637
5638Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenDialogOuter(
5639 JSContext* aCx, const nsAString& aUrl, const nsAString& aName,
5640 const nsAString& aOptions, const Sequence<JS::Value>& aExtraArgument,
5641 ErrorResult& aError) {
5642 nsCOMPtr<nsIJSArgArray> argvArray;
5643 aError =
5644 NS_CreateJSArgv(aCx, aExtraArgument.Length(), aExtraArgument.Elements(),
5645 getter_AddRefs(argvArray));
5646 if (aError.Failed()) {
5647 return nullptr;
5648 }
5649
5650 RefPtr<BrowsingContext> dialog;
5651 aError = OpenInternal(aUrl, aName, aOptions,
5652 true, // aDialog
5653 false, // aContentModal
5654 false, // aCalledNoScript
5655 false, // aDoJSFixups
5656 true, // aNavigate
5657 argvArray, nullptr, // Arguments
5658 nullptr, // aLoadState
5659 false, // aForceNoOpener
5660 PrintKind::None, getter_AddRefs(dialog));
5661 if (!dialog) {
5662 return nullptr;
5663 }
5664 return WindowProxyHolder(std::move(dialog));
5665}
5666
5667WindowProxyHolder nsGlobalWindowOuter::GetFramesOuter() {
5668 RefPtr<nsPIDOMWindowOuter> frames(this);
5669 FlushPendingNotifications(FlushType::ContentAndNotify);
5670 return WindowProxyHolder(mBrowsingContext);
5671}
5672
5673/* static */
5674bool nsGlobalWindowOuter::GatherPostMessageData(
5675 JSContext* aCx, const nsAString& aTargetOrigin, BrowsingContext** aSource,
5676 nsAString& aOrigin, nsIURI** aTargetOriginURI,
5677 nsIPrincipal** aCallerPrincipal, nsGlobalWindowInner** aCallerInnerWindow,
5678 nsIURI** aCallerURI, Maybe<nsID>* aCallerAgentClusterId,
5679 nsACString* aScriptLocation, ErrorResult& aError) {
5680 //
5681 // Window.postMessage is an intentional subversion of the same-origin policy.
5682 // As such, this code must be particularly careful in the information it
5683 // exposes to calling code.
5684 //
5685 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5686 //
5687
5688 // First, get the caller's window
5689 RefPtr<nsGlobalWindowInner> callerInnerWin =
5690 nsContentUtils::IncumbentInnerWindow();
5691 nsIPrincipal* callerPrin;
5692 if (callerInnerWin) {
5693 RefPtr<Document> doc = callerInnerWin->GetExtantDoc();
5694 if (!doc) {
5695 return false;
5696 }
5697 NS_IF_ADDREF(*aCallerURI = doc->GetDocumentURI())ns_if_addref(*aCallerURI = doc->GetDocumentURI());
5698
5699 // Compute the caller's origin either from its principal or, in the case the
5700 // principal doesn't carry a URI (e.g. the system principal), the caller's
5701 // document. We must get this now instead of when the event is created and
5702 // dispatched, because ultimately it is the identity of the calling window
5703 // *now* that determines who sent the message (and not an identity which
5704 // might have changed due to intervening navigations).
5705 callerPrin = callerInnerWin->GetPrincipal();
5706 } else {
5707 // In case the global is not a window, it can be a sandbox, and the
5708 // sandbox's principal can be used for the security check.
5709 nsIGlobalObject* global = GetIncumbentGlobal();
5710 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"
, 5710); MOZ_PretendNoReturn(); } } while (0)
;
5711 callerPrin = global->PrincipalOrNull();
5712 if (callerPrin) {
5713 BasePrincipal::Cast(callerPrin)->GetScriptLocation(*aScriptLocation);
5714 }
5715 }
5716 if (!callerPrin) {
5717 return false;
5718 }
5719
5720 // if the principal has a URI, use that to generate the origin
5721 if (!callerPrin->IsSystemPrincipal()) {
5722 nsAutoCString webExposedOriginSerialization;
5723 callerPrin->GetWebExposedOriginSerialization(webExposedOriginSerialization);
5724 CopyUTF8toUTF16(webExposedOriginSerialization, aOrigin);
5725 } else if (callerInnerWin) {
5726 if (!*aCallerURI) {
5727 return false;
5728 }
5729 // otherwise use the URI of the document to generate origin
5730 nsContentUtils::GetWebExposedOriginSerialization(*aCallerURI, aOrigin);
5731 } else {
5732 // in case of a sandbox with a system principal origin can be empty
5733 if (!callerPrin->IsSystemPrincipal()) {
5734 return false;
5735 }
5736 }
5737 NS_IF_ADDREF(*aCallerPrincipal = callerPrin)ns_if_addref(*aCallerPrincipal = callerPrin);
5738
5739 // "/" indicates same origin as caller, "*" indicates no specific origin is
5740 // required.
5741 if (!aTargetOrigin.EqualsASCII("/") && !aTargetOrigin.EqualsASCII("*")) {
5742 nsCOMPtr<nsIURI> targetOriginURI;
5743 if (NS_FAILED(NS_NewURI(getter_AddRefs(targetOriginURI), aTargetOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_NewURI(getter_AddRefs
(targetOriginURI), aTargetOrigin))), 0)))
) {
5744 aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
5745 return false;
5746 }
5747
5748 nsresult rv = NS_MutateURI(targetOriginURI)
5749 .SetUserPass(""_ns)
5750 .SetPathQueryRef(""_ns)
5751 .Finalize(aTargetOriginURI);
5752 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5753 return false;
5754 }
5755 }
5756
5757 if (!nsContentUtils::IsCallerChrome() && callerInnerWin &&
5758 callerInnerWin->GetOuterWindowInternal()) {
5759 NS_ADDREF(*aSource = callerInnerWin->GetOuterWindowInternal()(*aSource = callerInnerWin->GetOuterWindowInternal() ->
GetBrowsingContext())->AddRef()
5760 ->GetBrowsingContext())(*aSource = callerInnerWin->GetOuterWindowInternal() ->
GetBrowsingContext())->AddRef()
;
5761 } else {
5762 *aSource = nullptr;
5763 }
5764
5765 if (aCallerAgentClusterId && callerInnerWin &&
5766 callerInnerWin->GetDocGroup()) {
5767 *aCallerAgentClusterId =
5768 Some(callerInnerWin->GetDocGroup()->AgentClusterId());
5769 }
5770
5771 callerInnerWin.forget(aCallerInnerWindow);
5772
5773 return true;
5774}
5775
5776bool nsGlobalWindowOuter::GetPrincipalForPostMessage(
5777 const nsAString& aTargetOrigin, nsIURI* aTargetOriginURI,
5778 nsIPrincipal* aCallerPrincipal, nsIPrincipal& aSubjectPrincipal,
5779 nsIPrincipal** aProvidedPrincipal) {
5780 //
5781 // Window.postMessage is an intentional subversion of the same-origin policy.
5782 // As such, this code must be particularly careful in the information it
5783 // exposes to calling code.
5784 //
5785 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5786 //
5787
5788 // Convert the provided origin string into a URI for comparison purposes.
5789 nsCOMPtr<nsIPrincipal> providedPrincipal;
5790
5791 if (aTargetOrigin.EqualsASCII("/")) {
5792 providedPrincipal = aCallerPrincipal;
5793 }
5794 // "*" indicates no specific origin is required.
5795 else if (!aTargetOrigin.EqualsASCII("*")) {
5796 OriginAttributes attrs = aSubjectPrincipal.OriginAttributesRef();
5797 if (aSubjectPrincipal.IsSystemPrincipal()) {
5798 auto principal = BasePrincipal::Cast(GetPrincipal());
5799
5800 if (attrs != principal->OriginAttributesRef()) {
5801 nsAutoCString targetURL;
5802 nsAutoCString sourceOrigin;
5803 nsAutoCString targetOrigin;
5804
5805 if (NS_FAILED(principal->GetAsciiSpec(targetURL))((bool)(__builtin_expect(!!(NS_FAILED_impl(principal->GetAsciiSpec
(targetURL))), 0)))
||
5806 NS_FAILED(principal->GetOrigin(targetOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(principal->GetOrigin
(targetOrigin))), 0)))
||
5807 NS_FAILED(aSubjectPrincipal.GetOrigin(sourceOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(aSubjectPrincipal.
GetOrigin(sourceOrigin))), 0)))
) {
5808 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"
, 5808)
;
5809 return false;
5810 }
5811
5812 nsContentUtils::LogSimpleConsoleError(
5813 NS_ConvertUTF8toUTF16(nsPrintfCString(
5814 R"(Attempting to post a message to window with url "%s" and )"
5815 R"(origin "%s" from a system principal scope with mismatched )"
5816 R"(origin "%s".)",
5817 targetURL.get(), targetOrigin.get(), sourceOrigin.get())),
5818 "DOM"_ns, !!principal->PrivateBrowsingId(),
5819 principal->IsSystemPrincipal());
5820
5821 attrs = principal->OriginAttributesRef();
5822 }
5823 }
5824
5825 // Create a nsIPrincipal inheriting the app/browser attributes from the
5826 // caller.
5827 providedPrincipal =
5828 BasePrincipal::CreateContentPrincipal(aTargetOriginURI, attrs);
5829 if (NS_WARN_IF(!providedPrincipal)NS_warn_if_impl(!providedPrincipal, "!providedPrincipal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5829)
) {
5830 return false;
5831 }
5832 } else {
5833 // We still need to check the originAttributes if the target origin is '*'.
5834 // But we will ingore the FPD here since the FPDs are possible to be
5835 // different.
5836 auto principal = BasePrincipal::Cast(GetPrincipal());
5837 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"
, 5837); return false; } } while (false)
;
5838
5839 OriginAttributes targetAttrs = principal->OriginAttributesRef();
5840 OriginAttributes sourceAttrs = aSubjectPrincipal.OriginAttributesRef();
5841 // We have to exempt the check of OA if the subject prioncipal is a system
5842 // principal since there are many tests try to post messages to content from
5843 // chrome with a mismatch OA. For example, using the ContentTask.spawn() to
5844 // post a message into a private browsing window. The injected code in
5845 // ContentTask.spawn() will be executed under the system principal and the
5846 // OA of the system principal mismatches with the OA of a private browsing
5847 // window.
5848 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"
, 5849); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
")"); do { *((volatile int*)__null) = 5849; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5849 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"
, 5849); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
")"); do { *((volatile int*)__null) = 5849; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5850
5851 // If 'privacy.firstparty.isolate.block_post_message' is true, we will block
5852 // postMessage across different first party domains.
5853 if (OriginAttributes::IsBlockPostMessageForFPI() &&
5854 !aSubjectPrincipal.IsSystemPrincipal() &&
5855 sourceAttrs.mFirstPartyDomain != targetAttrs.mFirstPartyDomain) {
5856 return false;
5857 }
5858 }
5859
5860 providedPrincipal.forget(aProvidedPrincipal);
5861 return true;
5862}
5863
5864void nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx,
5865 JS::Handle<JS::Value> aMessage,
5866 const nsAString& aTargetOrigin,
5867 JS::Handle<JS::Value> aTransfer,
5868 nsIPrincipal& aSubjectPrincipal,
5869 ErrorResult& aError) {
5870 RefPtr<BrowsingContext> sourceBc;
5871 nsAutoString origin;
5872 nsCOMPtr<nsIURI> targetOriginURI;
5873 nsCOMPtr<nsIPrincipal> callerPrincipal;
5874 RefPtr<nsGlobalWindowInner> callerInnerWindow;
5875 nsCOMPtr<nsIURI> callerURI;
5876 Maybe<nsID> callerAgentClusterId = Nothing();
5877 nsAutoCString scriptLocation;
5878 if (!GatherPostMessageData(
5879 aCx, aTargetOrigin, getter_AddRefs(sourceBc), origin,
5880 getter_AddRefs(targetOriginURI), getter_AddRefs(callerPrincipal),
5881 getter_AddRefs(callerInnerWindow), getter_AddRefs(callerURI),
5882 &callerAgentClusterId, &scriptLocation, aError)) {
5883 return;
5884 }
5885
5886 nsCOMPtr<nsIPrincipal> providedPrincipal;
5887 if (!GetPrincipalForPostMessage(aTargetOrigin, targetOriginURI,
5888 callerPrincipal, aSubjectPrincipal,
5889 getter_AddRefs(providedPrincipal))) {
5890 return;
5891 }
5892
5893 // Create and asynchronously dispatch a runnable which will handle actual DOM
5894 // event creation and dispatch.
5895 RefPtr<PostMessageEvent> event = new PostMessageEvent(
5896 sourceBc, origin, this, providedPrincipal,
5897 callerInnerWindow ? callerInnerWindow->WindowID() : 0, callerURI,
5898 scriptLocation, callerAgentClusterId);
5899
5900 JS::CloneDataPolicy clonePolicy;
5901
5902 if (GetDocGroup() && callerAgentClusterId.isSome() &&
5903 GetDocGroup()->AgentClusterId().Equals(callerAgentClusterId.value())) {
5904 clonePolicy.allowIntraClusterClonableSharedObjects();
5905 }
5906
5907 if (callerInnerWindow && callerInnerWindow->IsSharedMemoryAllowed()) {
5908 clonePolicy.allowSharedMemoryObjects();
5909 }
5910
5911 event->Write(aCx, aMessage, aTransfer, clonePolicy, aError);
5912 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"
, 5912)
) {
5913 return;
5914 }
5915
5916 event->DispatchToTargetThread(aError);
5917}
5918
5919class nsCloseEvent : public Runnable {
5920 RefPtr<nsGlobalWindowOuter> mWindow;
5921 bool mIndirect;
5922
5923 nsCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect)
5924 : mozilla::Runnable("nsCloseEvent"),
5925 mWindow(aWindow),
5926 mIndirect(aIndirect) {}
5927
5928 public:
5929 static nsresult PostCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect) {
5930 nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
5931 return aWindow->Dispatch(ev.forget());
5932 }
5933
5934 NS_IMETHODvirtual nsresult Run() override {
5935 if (mWindow) {
5936 if (mIndirect) {
5937 return PostCloseEvent(mWindow, false);
5938 }
5939 mWindow->ReallyCloseWindow();
5940 }
5941 return NS_OK;
5942 }
5943};
5944
5945bool nsGlobalWindowOuter::CanClose() {
5946 if (mIsChrome) {
5947 nsCOMPtr<nsIBrowserDOMWindow> bwin = GetBrowserDOMWindow();
5948
5949 bool canClose = true;
5950 if (bwin && NS_SUCCEEDED(bwin->CanClose(&canClose))((bool)(__builtin_expect(!!(!NS_FAILED_impl(bwin->CanClose
(&canClose))), 1)))
) {
5951 return canClose;
5952 }
5953 }
5954
5955 if (!mDocShell) {
5956 return true;
5957 }
5958
5959 nsCOMPtr<nsIDocumentViewer> viewer;
5960 mDocShell->GetDocViewer(getter_AddRefs(viewer));
5961 if (viewer) {
5962 bool canClose;
5963 nsresult rv = viewer->PermitUnload(&canClose);
5964 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !canClose) return false;
5965 }
5966
5967 // If we still have to print, we delay the closing until print has happened.
5968 if (mShouldDelayPrintUntilAfterLoad && mDelayedPrintUntilAfterLoad) {
5969 mDelayedCloseForPrinting = true;
5970 return false;
5971 }
5972
5973 return true;
5974}
5975
5976void nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller) {
5977 if (!mDocShell || IsInModalState() || mBrowsingContext->IsSubframe()) {
5978 // window.close() is called on a frame in a frameset, on a window
5979 // that's already closed, or on a window for which there's
5980 // currently a modal dialog open. Ignore such calls.
5981 return;
5982 }
5983
5984 if (mHavePendingClose) {
5985 // We're going to be closed anyway; do nothing since we don't want
5986 // to double-close
5987 return;
5988 }
5989
5990 if (mBlockScriptedClosingFlag) {
5991 // A script's popup has been blocked and we don't want
5992 // the window to be closed directly after this event,
5993 // so the user can see that there was a blocked popup.
5994 return;
5995 }
5996
5997 // Don't allow scripts from content to close non-neterror windows that
5998 // were not opened by script.
5999 if (mDoc) {
6000 nsAutoString url;
6001 nsresult rv = mDoc->GetURL(url);
6002 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"
, 6002); return; } } while (false)
;
6003
6004 if (!StringBeginsWith(url, u"about:neterror"_ns) &&
6005 !mBrowsingContext->GetTopLevelCreatedByWebContent() &&
6006 !aTrustedCaller && !IsOnlyTopLevelDocumentInSHistory()) {
6007 bool allowClose =
6008 mAllowScriptsToClose ||
6009 Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
6010 if (!allowClose) {
6011 // We're blocking the close operation
6012 // report localized error msg in JS console
6013 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
6014 "DOM Window"_ns,
6015 mDoc, // Better name for the category?
6016 nsContentUtils::eDOM_PROPERTIES,
6017 "WindowCloseByScriptBlockedWarning");
6018
6019 return;
6020 }
6021 }
6022 }
6023
6024 if (!mInClose && !mIsClosed && !CanClose()) {
6025 return;
6026 }
6027
6028 // Fire a DOM event notifying listeners that this window is about to
6029 // be closed. The tab UI code may choose to cancel the default
6030 // action for this event, if so, we won't actually close the window
6031 // (since the tab UI code will close the tab in stead). Sure, this
6032 // could be abused by content code, but do we care? I don't think
6033 // so...
6034
6035 bool wasInClose = mInClose;
6036 mInClose = true;
6037
6038 if (!DispatchCustomEvent(u"DOMWindowClose"_ns, ChromeOnlyDispatch::eYes)) {
6039 // Someone chose to prevent the default action for this event, if
6040 // so, let's not close this window after all...
6041
6042 mInClose = wasInClose;
6043 return;
6044 }
6045
6046 FinalClose();
6047}
6048
6049bool nsGlobalWindowOuter::IsOnlyTopLevelDocumentInSHistory() {
6050 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"
, 6050); return false; } } while (false)
;
6051 // Disabled since IsFrame() is buggy in Fission
6052 // MOZ_ASSERT(mBrowsingContext->IsTop());
6053
6054 if (mozilla::SessionHistoryInParent()) {
6055 return mBrowsingContext->GetIsSingleToplevelInHistory();
6056 }
6057
6058 RefPtr<ChildSHistory> csh = nsDocShell::Cast(mDocShell)->GetSessionHistory();
6059 if (csh && csh->LegacySHistory()) {
6060 return csh->LegacySHistory()->IsEmptyOrHasEntriesForSingleTopLevelPage();
6061 }
6062
6063 return false;
6064}
6065
6066nsresult nsGlobalWindowOuter::Close() {
6067 CloseOuter(/* aTrustedCaller = */ true);
6068 return NS_OK;
6069}
6070
6071void nsGlobalWindowOuter::ForceClose() {
6072 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"
, 6072); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_GetProcessType() == GeckoProcessType_Default"
")"); do { *((volatile int*)__null) = 6072; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6073
6074 if (mBrowsingContext->IsSubframe() || !mDocShell) {
6075 // This may be a frame in a frameset, or a window that's already closed.
6076 // Ignore such calls.
6077 return;
6078 }
6079
6080 if (mHavePendingClose) {
6081 // We're going to be closed anyway; do nothing since we don't want
6082 // to double-close
6083 return;
6084 }
6085
6086 mInClose = true;
6087
6088 DispatchCustomEvent(u"DOMWindowClose"_ns, ChromeOnlyDispatch::eYes);
6089
6090 FinalClose();
6091}
6092
6093void nsGlobalWindowOuter::FinalClose() {
6094 // Flag that we were closed.
6095 mIsClosed = true;
6096
6097 if (!mBrowsingContext->IsDiscarded()) {
6098 MOZ_ALWAYS_SUCCEEDS(mBrowsingContext->SetClosed(true))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(mBrowsingContext->SetClosed(true))), 1)))), 1))) { } else
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(mBrowsingContext->SetClosed(true))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6098); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(mBrowsingContext->SetClosed(true))" ")"
); do { *((volatile int*)__null) = 6098; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6099 }
6100
6101 // If we get here from CloseOuter then it means that the parent process is
6102 // going to close our window for us. It's just important to set mIsClosed.
6103 if (XRE_GetProcessType() == GeckoProcessType_Content) {
6104 return;
6105 }
6106
6107 // This stuff is non-sensical but incredibly fragile. The reasons for the
6108 // behavior here don't make sense today and may not have ever made sense,
6109 // but various bits of frontend code break when you change them. If you need
6110 // to fix up this behavior, feel free to. It's a righteous task, but involves
6111 // wrestling with various download manager tests, frontend code, and possible
6112 // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
6113 // testing ground.
6114 //
6115 // In particular, if some inner of |win| is the entry global, we must
6116 // complete _two_ round-trips to the event loop before the call to
6117 // ReallyCloseWindow. This allows setTimeout handlers that are set after
6118 // FinalClose() is called to run before the window is torn down.
6119 nsCOMPtr<nsPIDOMWindowInner> entryWindow =
6120 do_QueryInterface(GetEntryGlobal());
6121 bool indirect = entryWindow && entryWindow->GetOuterWindow() == this;
6122 if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsCloseEvent::PostCloseEvent
(this, indirect))), 0)))
) {
6123 ReallyCloseWindow();
6124 } else {
6125 mHavePendingClose = true;
6126 }
6127}
6128
6129void nsGlobalWindowOuter::ReallyCloseWindow() {
6130 // Make sure we never reenter this method.
6131 mHavePendingClose = true;
6132
6133 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
6134 if (!treeOwnerAsWin) {
6135 return;
6136 }
6137
6138 treeOwnerAsWin->Destroy();
6139 CleanUp();
6140}
6141
6142void nsGlobalWindowOuter::SuppressEventHandling() {
6143 if (mSuppressEventHandlingDepth == 0) {
6144 if (BrowsingContext* bc = GetBrowsingContext()) {
6145 bc->PreOrderWalk([&](BrowsingContext* aBC) {
6146 if (nsCOMPtr<nsPIDOMWindowOuter> win = aBC->GetDOMWindow()) {
6147 if (RefPtr<Document> doc = win->GetExtantDoc()) {
6148 mSuspendedDocs.AppendElement(doc);
6149 // Note: Document::SuppressEventHandling will also automatically
6150 // suppress event handling for any in-process sub-documents.
6151 // However, since we need to deal with cases where remote
6152 // BrowsingContexts may be interleaved with in-process ones, we
6153 // still need to walk the entire tree ourselves. This may be
6154 // slightly redundant in some cases, but since event handling
6155 // suppressions maintain a count of current blockers, it does not
6156 // cause any problems.
6157 doc->SuppressEventHandling();
6158 }
6159 }
6160 });
6161 }
6162 }
6163 mSuppressEventHandlingDepth++;
6164}
6165
6166void nsGlobalWindowOuter::UnsuppressEventHandling() {
6167 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"
, 6167); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSuppressEventHandlingDepth != 0"
")"); do { *((volatile int*)__null) = 6167; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6168 mSuppressEventHandlingDepth--;
6169
6170 if (mSuppressEventHandlingDepth == 0 && mSuspendedDocs.Length()) {
6171 RefPtr<Document> currentDoc = GetExtantDoc();
6172 bool fireEvent = currentDoc == mSuspendedDocs[0];
6173 nsTArray<RefPtr<Document>> suspendedDocs = std::move(mSuspendedDocs);
6174 for (const auto& doc : suspendedDocs) {
6175 doc->UnsuppressEventHandlingAndFireEvents(fireEvent);
6176 }
6177 }
6178}
6179
6180nsGlobalWindowOuter* nsGlobalWindowOuter::EnterModalState() {
6181 // GetInProcessScriptableTop, not GetInProcessTop, so that EnterModalState
6182 // works properly with <iframe mozbrowser>.
6183 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6184
6185 if (!topWin) {
6186 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"
, 6186); MOZ_PretendNoReturn(); } while (0)
;
6187 return nullptr;
6188 }
6189
6190 // If there is an active ESM in this window, clear it. Otherwise, this can
6191 // cause a problem if a modal state is entered during a mouseup event.
6192 EventStateManager* activeESM = static_cast<EventStateManager*>(
6193 EventStateManager::GetActiveEventStateManager());
6194 if (activeESM && activeESM->GetPresContext()) {
6195 PresShell* activePresShell = activeESM->GetPresContext()->GetPresShell();
6196 if (activePresShell && (nsContentUtils::ContentIsCrossDocDescendantOf(
6197 activePresShell->GetDocument(), mDoc) ||
6198 nsContentUtils::ContentIsCrossDocDescendantOf(
6199 mDoc, activePresShell->GetDocument()))) {
6200 EventStateManager::ClearGlobalActiveContent(activeESM);
6201
6202 PresShell::ReleaseCapturingContent();
6203
6204 if (activePresShell) {
6205 RefPtr<nsFrameSelection> frameSelection =
6206 activePresShell->FrameSelection();
6207 frameSelection->SetDragState(false);
6208 }
6209 }
6210 }
6211
6212 // If there are any drag and drop operations in flight, try to end them.
6213 nsCOMPtr<nsIDragService> ds =
6214 do_GetService("@mozilla.org/widget/dragservice;1");
6215 if (ds && topWin->GetDocShell()) {
6216 if (PresShell* presShell = topWin->GetDocShell()->GetPresShell()) {
6217 if (nsViewManager* vm = presShell->GetViewManager()) {
6218 RefPtr<nsIWidget> widget = vm->GetRootWidget();
6219 if (nsCOMPtr<nsIDragSession> session = ds->GetCurrentSession(widget)) {
6220 session->EndDragSession(true, 0);
6221 }
6222 }
6223 }
6224 }
6225
6226 // Clear the capturing content if it is under topDoc.
6227 // Usually the activeESM check above does that, but there are cases when
6228 // we don't have activeESM, or it is for different document.
6229 Document* topDoc = topWin->GetExtantDoc();
6230 nsIContent* capturingContent = PresShell::GetCapturingContent();
6231 if (capturingContent && topDoc &&
6232 nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
6233 PresShell::ReleaseCapturingContent();
6234 }
6235
6236 if (topWin->mModalStateDepth == 0) {
6237 topWin->SuppressEventHandling();
6238
6239 if (nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(topWin)) {
6240 inner->Suspend();
6241 }
6242 }
6243 topWin->mModalStateDepth++;
6244 return topWin;
6245}
6246
6247void nsGlobalWindowOuter::LeaveModalState() {
6248 {
6249 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6250 if (!topWin) {
6251 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"
, 6251)
;
6252 return;
6253 }
6254
6255 if (topWin != this) {
6256 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"
, 6256); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSuspended()"
")"); do { *((volatile int*)__null) = 6256; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6257 return topWin->LeaveModalState();
6258 }
6259 }
6260
6261 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"
, 6261); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mModalStateDepth != 0"
")"); do { *((volatile int*)__null) = 6261; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6262 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"
, 6262); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSuspended()"
")"); do { *((volatile int*)__null) = 6262; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6263 mModalStateDepth--;
6264
6265 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6266 if (mModalStateDepth == 0) {
6267 if (inner) {
6268 inner->Resume();
6269 }
6270
6271 UnsuppressEventHandling();
6272 }
6273
6274 // Remember the time of the last dialog quit.
6275 if (auto* bcg = GetBrowsingContextGroup()) {
6276 bcg->SetLastDialogQuitTime(TimeStamp::Now());
6277 }
6278
6279 if (mModalStateDepth == 0) {
6280 RefPtr<Event> event = NS_NewDOMEvent(inner, nullptr, nullptr);
6281 event->InitEvent(u"endmodalstate"_ns, true, false);
6282 event->SetTrusted(true);
6283 event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
6284 DispatchEvent(*event);
6285 }
6286}
6287
6288bool nsGlobalWindowOuter::IsInModalState() {
6289 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6290
6291 if (!topWin) {
6292 // IsInModalState() getting called w/o a reachable top window is a bit
6293 // iffy, but valid enough not to make noise about it. See bug 404828
6294 return false;
6295 }
6296
6297 return topWin->mModalStateDepth != 0;
6298}
6299
6300void nsGlobalWindowOuter::NotifyWindowIDDestroyed(const char* aTopic) {
6301 nsCOMPtr<nsIRunnable> runnable =
6302 new WindowDestroyedEvent(this, mWindowID, aTopic);
6303 Dispatch(runnable.forget());
6304}
6305
6306Element* nsGlobalWindowOuter::GetFrameElement(nsIPrincipal& aSubjectPrincipal) {
6307 // Per HTML5, the frameElement getter returns null in cross-origin situations.
6308 Element* element = GetFrameElement();
6309 if (!element) {
6310 return nullptr;
6311 }
6312
6313 if (!aSubjectPrincipal.SubsumesConsideringDomain(element->NodePrincipal())) {
6314 return nullptr;
6315 }
6316
6317 return element;
6318}
6319
6320Element* nsGlobalWindowOuter::GetFrameElement() {
6321 if (!mBrowsingContext || mBrowsingContext->IsTop()) {
6322 return nullptr;
6323 }
6324 return mBrowsingContext->GetEmbedderElement();
6325}
6326
6327namespace {
6328class ChildCommandDispatcher : public Runnable {
6329 public:
6330 ChildCommandDispatcher(nsPIWindowRoot* aRoot, nsIBrowserChild* aBrowserChild,
6331 nsPIDOMWindowOuter* aWindow, const nsAString& aAction)
6332 : mozilla::Runnable("ChildCommandDispatcher"),
6333 mRoot(aRoot),
6334 mBrowserChild(aBrowserChild),
6335 mWindow(aWindow),
6336 mAction(aAction) {}
6337
6338 NS_IMETHODvirtual nsresult Run() override {
6339 AutoTArray<nsCString, 70> enabledCommands, disabledCommands;
6340 mRoot->GetEnabledDisabledCommands(enabledCommands, disabledCommands);
6341 if (enabledCommands.Length() || disabledCommands.Length()) {
6342 BrowserChild* bc = static_cast<BrowserChild*>(mBrowserChild.get());
6343 bc->SendEnableDisableCommands(mWindow->GetBrowsingContext(), mAction,
6344 enabledCommands, disabledCommands);
6345 }
6346
6347 return NS_OK;
6348 }
6349
6350 private:
6351 nsCOMPtr<nsPIWindowRoot> mRoot;
6352 nsCOMPtr<nsIBrowserChild> mBrowserChild;
6353 nsCOMPtr<nsPIDOMWindowOuter> mWindow;
6354 nsString mAction;
6355};
6356
6357class CommandDispatcher : public Runnable {
6358 public:
6359 CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
6360 const nsAString& aAction)
6361 : mozilla::Runnable("CommandDispatcher"),
6362 mDispatcher(aDispatcher),
6363 mAction(aAction) {}
6364
6365 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230, bug 1535398)
6366 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODvirtual nsresult Run() override {
6367 return mDispatcher->UpdateCommands(mAction);
6368 }
6369
6370 const nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
6371 nsString mAction;
6372};
6373} // anonymous namespace
6374
6375void nsGlobalWindowOuter::UpdateCommands(const nsAString& anAction) {
6376 // If this is a child process, redirect to the parent process.
6377 if (nsIDocShell* docShell = GetDocShell()) {
6378 if (nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild()) {
6379 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
6380 if (root) {
6381 nsContentUtils::AddScriptRunner(
6382 new ChildCommandDispatcher(root, child, this, anAction));
6383 }
6384 return;
6385 }
6386 }
6387
6388 nsPIDOMWindowOuter* rootWindow = GetPrivateRoot();
6389 if (!rootWindow) {
6390 return;
6391 }
6392
6393 Document* doc = rootWindow->GetExtantDoc();
6394
6395 if (!doc) {
6396 return;
6397 }
6398
6399 // Retrieve the command dispatcher and call updateCommands on it.
6400 nsIDOMXULCommandDispatcher* xulCommandDispatcher =
6401 doc->GetCommandDispatcher();
6402 if (xulCommandDispatcher) {
6403 nsContentUtils::AddScriptRunner(
6404 new CommandDispatcher(xulCommandDispatcher, anAction));
6405 }
6406}
6407
6408Selection* nsGlobalWindowOuter::GetSelectionOuter() {
6409 if (!mDocShell) {
6410 return nullptr;
6411 }
6412
6413 PresShell* presShell = mDocShell->GetPresShell();
6414 if (!presShell) {
6415 return nullptr;
6416 }
6417 return presShell->GetCurrentSelection(SelectionType::eNormal);
6418}
6419
6420already_AddRefed<Selection> nsGlobalWindowOuter::GetSelection() {
6421 RefPtr<Selection> selection = GetSelectionOuter();
6422 return selection.forget();
6423}
6424
6425bool nsGlobalWindowOuter::FindOuter(const nsAString& aString,
6426 bool aCaseSensitive, bool aBackwards,
6427 bool aWrapAround, bool aWholeWord,
6428 bool aSearchInFrames, bool aShowDialog,
6429 ErrorResult& aError) {
6430 Unused << aShowDialog;
6431
6432 nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
6433 if (!finder) {
6434 aError.Throw(NS_ERROR_NOT_AVAILABLE);
6435 return false;
6436 }
6437
6438 // Set the options of the search
6439 aError = finder->SetSearchString(aString);
6440 if (aError.Failed()) {
6441 return false;
6442 }
6443 finder->SetMatchCase(aCaseSensitive);
6444 finder->SetFindBackwards(aBackwards);
6445 finder->SetWrapFind(aWrapAround);
6446 finder->SetEntireWord(aWholeWord);
6447 finder->SetSearchFrames(aSearchInFrames);
6448
6449 // the nsIWebBrowserFind is initialized to use this window
6450 // as the search root, but uses focus to set the current search
6451 // frame. If we're being called from JS (as here), this window
6452 // should be the current search frame.
6453 nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
6454 if (framesFinder) {
6455 framesFinder->SetRootSearchFrame(this); // paranoia
6456 framesFinder->SetCurrentSearchFrame(this);
6457 }
6458
6459 if (aString.IsEmpty()) {
6460 return false;
6461 }
6462
6463 // Launch the search with the passed in search string
6464 bool didFind = false;
6465 aError = finder->FindNext(&didFind);
6466 return didFind;
6467}
6468
6469//*****************************************************************************
6470// EventTarget
6471//*****************************************************************************
6472
6473nsPIDOMWindowOuter* nsGlobalWindowOuter::GetOwnerGlobalForBindingsInternal() {
6474 return this;
6475}
6476
6477nsIGlobalObject* nsGlobalWindowOuter::GetOwnerGlobal() const {
6478 return GetCurrentInnerWindowInternal(this);
6479}
6480
6481bool nsGlobalWindowOuter::DispatchEvent(Event& aEvent, CallerType aCallerType,
6482 ErrorResult& aRv) {
6483 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"
, 6483); return false; } return GetCurrentInnerWindowInternal
(this)->DispatchEvent (aEvent, aCallerType, aRv); } while (
0)
;
6484}
6485
6486bool nsGlobalWindowOuter::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
6487 // It's OK that we just return false here on failure to create an
6488 // inner. GetOrCreateListenerManager() will likewise fail, and then
6489 // we won't be adding any listeners anyway.
6490 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)
;
6491}
6492
6493EventListenerManager* nsGlobalWindowOuter::GetOrCreateListenerManager() {
6494 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)
;
6495}
6496
6497EventListenerManager* nsGlobalWindowOuter::GetExistingListenerManager() const {
6498 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"
, 6498); return nullptr; } return GetCurrentInnerWindowInternal
(this)->GetExistingListenerManager (); } while (0)
;
6499}
6500
6501//*****************************************************************************
6502// nsGlobalWindowOuter::nsPIDOMWindow
6503//*****************************************************************************
6504
6505nsPIDOMWindowOuter* nsGlobalWindowOuter::GetPrivateParent() {
6506 nsCOMPtr<nsPIDOMWindowOuter> parent = GetInProcessParent();
6507
6508 if (this == parent) {
6509 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6510 if (!chromeElement)
6511 return nullptr; // This is ok, just means a null parent.
6512
6513 Document* doc = chromeElement->GetComposedDoc();
6514 if (!doc) return nullptr; // This is ok, just means a null parent.
6515
6516 return doc->GetWindow();
6517 }
6518
6519 return parent;
6520}
6521
6522nsPIDOMWindowOuter* nsGlobalWindowOuter::GetPrivateRoot() {
6523 nsCOMPtr<nsPIDOMWindowOuter> top = GetInProcessTop();
6524
6525 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6526 if (chromeElement) {
6527 Document* doc = chromeElement->GetComposedDoc();
6528 if (doc) {
6529 nsCOMPtr<nsPIDOMWindowOuter> parent = doc->GetWindow();
6530 if (parent) {
6531 top = parent->GetInProcessTop();
6532 }
6533 }
6534 }
6535
6536 return top;
6537}
6538
6539// This has a caller in Windows-only code (nsNativeAppSupportWin).
6540Location* nsGlobalWindowOuter::GetLocation() {
6541 // This method can be called on the outer window as well.
6542 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"
, 6542); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Location (); } while (0)
;
6543}
6544
6545void nsGlobalWindowOuter::SetIsBackground(bool aIsBackground) {
6546 bool changed = aIsBackground != IsBackground();
6547 SetIsBackgroundInternal(aIsBackground);
6548
6549 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6550
6551 if (inner && changed) {
6552 inner->UpdateBackgroundState();
6553 }
6554
6555 if (aIsBackground) {
6556 // Notify gamepadManager we are at the background window,
6557 // we need to stop vibrate.
6558 // Stop the vr telemery time spent when it switches to
6559 // the background window.
6560 if (inner && changed) {
6561 inner->StopGamepadHaptics();
6562 inner->StopVRActivity();
6563 // true is for asking to set the delta time to
6564 // the telemetry.
6565 inner->ResetVRTelemetry(true);
6566 }
6567 return;
6568 }
6569
6570 if (inner) {
6571 // When switching to be as a top tab, restart the telemetry.
6572 // false is for only resetting the timestamp.
6573 inner->ResetVRTelemetry(false);
6574 inner->SyncGamepadState();
6575 inner->StartVRActivity();
6576 }
6577}
6578
6579void nsGlobalWindowOuter::SetIsBackgroundInternal(bool aIsBackground) {
6580 mIsBackground = aIsBackground;
6581}
6582
6583void nsGlobalWindowOuter::SetChromeEventHandler(
6584 EventTarget* aChromeEventHandler) {
6585 SetChromeEventHandlerInternal(aChromeEventHandler);
6586 // update the chrome event handler on all our inner windows
6587 RefPtr<nsGlobalWindowInner> inner;
6588 for (PRCList* node = PR_LIST_HEAD(this)(this)->next; node != this;
6589 node = PR_NEXT_LINK(inner)((inner)->next)) {
6590 // This cast is only safe if `node != this`, as nsGlobalWindowOuter is also
6591 // in the list.
6592 inner = static_cast<nsGlobalWindowInner*>(node);
6593 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"
, 6594); MOZ_PretendNoReturn(); } } while (0)
6594 "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"
, 6594); MOZ_PretendNoReturn(); } } while (0)
;
6595 inner->SetChromeEventHandlerInternal(aChromeEventHandler);
6596 }
6597}
6598
6599void nsGlobalWindowOuter::SetFocusedElement(Element* aElement,
6600 uint32_t aFocusMethod,
6601 bool aNeedsFocus) {
6602 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"
, 6603); return; } GetCurrentInnerWindowInternal(this)->SetFocusedElement
(aElement, aFocusMethod, aNeedsFocus); return; } while (0)
6603 (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"
, 6603); return; } GetCurrentInnerWindowInternal(this)->SetFocusedElement
(aElement, aFocusMethod, aNeedsFocus); return; } while (0)
;
6604}
6605
6606uint32_t nsGlobalWindowOuter::GetFocusMethod() {
6607 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"
, 6607); return 0; } return GetCurrentInnerWindowInternal(this
)->GetFocusMethod (); } while (0)
;
6608}
6609
6610bool nsGlobalWindowOuter::ShouldShowFocusRing() {
6611 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"
, 6611); return false; } return GetCurrentInnerWindowInternal
(this)->ShouldShowFocusRing (); } while (0)
;
6612}
6613
6614bool nsGlobalWindowOuter::TakeFocus(bool aFocus, uint32_t aFocusMethod) {
6615 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"
, 6615); return false; } return GetCurrentInnerWindowInternal
(this)->TakeFocus (aFocus, aFocusMethod); } while (0)
;
6616}
6617
6618void nsGlobalWindowOuter::SetReadyForFocus() {
6619 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"
, 6619); return; } GetCurrentInnerWindowInternal(this)->SetReadyForFocus
(); return; } while (0)
;
6620}
6621
6622void nsGlobalWindowOuter::PageHidden() {
6623 FORWARD_TO_INNER_VOID(PageHidden, ())do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6623); return; } GetCurrentInnerWindowInternal(this)->PageHidden
(); return; } while (0)
;
6624}
6625
6626already_AddRefed<nsICSSDeclaration>
6627nsGlobalWindowOuter::GetComputedStyleHelperOuter(Element& aElt,
6628 const nsAString& aPseudoElt,
6629 bool aDefaultStylesOnly,
6630 ErrorResult& aRv) {
6631 if (!mDoc) {
6632 return nullptr;
6633 }
6634
6635 RefPtr<nsICSSDeclaration> compStyle = NS_NewComputedDOMStyle(
6636 &aElt, aPseudoElt, mDoc,
6637 aDefaultStylesOnly ? nsComputedDOMStyle::StyleType::DefaultOnly
6638 : nsComputedDOMStyle::StyleType::All,
6639 aRv);
6640
6641 return compStyle.forget();
6642}
6643
6644//*****************************************************************************
6645// nsGlobalWindowOuter::nsIInterfaceRequestor
6646//*****************************************************************************
6647
6648nsresult nsGlobalWindowOuter::GetInterfaceInternal(const nsIID& aIID,
6649 void** aSink) {
6650 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"
, 6650); return NS_ERROR_INVALID_POINTER; } } while (false)
;
6651 *aSink = nullptr;
6652
6653 if (aIID.Equals(NS_GET_IID(nsIWebNavigation)(nsIWebNavigation::COMTypeInfo<nsIWebNavigation, void>::
kIID)
)) {
6654 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
6655 webNav.forget(aSink);
6656 } else if (aIID.Equals(NS_GET_IID(nsIDocShell)(nsIDocShell::COMTypeInfo<nsIDocShell, void>::kIID))) {
6657 nsCOMPtr<nsIDocShell> docShell = mDocShell;
6658 docShell.forget(aSink);
6659 }
6660#ifdef NS_PRINTING1
6661 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint)(nsIWebBrowserPrint::COMTypeInfo<nsIWebBrowserPrint, void>
::kIID)
)) {
6662 if (mDocShell) {
6663 nsCOMPtr<nsIDocumentViewer> viewer;
6664 mDocShell->GetDocViewer(getter_AddRefs(viewer));
6665 if (viewer) {
6666 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
6667 webBrowserPrint.forget(aSink);
6668 }
6669 }
6670 }
6671#endif
6672 else if (aIID.Equals(NS_GET_IID(nsILoadContext)(nsILoadContext::COMTypeInfo<nsILoadContext, void>::kIID
)
)) {
6673 nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(mDocShell));
6674 loadContext.forget(aSink);
6675 }
6676
6677 return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
6678}
6679
6680NS_IMETHODIMPnsresult
6681nsGlobalWindowOuter::GetInterface(const nsIID& aIID, void** aSink) {
6682 nsresult rv = GetInterfaceInternal(aIID, aSink);
6683 if (rv == NS_ERROR_NO_INTERFACE) {
6684 return QueryInterface(aIID, aSink);
6685 }
6686 return rv;
6687}
6688
6689bool nsGlobalWindowOuter::IsSuspended() const {
6690 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"
, 6690); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6690; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6691 // No inner means we are effectively suspended
6692 if (!mInnerWindow) {
6693 return true;
6694 }
6695 return mInnerWindow->IsSuspended();
6696}
6697
6698bool nsGlobalWindowOuter::IsFrozen() const {
6699 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"
, 6699); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6699; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6700 // No inner means we are effectively frozen
6701 if (!mInnerWindow) {
6702 return true;
6703 }
6704 return mInnerWindow->IsFrozen();
6705}
6706
6707nsresult nsGlobalWindowOuter::FireDelayedDOMEvents(bool aIncludeSubWindows) {
6708 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"
, 6709); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->FireDelayedDOMEvents (aIncludeSubWindows); } while
(0)
6709 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"
, 6709); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->FireDelayedDOMEvents (aIncludeSubWindows); } while
(0)
;
6710}
6711
6712//*****************************************************************************
6713// nsGlobalWindowOuter: Window Control Functions
6714//*****************************************************************************
6715
6716nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessParentInternal() {
6717 nsCOMPtr<nsPIDOMWindowOuter> parent = GetInProcessParent();
6718
6719 if (parent && parent != this) {
6720 return parent;
6721 }
6722
6723 return nullptr;
6724}
6725
6726void nsGlobalWindowOuter::UnblockScriptedClosing() {
6727 mBlockScriptedClosingFlag = false;
6728}
6729
6730class AutoUnblockScriptClosing {
6731 private:
6732 RefPtr<nsGlobalWindowOuter> mWin;
6733
6734 public:
6735 explicit AutoUnblockScriptClosing(nsGlobalWindowOuter* aWin) : mWin(aWin) {
6736 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"
, 6736); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWin" ")");
do { *((volatile int*)__null) = 6736; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6737 }
6738 ~AutoUnblockScriptClosing() {
6739 void (nsGlobalWindowOuter::*run)() =
6740 &nsGlobalWindowOuter::UnblockScriptedClosing;
6741 nsCOMPtr<nsIRunnable> caller = NewRunnableMethod(
6742 "AutoUnblockScriptClosing::~AutoUnblockScriptClosing", mWin, run);
6743 mWin->Dispatch(caller.forget());
6744 }
6745};
6746
6747nsresult nsGlobalWindowOuter::OpenInternal(
6748 const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
6749 bool aDialog, bool aContentModal, bool aCalledNoScript, bool aDoJSFixups,
6750 bool aNavigate, nsIArray* argv, nsISupports* aExtraArgument,
6751 nsDocShellLoadState* aLoadState, bool aForceNoOpener, PrintKind aPrintKind,
6752 BrowsingContext** aReturn) {
6753#ifdef DEBUG1
6754 uint32_t argc = 0;
6755 if (argv) argv->GetLength(&argc);
1
Assuming 'argv' is null
2
Taking false branch
6756#endif
6757
6758 MOZ_ASSERT(!aExtraArgument || (!argv && argc == 0),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aExtraArgument || (!argv && argc == 0))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aExtraArgument || (!argv && argc == 0)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!aExtraArgument || (!argv && argc == 0)"
" (" "Can't pass in arguments both ways" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6759); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aExtraArgument || (!argv && argc == 0)"
") (" "Can't pass in arguments both ways" ")"); do { *((volatile
int*)__null) = 6759; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
3
Assuming 'aExtraArgument' is non-null
4
Taking false branch
5
Loop condition is false. Exiting loop
6759 "Can't pass in arguments both ways")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aExtraArgument || (!argv && argc == 0))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aExtraArgument || (!argv && argc == 0)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!aExtraArgument || (!argv && argc == 0)"
" (" "Can't pass in arguments both ways" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6759); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aExtraArgument || (!argv && argc == 0)"
") (" "Can't pass in arguments both ways" ")"); do { *((volatile
int*)__null) = 6759; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
6760 MOZ_ASSERT(!aCalledNoScript || (!argv && argc == 0),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aCalledNoScript || (!argv && argc == 0))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aCalledNoScript || (!argv && argc == 0)))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!aCalledNoScript || (!argv && argc == 0)"
" (" "Can't pass JS args when called via the noscript methods"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6761); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aCalledNoScript || (!argv && argc == 0)"
") (" "Can't pass JS args when called via the noscript methods"
")"); do { *((volatile int*)__null) = 6761; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6
Assuming 'aCalledNoScript' is true
7
Taking false branch
8
Loop condition is false. Exiting loop
6761 "Can't pass JS args when called via the noscript methods")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aCalledNoScript || (!argv && argc == 0))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aCalledNoScript || (!argv && argc == 0)))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!aCalledNoScript || (!argv && argc == 0)"
" (" "Can't pass JS args when called via the noscript methods"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6761); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aCalledNoScript || (!argv && argc == 0)"
") (" "Can't pass JS args when called via the noscript methods"
")"); do { *((volatile int*)__null) = 6761; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6762
6763 mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
6764
6765 // Calls to window.open from script should navigate.
6766 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"
, 6766); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCalledNoScript || aNavigate"
")"); do { *((volatile int*)__null) = 6766; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9
Taking false branch
10
Loop condition is false. Exiting loop
6767
6768 *aReturn = nullptr;
6769
6770 nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
6771 if (!chrome) {
11
Taking false branch
6772 // No chrome means we don't want to go through with this open call
6773 // -- see nsIWindowWatcher.idl
6774 return NS_ERROR_NOT_AVAILABLE;
6775 }
6776
6777 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"
, 6777); MOZ_PretendNoReturn(); } } while (0)
;
12
Taking false branch
13
Loop condition is false. Exiting loop
6778
6779 NS_ConvertUTF16toUTF8 optionsUtf8(aOptions);
6780
6781 WindowFeatures features;
6782 if (!features.Tokenize(optionsUtf8)) {
14
Assuming the condition is false
15
Taking false branch
6783 return NS_ERROR_FAILURE;
6784 }
6785
6786 bool forceNoOpener = aForceNoOpener;
6787 if (features.Exists("noopener")) {
16
Taking true branch
6788 forceNoOpener = features.GetBool("noopener");
6789 features.Remove("noopener");
17
Calling 'WindowFeatures::Remove'
6790 }
6791
6792 bool forceNoReferrer = false;
6793 if (features.Exists("noreferrer")) {
6794 forceNoReferrer = features.GetBool("noreferrer");
6795 if (forceNoReferrer) {
6796 // noreferrer implies noopener
6797 forceNoOpener = true;
6798 }
6799 features.Remove("noreferrer");
6800 }
6801
6802 nsAutoCString options;
6803 features.Stringify(options);
6804
6805 // If noopener is force-enabled for the current document, then set noopener to
6806 // true, and clear the name to "_blank".
6807 nsAutoString windowName(aName);
6808 if (nsDocShell::Cast(GetDocShell())->NoopenerForceEnabled()) {
6809 // FIXME: Eventually bypass force-enabling noopener if `aPrintKind !=
6810 // PrintKind::None`, so that we can print pages with noopener force-enabled.
6811 // This will require relaxing assertions elsewhere.
6812 if (aPrintKind != PrintKind::None) {
6813 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "printing frames with noopener force-enabled isn't supported yet"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6814)
6814 "printing frames with noopener force-enabled isn't supported yet")NS_DebugBreak(NS_DEBUG_WARNING, "printing frames with noopener force-enabled isn't supported yet"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6814)
;
6815 return NS_ERROR_FAILURE;
6816 }
6817
6818 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"
, 6819); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNavigate"
") (" "cannot OpenNoNavigate if noopener is force-enabled" ")"
); do { *((volatile int*)__null) = 6819; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6819 "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"
, 6819); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNavigate"
") (" "cannot OpenNoNavigate if noopener is force-enabled" ")"
); do { *((volatile int*)__null) = 6819; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6820
6821 forceNoOpener = true;
6822 windowName = u"_blank"_ns;
6823 }
6824
6825 bool windowExists = WindowExists(windowName, forceNoOpener, !aCalledNoScript);
6826
6827 // XXXbz When this gets fixed to not use LegacyIsCallerNativeCode()
6828 // (indirectly) maybe we can nix the AutoJSAPI usage OnLinkClickEvent::Run.
6829 // But note that if you change this to GetEntryGlobal(), say, then
6830 // OnLinkClickEvent::Run will need a full-blown AutoEntryScript.
6831 const bool checkForPopup =
6832 !nsContentUtils::LegacyIsCallerChromeOrNativeCode() && !aDialog &&
6833 !windowExists;
6834
6835 nsCOMPtr<nsIURI> uri;
6836
6837 // It's important to do this security check before determining whether this
6838 // window opening should be blocked, to ensure that we don't FireAbuseEvents
6839 // for a window opening that wouldn't have succeeded in the first place.
6840 if (!aUrl.IsEmpty()) {
6841 // Note: the Void handling here is very important, because the window
6842 // watcher expects a null URL string (not an empty string) if there is no
6843 // URL to load.
6844 nsCString url;
6845 url.SetIsVoid(true);
6846 AppendUTF16toUTF8(aUrl, url);
6847
6848 // It's safe to skip the security check below if we're a dialog because
6849 // window.openDialog is not callable from content script. See bug 56851.
6850 //
6851 // If we're not navigating, we assume that whoever *does* navigate the
6852 // window will do a security check of their own.
6853 if (!url.IsVoid()) {
6854 auto result =
6855 URIfromURLAndMaybeDoSecurityCheck(url, !aDialog && aNavigate);
6856 if (result.isErr()) {
6857 return result.unwrapErr();
6858 }
6859
6860 uri = result.unwrap();
6861 }
6862 } else if (mDoc) {
6863 mDoc->SetUseCounter(eUseCounter_custom_WindowOpenEmptyUrl);
6864 }
6865
6866 UserActivation::Modifiers modifiers;
6867 mBrowsingContext->GetUserActivationModifiersForPopup(&modifiers);
6868
6869 PopupBlocker::PopupControlState abuseLevel =
6870 PopupBlocker::GetPopupControlState();
6871 if (checkForPopup) {
6872 abuseLevel = mBrowsingContext->RevisePopupAbuseLevel(abuseLevel);
6873 if (abuseLevel >= PopupBlocker::openBlocked) {
6874 if (!aCalledNoScript) {
6875 // If script in some other window is doing a window.open on us and
6876 // it's being blocked, then it's OK to close us afterwards, probably.
6877 // But if we're doing a window.open on ourselves and block the popup,
6878 // prevent this window from closing until after this script terminates
6879 // so that whatever popup blocker UI the app has will be visible.
6880 nsCOMPtr<nsPIDOMWindowInner> entryWindow =
6881 do_QueryInterface(GetEntryGlobal());
6882 // Note that entryWindow can be null here if some JS component was the
6883 // place where script was entered for this JS execution.
6884 if (entryWindow && entryWindow->GetOuterWindow() == this) {
6885 mBlockScriptedClosingFlag = true;
6886 closeUnblocker.emplace(this);
6887 }
6888 }
6889
6890 FireAbuseEvents(aUrl, windowName, aOptions);
6891 return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
6892 }
6893 }
6894
6895 RefPtr<BrowsingContext> domReturn;
6896
6897 nsresult rv = NS_OK;
6898 nsCOMPtr<nsIWindowWatcher> wwatch =
6899 do_GetService(NS_WINDOWWATCHER_CONTRACTID"@mozilla.org/embedcomp/window-watcher;1", &rv);
6900 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"
, 6900); return rv; } } while (false)
;
6901
6902 NS_ConvertUTF16toUTF8 name(windowName);
6903
6904 nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
6905 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"
, 6905); return NS_ERROR_UNEXPECTED; } } while (false)
;
6906
6907 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"
, 6907); AnnotateMozCrashReason("MOZ_ASSERT" "(" "abuseLevel < PopupBlocker::openBlocked"
")"); do { *((volatile int*)__null) = 6907; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6908 // At this point we should know for a fact that if checkForPopup then
6909 // abuseLevel < PopupBlocker::openBlocked, so we could just check for
6910 // abuseLevel == PopupBlocker::openControlled. But let's be defensive just in
6911 // case and treat anything that fails the above assert as a spam popup too, if
6912 // it ever happens.
6913 bool isPopupSpamWindow =
6914 checkForPopup && (abuseLevel >= PopupBlocker::openControlled);
6915
6916 const auto wwPrintKind = [&] {
6917 switch (aPrintKind) {
6918 case PrintKind::None:
6919 return nsPIWindowWatcher::PRINT_NONE;
6920 case PrintKind::InternalPrint:
6921 return nsPIWindowWatcher::PRINT_INTERNAL;
6922 case PrintKind::WindowDotPrint:
6923 return nsPIWindowWatcher::PRINT_WINDOW_DOT_PRINT;
6924 }
6925 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"
, 6925); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Wat" ")"); do { *((volatile int*
)__null) = 6925; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6926 return nsPIWindowWatcher::PRINT_NONE;
6927 }();
6928
6929 {
6930 // Reset popup state while opening a window to prevent the
6931 // current state from being active the whole time a modal
6932 // dialog is open.
6933 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
6934
6935 if (!aCalledNoScript) {
6936 // We asserted at the top of this function that aNavigate is true for
6937 // !aCalledNoScript.
6938 rv = pwwatch->OpenWindow2(this, uri, name, options, modifiers,
6939 /* aCalledFromScript = */ true, aDialog,
6940 aNavigate, argv, isPopupSpamWindow,
6941 forceNoOpener, forceNoReferrer, wwPrintKind,
6942 aLoadState, getter_AddRefs(domReturn));
6943 } else {
6944 // Force a system caller here so that the window watcher won't screw us
6945 // up. We do NOT want this case looking at the JS context on the stack
6946 // when searching. Compare comments on
6947 // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
6948
6949 // Note: Because nsWindowWatcher is so broken, it's actually important
6950 // that we don't force a system caller here, because that screws it up
6951 // when it tries to compute the caller principal to associate with dialog
6952 // arguments. That whole setup just really needs to be rewritten. :-(
6953 Maybe<AutoNoJSAPI> nojsapi;
6954 if (!aContentModal) {
6955 nojsapi.emplace();
6956 }
6957
6958 rv = pwwatch->OpenWindow2(this, uri, name, options, modifiers,
6959 /* aCalledFromScript = */ false, aDialog,
6960 aNavigate, aExtraArgument, isPopupSpamWindow,
6961 forceNoOpener, forceNoReferrer, wwPrintKind,
6962 aLoadState, getter_AddRefs(domReturn));
6963 }
6964 }
6965
6966 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"
, 6966); return rv; } } while (false)
;
6967
6968 // success!
6969
6970 if (!aCalledNoScript && !windowExists && uri && !forceNoOpener) {
6971 MaybeAllowStorageForOpenedWindow(uri);
6972 }
6973
6974 if (domReturn && aDoJSFixups) {
6975 nsPIDOMWindowOuter* outer = domReturn->GetDOMWindow();
6976 if (outer && !nsGlobalWindowOuter::Cast(outer)->IsChromeWindow()) {
6977 // A new non-chrome window was created from a call to
6978 // window.open() from JavaScript, make sure there's a document in
6979 // the new window. We do this by simply asking the new window for
6980 // its document, this will synchronously create an empty document
6981 // if there is no document in the window.
6982 // XXXbz should this just use EnsureInnerWindow()?
6983
6984 // Force document creation.
6985 nsCOMPtr<Document> doc = outer->GetDoc();
6986 Unused << doc;
6987 }
6988 }
6989
6990 domReturn.forget(aReturn);
6991 return NS_OK;
6992}
6993
6994void nsGlobalWindowOuter::MaybeAllowStorageForOpenedWindow(nsIURI* aURI) {
6995 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6996 if (NS_WARN_IF(!inner)NS_warn_if_impl(!inner, "!inner", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6996)
) {
6997 return;
6998 }
6999
7000 // No 3rd party URL/window.
7001 if (!AntiTrackingUtils::IsThirdPartyWindow(inner, aURI)) {
7002 return;
7003 }
7004
7005 Document* doc = inner->GetDoc();
7006 if (!doc) {
7007 return;
7008 }
7009 nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateContentPrincipal(
7010 aURI, doc->NodePrincipal()->OriginAttributesRef());
7011
7012 // We don't care when the asynchronous work finishes here.
7013 // Without e10s or fission enabled this is run in the parent process.
7014 if (XRE_IsParentProcess()) {
7015 Unused << StorageAccessAPIHelper::AllowAccessForOnParentProcess(
7016 principal, GetBrowsingContext(), ContentBlockingNotifier::eOpener);
7017 } else {
7018 Unused << StorageAccessAPIHelper::AllowAccessForOnChildProcess(
7019 principal, GetBrowsingContext(), ContentBlockingNotifier::eOpener);
7020 }
7021}
7022
7023//*****************************************************************************
7024// nsGlobalWindowOuter: Helper Functions
7025//*****************************************************************************
7026
7027already_AddRefed<nsIDocShellTreeOwner> nsPIDOMWindowOuter::GetTreeOwner() {
7028 // If there's no docShellAsItem, this window must have been closed,
7029 // in that case there is no tree owner.
7030
7031 if (!mDocShell) {
7032 return nullptr;
7033 }
7034
7035 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
7036 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
7037 return treeOwner.forget();
7038}
7039
7040already_AddRefed<nsIBaseWindow> nsPIDOMWindowOuter::GetTreeOwnerWindow() {
7041 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
7042
7043 // If there's no mDocShell, this window must have been closed,
7044 // in that case there is no tree owner.
7045
7046 if (mDocShell) {
7047 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
7048 }
7049
7050 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
7051 return baseWindow.forget();
7052}
7053
7054already_AddRefed<nsIWebBrowserChrome>
7055nsPIDOMWindowOuter::GetWebBrowserChrome() {
7056 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
7057
7058 nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
7059 return browserChrome.forget();
7060}
7061
7062ScrollContainerFrame* nsGlobalWindowOuter::GetScrollContainerFrame() {
7063 if (!mDocShell) {
7064 return nullptr;
7065 }
7066
7067 PresShell* presShell = mDocShell->GetPresShell();
7068 if (presShell) {
7069 return presShell->GetRootScrollContainerFrame();
7070 }
7071 return nullptr;
7072}
7073
7074Result<already_AddRefed<nsIURI>, nsresult>
7075nsGlobalWindowOuter::URIfromURLAndMaybeDoSecurityCheck(const nsACString& aURL,
7076 bool aSecurityCheck) {
7077 nsCOMPtr<nsPIDOMWindowInner> sourceWindow =
7078 do_QueryInterface(GetEntryGlobal());
7079 if (!sourceWindow) {
7080 sourceWindow = GetCurrentInnerWindow();
7081 }
7082
7083 // Resolve the baseURI, which could be relative to the calling window.
7084 //
7085 // Note the algorithm to get the base URI should match the one
7086 // used to actually kick off the load in nsWindowWatcher.cpp.
7087 nsCOMPtr<Document> doc = sourceWindow->GetDoc();
7088 nsIURI* baseURI = nullptr;
7089 auto encoding = UTF_8_ENCODING; // default to utf-8
7090 if (doc) {
7091 baseURI = doc->GetDocBaseURI();
7092 encoding = doc->GetDocumentCharacterSet();
7093 }
7094 nsCOMPtr<nsIURI> uri;
7095 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, encoding, baseURI);
7096 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"
, 7096)
) {
7097 return Err(NS_ERROR_DOM_SYNTAX_ERR);
7098 }
7099
7100 if (aSecurityCheck) {
7101 AutoJSContext cx;
7102 nsGlobalWindowInner* sourceWin = nsGlobalWindowInner::Cast(sourceWindow);
7103 JSAutoRealm ar(cx, sourceWin->GetGlobalJSObject());
7104
7105 if (NS_FAILED(nsContentUtils::GetSecurityManager()->CheckLoadURIFromScript(((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckLoadURIFromScript( cx, uri))), 0)))
7106 cx, uri))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckLoadURIFromScript( cx, uri))), 0)))
) {
7107 return Err(NS_ERROR_FAILURE);
7108 }
7109 }
7110
7111 return uri.forget();
7112}
7113
7114void nsGlobalWindowOuter::FlushPendingNotifications(FlushType aType) {
7115 if (mDoc) {
7116 mDoc->FlushPendingNotifications(aType);
7117 }
7118}
7119
7120void nsGlobalWindowOuter::EnsureSizeAndPositionUpToDate() {
7121 // If we're a subframe, make sure our size is up to date. Make sure to go
7122 // through the document chain rather than the window chain to not flush on
7123 // detached iframes, see bug 1545516.
7124 if (mDoc && mDoc->StyleOrLayoutObservablyDependsOnParentDocumentLayout()) {
7125 RefPtr<Document> parent = mDoc->GetInProcessParentDocument();
7126 parent->FlushPendingNotifications(FlushType::Layout);
7127 }
7128}
7129
7130already_AddRefed<nsISupports> nsGlobalWindowOuter::SaveWindowState() {
7131 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"
, 7131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mozilla::SessionHistoryInParent()"
")"); do { *((volatile int*)__null) = 7131; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7132
7133 if (!mContext || !GetWrapperPreserveColor()) {
7134 // The window may be getting torn down; don't bother saving state.
7135 return nullptr;
7136 }
7137
7138 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
7139 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"
, 7139); MOZ_PretendNoReturn(); } } while (0)
;
7140
7141 if (WindowContext* wc = inner->GetWindowContext()) {
7142 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"
, 7142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wc->GetWindowStateSaved()"
")"); do { *((volatile int*)__null) = 7142; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7143 Unused << wc->SetWindowStateSaved(true);
7144 }
7145
7146 // Don't do anything else to this inner window! After this point, all
7147 // calls to SetTimeoutOrInterval will create entries in the timeout
7148 // list that will only run after this window has come out of the bfcache.
7149 // Also, while we're frozen, we won't dispatch online/offline events
7150 // to the page.
7151 inner->Freeze();
7152
7153 nsCOMPtr<nsISupports> state = new WindowStateHolder(inner);
7154
7155 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)
7156 ("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)
;
7157
7158 return state.forget();
7159}
7160
7161nsresult nsGlobalWindowOuter::RestoreWindowState(nsISupports* aState) {
7162 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"
, 7162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mozilla::SessionHistoryInParent()"
")"); do { *((volatile int*)__null) = 7162; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7163
7164 if (!mContext || !GetWrapperPreserveColor()) {
7165 // The window may be getting torn down; don't bother restoring state.
7166 return NS_OK;
7167 }
7168
7169 nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
7170 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"
, 7170); return NS_ERROR_FAILURE; } } while (false)
;
7171
7172 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)
7173 ("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)
;
7174
7175 // And we're ready to go!
7176 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
7177
7178 // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
7179 // it easy to tell which link was last clicked when going back a page.
7180 RefPtr<Element> focusedElement = inner->GetFocusedElement();
7181 if (nsContentUtils::ContentIsLink(focusedElement)) {
7182 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
7183 fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
7184 nsIFocusManager::FLAG_SHOWRING);
7185 }
7186 }
7187
7188 if (WindowContext* wc = inner->GetWindowContext()) {
7189 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"
, 7189); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wc->GetWindowStateSaved()"
")"); do { *((volatile int*)__null) = 7189; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7190 Unused << wc->SetWindowStateSaved(false);
7191 }
7192
7193 inner->Thaw();
7194
7195 holder->DidRestoreWindow();
7196
7197 return NS_OK;
7198}
7199
7200void nsGlobalWindowOuter::AddSizeOfIncludingThis(
7201 nsWindowSizes& aWindowSizes) const {
7202 aWindowSizes.mDOMSizes.mDOMOtherSize +=
7203 aWindowSizes.mState.mMallocSizeOf(this);
7204}
7205
7206uint32_t nsGlobalWindowOuter::GetAutoActivateVRDisplayID() {
7207 uint32_t retVal = mAutoActivateVRDisplayID;
7208 mAutoActivateVRDisplayID = 0;
7209 return retVal;
7210}
7211
7212void nsGlobalWindowOuter::SetAutoActivateVRDisplayID(
7213 uint32_t aAutoActivateVRDisplayID) {
7214 mAutoActivateVRDisplayID = aAutoActivateVRDisplayID;
7215}
7216
7217already_AddRefed<nsWindowRoot> nsGlobalWindowOuter::GetWindowRootOuter() {
7218 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
7219 return root.forget().downcast<nsWindowRoot>();
7220}
7221
7222nsIDOMWindowUtils* nsGlobalWindowOuter::WindowUtils() {
7223 if (!mWindowUtils) {
7224 mWindowUtils = new nsDOMWindowUtils(this);
7225 }
7226 return mWindowUtils;
7227}
7228
7229bool nsGlobalWindowOuter::IsInSyncOperation() {
7230 return GetExtantDoc() && GetExtantDoc()->IsInSyncOperation();
7231}
7232
7233// Note: This call will lock the cursor, it will not change as it moves.
7234// To unlock, the cursor must be set back to Auto.
7235void nsGlobalWindowOuter::SetCursorOuter(const nsACString& aCursor,
7236 ErrorResult& aError) {
7237 auto cursor = StyleCursorKind::Auto;
7238 if (!Servo_CursorKind_Parse(&aCursor, &cursor)) {
7239 // FIXME: It's a bit weird that this doesn't throw but stuff below does, but
7240 // matches previous behavior so...
7241 return;
7242 }
7243
7244 RefPtr<nsPresContext> presContext;
7245 if (mDocShell) {
7246 presContext = mDocShell->GetPresContext();
7247 }
7248
7249 if (presContext) {
7250 // Need root widget.
7251 PresShell* presShell = mDocShell->GetPresShell();
7252 if (!presShell) {
7253 aError.Throw(NS_ERROR_FAILURE);
7254 return;
7255 }
7256
7257 nsViewManager* vm = presShell->GetViewManager();
7258 if (!vm) {
7259 aError.Throw(NS_ERROR_FAILURE);
7260 return;
7261 }
7262
7263 nsView* rootView = vm->GetRootView();
7264 if (!rootView) {
7265 aError.Throw(NS_ERROR_FAILURE);
7266 return;
7267 }
7268
7269 nsIWidget* widget = rootView->GetNearestWidget(nullptr);
7270 if (!widget) {
7271 aError.Throw(NS_ERROR_FAILURE);
7272 return;
7273 }
7274
7275 // Call esm and set cursor.
7276 aError = presContext->EventStateManager()->SetCursor(
7277 cursor, nullptr, {}, Nothing(), widget, true);
7278 }
7279}
7280
7281nsIBrowserDOMWindow* nsGlobalWindowOuter::GetBrowserDOMWindow() {
7282 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"
, 7282); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "IsChromeWindow()"
")"); do { *((volatile int*)__null) = 7282; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7283 return mChromeFields.mBrowserDOMWindow;
7284}
7285
7286void nsGlobalWindowOuter::SetBrowserDOMWindowOuter(
7287 nsIBrowserDOMWindow* aBrowserWindow) {
7288 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"
, 7288); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsChromeWindow()"
")"); do { *((volatile int*)__null) = 7288; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7289 mChromeFields.mBrowserDOMWindow = aBrowserWindow;
7290}
7291
7292ChromeMessageBroadcaster* nsGlobalWindowOuter::GetMessageManager() {
7293 if (!mInnerWindow) {
7294 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"
, 7294)
;
7295 return nullptr;
7296 }
7297 return GetCurrentInnerWindowInternal(this)->MessageManager();
7298}
7299
7300ChromeMessageBroadcaster* nsGlobalWindowOuter::GetGroupMessageManager(
7301 const nsAString& aGroup) {
7302 if (!mInnerWindow) {
7303 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"
, 7303)
;
7304 return nullptr;
7305 }
7306 return GetCurrentInnerWindowInternal(this)->GetGroupMessageManager(aGroup);
7307}
7308
7309void nsGlobalWindowOuter::InitWasOffline() { mWasOffline = NS_IsOffline(); }
7310
7311#if defined(_WINDOWS_) && !defined(MOZ_WRAPPED_WINDOWS_H)
7312# pragma message( \
7313 "wrapper failure reason: " MOZ_WINDOWS_WRAPPER_DISABLED_REASON)
7314# error "Never include unwrapped windows.h in this file!"
7315#endif
7316
7317// Helper called by methods that move/resize the window,
7318// to ensure the presContext (if any) is aware of resolution
7319// change that may happen in multi-monitor configuration.
7320void nsGlobalWindowOuter::CheckForDPIChange() {
7321 if (mDocShell) {
7322 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
7323 if (presContext) {
7324 if (presContext->DeviceContext()->CheckDPIChange()) {
7325 presContext->UIResolutionChanged();
7326 }
7327 }
7328 }
7329}
7330
7331nsresult nsGlobalWindowOuter::Dispatch(
7332 already_AddRefed<nsIRunnable>&& aRunnable) const {
7333 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"
, 7333); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 7333; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7334 return NS_DispatchToCurrentThread(std::move(aRunnable));
7335}
7336
7337nsISerialEventTarget* nsGlobalWindowOuter::SerialEventTarget() const {
7338 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"
, 7338); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 7338; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7339 return GetMainThreadSerialEventTarget();
7340}
7341
7342void nsGlobalWindowOuter::MaybeResetWindowName(Document* aNewDocument) {
7343 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"
, 7343); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewDocument"
")"); do { *((volatile int*)__null) = 7343; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7344
7345 if (!StaticPrefs::privacy_window_name_update_enabled()) {
7346 return;
7347 }
7348
7349 const LoadingSessionHistoryInfo* info =
7350 nsDocShell::Cast(mDocShell)->GetLoadingSessionHistoryInfo();
7351 if (!info || info->mForceMaybeResetName.isNothing()) {
7352 // We only reset the window name for the top-level content as well as
7353 // storing in session entries.
7354 if (!GetBrowsingContext()->IsTopContent()) {
7355 return;
7356 }
7357
7358 // Following implements https://html.spec.whatwg.org/#history-traversal:
7359 // Step 4.2. Check if the loading document has a different origin than the
7360 // previous document.
7361
7362 // We don't need to do anything if we haven't loaded a non-initial document.
7363 if (!GetBrowsingContext()->GetHasLoadedNonInitialDocument()) {
7364 return;
7365 }
7366
7367 // If we have an existing document, directly check the document prinicpals
7368 // with the new document to know if it is cross-origin.
7369 //
7370 // Note that there will be an issue of initial document handling in Fission
7371 // when running the WPT unset_context_name-1.html. In the test, the first
7372 // about:blank page would be loaded with the principal of the testing domain
7373 // in Fission and the window.name will be set there. Then, The window.name
7374 // won't be reset after navigating to the testing page because the principal
7375 // is the same. But, it won't be the case for non-Fission mode that the
7376 // first about:blank will be loaded with a null principal and the
7377 // window.name will be reset when loading the test page.
7378 if (mDoc && mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal())) {
7379 return;
7380 }
7381
7382 // If we don't have an existing document, and if it's not the initial
7383 // about:blank, we could be loading a document because of the
7384 // process-switching. In this case, this should be a cross-origin
7385 // navigation.
7386 } else if (!info->mForceMaybeResetName.ref()) {
7387 return;
7388 }
7389
7390 // Step 4.2.2 Store the window.name into all session history entries that have
7391 // the same origin as the previous document.
7392 nsDocShell::Cast(mDocShell)->StoreWindowNameToSHEntries();
7393
7394 // Step 4.2.3 Clear the window.name if the browsing context is the top-level
7395 // content and doesn't have an opener.
7396
7397 // We need to reset the window name in case of a cross-origin navigation,
7398 // without an opener.
7399 RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext();
7400 if (opener) {
7401 return;
7402 }
7403
7404 Unused << mBrowsingContext->SetName(EmptyString());
7405}
7406
7407nsGlobalWindowOuter::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
7408 BrowsingContext* aBC) {
7409 BrowsingContextGroup* group = aBC->Group();
7410 if (!group) {
7411 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"
, 7413); MOZ_PretendNoReturn(); } while (0)
7412 "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"
, 7413); MOZ_PretendNoReturn(); } while (0)
7413 "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"
, 7413); MOZ_PretendNoReturn(); } while (0)
;
7414 return;
7415 }
7416
7417 if (group) {
7418 mGroup = group;
7419 mSavedDialogsEnabled = group->GetAreDialogsEnabled();
7420 group->SetAreDialogsEnabled(false);
7421 }
7422}
7423
7424nsGlobalWindowOuter::TemporarilyDisableDialogs::~TemporarilyDisableDialogs() {
7425 if (mGroup) {
7426 mGroup->SetAreDialogsEnabled(mSavedDialogsEnabled);
7427 }
7428}
7429
7430/* static */
7431already_AddRefed<nsGlobalWindowOuter> nsGlobalWindowOuter::Create(
7432 nsDocShell* aDocShell, bool aIsChrome) {
7433 uint64_t outerWindowID = aDocShell->GetOuterWindowID();
7434 RefPtr<nsGlobalWindowOuter> window = new nsGlobalWindowOuter(outerWindowID);
7435 if (aIsChrome) {
7436 window->mIsChrome = true;
7437 }
7438 window->SetDocShell(aDocShell);
7439
7440 window->InitWasOffline();
7441 return window.forget();
7442}
7443
7444nsIURI* nsPIDOMWindowOuter::GetDocumentURI() const {
7445 return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
7446}
7447
7448void nsPIDOMWindowOuter::MaybeCreateDoc() {
7449 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"
, 7449); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDoc" ")")
; do { *((volatile int*)__null) = 7449; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7450 if (nsIDocShell* docShell = GetDocShell()) {
7451 // Note that |document| here is the same thing as our mDoc, but we
7452 // don't have to explicitly set the member variable because the docshell
7453 // has already called SetNewDocument().
7454 nsCOMPtr<Document> document = docShell->GetDocument();
7455 Unused << document;
7456 }
7457}
7458
7459void nsPIDOMWindowOuter::SetChromeEventHandlerInternal(
7460 EventTarget* aChromeEventHandler) {
7461 // Out-of-line so we don't need to include ContentFrameMessageManager.h in
7462 // nsPIDOMWindow.h.
7463 mChromeEventHandler = aChromeEventHandler;
7464
7465 // mParentTarget and mMessageManager will be set when the next event is
7466 // dispatched or someone asks for our message manager.
7467 mParentTarget = nullptr;
7468 mMessageManager = nullptr;
7469}
7470
7471mozilla::dom::DocGroup* nsPIDOMWindowOuter::GetDocGroup() const {
7472 Document* doc = GetExtantDoc();
7473 if (doc) {
7474 return doc->GetDocGroup();
7475 }
7476 return nullptr;
7477}
7478
7479nsPIDOMWindowOuter::nsPIDOMWindowOuter(uint64_t aWindowID)
7480 : mFrameElement(nullptr),
7481 mModalStateDepth(0),
7482 mSuppressEventHandlingDepth(0),
7483 mIsBackground(false),
7484 mIsRootOuterWindow(false),
7485 mInnerWindow(nullptr),
7486 mWindowID(aWindowID),
7487 mMarkedCCGeneration(0) {}
7488
7489nsPIDOMWindowOuter::~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)
;
18
Assuming the condition is false
19
Taking false branch
20
Loop condition is false. Exiting loop
98 nsLiteralCString name(aName);
99 tokenizedFeatures_.remove(name);
21
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 // -- Status and sizing ----------------------------------------------------
184
185 // The map's current generation.
186 Generation generation() const { return mImpl.generation(); }
187
188 // Is the map empty?
189 bool empty() const { return mImpl.empty(); }
190
191 // Number of keys/values in the map.
192 uint32_t count() const { return mImpl.count(); }
193
194 // Number of key/value slots in the map. Note: resize will happen well before
195 // count() == capacity().
196 uint32_t capacity() const { return mImpl.capacity(); }
197
198 // The size of the map's entry storage, in bytes. If the keys/values contain
199 // pointers to other heap blocks, you must iterate over the map and measure
200 // them separately; hence the "shallow" prefix.
201 size_t shallowSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
202 return mImpl.shallowSizeOfExcludingThis(aMallocSizeOf);
203 }
204 size_t shallowSizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
205 return aMallocSizeOf(this) +
206 mImpl.shallowSizeOfExcludingThis(aMallocSizeOf);
207 }
208
209 // Attempt to minimize the capacity(). If the table is empty, this will free
210 // the empty storage and upon regrowth it will be given the minimum capacity.
211 void compact() { mImpl.compact(); }
212
213 // Attempt to reserve enough space to fit at least |aLen| elements. This is
214 // total capacity, including elements already present. Does nothing if the
215 // map already has sufficient capacity.
216 [[nodiscard]] bool reserve(uint32_t aLen) { return mImpl.reserve(aLen); }
217
218 // -- Lookups --------------------------------------------------------------
219
220 // Does the map contain a key/value matching |aLookup|?
221 bool has(const Lookup& aLookup) const {
222 return mImpl.lookup(aLookup).found();
223 }
224
225 // Return a Ptr indicating whether a key/value matching |aLookup| is
226 // present in the map. E.g.:
227 //
228 // using HM = HashMap<int,char>;
229 // HM h;
230 // if (HM::Ptr p = h.lookup(3)) {
231 // assert(p->key() == 3);
232 // char val = p->value();
233 // }
234 //
235 using Ptr = typename Impl::Ptr;
236 MOZ_ALWAYS_INLINEinline Ptr lookup(const Lookup& aLookup) const {
237 return mImpl.lookup(aLookup);
23
Calling 'HashTable::lookup'
33
Returning from 'HashTable::lookup'
238 }
239
240 // Like lookup(), but does not assert if two threads call it at the same
241 // time. Only use this method when none of the threads will modify the map.
242 MOZ_ALWAYS_INLINEinline Ptr readonlyThreadsafeLookup(const Lookup& aLookup) const {
243 return mImpl.readonlyThreadsafeLookup(aLookup);
244 }
245
246 // -- Insertions -----------------------------------------------------------
247
248 // Overwrite existing value with |aValue|, or add it if not present. Returns
249 // false on OOM.
250 template <typename KeyInput, typename ValueInput>
251 [[nodiscard]] bool put(KeyInput&& aKey, ValueInput&& aValue) {
252 return put(aKey, std::forward<KeyInput>(aKey),
253 std::forward<ValueInput>(aValue));
254 }
255
256 template <typename KeyInput, typename ValueInput>
257 [[nodiscard]] bool put(const Lookup& aLookup, KeyInput&& aKey,
258 ValueInput&& aValue) {
259 AddPtr p = lookupForAdd(aLookup);
260 if (p) {
261 p->value() = std::forward<ValueInput>(aValue);
262 return true;
263 }
264 return add(p, std::forward<KeyInput>(aKey),
265 std::forward<ValueInput>(aValue));
266 }
267
268 // Like put(), but slightly faster. Must only be used when the given key is
269 // not already present. (In debug builds, assertions check this.)
270 template <typename KeyInput, typename ValueInput>
271 [[nodiscard]] bool putNew(KeyInput&& aKey, ValueInput&& aValue) {
272 return mImpl.putNew(aKey, std::forward<KeyInput>(aKey),
273 std::forward<ValueInput>(aValue));
274 }
275
276 template <typename KeyInput, typename ValueInput>
277 [[nodiscard]] bool putNew(const Lookup& aLookup, KeyInput&& aKey,
278 ValueInput&& aValue) {
279 return mImpl.putNew(aLookup, std::forward<KeyInput>(aKey),
280 std::forward<ValueInput>(aValue));
281 }
282
283 // Like putNew(), but should be only used when the table is known to be big
284 // enough for the insertion, and hashing cannot fail. Typically this is used
285 // to populate an empty map with known-unique keys after reserving space with
286 // reserve(), e.g.
287 //
288 // using HM = HashMap<int,char>;
289 // HM h;
290 // if (!h.reserve(3)) {
291 // MOZ_CRASH("OOM");
292 // }
293 // h.putNewInfallible(1, 'a'); // unique key
294 // h.putNewInfallible(2, 'b'); // unique key
295 // h.putNewInfallible(3, 'c'); // unique key
296 //
297 template <typename KeyInput, typename ValueInput>
298 void putNewInfallible(KeyInput&& aKey, ValueInput&& aValue) {
299 mImpl.putNewInfallible(aKey, std::forward<KeyInput>(aKey),
300 std::forward<ValueInput>(aValue));
301 }
302
303 // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient
304 // insertion of Key |k| (where |HashPolicy::match(k,l) == true|) using
305 // |add(p,k,v)|. After |add(p,k,v)|, |p| points to the new key/value. E.g.:
306 //
307 // using HM = HashMap<int,char>;
308 // HM h;
309 // HM::AddPtr p = h.lookupForAdd(3);
310 // if (!p) {
311 // if (!h.add(p, 3, 'a')) {
312 // return false;
313 // }
314 // }
315 // assert(p->key() == 3);
316 // char val = p->value();
317 //
318 // N.B. The caller must ensure that no mutating hash table operations occur
319 // between a pair of lookupForAdd() and add() calls. To avoid looking up the
320 // key a second time, the caller may use the more efficient relookupOrAdd()
321 // method. This method reuses part of the hashing computation to more
322 // efficiently insert the key if it has not been added. For example, a
323 // mutation-handling version of the previous example:
324 //
325 // HM::AddPtr p = h.lookupForAdd(3);
326 // if (!p) {
327 // call_that_may_mutate_h();
328 // if (!h.relookupOrAdd(p, 3, 'a')) {
329 // return false;
330 // }
331 // }
332 // assert(p->key() == 3);
333 // char val = p->value();
334 //
335 using AddPtr = typename Impl::AddPtr;
336 MOZ_ALWAYS_INLINEinline AddPtr lookupForAdd(const Lookup& aLookup) {
337 return mImpl.lookupForAdd(aLookup);
338 }
339
340 // Add a key/value. Returns false on OOM.
341 template <typename KeyInput, typename ValueInput>
342 [[nodiscard]] bool add(AddPtr& aPtr, KeyInput&& aKey, ValueInput&& aValue) {
343 return mImpl.add(aPtr, std::forward<KeyInput>(aKey),
344 std::forward<ValueInput>(aValue));
345 }
346
347 // See the comment above lookupForAdd() for details.
348 template <typename KeyInput, typename ValueInput>
349 [[nodiscard]] bool relookupOrAdd(AddPtr& aPtr, KeyInput&& aKey,
350 ValueInput&& aValue) {
351 return mImpl.relookupOrAdd(aPtr, aKey, std::forward<KeyInput>(aKey),
352 std::forward<ValueInput>(aValue));
353 }
354
355 // -- Removal --------------------------------------------------------------
356
357 // Lookup and remove the key/value matching |aLookup|, if present.
358 void remove(const Lookup& aLookup) {
359 if (Ptr p = lookup(aLookup)) {
22
Calling 'HashMap::lookup'
34
Returning from 'HashMap::lookup'
35
'p' initialized here
36
Assuming the condition is true
37
Taking true branch
360 remove(p);
38
Value assigned to 'aPtr'
39
Null pointer value stored to 'aPtr.mSlot.mKeyHash'
40
Calling 'HashMap::remove'
361 }
362 }
363
364 // Remove a previously found key/value (assuming aPtr.found()). The map must
365 // not have been mutated in the interim.
366 void remove(Ptr aPtr) { mImpl.remove(aPtr); }
41
Null pointer value stored to 'aPtr.mSlot.mKeyHash'
42
Calling 'HashTable::remove'
367
368 // Remove all keys/values without changing the capacity.
369 void clear() { mImpl.clear(); }
370
371 // Like clear() followed by compact().
372 void clearAndCompact() { mImpl.clearAndCompact(); }
373
374 // -- Rekeying -------------------------------------------------------------
375
376 // Infallibly rekey one entry, if necessary. Requires that template
377 // parameters Key and HashPolicy::Lookup are the same type.
378 void rekeyIfMoved(const Key& aOldKey, const Key& aNewKey) {
379 if (aOldKey != aNewKey) {
380 rekeyAs(aOldKey, aNewKey, aNewKey);
381 }
382 }
383
384 // Infallibly rekey one entry if present, and return whether that happened.
385 bool rekeyAs(const Lookup& aOldLookup, const Lookup& aNewLookup,
386 const Key& aNewKey) {
387 if (Ptr p = lookup(aOldLookup)) {
388 mImpl.rekeyAndMaybeRehash(p, aNewLookup, aNewKey);
389 return true;
390 }
391 return false;
392 }
393
394 // -- Iteration ------------------------------------------------------------
395
396 // |iter()| returns an Iterator:
397 //
398 // HashMap<int, char> h;
399 // for (auto iter = h.iter(); !iter.done(); iter.next()) {
400 // char c = iter.get().value();
401 // }
402 //
403 using Iterator = typename Impl::Iterator;
404 Iterator iter() const { return mImpl.iter(); }
405
406 // |modIter()| returns a ModIterator:
407 //
408 // HashMap<int, char> h;
409 // for (auto iter = h.modIter(); !iter.done(); iter.next()) {
410 // if (iter.get().value() == 'l') {
411 // iter.remove();
412 // }
413 // }
414 //
415 // Table resize may occur in ModIterator's destructor.
416 using ModIterator = typename Impl::ModIterator;
417 ModIterator modIter() { return mImpl.modIter(); }
418
419 // These are similar to Iterator/ModIterator/iter(), but use different
420 // terminology.
421 using Range = typename Impl::Range;
422 using Enum = typename Impl::Enum;
423 Range all() const { return mImpl.all(); }
424};
425
426//---------------------------------------------------------------------------
427// HashSet
428//---------------------------------------------------------------------------
429
430// HashSet is a fast hash-based set of values.
431//
432// Template parameter requirements:
433// - T: movable, destructible, assignable.
434// - HashPolicy: see the "Hash Policy" section below.
435// - AllocPolicy: see AllocPolicy.h
436//
437// Note:
438// - HashSet is not reentrant: T/HashPolicy/AllocPolicy members called by
439// HashSet must not call back into the same HashSet object.
440//
441template <class T, class HashPolicy = DefaultHasher<T>,
442 class AllocPolicy = MallocAllocPolicy>
443class HashSet {
444 // -- Implementation details -----------------------------------------------
445
446 // HashSet is not copyable or assignable.
447 HashSet(const HashSet& hs) = delete;
448 HashSet& operator=(const HashSet& hs) = delete;
449
450 struct SetHashPolicy : HashPolicy {
451 using Base = HashPolicy;
452 using KeyType = T;
453
454 static const KeyType& getKey(const T& aT) { return aT; }
455
456 static void setKey(T& aT, KeyType& aKey) { HashPolicy::rekey(aT, aKey); }
457 };
458
459 using Impl = detail::HashTable<const T, SetHashPolicy, AllocPolicy>;
460 Impl mImpl;
461
462 friend class Impl::Enum;
463
464 public:
465 using Lookup = typename HashPolicy::Lookup;
466 using Entry = T;
467
468 // -- Initialization -------------------------------------------------------
469
470 explicit HashSet(AllocPolicy aAllocPolicy = AllocPolicy(),
471 uint32_t aLen = Impl::sDefaultLen)
472 : mImpl(std::move(aAllocPolicy), aLen) {}
473
474 explicit HashSet(uint32_t aLen) : mImpl(AllocPolicy(), aLen) {}
475
476 // HashSet is movable.
477 HashSet(HashSet&& aRhs) = default;
478 HashSet& operator=(HashSet&& aRhs) = default;
479
480 // -- Status and sizing ----------------------------------------------------
481
482 // The set's current generation.
483 Generation generation() const { return mImpl.generation(); }
484
485 // Is the set empty?
486 bool empty() const { return mImpl.empty(); }
487
488 // Number of elements in the set.
489 uint32_t count() const { return mImpl.count(); }
490
491 // Number of element slots in the set. Note: resize will happen well before
492 // count() == capacity().
493 uint32_t capacity() const { return mImpl.capacity(); }
494
495 // The size of the set's entry storage, in bytes. If the elements contain
496 // pointers to other heap blocks, you must iterate over the set and measure
497 // them separately; hence the "shallow" prefix.
498 size_t shallowSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
499 return mImpl.shallowSizeOfExcludingThis(aMallocSizeOf);
500 }
501 size_t shallowSizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
502 return aMallocSizeOf(this) +
503 mImpl.shallowSizeOfExcludingThis(aMallocSizeOf);
504 }
505
506 // Attempt to minimize the capacity(). If the table is empty, this will free
507 // the empty storage and upon regrowth it will be given the minimum capacity.
508 void compact() { mImpl.compact(); }
509
510 // Attempt to reserve enough space to fit at least |aLen| elements. This is
511 // total capacity, including elements already present. Does nothing if the
512 // map already has sufficient capacity.
513 [[nodiscard]] bool reserve(uint32_t aLen) { return mImpl.reserve(aLen); }
514
515 // -- Lookups --------------------------------------------------------------
516
517 // Does the set contain an element matching |aLookup|?
518 bool has(const Lookup& aLookup) const {
519 return mImpl.lookup(aLookup).found();
520 }
521
522 // Return a Ptr indicating whether an element matching |aLookup| is present
523 // in the set. E.g.:
524 //
525 // using HS = HashSet<int>;
526 // HS h;
527 // if (HS::Ptr p = h.lookup(3)) {
528 // assert(*p == 3); // p acts like a pointer to int
529 // }
530 //
531 using Ptr = typename Impl::Ptr;
532 MOZ_ALWAYS_INLINEinline Ptr lookup(const Lookup& aLookup) const {
533 return mImpl.lookup(aLookup);
534 }
535
536 // Like lookup(), but does not assert if two threads call it at the same
537 // time. Only use this method when none of the threads will modify the set.
538 MOZ_ALWAYS_INLINEinline Ptr readonlyThreadsafeLookup(const Lookup& aLookup) const {
539 return mImpl.readonlyThreadsafeLookup(aLookup);
540 }
541
542 // -- Insertions -----------------------------------------------------------
543
544 // Add |aU| if it is not present already. Returns false on OOM.
545 template <typename U>
546 [[nodiscard]] bool put(U&& aU) {
547 AddPtr p = lookupForAdd(aU);
548 return p ? true : add(p, std::forward<U>(aU));
549 }
550
551 // Like put(), but slightly faster. Must only be used when the given element
552 // is not already present. (In debug builds, assertions check this.)
553 template <typename U>
554 [[nodiscard]] bool putNew(U&& aU) {
555 return mImpl.putNew(aU, std::forward<U>(aU));
556 }
557
558 // Like the other putNew(), but for when |Lookup| is different to |T|.
559 template <typename U>
560 [[nodiscard]] bool putNew(const Lookup& aLookup, U&& aU) {
561 return mImpl.putNew(aLookup, std::forward<U>(aU));
562 }
563
564 // Like putNew(), but should be only used when the table is known to be big
565 // enough for the insertion, and hashing cannot fail. Typically this is used
566 // to populate an empty set with known-unique elements after reserving space
567 // with reserve(), e.g.
568 //
569 // using HS = HashMap<int>;
570 // HS h;
571 // if (!h.reserve(3)) {
572 // MOZ_CRASH("OOM");
573 // }
574 // h.putNewInfallible(1); // unique element
575 // h.putNewInfallible(2); // unique element
576 // h.putNewInfallible(3); // unique element
577 //
578 template <typename U>
579 void putNewInfallible(const Lookup& aLookup, U&& aU) {
580 mImpl.putNewInfallible(aLookup, std::forward<U>(aU));
581 }
582
583 // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient
584 // insertion of T value |t| (where |HashPolicy::match(t,l) == true|) using
585 // |add(p,t)|. After |add(p,t)|, |p| points to the new element. E.g.:
586 //
587 // using HS = HashSet<int>;
588 // HS h;
589 // HS::AddPtr p = h.lookupForAdd(3);
590 // if (!p) {
591 // if (!h.add(p, 3)) {
592 // return false;
593 // }
594 // }
595 // assert(*p == 3); // p acts like a pointer to int
596 //
597 // N.B. The caller must ensure that no mutating hash table operations occur
598 // between a pair of lookupForAdd() and add() calls. To avoid looking up the
599 // key a second time, the caller may use the more efficient relookupOrAdd()
600 // method. This method reuses part of the hashing computation to more
601 // efficiently insert the key if it has not been added. For example, a
602 // mutation-handling version of the previous example:
603 //
604 // HS::AddPtr p = h.lookupForAdd(3);
605 // if (!p) {
606 // call_that_may_mutate_h();
607 // if (!h.relookupOrAdd(p, 3, 3)) {
608 // return false;
609 // }
610 // }
611 // assert(*p == 3);
612 //
613 // Note that relookupOrAdd(p,l,t) performs Lookup using |l| and adds the
614 // entry |t|, where the caller ensures match(l,t).
615 using AddPtr = typename Impl::AddPtr;
616 MOZ_ALWAYS_INLINEinline AddPtr lookupForAdd(const Lookup& aLookup) {
617 return mImpl.lookupForAdd(aLookup);
618 }
619
620 // Add an element. Returns false on OOM.
621 template <typename U>
622 [[nodiscard]] bool add(AddPtr& aPtr, U&& aU) {
623 return mImpl.add(aPtr, std::forward<U>(aU));
624 }
625
626 // See the comment above lookupForAdd() for details.
627 template <typename U>
628 [[nodiscard]] bool relookupOrAdd(AddPtr& aPtr, const Lookup& aLookup,
629 U&& aU) {
630 return mImpl.relookupOrAdd(aPtr, aLookup, std::forward<U>(aU));
631 }
632
633 // -- Removal --------------------------------------------------------------
634
635 // Lookup and remove the element matching |aLookup|, if present.
636 void remove(const Lookup& aLookup) {
637 if (Ptr p = lookup(aLookup)) {
638 remove(p);
639 }
640 }
641
642 // Remove a previously found element (assuming aPtr.found()). The set must
643 // not have been mutated in the interim.
644 void remove(Ptr aPtr) { mImpl.remove(aPtr); }
645
646 // Remove all keys/values without changing the capacity.
647 void clear() { mImpl.clear(); }
648
649 // Like clear() followed by compact().
650 void clearAndCompact() { mImpl.clearAndCompact(); }
651
652 // -- Rekeying -------------------------------------------------------------
653
654 // Infallibly rekey one entry, if present. Requires that template parameters
655 // T and HashPolicy::Lookup are the same type.
656 void rekeyIfMoved(const Lookup& aOldValue, const T& aNewValue) {
657 if (aOldValue != aNewValue) {
658 rekeyAs(aOldValue, aNewValue, aNewValue);
659 }
660 }
661
662 // Infallibly rekey one entry if present, and return whether that happened.
663 bool rekeyAs(const Lookup& aOldLookup, const Lookup& aNewLookup,
664 const T& aNewValue) {
665 if (Ptr p = lookup(aOldLookup)) {
666 mImpl.rekeyAndMaybeRehash(p, aNewLookup, aNewValue);
667 return true;
668 }
669 return false;
670 }
671
672 // Infallibly replace the current key at |aPtr| with an equivalent key.
673 // Specifically, both HashPolicy::hash and HashPolicy::match must return
674 // identical results for the new and old key when applied against all
675 // possible matching values.
676 void replaceKey(Ptr aPtr, const Lookup& aLookup, const T& aNewValue) {
677 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"
, 677); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.found()"
")"); do { *((volatile int*)__null) = 677; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
678 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"
, 678); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aPtr != aNewValue"
")"); do { *((volatile int*)__null) = 678; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
679 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"
, 679); AnnotateMozCrashReason("MOZ_ASSERT" "(" "HashPolicy::match(*aPtr, aLookup)"
")"); do { *((volatile int*)__null) = 679; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
680 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"
, 680); AnnotateMozCrashReason("MOZ_ASSERT" "(" "HashPolicy::match(aNewValue, aLookup)"
")"); do { *((volatile int*)__null) = 680; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
681 const_cast<T&>(*aPtr) = aNewValue;
682 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"
, 682); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*lookup(aLookup) == aNewValue"
")"); do { *((volatile int*)__null) = 682; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
683 }
684 void replaceKey(Ptr aPtr, const T& aNewValue) {
685 replaceKey(aPtr, aNewValue, aNewValue);
686 }
687
688 // -- Iteration ------------------------------------------------------------
689
690 // |iter()| returns an Iterator:
691 //
692 // HashSet<int> h;
693 // for (auto iter = h.iter(); !iter.done(); iter.next()) {
694 // int i = iter.get();
695 // }
696 //
697 using Iterator = typename Impl::Iterator;
698 Iterator iter() const { return mImpl.iter(); }
699
700 // |modIter()| returns a ModIterator:
701 //
702 // HashSet<int> h;
703 // for (auto iter = h.modIter(); !iter.done(); iter.next()) {
704 // if (iter.get() == 42) {
705 // iter.remove();
706 // }
707 // }
708 //
709 // Table resize may occur in ModIterator's destructor.
710 using ModIterator = typename Impl::ModIterator;
711 ModIterator modIter() { return mImpl.modIter(); }
712
713 // These are similar to Iterator/ModIterator/iter(), but use different
714 // terminology.
715 using Range = typename Impl::Range;
716 using Enum = typename Impl::Enum;
717 Range all() const { return mImpl.all(); }
718};
719
720//---------------------------------------------------------------------------
721// Hash Policy
722//---------------------------------------------------------------------------
723
724// A hash policy |HP| for a hash table with key-type |Key| must provide:
725//
726// - a type |HP::Lookup| to use to lookup table entries;
727//
728// - a static member function |HP::hash| that hashes lookup values:
729//
730// static mozilla::HashNumber hash(const Lookup&);
731//
732// - a static member function |HP::match| that tests equality of key and
733// lookup values:
734//
735// static bool match(const Key& aKey, const Lookup& aLookup);
736//
737// |aKey| and |aLookup| can have different hash numbers, only when a
738// collision happens with |prepareHash| operation, which is less frequent.
739// Thus, |HP::match| shouldn't assume the hash equality in the comparison,
740// even if the hash numbers are almost always same between them.
741//
742// Normally, Lookup = Key. In general, though, different values and types of
743// values can be used to lookup and store. If a Lookup value |l| is not equal
744// to the added Key value |k|, the user must ensure that |HP::match(k,l)| is
745// true. E.g.:
746//
747// mozilla::HashSet<Key, HP>::AddPtr p = h.lookup(l);
748// if (!p) {
749// assert(HP::match(k, l)); // must hold
750// h.add(p, k);
751// }
752
753// A pointer hashing policy that uses HashGeneric() to create good hashes for
754// pointers. Note that we don't shift out the lowest k bits because we don't
755// want to assume anything about the alignment of the pointers.
756template <typename Key>
757struct PointerHasher {
758 using Lookup = Key;
759
760 static HashNumber hash(const Lookup& aLookup) { return HashGeneric(aLookup); }
761
762 static bool match(const Key& aKey, const Lookup& aLookup) {
763 return aKey == aLookup;
764 }
765
766 static void rekey(Key& aKey, const Key& aNewKey) { aKey = aNewKey; }
767};
768
769// The default hash policy, which only works with integers.
770template <class Key, typename>
771struct DefaultHasher {
772 using Lookup = Key;
773
774 static HashNumber hash(const Lookup& aLookup) {
775 // Just convert the integer to a HashNumber and use that as is. (This
776 // discards the high 32-bits of 64-bit integers!) ScrambleHashCode() is
777 // subsequently called on the value to improve the distribution.
778 return aLookup;
779 }
780
781 static bool match(const Key& aKey, const Lookup& aLookup) {
782 // Use builtin or overloaded operator==.
783 return aKey == aLookup;
784 }
785
786 static void rekey(Key& aKey, const Key& aNewKey) { aKey = aNewKey; }
787};
788
789// A DefaultHasher specialization for enums.
790template <class T>
791struct DefaultHasher<T, std::enable_if_t<std::is_enum_v<T>>> {
792 using Key = T;
793 using Lookup = Key;
794
795 static HashNumber hash(const Lookup& aLookup) { return HashGeneric(aLookup); }
796
797 static bool match(const Key& aKey, const Lookup& aLookup) {
798 // Use builtin or overloaded operator==.
799 return aKey == static_cast<Key>(aLookup);
800 }
801
802 static void rekey(Key& aKey, const Key& aNewKey) { aKey = aNewKey; }
803};
804
805// A DefaultHasher specialization for pointers.
806template <class T>
807struct DefaultHasher<T*> : PointerHasher<T*> {};
808
809// A DefaultHasher specialization for mozilla::UniquePtr.
810template <class T, class D>
811struct DefaultHasher<UniquePtr<T, D>> {
812 using Key = UniquePtr<T, D>;
813 using Lookup = Key;
814 using PtrHasher = PointerHasher<T*>;
815
816 static HashNumber hash(const Lookup& aLookup) {
817 return PtrHasher::hash(aLookup.get());
818 }
819
820 static bool match(const Key& aKey, const Lookup& aLookup) {
821 return PtrHasher::match(aKey.get(), aLookup.get());
822 }
823
824 static void rekey(UniquePtr<T, D>& aKey, UniquePtr<T, D>&& aNewKey) {
825 aKey = std::move(aNewKey);
826 }
827};
828
829// A DefaultHasher specialization for doubles.
830template <>
831struct DefaultHasher<double> {
832 using Key = double;
833 using Lookup = Key;
834
835 static HashNumber hash(const Lookup& aLookup) {
836 // Just xor the high bits with the low bits, and then treat the bits of the
837 // result as a uint32_t.
838 static_assert(sizeof(HashNumber) == 4,
839 "subsequent code assumes a four-byte hash");
840 uint64_t u = BitwiseCast<uint64_t>(aLookup);
841 return HashNumber(u ^ (u >> 32));
842 }
843
844 static bool match(const Key& aKey, const Lookup& aLookup) {
845 return BitwiseCast<uint64_t>(aKey) == BitwiseCast<uint64_t>(aLookup);
846 }
847};
848
849// A DefaultHasher specialization for floats.
850template <>
851struct DefaultHasher<float> {
852 using Key = float;
853 using Lookup = Key;
854
855 static HashNumber hash(const Lookup& aLookup) {
856 // Just use the value as if its bits form an integer. ScrambleHashCode() is
857 // subsequently called on the value to improve the distribution.
858 static_assert(sizeof(HashNumber) == 4,
859 "subsequent code assumes a four-byte hash");
860 return HashNumber(BitwiseCast<uint32_t>(aLookup));
861 }
862
863 static bool match(const Key& aKey, const Lookup& aLookup) {
864 return BitwiseCast<uint32_t>(aKey) == BitwiseCast<uint32_t>(aLookup);
865 }
866};
867
868// A hash policy for C strings.
869struct CStringHasher {
870 using Key = const char*;
871 using Lookup = const char*;
872
873 static HashNumber hash(const Lookup& aLookup) { return HashString(aLookup); }
874
875 static bool match(const Key& aKey, const Lookup& aLookup) {
876 return strcmp(aKey, aLookup) == 0;
877 }
878};
879
880//---------------------------------------------------------------------------
881// Fallible Hashing Interface
882//---------------------------------------------------------------------------
883
884// Most of the time generating a hash code is infallible, but sometimes it is
885// necessary to generate hash codes on demand in a way that can fail. Specialize
886// this class for your own hash policy to provide fallible hashing.
887//
888// This is used by MovableCellHasher to handle the fact that generating a unique
889// ID for cell pointer may fail due to OOM.
890//
891// The default implementations of these methods delegate to the usual HashPolicy
892// implementation and always succeed.
893template <typename HashPolicy>
894struct FallibleHashMethods {
895 // Return true if a hashcode is already available for its argument, and
896 // sets |aHashOut|. Once this succeeds for a specific argument it
897 // must continue to do so.
898 //
899 // Return false if a hashcode is not already available. This implies that any
900 // lookup must fail, as the hash code would have to have been successfully
901 // created on insertion.
902 template <typename Lookup>
903 static bool maybeGetHash(Lookup&& aLookup, HashNumber* aHashOut) {
904 *aHashOut = HashPolicy::hash(aLookup);
905 return true;
906 }
907
908 // Fallible method to ensure a hashcode exists for its argument and create one
909 // if not. Sets |aHashOut| to the hashcode and retuns true on success. Returns
910 // false on error, e.g. out of memory.
911 template <typename Lookup>
912 static bool ensureHash(Lookup&& aLookup, HashNumber* aHashOut) {
913 *aHashOut = HashPolicy::hash(aLookup);
914 return true;
915 }
916};
917
918template <typename HashPolicy, typename Lookup>
919static bool MaybeGetHash(Lookup&& aLookup, HashNumber* aHashOut) {
920 return FallibleHashMethods<typename HashPolicy::Base>::maybeGetHash(
921 std::forward<Lookup>(aLookup), aHashOut);
922}
923
924template <typename HashPolicy, typename Lookup>
925static bool EnsureHash(Lookup&& aLookup, HashNumber* aHashOut) {
926 return FallibleHashMethods<typename HashPolicy::Base>::ensureHash(
927 std::forward<Lookup>(aLookup), aHashOut);
928}
929
930//---------------------------------------------------------------------------
931// Implementation Details (HashMapEntry, HashTableEntry, HashTable)
932//---------------------------------------------------------------------------
933
934// Both HashMap and HashSet are implemented by a single HashTable that is even
935// more heavily parameterized than the other two. This leaves HashTable gnarly
936// and extremely coupled to HashMap and HashSet; thus code should not use
937// HashTable directly.
938
939template <class Key, class Value>
940class HashMapEntry {
941 Key key_;
942 Value value_;
943
944 template <class, class, class>
945 friend class detail::HashTable;
946 template <class>
947 friend class detail::HashTableEntry;
948 template <class, class, class, class>
949 friend class HashMap;
950
951 public:
952 template <typename KeyInput, typename ValueInput>
953 HashMapEntry(KeyInput&& aKey, ValueInput&& aValue)
954 : key_(std::forward<KeyInput>(aKey)),
955 value_(std::forward<ValueInput>(aValue)) {}
956
957 HashMapEntry(HashMapEntry&& aRhs) = default;
958 HashMapEntry& operator=(HashMapEntry&& aRhs) = default;
959
960 using KeyType = Key;
961 using ValueType = Value;
962
963 const Key& key() const { return key_; }
964
965 // Use this method with caution! If the key is changed such that its hash
966 // value also changes, the map will be left in an invalid state.
967 Key& mutableKey() { return key_; }
968
969 const Value& value() const { return value_; }
970 Value& value() { return value_; }
971
972 private:
973 HashMapEntry(const HashMapEntry&) = delete;
974 void operator=(const HashMapEntry&) = delete;
975};
976
977namespace detail {
978
979template <class T, class HashPolicy, class AllocPolicy>
980class HashTable;
981
982template <typename T>
983class EntrySlot;
984
985template <typename T>
986class HashTableEntry {
987 private:
988 using NonConstT = std::remove_const_t<T>;
989
990 // Instead of having a hash table entry store that looks like this:
991 //
992 // +--------+--------+--------+--------+
993 // | entry0 | entry1 | .... | entryN |
994 // +--------+--------+--------+--------+
995 //
996 // where the entries contained their cached hash code, we're going to lay out
997 // the entry store thusly:
998 //
999 // +-------+-------+-------+-------+--------+--------+--------+--------+
1000 // | hash0 | hash1 | ... | hashN | entry0 | entry1 | .... | entryN |
1001 // +-------+-------+-------+-------+--------+--------+--------+--------+
1002 //
1003 // with all the cached hashes prior to the actual entries themselves.
1004 //
1005 // We do this because implementing the first strategy requires us to make
1006 // HashTableEntry look roughly like:
1007 //
1008 // template <typename T>
1009 // class HashTableEntry {
1010 // HashNumber mKeyHash;
1011 // T mValue;
1012 // };
1013 //
1014 // The problem with this setup is that, depending on the layout of `T`, there
1015 // may be platform ABI-mandated padding between `mKeyHash` and the first
1016 // member of `T`. This ABI-mandated padding is wasted space, and can be
1017 // surprisingly common, e.g. when `T` is a single pointer on 64-bit platforms.
1018 // In such cases, we're throwing away a quarter of our entry store on padding,
1019 // which is undesirable.
1020 //
1021 // The second layout above, namely:
1022 //
1023 // +-------+-------+-------+-------+--------+--------+--------+--------+
1024 // | hash0 | hash1 | ... | hashN | entry0 | entry1 | .... | entryN |
1025 // +-------+-------+-------+-------+--------+--------+--------+--------+
1026 //
1027 // means there is no wasted space between the hashes themselves, and no wasted
1028 // space between the entries themselves. However, we would also like there to
1029 // be no gap between the last hash and the first entry. The memory allocator
1030 // guarantees the alignment of the start of the hashes. The use of a
1031 // power-of-two capacity of at least 4 guarantees that the alignment of the
1032 // *end* of the hash array is no less than the alignment of the start.
1033 // Finally, the static_asserts here guarantee that the entries themselves
1034 // don't need to be any more aligned than the alignment of the entry store
1035 // itself.
1036 //
1037 // This assertion is safe for 32-bit builds because on both Windows and Linux
1038 // (including Android), the minimum alignment for allocations larger than 8
1039 // bytes is 8 bytes, and the actual data for entries in our entry store is
1040 // guaranteed to have that alignment as well, thanks to the power-of-two
1041 // number of cached hash values stored prior to the entry data.
1042
1043 // The allocation policy must allocate a table with at least this much
1044 // alignment.
1045 static constexpr size_t kMinimumAlignment = 8;
1046
1047 static_assert(alignof(HashNumber) <= kMinimumAlignment,
1048 "[N*2 hashes, N*2 T values] allocation's alignment must be "
1049 "enough to align each hash");
1050 static_assert(alignof(NonConstT) <= 2 * sizeof(HashNumber),
1051 "subsequent N*2 T values must not require more than an even "
1052 "number of HashNumbers provides");
1053
1054 static const HashNumber sFreeKey = 0;
1055 static const HashNumber sRemovedKey = 1;
1056 static const HashNumber sCollisionBit = 1;
1057
1058 alignas(NonConstT) unsigned char mValueData[sizeof(NonConstT)];
1059
1060 private:
1061 template <class, class, class>
1062 friend class HashTable;
1063 template <typename>
1064 friend class EntrySlot;
1065
1066 // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
1067 // -Werror compile error) to reinterpret_cast<> |mValueData| to |T*|, even
1068 // through |void*|. Placing the latter cast in these separate functions
1069 // breaks the chain such that affected GCC versions no longer warn/error.
1070 void* rawValuePtr() { return mValueData; }
1071
1072 static bool isLiveHash(HashNumber hash) { return hash > sRemovedKey; }
1073
1074 HashTableEntry(const HashTableEntry&) = delete;
1075 void operator=(const HashTableEntry&) = delete;
1076
1077 NonConstT* valuePtr() { return reinterpret_cast<NonConstT*>(rawValuePtr()); }
1078
1079 void destroyStoredT() {
1080 NonConstT* ptr = valuePtr();
1081 ptr->~T();
1082 MOZ_MAKE_MEM_UNDEFINED(ptr, sizeof(*ptr))do { } while (0);
1083 }
1084
1085 public:
1086 HashTableEntry() = default;
1087
1088 ~HashTableEntry() { MOZ_MAKE_MEM_UNDEFINED(this, sizeof(*this))do { } while (0); }
1089
1090 void destroy() { destroyStoredT(); }
1091
1092 void swap(HashTableEntry* aOther, bool aIsLive) {
1093 // This allows types to use Argument-Dependent-Lookup, and thus use a custom
1094 // std::swap, which is needed by types like JS::Heap and such.
1095 using std::swap;
1096
1097 if (this == aOther) {
1098 return;
1099 }
1100 if (aIsLive) {
1101 swap(*valuePtr(), *aOther->valuePtr());
1102 } else {
1103 *aOther->valuePtr() = std::move(*valuePtr());
1104 destroy();
1105 }
1106 }
1107
1108 T& get() { return *valuePtr(); }
1109
1110 NonConstT& getMutable() { return *valuePtr(); }
1111};
1112
1113// A slot represents a cached hash value and its associated entry stored
1114// in the hash table. These two things are not stored in contiguous memory.
1115template <class T>
1116class EntrySlot {
1117 using NonConstT = std::remove_const_t<T>;
1118
1119 using Entry = HashTableEntry<T>;
1120
1121 Entry* mEntry;
1122 HashNumber* mKeyHash;
1123
1124 template <class, class, class>
1125 friend class HashTable;
1126
1127 EntrySlot(Entry* aEntry, HashNumber* aKeyHash)
1128 : mEntry(aEntry), mKeyHash(aKeyHash) {}
29
Null pointer value stored to 'p.mSlot.mKeyHash'
1129
1130 public:
1131 static bool isLiveHash(HashNumber hash) { return hash > Entry::sRemovedKey; }
1132
1133 EntrySlot(const EntrySlot&) = default;
1134 EntrySlot(EntrySlot&& aOther) = default;
1135
1136 EntrySlot& operator=(const EntrySlot&) = default;
1137 EntrySlot& operator=(EntrySlot&&) = default;
1138
1139 bool operator==(const EntrySlot& aRhs) const { return mEntry == aRhs.mEntry; }
1140
1141 bool operator<(const EntrySlot& aRhs) const { return mEntry < aRhs.mEntry; }
1142
1143 EntrySlot& operator++() {
1144 ++mEntry;
1145 ++mKeyHash;
1146 return *this;
1147 }
1148
1149 void destroy() { mEntry->destroy(); }
1150
1151 void swap(EntrySlot& aOther) {
1152 mEntry->swap(aOther.mEntry, aOther.isLive());
1153 std::swap(*mKeyHash, *aOther.mKeyHash);
1154 }
1155
1156 T& get() const { return mEntry->get(); }
1157
1158 NonConstT& getMutable() { return mEntry->getMutable(); }
1159
1160 bool isFree() const { return *mKeyHash == Entry::sFreeKey; }
1161
1162 void clearLive() {
1163 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"
, 1163); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLive()" ")"
); do { *((volatile int*)__null) = 1163; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1164 *mKeyHash = Entry::sFreeKey;
1165 mEntry->destroyStoredT();
1166 }
1167
1168 void clear() {
1169 if (isLive()) {
1170 mEntry->destroyStoredT();
1171 }
1172 MOZ_MAKE_MEM_UNDEFINED(mEntry, sizeof(*mEntry))do { } while (0);
1173 *mKeyHash = Entry::sFreeKey;
1174 }
1175
1176 bool isRemoved() const { return *mKeyHash == Entry::sRemovedKey; }
1177
1178 void removeLive() {
1179 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"
, 1179); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLive()" ")"
); do { *((volatile int*)__null) = 1179; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1180 *mKeyHash = Entry::sRemovedKey;
1181 mEntry->destroyStoredT();
1182 }
1183
1184 bool isLive() const { return isLiveHash(*mKeyHash); }
1185
1186 void setCollision() {
1187 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"
, 1187); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLive()" ")"
); do { *((volatile int*)__null) = 1187; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1188 *mKeyHash |= Entry::sCollisionBit;
1189 }
1190 void unsetCollision() { *mKeyHash &= ~Entry::sCollisionBit; }
1191 bool hasCollision() const { return *mKeyHash & Entry::sCollisionBit; }
55
Dereference of null pointer (loaded from field 'mKeyHash')
1192 bool matchHash(HashNumber hn) {
1193 return (*mKeyHash & ~Entry::sCollisionBit) == hn;
1194 }
1195 HashNumber getKeyHash() const { return *mKeyHash & ~Entry::sCollisionBit; }
1196
1197 template <typename... Args>
1198 void setLive(HashNumber aHashNumber, Args&&... aArgs) {
1199 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"
, 1199); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isLive()" ")"
); do { *((volatile int*)__null) = 1199; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1200 *mKeyHash = aHashNumber;
1201 new (KnownNotNull, mEntry->valuePtr()) T(std::forward<Args>(aArgs)...);
1202 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"
, 1202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLive()" ")"
); do { *((volatile int*)__null) = 1202; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1203 }
1204
1205 Entry* toEntry() const { return mEntry; }
1206};
1207
1208template <class T, class HashPolicy, class AllocPolicy>
1209class HashTable : private AllocPolicy {
1210 friend class mozilla::ReentrancyGuard;
1211
1212 using NonConstT = std::remove_const_t<T>;
1213 using Key = typename HashPolicy::KeyType;
1214 using Lookup = typename HashPolicy::Lookup;
1215
1216 public:
1217 using Entry = HashTableEntry<T>;
1218 using Slot = EntrySlot<T>;
1219
1220 template <typename F>
1221 static void forEachSlot(char* aTable, uint32_t aCapacity, F&& f) {
1222 auto hashes = reinterpret_cast<HashNumber*>(aTable);
1223 auto entries = reinterpret_cast<Entry*>(&hashes[aCapacity]);
1224 Slot slot(entries, hashes);
1225 for (size_t i = 0; i < size_t(aCapacity); ++i) {
1226 f(slot);
1227 ++slot;
1228 }
1229 }
1230
1231 // A nullable pointer to a hash table element. A Ptr |p| can be tested
1232 // either explicitly |if (p.found()) p->...| or using boolean conversion
1233 // |if (p) p->...|. Ptr objects must not be used after any mutating hash
1234 // table operations unless |generation()| is tested.
1235 class Ptr {
1236 friend class HashTable;
1237
1238 Slot mSlot;
1239#ifdef DEBUG1
1240 const HashTable* mTable;
1241 Generation mGeneration;
1242#endif
1243
1244 protected:
1245 Ptr(Slot aSlot, const HashTable& aTable)
1246 : mSlot(aSlot)
1247#ifdef DEBUG1
1248 ,
1249 mTable(&aTable),
1250 mGeneration(aTable.generation())
1251#endif
1252 {
1253 }
1254
1255 // This constructor is used only by AddPtr() within lookupForAdd().
1256 explicit Ptr(const HashTable& aTable)
1257 : mSlot(nullptr, nullptr)
1258#ifdef DEBUG1
1259 ,
1260 mTable(&aTable),
1261 mGeneration(aTable.generation())
1262#endif
1263 {
1264 }
1265
1266 bool isValid() const { return !!mSlot.toEntry(); }
1267
1268 public:
1269 Ptr()
1270 : mSlot(nullptr, nullptr)
27
Passing null pointer value via 2nd parameter 'aKeyHash'
28
Calling constructor for 'EntrySlot<mozilla::HashMapEntry<nsTString<char>, nsTString<char>>>'
30
Returning from constructor for 'EntrySlot<mozilla::HashMapEntry<nsTString<char>, nsTString<char>>>'
1271#ifdef DEBUG1
1272 ,
1273 mTable(nullptr),
1274 mGeneration(0)
1275#endif
1276 {
1277 }
1278
1279 bool found() const {
1280 if (!isValid()) {
1281 return false;
1282 }
1283#ifdef DEBUG1
1284 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"
, 1284); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable->generation()"
")"); do { *((volatile int*)__null) = 1284; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1285#endif
1286 return mSlot.isLive();
1287 }
1288
1289 explicit operator bool() const { return found(); }
1290
1291 bool operator==(const Ptr& aRhs) const {
1292 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"
, 1292); AnnotateMozCrashReason("MOZ_ASSERT" "(" "found() && aRhs.found()"
")"); do { *((volatile int*)__null) = 1292; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1293 return mSlot == aRhs.mSlot;
1294 }
1295
1296 bool operator!=(const Ptr& aRhs) const {
1297#ifdef DEBUG1
1298 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"
, 1298); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable->generation()"
")"); do { *((volatile int*)__null) = 1298; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1299#endif
1300 return !(*this == aRhs);
1301 }
1302
1303 T& operator*() const {
1304#ifdef DEBUG1
1305 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"
, 1305); AnnotateMozCrashReason("MOZ_ASSERT" "(" "found()" ")"
); do { *((volatile int*)__null) = 1305; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1306 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"
, 1306); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable->generation()"
")"); do { *((volatile int*)__null) = 1306; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1307#endif
1308 return mSlot.get();
1309 }
1310
1311 T* operator->() const {
1312#ifdef DEBUG1
1313 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"
, 1313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "found()" ")"
); do { *((volatile int*)__null) = 1313; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1314 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"
, 1314); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable->generation()"
")"); do { *((volatile int*)__null) = 1314; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1315#endif
1316 return &mSlot.get();
1317 }
1318 };
1319
1320 // A Ptr that can be used to add a key after a failed lookup.
1321 class AddPtr : public Ptr {
1322 friend class HashTable;
1323
1324 HashNumber mKeyHash;
1325#ifdef DEBUG1
1326 uint64_t mMutationCount;
1327#endif
1328
1329 AddPtr(Slot aSlot, const HashTable& aTable, HashNumber aHashNumber)
1330 : Ptr(aSlot, aTable),
1331 mKeyHash(aHashNumber)
1332#ifdef DEBUG1
1333 ,
1334 mMutationCount(aTable.mMutationCount)
1335#endif
1336 {
1337 }
1338
1339 // This constructor is used when lookupForAdd() is performed on a table
1340 // lacking entry storage; it leaves mSlot null but initializes everything
1341 // else.
1342 AddPtr(const HashTable& aTable, HashNumber aHashNumber)
1343 : Ptr(aTable),
1344 mKeyHash(aHashNumber)
1345#ifdef DEBUG1
1346 ,
1347 mMutationCount(aTable.mMutationCount)
1348#endif
1349 {
1350 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"
, 1350); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLive()" ")"
); do { *((volatile int*)__null) = 1350; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1351 }
1352
1353 bool isLive() const { return isLiveHash(mKeyHash); }
1354
1355 public:
1356 AddPtr() : mKeyHash(0) {}
1357 };
1358
1359 // A hash table iterator that (mostly) doesn't allow table modifications.
1360 // As with Ptr/AddPtr, Iterator objects must not be used after any mutating
1361 // hash table operation unless the |generation()| is tested.
1362 class Iterator {
1363 void moveToNextLiveEntry() {
1364 while (++mCur < mEnd && !mCur.isLive()) {
1365 continue;
1366 }
1367 }
1368
1369 protected:
1370 friend class HashTable;
1371
1372 explicit Iterator(const HashTable& aTable)
1373 : mCur(aTable.slotForIndex(0)),
1374 mEnd(aTable.slotForIndex(aTable.capacity()))
1375#ifdef DEBUG1
1376 ,
1377 mTable(aTable),
1378 mMutationCount(aTable.mMutationCount),
1379 mGeneration(aTable.generation()),
1380 mValidEntry(true)
1381#endif
1382 {
1383 if (!done() && !mCur.isLive()) {
1384 moveToNextLiveEntry();
1385 }
1386 }
1387
1388 Slot mCur;
1389 Slot mEnd;
1390#ifdef DEBUG1
1391 const HashTable& mTable;
1392 uint64_t mMutationCount;
1393 Generation mGeneration;
1394 bool mValidEntry;
1395#endif
1396
1397 public:
1398 bool done() const {
1399 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"
, 1399); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable.generation()"
")"); do { *((volatile int*)__null) = 1399; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1400 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"
, 1400); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMutationCount == mTable.mMutationCount"
")"); do { *((volatile int*)__null) = 1400; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1401 return mCur == mEnd;
1402 }
1403
1404 T& get() const {
1405 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"
, 1405); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!done()" ")"
); do { *((volatile int*)__null) = 1405; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1406 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"
, 1406); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mValidEntry"
")"); do { *((volatile int*)__null) = 1406; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1407 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"
, 1407); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable.generation()"
")"); do { *((volatile int*)__null) = 1407; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1408 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"
, 1408); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMutationCount == mTable.mMutationCount"
")"); do { *((volatile int*)__null) = 1408; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1409 return mCur.get();
1410 }
1411
1412 void next() {
1413 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"
, 1413); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!done()" ")"
); do { *((volatile int*)__null) = 1413; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1414 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"
, 1414); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGeneration == mTable.generation()"
")"); do { *((volatile int*)__null) = 1414; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1415 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"
, 1415); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMutationCount == mTable.mMutationCount"
")"); do { *((volatile int*)__null) = 1415; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1416 moveToNextLiveEntry();
1417#ifdef DEBUG1
1418 mValidEntry = true;
1419#endif
1420 }
1421 };
1422
1423 // A hash table iterator that permits modification, removal and rekeying.
1424 // Since rehashing when elements were removed during enumeration would be
1425 // bad, it is postponed until the ModIterator is destructed. Since the
1426 // ModIterator's destructor touches the hash table, the user must ensure
1427 // that the hash table is still alive when the destructor runs.
1428 class ModIterator : public Iterator {
1429 friend class HashTable;
1430
1431 HashTable& mTable;
1432 bool mRekeyed;
1433 bool mRemoved;
1434
1435 // ModIterator is movable but not copyable.
1436 ModIterator(const ModIterator&) = delete;
1437 void operator=(const ModIterator&) = delete;
1438
1439 protected:
1440 explicit ModIterator(HashTable& aTable)
1441 : Iterator(aTable), mTable(aTable), mRekeyed(false), mRemoved(false) {}
1442
1443 public:
1444 MOZ_IMPLICIT ModIterator(ModIterator&& aOther)
1445 : Iterator(aOther),
1446 mTable(aOther.mTable),
1447 mRekeyed(aOther.mRekeyed),
1448 mRemoved(aOther.mRemoved) {
1449 aOther.mRekeyed = false;
1450 aOther.mRemoved = false;
1451 }
1452
1453 // Removes the current element from the table, leaving |get()|
1454 // invalid until the next call to |next()|.
1455 void remove() {
1456 mTable.remove(this->mCur);
1457 mRemoved = true;
1458#ifdef DEBUG1
1459 this->mValidEntry = false;
1460 this->mMutationCount = mTable.mMutationCount;
1461#endif
1462 }
1463
1464 NonConstT& getMutable() {
1465 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"
, 1465); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!this->done()"
")"); do { *((volatile int*)__null) = 1465; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1466 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"
, 1466); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this->mValidEntry"
")"); do { *((volatile int*)__null) = 1466; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1467 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"
, 1467); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this->mGeneration == this->Iterator::mTable.generation()"
")"); do { *((volatile int*)__null) = 1467; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1468 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"
, 1468); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this->mMutationCount == this->Iterator::mTable.mMutationCount"
")"); do { *((volatile int*)__null) = 1468; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1469 return this->mCur.getMutable();
1470 }
1471
1472 // Removes the current element and re-inserts it into the table with
1473 // a new key at the new Lookup position. |get()| is invalid after
1474 // this operation until the next call to |next()|.
1475 void rekey(const Lookup& l, const Key& k) {
1476 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"
, 1476); AnnotateMozCrashReason("MOZ_ASSERT" "(" "&k != &HashPolicy::getKey(this->mCur.get())"
")"); do { *((volatile int*)__null) = 1476; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1477 Ptr p(this->mCur, mTable);
1478 mTable.rekeyWithoutRehash(p, l, k);
1479 mRekeyed = true;
1480#ifdef DEBUG1
1481 this->mValidEntry = false;
1482 this->mMutationCount = mTable.mMutationCount;
1483#endif
1484 }
1485
1486 void rekey(const Key& k) { rekey(k, k); }
1487
1488 // Potentially rehashes the table.
1489 ~ModIterator() {
1490 if (mRekeyed) {
1491 mTable.mGen++;
1492 mTable.infallibleRehashIfOverloaded();
1493 }
1494
1495 if (mRemoved) {
1496 mTable.compact();
1497 }
1498 }
1499 };
1500
1501 // Range is similar to Iterator, but uses different terminology.
1502 class Range {
1503 friend class HashTable;
1504
1505 Iterator mIter;
1506
1507 protected:
1508 explicit Range(const HashTable& table) : mIter(table) {}
1509
1510 public:
1511 bool empty() const { return mIter.done(); }
1512
1513 T& front() const { return mIter.get(); }
1514
1515 void popFront() { return mIter.next(); }
1516 };
1517
1518 // Enum is similar to ModIterator, but uses different terminology.
1519 class Enum {
1520 ModIterator mIter;
1521
1522 // Enum is movable but not copyable.
1523 Enum(const Enum&) = delete;
1524 void operator=(const Enum&) = delete;
1525
1526 public:
1527 template <class Map>
1528 explicit Enum(Map& map) : mIter(map.mImpl) {}
1529
1530 MOZ_IMPLICIT Enum(Enum&& other) : mIter(std::move(other.mIter)) {}
1531
1532 bool empty() const { return mIter.done(); }
1533
1534 T& front() const { return mIter.get(); }
1535
1536 void popFront() { return mIter.next(); }
1537
1538 void removeFront() { mIter.remove(); }
1539
1540 NonConstT& mutableFront() { return mIter.getMutable(); }
1541
1542 void rekeyFront(const Lookup& aLookup, const Key& aKey) {
1543 mIter.rekey(aLookup, aKey);
1544 }
1545
1546 void rekeyFront(const Key& aKey) { mIter.rekey(aKey); }
1547 };
1548
1549 // HashTable is movable
1550 HashTable(HashTable&& aRhs) : AllocPolicy(std::move(aRhs)) { moveFrom(aRhs); }
1551 HashTable& operator=(HashTable&& aRhs) {
1552 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"
, 1552); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this != &aRhs"
") (" "self-move assignment is prohibited" ")"); do { *((volatile
int*)__null) = 1552; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1553 if (mTable) {
1554 destroyTable(*this, mTable, capacity());
1555 }
1556 AllocPolicy::operator=(std::move(aRhs));
1557 moveFrom(aRhs);
1558 return *this;
1559 }
1560
1561 private:
1562 void moveFrom(HashTable& aRhs) {
1563 mGen = aRhs.mGen;
1564 mHashShift = aRhs.mHashShift;
1565 mTable = aRhs.mTable;
1566 mEntryCount = aRhs.mEntryCount;
1567 mRemovedCount = aRhs.mRemovedCount;
1568#ifdef DEBUG1
1569 mMutationCount = aRhs.mMutationCount;
1570 mEntered = aRhs.mEntered;
1571#endif
1572 aRhs.mTable = nullptr;
1573 aRhs.clearAndCompact();
1574 }
1575
1576 // HashTable is not copyable or assignable
1577 HashTable(const HashTable&) = delete;
1578 void operator=(const HashTable&) = delete;
1579
1580 static const uint32_t CAP_BITS = 30;
1581
1582 public:
1583 uint64_t mGen : 56; // entry storage generation number
1584 uint64_t mHashShift : 8; // multiplicative hash shift
1585 char* mTable; // entry storage
1586 uint32_t mEntryCount; // number of entries in mTable
1587 uint32_t mRemovedCount; // removed entry sentinels in mTable
1588
1589#ifdef DEBUG1
1590 uint64_t mMutationCount;
1591 mutable bool mEntered;
1592#endif
1593
1594 // The default initial capacity is 32 (enough to hold 16 elements), but it
1595 // can be as low as 4.
1596 static const uint32_t sDefaultLen = 16;
1597 static const uint32_t sMinCapacity = 4;
1598 // See the comments in HashTableEntry about this value.
1599 static_assert(sMinCapacity >= 4, "too-small sMinCapacity breaks assumptions");
1600 static const uint32_t sMaxInit = 1u << (CAP_BITS - 1);
1601 static const uint32_t sMaxCapacity = 1u << CAP_BITS;
1602
1603 // Hash-table alpha is conceptually a fraction, but to avoid floating-point
1604 // math we implement it as a ratio of integers.
1605 static const uint8_t sAlphaDenominator = 4;
1606 static const uint8_t sMinAlphaNumerator = 1; // min alpha: 1/4
1607 static const uint8_t sMaxAlphaNumerator = 3; // max alpha: 3/4
1608
1609 static const HashNumber sFreeKey = Entry::sFreeKey;
1610 static const HashNumber sRemovedKey = Entry::sRemovedKey;
1611 static const HashNumber sCollisionBit = Entry::sCollisionBit;
1612
1613 static uint32_t bestCapacity(uint32_t aLen) {
1614 static_assert(
1615 (sMaxInit * sAlphaDenominator) / sAlphaDenominator == sMaxInit,
1616 "multiplication in numerator below could overflow");
1617 static_assert(
1618 sMaxInit * sAlphaDenominator <= UINT32_MAX(4294967295U) - sMaxAlphaNumerator,
1619 "numerator calculation below could potentially overflow");
1620
1621 // Callers should ensure this is true.
1622 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"
, 1622); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLen <= sMaxInit"
")"); do { *((volatile int*)__null) = 1622; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1623
1624 // Compute the smallest capacity allowing |aLen| elements to be
1625 // inserted without rehashing: ceil(aLen / max-alpha). (Ceiling
1626 // integral division: <http://stackoverflow.com/a/2745086>.)
1627 uint32_t capacity = (aLen * sAlphaDenominator + sMaxAlphaNumerator - 1) /
1628 sMaxAlphaNumerator;
1629 capacity = (capacity < sMinCapacity) ? sMinCapacity : RoundUpPow2(capacity);
1630
1631 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"
, 1631); AnnotateMozCrashReason("MOZ_ASSERT" "(" "capacity >= aLen"
")"); do { *((volatile int*)__null) = 1631; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1632 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"
, 1632); AnnotateMozCrashReason("MOZ_ASSERT" "(" "capacity <= sMaxCapacity"
")"); do { *((volatile int*)__null) = 1632; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1633
1634 return capacity;
1635 }
1636
1637 static uint32_t hashShift(uint32_t aLen) {
1638 // Reject all lengths whose initial computed capacity would exceed
1639 // sMaxCapacity. Round that maximum aLen down to the nearest power of two
1640 // for speedier code.
1641 if (MOZ_UNLIKELY(aLen > sMaxInit)(__builtin_expect(!!(aLen > sMaxInit), 0))) {
1642 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"
, 1642); AnnotateMozCrashReason("MOZ_CRASH(" "initial length is too large"
")"); do { *((volatile int*)__null) = 1642; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1643 }
1644
1645 return kHashNumberBits - mozilla::CeilingLog2(bestCapacity(aLen));
1646 }
1647
1648 static bool isLiveHash(HashNumber aHash) { return Entry::isLiveHash(aHash); }
1649
1650 static HashNumber prepareHash(HashNumber aInputHash) {
1651 HashNumber keyHash = ScrambleHashCode(aInputHash);
1652
1653 // Avoid reserved hash codes.
1654 if (!isLiveHash(keyHash)) {
1655 keyHash -= (sRemovedKey + 1);
1656 }
1657 return keyHash & ~sCollisionBit;
1658 }
1659
1660 enum FailureBehavior { DontReportFailure = false, ReportFailure = true };
1661
1662 // Fake a struct that we're going to alloc. See the comments in
1663 // HashTableEntry about how the table is laid out, and why it's safe.
1664 struct FakeSlot {
1665 unsigned char c[sizeof(HashNumber) + sizeof(typename Entry::NonConstT)];
1666 };
1667
1668 static char* createTable(AllocPolicy& aAllocPolicy, uint32_t aCapacity,
1669 FailureBehavior aReportFailure = ReportFailure) {
1670 FakeSlot* fake =
1671 aReportFailure
1672 ? aAllocPolicy.template pod_malloc<FakeSlot>(aCapacity)
1673 : aAllocPolicy.template maybe_pod_malloc<FakeSlot>(aCapacity);
1674
1675 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"
, 1676); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(reinterpret_cast<uintptr_t>(fake) % Entry::kMinimumAlignment) == 0"
")"); do { *((volatile int*)__null) = 1676; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1676 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"
, 1676); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(reinterpret_cast<uintptr_t>(fake) % Entry::kMinimumAlignment) == 0"
")"); do { *((volatile int*)__null) = 1676; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1677
1678 char* table = reinterpret_cast<char*>(fake);
1679 if (table) {
1680 forEachSlot(table, aCapacity, [&](Slot& slot) {
1681 *slot.mKeyHash = sFreeKey;
1682 new (KnownNotNull, slot.toEntry()) Entry();
1683 });
1684 }
1685 return table;
1686 }
1687
1688 static void destroyTable(AllocPolicy& aAllocPolicy, char* aOldTable,
1689 uint32_t aCapacity) {
1690 forEachSlot(aOldTable, aCapacity, [&](const Slot& slot) {
1691 if (slot.isLive()) {
1692 slot.toEntry()->destroyStoredT();
1693 }
1694 });
1695 freeTable(aAllocPolicy, aOldTable, aCapacity);
1696 }
1697
1698 static void freeTable(AllocPolicy& aAllocPolicy, char* aOldTable,
1699 uint32_t aCapacity) {
1700 FakeSlot* fake = reinterpret_cast<FakeSlot*>(aOldTable);
1701 aAllocPolicy.free_(fake, aCapacity);
1702 }
1703
1704 public:
1705 HashTable(AllocPolicy aAllocPolicy, uint32_t aLen)
1706 : AllocPolicy(std::move(aAllocPolicy)),
1707 mGen(0),
1708 mHashShift(hashShift(aLen)),
1709 mTable(nullptr),
1710 mEntryCount(0),
1711 mRemovedCount(0)
1712#ifdef DEBUG1
1713 ,
1714 mMutationCount(0),
1715 mEntered(false)
1716#endif
1717 {
1718 }
1719
1720 explicit HashTable(AllocPolicy aAllocPolicy)
1721 : HashTable(aAllocPolicy, sDefaultLen) {}
1722
1723 ~HashTable() {
1724 if (mTable) {
1725 destroyTable(*this, mTable, capacity());
1726 }
1727 }
1728
1729 private:
1730 HashNumber hash1(HashNumber aHash0) const { return aHash0 >> mHashShift; }
1731
1732 struct DoubleHash {
1733 HashNumber mHash2;
1734 HashNumber mSizeMask;
1735 };
1736
1737 DoubleHash hash2(HashNumber aCurKeyHash) const {
1738 uint32_t sizeLog2 = kHashNumberBits - mHashShift;
1739 DoubleHash dh = {((aCurKeyHash << sizeLog2) >> mHashShift) | 1,
1740 (HashNumber(1) << sizeLog2) - 1};
1741 return dh;
1742 }
1743
1744 static HashNumber applyDoubleHash(HashNumber aHash1,
1745 const DoubleHash& aDoubleHash) {
1746 return WrappingSubtract(aHash1, aDoubleHash.mHash2) & aDoubleHash.mSizeMask;
1747 }
1748
1749 static MOZ_ALWAYS_INLINEinline bool match(T& aEntry, const Lookup& aLookup) {
1750 return HashPolicy::match(HashPolicy::getKey(aEntry), aLookup);
1751 }
1752
1753 enum LookupReason { ForNonAdd, ForAdd };
1754
1755 Slot slotForIndex(HashNumber aIndex) const {
1756 auto hashes = reinterpret_cast<HashNumber*>(mTable);
1757 auto entries = reinterpret_cast<Entry*>(&hashes[capacity()]);
1758 return Slot(&entries[aIndex], &hashes[aIndex]);
1759 }
1760
1761 // Warning: in order for readonlyThreadsafeLookup() to be safe this
1762 // function must not modify the table in any way when Reason==ForNonAdd.
1763 template <LookupReason Reason>
1764 MOZ_ALWAYS_INLINEinline Slot lookup(const Lookup& aLookup,
1765 HashNumber aKeyHash) const {
1766 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"
, 1766); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLiveHash(aKeyHash)"
")"); do { *((volatile int*)__null) = 1766; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1767 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"
, 1767); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(aKeyHash & sCollisionBit)"
")"); do { *((volatile int*)__null) = 1767; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1768 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"
, 1768); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 1768; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1769
1770 // Compute the primary hash address.
1771 HashNumber h1 = hash1(aKeyHash);
1772 Slot slot = slotForIndex(h1);
1773
1774 // Miss: return space for a new entry.
1775 if (slot.isFree()) {
1776 return slot;
1777 }
1778
1779 // Hit: return entry.
1780 if (slot.matchHash(aKeyHash) && match(slot.get(), aLookup)) {
1781 return slot;
1782 }
1783
1784 // Collision: double hash.
1785 DoubleHash dh = hash2(aKeyHash);
1786
1787 // Save the first removed entry pointer so we can recycle later.
1788 Maybe<Slot> firstRemoved;
1789
1790 while (true) {
1791 if (Reason == ForAdd && !firstRemoved) {
1792 if (MOZ_UNLIKELY(slot.isRemoved())(__builtin_expect(!!(slot.isRemoved()), 0))) {
1793 firstRemoved.emplace(slot);
1794 } else {
1795 slot.setCollision();
1796 }
1797 }
1798
1799 h1 = applyDoubleHash(h1, dh);
1800
1801 slot = slotForIndex(h1);
1802 if (slot.isFree()) {
1803 return firstRemoved.refOr(slot);
1804 }
1805
1806 if (slot.matchHash(aKeyHash) && match(slot.get(), aLookup)) {
1807 return slot;
1808 }
1809 }
1810 }
1811
1812 // This is a copy of lookup() hardcoded to the assumptions:
1813 // 1. the lookup is for an add;
1814 // 2. the key, whose |keyHash| has been passed, is not in the table.
1815 Slot findNonLiveSlot(HashNumber aKeyHash) {
1816 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"
, 1816); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(aKeyHash & sCollisionBit)"
")"); do { *((volatile int*)__null) = 1816; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1817 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"
, 1817); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 1817; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1818
1819 // We assume 'aKeyHash' has already been distributed.
1820
1821 // Compute the primary hash address.
1822 HashNumber h1 = hash1(aKeyHash);
1823 Slot slot = slotForIndex(h1);
1824
1825 // Miss: return space for a new entry.
1826 if (!slot.isLive()) {
1827 return slot;
1828 }
1829
1830 // Collision: double hash.
1831 DoubleHash dh = hash2(aKeyHash);
1832
1833 while (true) {
1834 slot.setCollision();
1835
1836 h1 = applyDoubleHash(h1, dh);
1837
1838 slot = slotForIndex(h1);
1839 if (!slot.isLive()) {
1840 return slot;
1841 }
1842 }
1843 }
1844
1845 enum RebuildStatus { NotOverloaded, Rehashed, RehashFailed };
1846
1847 RebuildStatus changeTableSize(
1848 uint32_t newCapacity, FailureBehavior aReportFailure = ReportFailure) {
1849 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"
, 1849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsPowerOfTwo(newCapacity)"
")"); do { *((volatile int*)__null) = 1849; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1850 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"
, 1850); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!!mTable == !!capacity()"
")"); do { *((volatile int*)__null) = 1850; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1851
1852 // Look, but don't touch, until we succeed in getting new entry store.
1853 char* oldTable = mTable;
1854 uint32_t oldCapacity = capacity();
1855 uint32_t newLog2 = mozilla::CeilingLog2(newCapacity);
1856
1857 if (MOZ_UNLIKELY(newCapacity > sMaxCapacity)(__builtin_expect(!!(newCapacity > sMaxCapacity), 0))) {
1858 if (aReportFailure) {
1859 this->reportAllocOverflow();
1860 }
1861 return RehashFailed;
1862 }
1863
1864 char* newTable = createTable(*this, newCapacity, aReportFailure);
1865 if (!newTable) {
1866 return RehashFailed;
1867 }
1868
1869 // We can't fail from here on, so update table parameters.
1870 mHashShift = kHashNumberBits - newLog2;
1871 mRemovedCount = 0;
1872 mGen++;
1873 mTable = newTable;
1874
1875 // Copy only live entries, leaving removed ones behind.
1876 forEachSlot(oldTable, oldCapacity, [&](Slot& slot) {
1877 if (slot.isLive()) {
1878 HashNumber hn = slot.getKeyHash();
1879 findNonLiveSlot(hn).setLive(
1880 hn, std::move(const_cast<typename Entry::NonConstT&>(slot.get())));
1881 }
1882
1883 slot.clear();
1884 });
1885
1886 // All entries have been destroyed, no need to destroyTable.
1887 freeTable(*this, oldTable, oldCapacity);
1888 return Rehashed;
1889 }
1890
1891 RebuildStatus rehashIfOverloaded(
1892 FailureBehavior aReportFailure = ReportFailure) {
1893 static_assert(sMaxCapacity <= UINT32_MAX(4294967295U) / sMaxAlphaNumerator,
1894 "multiplication below could overflow");
1895
1896 // Note: if capacity() is zero, this will always succeed, which is
1897 // what we want.
1898 bool overloaded = mEntryCount + mRemovedCount >=
1899 capacity() * sMaxAlphaNumerator / sAlphaDenominator;
1900
1901 if (!overloaded) {
1902 return NotOverloaded;
1903 }
1904
1905 // Succeed if a quarter or more of all entries are removed. Note that this
1906 // always succeeds if capacity() == 0 (i.e. entry storage has not been
1907 // allocated), which is what we want, because it means changeTableSize()
1908 // will allocate the requested capacity rather than doubling it.
1909 bool manyRemoved = mRemovedCount >= (capacity() >> 2);
1910 uint32_t newCapacity = manyRemoved ? rawCapacity() : rawCapacity() * 2;
1911 return changeTableSize(newCapacity, aReportFailure);
1912 }
1913
1914 void infallibleRehashIfOverloaded() {
1915 if (rehashIfOverloaded(DontReportFailure) == RehashFailed) {
1916 rehashTableInPlace();
1917 }
1918 }
1919
1920 void remove(Slot& aSlot) {
1921 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"
, 1921); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 1921; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
52
Taking false branch
53
Loop condition is false. Exiting loop
1922
1923 if (aSlot.hasCollision()) {
54
Calling 'EntrySlot::hasCollision'
1924 aSlot.removeLive();
1925 mRemovedCount++;
1926 } else {
1927 aSlot.clearLive();
1928 }
1929 mEntryCount--;
1930#ifdef DEBUG1
1931 mMutationCount++;
1932#endif
1933 }
1934
1935 void shrinkIfUnderloaded() {
1936 static_assert(sMaxCapacity <= UINT32_MAX(4294967295U) / sMinAlphaNumerator,
1937 "multiplication below could overflow");
1938 bool underloaded =
1939 capacity() > sMinCapacity &&
1940 mEntryCount <= capacity() * sMinAlphaNumerator / sAlphaDenominator;
1941
1942 if (underloaded) {
1943 (void)changeTableSize(capacity() / 2, DontReportFailure);
1944 }
1945 }
1946
1947 // This is identical to changeTableSize(currentSize), but without requiring
1948 // a second table. We do this by recycling the collision bits to tell us if
1949 // the element is already inserted or still waiting to be inserted. Since
1950 // already-inserted elements win any conflicts, we get the same table as we
1951 // would have gotten through random insertion order.
1952 void rehashTableInPlace() {
1953 mRemovedCount = 0;
1954 mGen++;
1955 forEachSlot(mTable, capacity(), [&](Slot& slot) { slot.unsetCollision(); });
1956 for (uint32_t i = 0; i < capacity();) {
1957 Slot src = slotForIndex(i);
1958
1959 if (!src.isLive() || src.hasCollision()) {
1960 ++i;
1961 continue;
1962 }
1963
1964 HashNumber keyHash = src.getKeyHash();
1965 HashNumber h1 = hash1(keyHash);
1966 DoubleHash dh = hash2(keyHash);
1967 Slot tgt = slotForIndex(h1);
1968 while (true) {
1969 if (!tgt.hasCollision()) {
1970 src.swap(tgt);
1971 tgt.setCollision();
1972 break;
1973 }
1974
1975 h1 = applyDoubleHash(h1, dh);
1976 tgt = slotForIndex(h1);
1977 }
1978 }
1979
1980 // TODO: this algorithm leaves collision bits on *all* elements, even if
1981 // they are on no collision path. We have the option of setting the
1982 // collision bits correctly on a subsequent pass or skipping the rehash
1983 // unless we are totally filled with tombstones: benchmark to find out
1984 // which approach is best.
1985 }
1986
1987 // Prefer to use putNewInfallible; this function does not check
1988 // invariants.
1989 template <typename... Args>
1990 void putNewInfallibleInternal(HashNumber aKeyHash, Args&&... aArgs) {
1991 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"
, 1991); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 1991; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1992
1993 Slot slot = findNonLiveSlot(aKeyHash);
1994
1995 if (slot.isRemoved()) {
1996 mRemovedCount--;
1997 aKeyHash |= sCollisionBit;
1998 }
1999
2000 slot.setLive(aKeyHash, std::forward<Args>(aArgs)...);
2001 mEntryCount++;
2002#ifdef DEBUG1
2003 mMutationCount++;
2004#endif
2005 }
2006
2007 public:
2008 void clear() {
2009 forEachSlot(mTable, capacity(), [&](Slot& slot) { slot.clear(); });
2010 mRemovedCount = 0;
2011 mEntryCount = 0;
2012#ifdef DEBUG1
2013 mMutationCount++;
2014#endif
2015 }
2016
2017 // Resize the table down to the smallest capacity that doesn't overload the
2018 // table. Since we call shrinkIfUnderloaded() on every remove, you only need
2019 // to call this after a bulk removal of items done without calling remove().
2020 void compact() {
2021 if (empty()) {
2022 // Free the entry storage.
2023 freeTable(*this, mTable, capacity());
2024 mGen++;
2025 mHashShift = hashShift(0); // gives minimum capacity on regrowth
2026 mTable = nullptr;
2027 mRemovedCount = 0;
2028 return;
2029 }
2030
2031 uint32_t bestCapacity = this->bestCapacity(mEntryCount);
2032 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"
, 2032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bestCapacity <= capacity()"
")"); do { *((volatile int*)__null) = 2032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2033
2034 if (bestCapacity < capacity()) {
2035 (void)changeTableSize(bestCapacity, DontReportFailure);
2036 }
2037 }
2038
2039 void clearAndCompact() {
2040 clear();
2041 compact();
2042 }
2043
2044 [[nodiscard]] bool reserve(uint32_t aLen) {
2045 if (aLen == 0) {
2046 return true;
2047 }
2048
2049 if (MOZ_UNLIKELY(aLen > sMaxInit)(__builtin_expect(!!(aLen > sMaxInit), 0))) {
2050 this->reportAllocOverflow();
2051 return false;
2052 }
2053
2054 uint32_t bestCapacity = this->bestCapacity(aLen);
2055 if (bestCapacity <= capacity()) {
2056 return true; // Capacity is already sufficient.
2057 }
2058
2059 RebuildStatus status = changeTableSize(bestCapacity, ReportFailure);
2060 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"
, 2060); AnnotateMozCrashReason("MOZ_ASSERT" "(" "status != NotOverloaded"
")"); do { *((volatile int*)__null) = 2060; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2061 return status != RehashFailed;
2062 }
2063
2064 Iterator iter() const { return Iterator(*this); }
2065
2066 ModIterator modIter() { return ModIterator(*this); }
2067
2068 Range all() const { return Range(*this); }
2069
2070 bool empty() const { return mEntryCount == 0; }
2071
2072 uint32_t count() const { return mEntryCount; }
2073
2074 uint32_t rawCapacity() const { return 1u << (kHashNumberBits - mHashShift); }
2075
2076 uint32_t capacity() const { return mTable ? rawCapacity() : 0; }
2077
2078 Generation generation() const { return Generation(mGen); }
2079
2080 size_t shallowSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
2081 return aMallocSizeOf(mTable);
2082 }
2083
2084 size_t shallowSizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
2085 return aMallocSizeOf(this) + shallowSizeOfExcludingThis(aMallocSizeOf);
2086 }
2087
2088 MOZ_ALWAYS_INLINEinline Ptr readonlyThreadsafeLookup(const Lookup& aLookup) const {
2089 if (empty()) {
25
Taking true branch
2090 return Ptr();
26
Calling default constructor for 'Ptr'
31
Returning from default constructor for 'Ptr'
2091 }
2092
2093 HashNumber inputHash;
2094 if (!MaybeGetHash<HashPolicy>(aLookup, &inputHash)) {
2095 return Ptr();
2096 }
2097
2098 HashNumber keyHash = prepareHash(inputHash);
2099 return Ptr(lookup<ForNonAdd>(aLookup, keyHash), *this);
2100 }
2101
2102 MOZ_ALWAYS_INLINEinline Ptr lookup(const Lookup& aLookup) const {
2103 ReentrancyGuard g(*this);
2104 return readonlyThreadsafeLookup(aLookup);
24
Calling 'HashTable::readonlyThreadsafeLookup'
32
Returning from 'HashTable::readonlyThreadsafeLookup'
2105 }
2106
2107 MOZ_ALWAYS_INLINEinline AddPtr lookupForAdd(const Lookup& aLookup) {
2108 ReentrancyGuard g(*this);
2109
2110 HashNumber inputHash;
2111 if (!EnsureHash<HashPolicy>(aLookup, &inputHash)) {
2112 return AddPtr();
2113 }
2114
2115 HashNumber keyHash = prepareHash(inputHash);
2116
2117 if (!mTable) {
2118 return AddPtr(*this, keyHash);
2119 }
2120
2121 // Directly call the constructor in the return statement to avoid
2122 // excess copying when building with Visual Studio 2017.
2123 // See bug 1385181.
2124 return AddPtr(lookup<ForAdd>(aLookup, keyHash), *this, keyHash);
2125 }
2126
2127 template <typename... Args>
2128 [[nodiscard]] bool add(AddPtr& aPtr, Args&&... aArgs) {
2129 ReentrancyGuard g(*this);
2130 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"
, 2130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 2130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2131 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"
, 2131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.mTable == this"
")"); do { *((volatile int*)__null) = 2131; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2132 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"
, 2132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPtr.found()"
")"); do { *((volatile int*)__null) = 2132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2133 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"
, 2133); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(aPtr.mKeyHash & sCollisionBit)"
")"); do { *((volatile int*)__null) = 2133; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2134
2135 // Check for error from ensureHash() here.
2136 if (!aPtr.isLive()) {
2137 return false;
2138 }
2139
2140 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"
, 2140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.mGeneration == generation()"
")"); do { *((volatile int*)__null) = 2140; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2141#ifdef DEBUG1
2142 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"
, 2142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.mMutationCount == mMutationCount"
")"); do { *((volatile int*)__null) = 2142; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2143#endif
2144
2145 if (!aPtr.isValid()) {
2146 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"
, 2146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mTable && mEntryCount == 0"
")"); do { *((volatile int*)__null) = 2146; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2147 uint32_t newCapacity = rawCapacity();
2148 RebuildStatus status = changeTableSize(newCapacity, ReportFailure);
2149 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"
, 2149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "status != NotOverloaded"
")"); do { *((volatile int*)__null) = 2149; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2150 if (status == RehashFailed) {
2151 return false;
2152 }
2153 aPtr.mSlot = findNonLiveSlot(aPtr.mKeyHash);
2154
2155 } else if (aPtr.mSlot.isRemoved()) {
2156 // Changing an entry from removed to live does not affect whether we are
2157 // overloaded and can be handled separately.
2158 if (!this->checkSimulatedOOM()) {
2159 return false;
2160 }
2161 mRemovedCount--;
2162 aPtr.mKeyHash |= sCollisionBit;
2163
2164 } else {
2165 // Preserve the validity of |aPtr.mSlot|.
2166 RebuildStatus status = rehashIfOverloaded();
2167 if (status == RehashFailed) {
2168 return false;
2169 }
2170 if (status == NotOverloaded && !this->checkSimulatedOOM()) {
2171 return false;
2172 }
2173 if (status == Rehashed) {
2174 aPtr.mSlot = findNonLiveSlot(aPtr.mKeyHash);
2175 }
2176 }
2177
2178 aPtr.mSlot.setLive(aPtr.mKeyHash, std::forward<Args>(aArgs)...);
2179 mEntryCount++;
2180#ifdef DEBUG1
2181 mMutationCount++;
2182 aPtr.mGeneration = generation();
2183 aPtr.mMutationCount = mMutationCount;
2184#endif
2185 return true;
2186 }
2187
2188 // Note: |aLookup| may reference pieces of arguments in |aArgs|, so this
2189 // function must take care not to use |aLookup| after moving |aArgs|.
2190 template <typename... Args>
2191 void putNewInfallible(const Lookup& aLookup, Args&&... aArgs) {
2192 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"
, 2192); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!lookup(aLookup).found()"
")"); do { *((volatile int*)__null) = 2192; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2193 ReentrancyGuard g(*this);
2194 HashNumber keyHash = prepareHash(HashPolicy::hash(aLookup));
2195 putNewInfallibleInternal(keyHash, std::forward<Args>(aArgs)...);
2196 }
2197
2198 // Note: |aLookup| may alias arguments in |aArgs|, so this function must take
2199 // care not to use |aLookup| after moving |aArgs|.
2200 template <typename... Args>
2201 [[nodiscard]] bool putNew(const Lookup& aLookup, Args&&... aArgs) {
2202 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"
, 2202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!lookup(aLookup).found()"
")"); do { *((volatile int*)__null) = 2202; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2203 ReentrancyGuard g(*this);
2204 if (!this->checkSimulatedOOM()) {
2205 return false;
2206 }
2207 HashNumber inputHash;
2208 if (!EnsureHash<HashPolicy>(aLookup, &inputHash)) {
2209 return false;
2210 }
2211 HashNumber keyHash = prepareHash(inputHash);
2212 if (rehashIfOverloaded() == RehashFailed) {
2213 return false;
2214 }
2215 putNewInfallibleInternal(keyHash, std::forward<Args>(aArgs)...);
2216 return true;
2217 }
2218
2219 // Note: |aLookup| may be a reference pieces of arguments in |aArgs|, so this
2220 // function must take care not to use |aLookup| after moving |aArgs|.
2221 template <typename... Args>
2222 [[nodiscard]] bool relookupOrAdd(AddPtr& aPtr, const Lookup& aLookup,
2223 Args&&... aArgs) {
2224 // Check for error from ensureHash() here.
2225 if (!aPtr.isLive()) {
2226 return false;
2227 }
2228#ifdef DEBUG1
2229 aPtr.mGeneration = generation();
2230 aPtr.mMutationCount = mMutationCount;
2231#endif
2232 if (mTable) {
2233 ReentrancyGuard g(*this);
2234 // Check that aLookup has not been destroyed.
2235 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"
, 2235); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prepareHash(HashPolicy::hash(aLookup)) == aPtr.mKeyHash"
")"); do { *((volatile int*)__null) = 2235; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2236 aPtr.mSlot = lookup<ForAdd>(aLookup, aPtr.mKeyHash);
2237 if (aPtr.found()) {
2238 return true;
2239 }
2240 } else {
2241 // Clear aPtr so it's invalid; add() will allocate storage and redo the
2242 // lookup.
2243 aPtr.mSlot = Slot(nullptr, nullptr);
2244 }
2245 return add(aPtr, std::forward<Args>(aArgs)...);
2246 }
2247
2248 void remove(Ptr aPtr) {
2249 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"
, 2249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 2249; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
43
Assuming field 'mTable' is non-null
44
Taking false branch
45
Loop condition is false. Exiting loop
2250 ReentrancyGuard g(*this);
2251 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"
, 2251); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.found()"
")"); do { *((volatile int*)__null) = 2251; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
46
Assuming the condition is false
47
Taking false branch
48
Loop condition is false. Exiting loop
2252 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"
, 2252); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.mGeneration == generation()"
")"); do { *((volatile int*)__null) = 2252; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
49
Taking false branch
50
Loop condition is false. Exiting loop
2253 remove(aPtr.mSlot);
51
Calling 'HashTable::remove'
2254 shrinkIfUnderloaded();
2255 }
2256
2257 void rekeyWithoutRehash(Ptr aPtr, const Lookup& aLookup, const Key& aKey) {
2258 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"
, 2258); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTable" ")"
); do { *((volatile int*)__null) = 2258; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2259 ReentrancyGuard g(*this);
2260 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"
, 2260); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.found()"
")"); do { *((volatile int*)__null) = 2260; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2261 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"
, 2261); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPtr.mGeneration == generation()"
")"); do { *((volatile int*)__null) = 2261; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2262 typename HashTableEntry<T>::NonConstT t(std::move(*aPtr));
2263 HashPolicy::setKey(t, const_cast<Key&>(aKey));
2264 remove(aPtr.mSlot);
2265 HashNumber keyHash = prepareHash(HashPolicy::hash(aLookup));
2266 putNewInfallibleInternal(keyHash, std::move(t));
2267 }
2268
2269 void rekeyAndMaybeRehash(Ptr aPtr, const Lookup& aLookup, const Key& aKey) {
2270 rekeyWithoutRehash(aPtr, aLookup, aKey);
2271 infallibleRehashIfOverloaded();
2272 }
2273};
2274
2275} // namespace detail
2276} // namespace mozilla
2277
2278#endif /* mozilla_HashTable_h */