Bug 1535124 part 3. Add MOZ_CAN_RUN_SCRIPT annotations to geolocation code as needed. r=jdm
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 20 Mar 2019 18:05:09 +0000
changeset 465263 3ab48ce01773af9a130477e46c50e17f9042ea4b
parent 465262 b0af7322659c66d6bd72958713c5737f3ce30822
child 465264 93b76c2b5d626380e2ae2da052f378808f0e26b6
push id112496
push usershindli@mozilla.com
push dateThu, 21 Mar 2019 04:37:39 +0000
treeherdermozilla-inbound@29476d3ca61d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm
bugs1535124
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1535124 part 3. Add MOZ_CAN_RUN_SCRIPT annotations to geolocation code as needed. r=jdm Differential Revision: https://phabricator.services.mozilla.com/D23521
dom/base/nsContentPermissionHelper.cpp
dom/base/nsContentPermissionHelper.h
dom/geolocation/PositionError.cpp
dom/geolocation/PositionError.h
dom/geolocation/nsGeolocation.cpp
dom/geolocation/nsGeolocation.h
dom/interfaces/base/nsIContentPermissionPrompt.idl
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/system/mac/CoreLocationLocationProvider.h
dom/system/mac/CoreLocationLocationProvider.mm
dom/system/windows/WindowsLocationProvider.cpp
dom/webidl/Geolocation.webidl
xpcom/system/nsIGeolocationProvider.idl
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -12,16 +12,17 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/PContentPermission.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/PContentPermissionRequestParent.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/TabParent.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Unused.h"
 #include "nsComponentManagerUtils.h"
 #include "nsArrayUtils.h"
 #include "nsIMutableArray.h"
 #include "nsContentPermissionHelper.h"
 #include "nsJSUtils.h"
@@ -130,16 +131,18 @@ class ContentPermissionRequestParent : p
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
   nsCOMPtr<Element> mElement;
   bool mIsHandlingUserInput;
   RefPtr<nsContentPermissionRequestProxy> mProxy;
   nsTArray<PermissionRequest> mRequests;
 
  private:
+  // Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   virtual mozilla::ipc::IPCResult Recvprompt() override;
   virtual mozilla::ipc::IPCResult RecvNotifyVisibility(
       const bool& aIsVisible) override;
   virtual mozilla::ipc::IPCResult RecvDestroy() override;
   virtual void ActorDestroy(ActorDestroyReason why) override;
 };
 
 ContentPermissionRequestParent::ContentPermissionRequestParent(
@@ -157,17 +160,18 @@ ContentPermissionRequestParent::ContentP
 
 ContentPermissionRequestParent::~ContentPermissionRequestParent() {
   MOZ_COUNT_DTOR(ContentPermissionRequestParent);
 }
 
 mozilla::ipc::IPCResult ContentPermissionRequestParent::Recvprompt() {
   mProxy = new nsContentPermissionRequestProxy(this);
   if (NS_FAILED(mProxy->Init(mRequests))) {
-    mProxy->Cancel();
+    RefPtr<nsContentPermissionRequestProxy> proxy(mProxy);
+    proxy->Cancel();
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentPermissionRequestParent::RecvNotifyVisibility(
     const bool& aIsVisible) {
   if (!mProxy) {
     return IPC_FAIL_NO_REASON(this);
@@ -626,21 +630,24 @@ class RequestPromptEvent : public Runnab
 
 class RequestAllowEvent : public Runnable {
  public:
   RequestAllowEvent(bool allow, ContentPermissionRequestBase* request)
       : mozilla::Runnable("RequestAllowEvent"),
         mAllow(allow),
         mRequest(request) {}
 
+  // Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   NS_IMETHOD Run() override {
+    // MOZ_KnownLive is OK, because we never drop the ref to mRequest.
     if (mAllow) {
-      mRequest->Allow(JS::UndefinedHandleValue);
+      MOZ_KnownLive(mRequest)->Allow(JS::UndefinedHandleValue);
     } else {
-      mRequest->Cancel();
+      MOZ_KnownLive(mRequest)->Cancel();
     }
     return NS_OK;
   }
 
  private:
   bool mAllow;
   RefPtr<ContentPermissionRequestBase> mRequest;
 };
@@ -926,22 +933,24 @@ RemotePermissionRequest::RemotePermissio
 RemotePermissionRequest::~RemotePermissionRequest() {
   MOZ_ASSERT(
       !mIPCOpen,
       "Protocol must not be open when RemotePermissionRequest is destroyed.");
 }
 
 void RemotePermissionRequest::DoCancel() {
   NS_ASSERTION(mRequest, "We need a request");
-  mRequest->Cancel();
+  nsCOMPtr<nsIContentPermissionRequest> request(mRequest);
+  request->Cancel();
 }
 
 void RemotePermissionRequest::DoAllow(JS::HandleValue aChoices) {
   NS_ASSERTION(mRequest, "We need a request");
-  mRequest->Allow(aChoices);
+  nsCOMPtr<nsIContentPermissionRequest> request(mRequest);
+  request->Allow(aChoices);
 }
 
 // PContentPermissionRequestChild
 mozilla::ipc::IPCResult RemotePermissionRequest::RecvNotifyResult(
     const bool& aAllow, InfallibleTArray<PermissionChoice>&& aChoices) {
   Destroy();
 
   if (aAllow && mWindow->IsCurrentInnerWindow()) {
--- a/dom/base/nsContentPermissionHelper.h
+++ b/dom/base/nsContentPermissionHelper.h
@@ -215,17 +215,19 @@ class RemotePermissionRequest final
       public mozilla::dom::PContentPermissionRequestChild {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICONTENTPERMISSIONREQUESTCALLBACK
 
   RemotePermissionRequest(nsIContentPermissionRequest* aRequest,
                           nsPIDOMWindowInner* aWindow);
 
-  // It will be called when prompt dismissed.
+  // It will be called when prompt dismissed.  MOZ_CAN_RUN_SCRIPT_BOUNDARY
+  // because we don't have MOZ_CAN_RUN_SCRIPT bits in IPC code yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   mozilla::ipc::IPCResult RecvNotifyResult(
       const bool& aAllow, InfallibleTArray<PermissionChoice>&& aChoices);
 
   mozilla::ipc::IPCResult RecvGetVisibility();
 
   void IPDLAddRef() {
     mIPCOpen = true;
     AddRef();
@@ -238,17 +240,19 @@ class RemotePermissionRequest final
 
   void Destroy();
 
   bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
 
  private:
   virtual ~RemotePermissionRequest();
 
+  MOZ_CAN_RUN_SCRIPT
   void DoAllow(JS::HandleValue aChoices);
+  MOZ_CAN_RUN_SCRIPT
   void DoCancel();
 
   nsCOMPtr<nsIContentPermissionRequest> mRequest;
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   bool mIPCOpen;
   bool mDestroyed;
   RefPtr<VisibilityChangeListener> mListener;
 };
--- a/dom/geolocation/PositionError.cpp
+++ b/dom/geolocation/PositionError.cpp
@@ -42,17 +42,17 @@ nsWrapperCache* PositionError::GetParent
 JSObject* PositionError::WrapObject(JSContext* aCx,
                                     JS::Handle<JSObject*> aGivenProto) {
   return PositionError_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 void PositionError::NotifyCallback(const GeoPositionErrorCallback& aCallback) {
   nsAutoMicroTask mt;
   if (aCallback.HasWebIDLCallback()) {
-    PositionErrorCallback* callback = aCallback.GetWebIDLCallback();
+    RefPtr<PositionErrorCallback> callback = aCallback.GetWebIDLCallback();
 
     if (callback) {
       callback->Call(*this);
     }
   } else {
     nsIDOMGeoPositionErrorCallback* callback = aCallback.GetXPCOMCallback();
     if (callback) {
       callback->HandleEvent(this);
--- a/dom/geolocation/PositionError.h
+++ b/dom/geolocation/PositionError.h
@@ -33,16 +33,17 @@ class PositionError final : public nsWra
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   int16_t Code() const { return mCode; }
 
   void GetMessage(nsAString& aMessage) const;
 
+  MOZ_CAN_RUN_SCRIPT
   void NotifyCallback(const GeoPositionErrorCallback& callback);
 
  private:
   ~PositionError();
   int16_t mCode;
   RefPtr<Geolocation> mParent;
 };
 
--- a/dom/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -78,29 +78,34 @@ class nsGeolocationRequest final
   nsGeolocationRequest(Geolocation* aLocator, GeoPositionCallback aCallback,
                        GeoPositionErrorCallback aErrorCallback,
                        UniquePtr<PositionOptions>&& aOptions,
                        uint8_t aProtocolType, nsIEventTarget* aMainThreadTarget,
                        bool aWatchPositionRequest = false,
                        int32_t aWatchId = 0);
 
   // nsIContentPermissionRequest
-  NS_IMETHOD Cancel(void) override;
-  NS_IMETHOD Allow(JS::HandleValue choices) override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD Cancel(void) override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD Allow(JS::HandleValue choices) override;
 
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsGeolocationRequest)
 
   void Shutdown();
 
+  // MOZ_CAN_RUN_SCRIPT_BOUNDARY is OK here because we're always called from a
+  // runnable.  Ideally nsIRunnable::Run and its overloads would just be
+  // MOZ_CAN_RUN_SCRIPT and then we could be too...
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   void SendLocation(nsIDOMGeoPosition* aLocation);
   bool WantsHighAccuracy() {
     return !mShutdown && mOptions && mOptions->mEnableHighAccuracy;
   }
   void SetTimeoutTimer();
   void StopTimeoutTimer();
+  MOZ_CAN_RUN_SCRIPT
   void NotifyErrorAndShutdown(uint16_t);
   using ContentPermissionRequestBase::GetPrincipal;
   nsIPrincipal* GetPrincipal();
 
   bool IsWatch() { return mIsWatchPositionRequest; }
   int32_t WatchId() { return mWatchId; }
 
  private:
@@ -119,17 +124,18 @@ class nsGeolocationRequest final
       return NS_OK;
     }
 
    private:
     ~TimerCallbackHolder() = default;
     WeakPtr<nsGeolocationRequest> mRequest;
   };
 
-  void Notify();
+  // Only called from a timer, so MOZ_CAN_RUN_SCRIPT_BOUNDARY ok for now.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY void Notify();
 
   bool mIsWatchPositionRequest;
 
   nsCOMPtr<nsITimer> mTimeoutTimer;
   GeoPositionCallback mCallback;
   GeoPositionErrorCallback mErrorCallback;
   UniquePtr<PositionOptions> mOptions;
 
@@ -327,17 +333,18 @@ nsGeolocationRequest::Allow(JS::HandleVa
     // invoke the errorCallback (if present) with TIMEOUT code
     if (mOptions && mOptions->mTimeout == 0 && !mIsWatchPositionRequest) {
       NotifyError(PositionError_Binding::TIMEOUT);
       return NS_OK;
     }
   }
 
   // Kick off the geo device, if it isn't already running
-  nsresult rv = gs->StartDevice(GetPrincipal());
+  nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
+  nsresult rv = gs->StartDevice(principal);
 
   if (NS_FAILED(rv)) {
     // Location provider error
     NotifyError(PositionError_Binding::POSITION_UNAVAILABLE);
     return NS_OK;
   }
 
   if (mIsWatchPositionRequest || !canUseCache) {
@@ -405,17 +412,17 @@ void nsGeolocationRequest::SendLocation(
   if (!mIsWatchPositionRequest) {
     // Cancel timer and position updates in case the position
     // callback spins the event loop
     Shutdown();
   }
 
   nsAutoMicroTask mt;
   if (mCallback.HasWebIDLCallback()) {
-    PositionCallback* callback = mCallback.GetWebIDLCallback();
+    RefPtr<PositionCallback> callback = mCallback.GetWebIDLCallback();
 
     MOZ_ASSERT(callback);
     callback->Call(*wrapped);
   } else {
     nsIDOMGeoPositionCallback* callback = mCallback.GetXPCOMCallback();
     MOZ_ASSERT(callback);
     callback->HandleEvent(aPosition);
   }
@@ -937,23 +944,25 @@ Geolocation::NotifyError(uint16_t aError
   if (!WindowOwnerStillExists()) {
     Shutdown();
     return NS_OK;
   }
 
   mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ERROR, true);
 
   for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
-    mPendingCallbacks[i - 1]->NotifyErrorAndShutdown(aErrorCode);
+    RefPtr<nsGeolocationRequest> request = mPendingCallbacks[i - 1];
+    request->NotifyErrorAndShutdown(aErrorCode);
     // NotifyErrorAndShutdown() removes the request from the array
   }
 
   // notify everyone that is watching
   for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
-    mWatchingCallbacks[i]->NotifyErrorAndShutdown(aErrorCode);
+    RefPtr<nsGeolocationRequest> request = mWatchingCallbacks[i];
+    request->NotifyErrorAndShutdown(aErrorCode);
   }
 
   return NS_OK;
 }
 
 bool Geolocation::IsAlreadyCleared(nsGeolocationRequest* aRequest) {
   for (uint32_t i = 0, length = mClearedWatchIDs.Length(); i < length; ++i) {
     if (mClearedWatchIDs[i] == aRequest->WatchId()) {
--- a/dom/geolocation/nsGeolocation.h
+++ b/dom/geolocation/nsGeolocation.h
@@ -71,16 +71,17 @@ class nsGeolocationService final : publi
   // Management of the Geolocation objects
   void AddLocator(mozilla::dom::Geolocation* locator);
   void RemoveLocator(mozilla::dom::Geolocation* locator);
 
   void SetCachedPosition(nsIDOMGeoPosition* aPosition);
   CachedPositionAndAccuracy GetCachedPosition();
 
   // Find and startup a geolocation device (gps, nmea, etc.)
+  MOZ_CAN_RUN_SCRIPT
   nsresult StartDevice(nsIPrincipal* aPrincipal);
 
   // Stop the started geolocation device (gps, nmea, etc.)
   void StopDevice();
 
   // create, or reinitalize the callback timer
   void SetDisconnectTimer();
 
@@ -127,27 +128,29 @@ class Geolocation final : public nsIGeol
   Geolocation();
 
   nsresult Init(nsPIDOMWindowInner* aContentDom = nullptr);
 
   nsPIDOMWindowInner* GetParentObject() const;
   virtual JSObject* WrapObject(JSContext* aCtx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
+  MOZ_CAN_RUN_SCRIPT
   int32_t WatchPosition(PositionCallback& aCallback,
                         PositionErrorCallback* aErrorCallback,
                         const PositionOptions& aOptions, CallerType aCallerType,
                         ErrorResult& aRv);
   void GetCurrentPosition(PositionCallback& aCallback,
                           PositionErrorCallback* aErrorCallback,
                           const PositionOptions& aOptions,
                           CallerType aCallerType, ErrorResult& aRv);
   void ClearWatch(int32_t aWatchId);
 
   // A WatchPosition for C++ use.  Returns -1 if we failed to actually watch.
+  MOZ_CAN_RUN_SCRIPT
   int32_t WatchPosition(nsIDOMGeoPositionCallback* aCallback,
                         nsIDOMGeoPositionErrorCallback* aErrorCallback,
                         UniquePtr<PositionOptions>&& aOptions);
 
   // Returns true if any of the callbacks are repeating
   bool HasActiveCallbacks();
 
   // Register an allowed request
@@ -181,16 +184,17 @@ class Geolocation final : public nsIGeol
 
  private:
   ~Geolocation();
 
   nsresult GetCurrentPosition(GeoPositionCallback aCallback,
                               GeoPositionErrorCallback aErrorCallback,
                               UniquePtr<PositionOptions>&& aOptions,
                               CallerType aCallerType);
+  MOZ_CAN_RUN_SCRIPT
   int32_t WatchPosition(GeoPositionCallback aCallback,
                         GeoPositionErrorCallback aErrorCallback,
                         UniquePtr<PositionOptions>&& aOptions,
                         CallerType aCallerType, ErrorResult& aRv);
 
   bool RegisterRequestWithPrompt(nsGeolocationRequest* request);
 
   // Check if clearWatch is already called
--- a/dom/interfaces/base/nsIContentPermissionPrompt.idl
+++ b/dom/interfaces/base/nsIContentPermissionPrompt.idl
@@ -93,18 +93,19 @@ interface nsIContentPermissionRequest : 
    *  The requester to get the required information of
    *  the window.
    */
   readonly attribute nsIContentPermissionRequester requester;
 
   /**
    * allow or cancel the request
    */
-
+  [can_run_script]
   void cancel();
+  [can_run_script]
   void allow([optional] in jsval choices); // {"type1": "choice1", "type2": "choiceA"}
 };
 
 /**
  * Interface provides a way for the application to handle
  * the UI prompts associated with geo position.
  */
 [scriptable, function, uuid(F72DE90D-E954-4E69-9A61-917303029301)]
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -371,16 +371,19 @@ class ContentChild final : public PConte
       nsTArray<StringBundleDescriptor>&& stringBundles);
 
   mozilla::ipc::IPCResult RecvUpdateSharedData(
       const FileDescriptor& aMapFile, const uint32_t& aMapSize,
       nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys);
 
   mozilla::ipc::IPCResult RecvGeolocationUpdate(nsIDOMGeoPosition* aPosition);
 
+  // MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
+  // in IPC code yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   mozilla::ipc::IPCResult RecvGeolocationError(const uint16_t& errorCode);
 
   mozilla::ipc::IPCResult RecvUpdateDictionaryList(
       InfallibleTArray<nsString>&& aDictionaries);
 
   mozilla::ipc::IPCResult RecvUpdateFontList(
       InfallibleTArray<SystemFontListEntry>&& aFontList);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3996,16 +3996,17 @@ mozilla::ipc::IPCResult ContentParent::R
     ipc::UnpackClonedMessageDataForParent(aData, data);
 
     ppm->ReceiveMessage(ppm, nullptr, aMsg, false, &data, &cpows, aPrincipal,
                         nullptr, IgnoreErrors());
   }
   return IPC_OK();
 }
 
+MOZ_CAN_RUN_SCRIPT
 static int32_t AddGeolocationListener(
     nsIDOMGeoPositionCallback* watcher,
     nsIDOMGeoPositionErrorCallback* errorCallBack, bool highAccuracy) {
   RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
 
   UniquePtr<PositionOptions> options = MakeUnique<PositionOptions>();
   options->mTimeout = 0;
   options->mMaximumAge = 0;
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -984,20 +984,26 @@ class ContentParent final : public PCont
       InfallibleTArray<CpowEntry>&& aCpows, const IPC::Principal& aPrincipal,
       nsTArray<StructuredCloneData>* aRetvals);
 
   mozilla::ipc::IPCResult RecvAsyncMessage(const nsString& aMsg,
                                            InfallibleTArray<CpowEntry>&& aCpows,
                                            const IPC::Principal& aPrincipal,
                                            const ClonedMessageData& aData);
 
+  // MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
+  // in IPC code yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   mozilla::ipc::IPCResult RecvAddGeolocationListener(
       const IPC::Principal& aPrincipal, const bool& aHighAccuracy);
   mozilla::ipc::IPCResult RecvRemoveGeolocationListener();
 
+  // MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
+  // in IPC code yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   mozilla::ipc::IPCResult RecvSetGeolocationHigherAccuracy(const bool& aEnable);
 
   mozilla::ipc::IPCResult RecvConsoleMessage(const nsString& aMessage);
 
   mozilla::ipc::IPCResult RecvScriptError(
       const nsString& aMessage, const nsString& aSourceName,
       const nsString& aSourceLine, const uint32_t& aLineNumber,
       const uint32_t& aColNumber, const uint32_t& aFlags,
--- a/dom/system/mac/CoreLocationLocationProvider.h
+++ b/dom/system/mac/CoreLocationLocationProvider.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCOMPtr.h"
 #include "nsIGeolocationProvider.h"
+#include "mozilla/Attributes.h"
 
 /*
  * The CoreLocationObjects class contains the CoreLocation objects
  * we'll need.
  *
  * Declaring them directly in CoreLocationLocationProvider
  * would require Objective-C++ syntax, which would contaminate all
  * files that include this header and require them to be Objective-C++
@@ -25,16 +26,20 @@ class CoreLocationObjects;
 class MLSFallback;
 
 class CoreLocationLocationProvider : public nsIGeolocationProvider {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIGEOLOCATIONPROVIDER
 
   CoreLocationLocationProvider();
+  // MOZ_CAN_RUN_SCRIPT_BOUNDARY because we can't mark Objective-C methods as
+  // MOZ_CAN_RUN_SCRIPT as far as I can tell, and this method is called from
+  // Objective-C.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   void NotifyError(uint16_t aErrorCode);
   void Update(nsIDOMGeoPosition* aSomewhere);
   void CreateMLSFallbackProvider();
   void CancelMLSFallbackProvider();
 
  private:
   virtual ~CoreLocationLocationProvider() = default;
 
--- a/dom/system/mac/CoreLocationLocationProvider.mm
+++ b/dom/system/mac/CoreLocationLocationProvider.mm
@@ -219,17 +219,18 @@ CoreLocationLocationProvider::SetHighAcc
 }
 
 void CoreLocationLocationProvider::Update(nsIDOMGeoPosition* aSomewhere) {
   if (aSomewhere && mCallback) {
     mCallback->Update(aSomewhere);
   }
 }
 void CoreLocationLocationProvider::NotifyError(uint16_t aErrorCode) {
-  mCallback->NotifyError(aErrorCode);
+  nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
+  callback->NotifyError(aErrorCode);
 }
 void CoreLocationLocationProvider::CreateMLSFallbackProvider() {
   if (mMLSFallbackProvider) {
     return;
   }
 
   mMLSFallbackProvider = new MLSFallback(0);
   mMLSFallbackProvider->Startup(new MLSUpdate(*this));
--- a/dom/system/windows/WindowsLocationProvider.cpp
+++ b/dom/system/windows/WindowsLocationProvider.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WindowsLocationProvider.h"
 #include "nsGeoPosition.h"
 #include "nsComponentManagerUtils.h"
 #include "prtime.h"
 #include "MLSFallback.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/PositionErrorBinding.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS(WindowsLocationProvider::MLSUpdate, nsIGeolocationUpdate);
@@ -35,31 +36,33 @@ WindowsLocationProvider::MLSUpdate::Upda
   Telemetry::Accumulate(Telemetry::GEOLOCATION_WIN8_SOURCE_IS_MLS, true);
   return mCallback->Update(aPosition);
 }
 NS_IMETHODIMP
 WindowsLocationProvider::MLSUpdate::NotifyError(uint16_t aError) {
   if (!mCallback) {
     return NS_ERROR_FAILURE;
   }
-  return mCallback->NotifyError(aError);
+  nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
+  return callback->NotifyError(aError);
 }
 
 class LocationEvent final : public ILocationEvents {
  public:
   LocationEvent(nsIGeolocationUpdate* aCallback,
                 WindowsLocationProvider* aProvider)
       : mCallback(aCallback), mProvider(aProvider), mCount(0) {}
 
   // IUnknown interface
   STDMETHODIMP_(ULONG) AddRef() override;
   STDMETHODIMP_(ULONG) Release() override;
   STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override;
 
   // ILocationEvents interface
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   STDMETHODIMP OnStatusChanged(REFIID aReportType,
                                LOCATION_REPORT_STATUS aStatus) override;
   STDMETHODIMP OnLocationChanged(REFIID aReportType,
                                  ILocationReport* aReport) override;
 
  private:
   nsCOMPtr<nsIGeolocationUpdate> mCallback;
   RefPtr<WindowsLocationProvider> mProvider;
@@ -122,17 +125,18 @@ LocationEvent::OnStatusChanged(REFIID aR
       break;
     case REPORT_NOT_SUPPORTED:
     case REPORT_ERROR:
       err = PositionError_Binding::POSITION_UNAVAILABLE;
       break;
     default:
       return S_OK;
   }
-  mCallback->NotifyError(err);
+  nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
+  callback->NotifyError(err);
   return S_OK;
 }
 
 STDMETHODIMP
 LocationEvent::OnLocationChanged(REFIID aReportType, ILocationReport* aReport) {
   if (aReportType != IID_ILatLongReport) {
     return S_OK;
   }
--- a/dom/webidl/Geolocation.webidl
+++ b/dom/webidl/Geolocation.webidl
@@ -26,13 +26,11 @@ interface Geolocation {
   [Throws, NeedsCallerType]
   long watchPosition(PositionCallback successCallback,
                      optional PositionErrorCallback? errorCallback = null,
                      optional PositionOptions options);
 
   void clearWatch(long watchId);
 };
 
-[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PositionCallback = void (Position position);
 
-[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PositionErrorCallback = void (PositionError positionError);
--- a/xpcom/system/nsIGeolocationProvider.idl
+++ b/xpcom/system/nsIGeolocationProvider.idl
@@ -30,16 +30,17 @@ interface nsIGeolocationUpdate : nsISupp
    * This must be called on the main thread.
    * The parameter refers to one of the constants in the
    * nsIDOMGeoPositionError interface.
    * Use this to report spurious errors coming from the
    * provider; for errors occurring inside the methods in
    * the nsIGeolocationProvider interface, just use the return
    * value.
    */
+  [can_run_script]
   void notifyError(in unsigned short error);
 };
 
 
 /**
  * Interface provides location information to the nsGeolocator
  * via the nsIDOMGeolocationCallback interface.  After
  * startup is called, any geo location change should call