Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  nsXPConnect.cpp   Sprache: C

 
/* -*- 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/. */


/* High level class and public functions implementation. */

#include "js/Transcoding.h"
#include "mozilla/Assertions.h"
#include "mozilla/Base64.h"
#include "mozilla/Likely.h"
#include "mozilla/Unused.h"

#include "XPCWrapper.h"
#include "jsfriendapi.h"
#include "js/AllocationLogging.h"  // JS::SetLogCtorDtorFunctions
#include "js/CompileOptions.h"     // JS::ReadOnlyCompileOptions
#include "js/Object.h"             // JS::GetClass
#include "js/ProfilingStack.h"
#include "GeckoProfiler.h"
#include "mozJSModuleLoader.h"
#include "nsJSEnvironment.h"
#include "nsThreadUtils.h"
#include "nsDOMJSUtils.h"

#include "WrapperFactory.h"
#include "AccessCheck.h"
#include "JSServices.h"

#include "mozilla/BasePrincipal.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/Exceptions.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/glean/bindings/Glean.h"
#include "mozilla/glean/bindings/GleanPings.h"
#include "mozilla/ScriptPreloader.h"

#include "nsDOMMutationObserver.h"
#include "nsICycleCollectorListener.h"
#include "nsCycleCollector.h"
#include "nsIOService.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsScriptSecurityManager.h"
#include "nsContentUtils.h"
#include "nsScriptError.h"
#include "nsJSUtils.h"
#include "nsRFPService.h"
#include "prsystem.h"

#include "xpcprivate.h"

#ifdef XP_WIN
#  include "mozilla/WinHeaderOnlyUtils.h"
#else
#  include <sys/mman.h>
#endif

using namespace mozilla;
using namespace mozilla::dom;
using namespace xpc;
using namespace JS;

NS_IMPL_ISUPPORTS(nsXPConnect, nsIXPConnect)

nsXPConnect* nsXPConnect::gSelf = nullptr;
bool nsXPConnect::gOnceAliveNowDead = false;

// Global cache of the default script security manager (QI'd to
// nsIScriptSecurityManager) and the system principal.
nsIScriptSecurityManager* nsXPConnect::gScriptSecurityManager = nullptr;
nsIPrincipal* nsXPConnect::gSystemPrincipal = nullptr;

const char XPC_EXCEPTION_CONTRACTID[] = "@mozilla.org/js/xpc/Exception;1";
const char XPC_CONSOLE_CONTRACTID[] = "@mozilla.org/consoleservice;1";
const char XPC_SCRIPT_ERROR_CONTRACTID[] = "@mozilla.org/scripterror;1";

/***************************************************************************/

nsXPConnect::nsXPConnect() {
#ifdef MOZ_GECKO_PROFILER
  JS::SetProfilingThreadCallbacks(profiler_register_thread,
                                  profiler_unregister_thread);
#endif
}

// static
void nsXPConnect::InitJSContext() {
  MOZ_ASSERT(!gSelf->mContext);

  XPCJSContext* xpccx = XPCJSContext::NewXPCJSContext();
  if (!xpccx) {
    MOZ_CRASH("Couldn't create XPCJSContext.");
  }
  gSelf->mContext = xpccx;
  gSelf->mRuntime = xpccx->Runtime();

  mozJSModuleLoader::InitStatics();

  // Initialize the script preloader cache.
  Unused << mozilla::ScriptPreloader::GetSingleton();

  nsJSContext::EnsureStatics();
}

void xpc::InitializeJSContext() { nsXPConnect::InitJSContext(); }

nsXPConnect::~nsXPConnect() {
  MOZ_ASSERT(mRuntime);

  mRuntime->DeleteSingletonScopes();

  // In order to clean up everything properly, we need to GC twice: once now,
  // to clean anything that can go away on its own (like the Junk Scope, which
  // we unrooted above), and once after forcing a bunch of shutdown in
  // XPConnect, to clean the stuff we forcibly disconnected. The forced
  // shutdown code defaults to leaking in a number of situations, so we can't
  // get by with only the second GC. :-(
  //
  // Bug 1650075: These should really pass GCOptions::Shutdown but doing that
  // seems to cause crashes.
  mRuntime->GarbageCollect(JS::GCOptions::Normal,
                           JS::GCReason::XPCONNECT_SHUTDOWN);

  XPCWrappedNativeScope::SystemIsBeingShutDown();

  // The above causes us to clean up a bunch of XPConnect data structures,
  // after which point we need to GC to clean everything up. We need to do
  // this before deleting the XPCJSContext, because doing so destroys the
  // maps that our finalize callback depends on.
  mRuntime->GarbageCollect(JS::GCOptions::Normal,
                           JS::GCReason::XPCONNECT_SHUTDOWN);

  NS_RELEASE(gSystemPrincipal);
  gScriptSecurityManager = nullptr;

  // shutdown the logging system
  XPC_LOG_FINISH();

  delete mContext;

  MOZ_ASSERT(gSelf == this);
  gSelf = nullptr;
  gOnceAliveNowDead = true;
}

// static
void nsXPConnect::InitStatics() {
#ifdef NS_BUILD_REFCNT_LOGGING
  // These functions are used for reporting leaks, so we register them as early
  // as possible to avoid missing any classes' creations.
  JS::SetLogCtorDtorFunctions(NS_LogCtor, NS_LogDtor);
#endif

  gSelf = new nsXPConnect();
  gOnceAliveNowDead = false;

  // Initial extra ref to keep the singleton alive
  // balanced by explicit call to ReleaseXPConnectSingleton()
  NS_ADDREF(gSelf);

  // Fire up the SSM.
  nsScriptSecurityManager::InitStatics();
  gScriptSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager();
  gScriptSecurityManager->GetSystemPrincipal(&gSystemPrincipal);
  MOZ_RELEASE_ASSERT(gSystemPrincipal);
}

// static
void nsXPConnect::ReleaseXPConnectSingleton() {
  nsXPConnect* xpc = gSelf;
  if (xpc) {
    nsrefcnt cnt;
    NS_RELEASE2(xpc, cnt);
  }

  mozJSModuleLoader::ShutdownLoaders();
}

// static
XPCJSRuntime* nsXPConnect::GetRuntimeInstance() {
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
  return gSelf->mRuntime;
}

void xpc::ErrorBase::Init(JSErrorBase* aReport) {
  if (!aReport->filename) {
    mFileName.SetIsVoid(true);
  } else {
    mFileName.Assign(aReport->filename.c_str());
  }

  mSourceId = aReport->sourceId;
  mLineNumber = aReport->lineno;
  mColumn = aReport->column.oneOriginValue();
}

void xpc::ErrorNote::Init(JSErrorNotes::Note* aNote) {
  xpc::ErrorBase::Init(aNote);

  ErrorNoteToMessageString(aNote, mErrorMsg);
}

void xpc::ErrorReport::Init(JSErrorReport* aReport, const char* aToStringResult,
                            bool aIsChrome, uint64_t aWindowID) {
  xpc::ErrorBase::Init(aReport);
  mCategory = aIsChrome ? "chrome javascript"_ns : "content javascript"_ns;
  mWindowID = aWindowID;

  if (aToStringResult) {
    AppendUTF8toUTF16(mozilla::MakeStringSpan(aToStringResult), mErrorMsg);
  }
  if (mErrorMsg.IsEmpty()) {
    ErrorReportToMessageString(aReport, mErrorMsg);
  }
  if (mErrorMsg.IsEmpty()) {
    mErrorMsg.AssignLiteral("");
  }

  if (aReport->errorMessageName) {
    mErrorMsgName.AssignASCII(aReport->errorMessageName);
  } else {
    mErrorMsgName.Truncate();
  }

  mIsWarning = aReport->isWarning();
  mIsMuted = aReport->isMuted;

  if (aReport->notes) {
    if (!mNotes.SetLength(aReport->notes->length(), fallible)) {
      return;
    }

    size_t i = 0;
    for (auto&& note : *aReport->notes) {
      mNotes.ElementAt(i).Init(note.get());
      i++;
    }
  }
}

void xpc::ErrorReport::Init(JSContext* aCx, mozilla::dom::Exception* aException,
                            bool aIsChrome, uint64_t aWindowID) {
  mCategory = aIsChrome ? "chrome javascript"_ns : "content javascript"_ns;
  mWindowID = aWindowID;

  aException->GetErrorMessage(mErrorMsg);

  aException->GetFilename(aCx, mFileName);
  if (mFileName.IsEmpty()) {
    mFileName.SetIsVoid(true);
  }
  mSourceId = aException->SourceId(aCx);
  mLineNumber = aException->LineNumber(aCx);
  mColumn = aException->ColumnNumber();
}

static LazyLogModule gJSDiagnostics("JSDiagnostics");

void xpc::ErrorBase::AppendErrorDetailsTo(nsCString& error) {
  error.Append(mFileName);
  error.AppendLiteral(", line ");
  error.AppendInt(mLineNumber, 10);
  error.AppendLiteral(": ");
  AppendUTF16toUTF8(mErrorMsg, error);
}

void xpc::ErrorNote::LogToStderr() {
  if (!nsJSUtils::DumpEnabled()) {
    return;
  }

  nsAutoCString error;
  error.AssignLiteral("JavaScript note: ");
  AppendErrorDetailsTo(error);

  fprintf(stderr, "%s\n", error.get());
  fflush(stderr);
}

void xpc::ErrorReport::LogToStderr() {
  if (!nsJSUtils::DumpEnabled()) {
    return;
  }

  nsAutoCString error;
  error.AssignLiteral("JavaScript ");
  if (IsWarning()) {
    error.AppendLiteral("warning: ");
  } else {
    error.AppendLiteral("error: ");
  }
  AppendErrorDetailsTo(error);

  fprintf(stderr, "%s\n", error.get());
  fflush(stderr);

  for (size_t i = 0, len = mNotes.Length(); i < len; i++) {
    ErrorNote& note = mNotes[i];
    note.LogToStderr();
  }
}

void xpc::ErrorReport::LogToConsole() {
  LogToConsoleWithStack(nullptr, JS::NothingHandleValue, nullptr, nullptr);
}

void xpc::ErrorReport::LogToConsoleWithStack(
    nsGlobalWindowInner* aWin, JS::Handle<mozilla::Maybe<JS::Value>> aException,
    JS::HandleObject aStack, JS::HandleObject aStackGlobal) {
  if (aStack) {
    MOZ_ASSERT(aStackGlobal);
    MOZ_ASSERT(JS_IsGlobalObject(aStackGlobal));
    js::AssertSameCompartment(aStack, aStackGlobal);
  } else {
    MOZ_ASSERT(!aStackGlobal);
  }

  LogToStderr();

  MOZ_LOG(gJSDiagnostics, IsWarning() ? LogLevel::Warning : LogLevel::Error,
          ("file %s, line %u\n%s", mFileName.get(), mLineNumber,
           NS_ConvertUTF16toUTF8(mErrorMsg).get()));

  // Log to the console. We do this last so that we can simply return if
  // there's no console service without affecting the other reporting
  // mechanisms.
  nsCOMPtr<nsIConsoleService> consoleService =
      do_GetService(NS_CONSOLESERVICE_CONTRACTID);
  NS_ENSURE_TRUE_VOID(consoleService);

  RefPtr<nsScriptErrorBase> errorObject =
      CreateScriptError(aWin, aException, aStack, aStackGlobal);
  errorObject->SetErrorMessageName(mErrorMsgName);

  uint32_t flags =
      mIsWarning ? nsIScriptError::warningFlag : nsIScriptError::errorFlag;
  nsresult rv = errorObject->InitWithWindowID(
      mErrorMsg, mFileName, mLineNumber, mColumn, flags, mCategory, mWindowID,
      mCategory.Equals("chrome javascript"_ns));
  NS_ENSURE_SUCCESS_VOID(rv);

  rv = errorObject->InitSourceId(mSourceId);
  NS_ENSURE_SUCCESS_VOID(rv);

  rv = errorObject->InitIsPromiseRejection(mIsPromiseRejection);
  NS_ENSURE_SUCCESS_VOID(rv);

  for (size_t i = 0, len = mNotes.Length(); i < len; i++) {
    ErrorNote& note = mNotes[i];

    nsScriptErrorNote* noteObject = new nsScriptErrorNote();
    noteObject->Init(note.mErrorMsg, note.mFileName, note.mSourceId,
                     note.mLineNumber, note.mColumn);
    errorObject->AddNote(noteObject);
  }

  consoleService->LogMessage(errorObject);
}

/* static */
void xpc::ErrorNote::ErrorNoteToMessageString(JSErrorNotes::Note* aNote,
                                              nsAString& aString) {
  aString.Truncate();
  if (aNote->message()) {
    aString.Append(NS_ConvertUTF8toUTF16(aNote->message().c_str()));
  }
}

/* static */
void xpc::ErrorReport::ErrorReportToMessageString(JSErrorReport* aReport,
                                                  nsAString& aString) {
  aString.Truncate();
  if (aReport->message()) {
    // Don't prefix warnings with an often misleading name like "Error: ".
    if (!aReport->isWarning()) {
      JSLinearString* name = js::GetErrorTypeName(
          CycleCollectedJSContext::Get()->Context(), aReport->exnType);
      if (name) {
        AssignJSLinearString(aString, name);
        aString.AppendLiteral(": ");
      }
    }
    aString.Append(NS_ConvertUTF8toUTF16(aReport->message().c_str()));
  }
}

/***************************************************************************/

void xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS) {
  // QIing to nsIXPConnectWrappedJSUnmarkGray may have side effects!
  nsCOMPtr<nsIXPConnectWrappedJSUnmarkGray> wjsug =
      do_QueryInterface(aWrappedJS);
  Unused << wjsug;
  MOZ_ASSERT(!wjsug,
             "One should never be able to QI to "
             "nsIXPConnectWrappedJSUnmarkGray successfully!");
}

/***************************************************************************/
/***************************************************************************/
// nsIXPConnect interface methods...

template <typename T>
static inline T UnexpectedFailure(T rv) {
  NS_ERROR("This is not supposed to fail!");
  return rv;
}

void xpc::TraceXPCGlobal(JSTracer* trc, JSObject* obj) {
  if (JS::GetClass(obj)->flags & JSCLASS_DOM_GLOBAL) {
    mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
  }

  // We might be called from a GC during the creation of a global, before we've
  // been able to set up the compartment private.
  if (xpc::CompartmentPrivate* priv = xpc::CompartmentPrivate::Get(obj)) {
    MOZ_ASSERT(priv->GetScope());
    priv->GetScope()->TraceInside(trc);
  }
}

namespace xpc {

JSObject* CreateGlobalObject(JSContext* cx, const JSClass* clasp,
                             nsIPrincipal* principal,
                             JS::RealmOptions& aOptions) {
  MOZ_ASSERT(NS_IsMainThread(), "using a principal off the main thread?");
  MOZ_ASSERT(principal);

  MOZ_RELEASE_ASSERT(
      principal != nsContentUtils::GetNullSubjectPrincipal(),
      "The null subject principal is getting inherited - fix that!");

  RootedObject global(cx);
  {
    SiteIdentifier site;
    nsresult rv = BasePrincipal::Cast(principal)->GetSiteIdentifier(site);
    NS_ENSURE_SUCCESS(rv, nullptr);

    global = JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal),
                                JS::DontFireOnNewGlobalHook, aOptions);
    if (!global) {
      return nullptr;
    }
    JSAutoRealm ar(cx, global);

    RealmPrivate::Init(global, site);

    if (clasp->flags & JSCLASS_DOM_GLOBAL) {
#ifdef DEBUG
      // Verify that the right trace hook is called. Note that this doesn't
      // work right for wrapped globals, since the tracing situation there is
      // more complicated. Manual inspection shows that they do the right
      // thing. Also note that we only check this for JSCLASS_DOM_GLOBAL
      // classes because xpc::TraceXPCGlobal won't call TraceProtoAndIfaceCache
      // unless that flag is set.
      if (!((const JSClass*)clasp)->isWrappedNative()) {
        VerifyTraceProtoAndIfaceCacheCalledTracer trc(cx);
        TraceChildren(&trc, GCCellPtr(global.get()));
        MOZ_ASSERT(trc.ok,
                   "Trace hook on global needs to call TraceXPCGlobal for "
                   "XPConnect compartments.");
      }
#endif

      const char* className = clasp->name;
      AllocateProtoAndIfaceCache(global,
                                 (strcmp(className, "Window") == 0 ||
                                  strcmp(className, "ChromeWindow") == 0)
                                     ? ProtoAndIfaceCache::WindowLike
                                     : ProtoAndIfaceCache::NonWindowLike);
    }
  }

  return global;
}

void InitGlobalObjectOptions(JS::RealmOptions& aOptions,
                             bool aIsSystemPrincipal, bool aSecureContext,
                             bool aForceUTC, bool aAlwaysUseFdlibm,
                             bool aLocaleEnUS) {
  if (aIsSystemPrincipal) {
    // Make toSource functions [ChromeOnly]
    aOptions.creationOptions().setToSourceEnabled(true);
    // Make sure [SecureContext] APIs are visible:
    aOptions.creationOptions().setSecureContext(true);
    aOptions.behaviors().setClampAndJitterTime(false);
    aOptions.behaviors().setDiscardSource(ShouldDiscardSystemSource());
    MOZ_ASSERT(aSecureContext,
               "aIsSystemPrincipal should imply aSecureContext");
  } else {
    aOptions.creationOptions().setSecureContext(aSecureContext);
  }

  aOptions.creationOptions().setForceUTC(aForceUTC);
  aOptions.creationOptions().setAlwaysUseFdlibm(aAlwaysUseFdlibm);
  if (aLocaleEnUS) {
    nsCString locale = nsRFPService::GetSpoofedJSLocale();
    aOptions.creationOptions().setLocaleCopyZ(locale.get());
  }
}

bool InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal,
                      uint32_t aFlags) {
  // Immediately enter the global's realm so that everything we create
  // ends up there.
  JSAutoRealm ar(aJSContext, aGlobal);

  // Stuff coming through this path always ends up as a DOM global.
  MOZ_ASSERT(JS::GetClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL);

  if (!(aFlags & xpc::OMIT_COMPONENTS_OBJECT)) {
    // XPCCallContext gives us an active request needed to save/restore.
    if (!ObjectScope(aGlobal)->AttachComponentsObject(aJSContext) ||
        !XPCNativeWrapper::AttachNewConstructorObject(aJSContext, aGlobal)) {
      return UnexpectedFailure(false);
    }

    if (!mozJSModuleLoader::Get()->DefineJSServices(aJSContext, aGlobal)) {
      return UnexpectedFailure(false);
    }
  }

  if (!(aFlags & xpc::DONT_FIRE_ONNEWGLOBALHOOK)) {
    JS_FireOnNewGlobalObject(aJSContext, aGlobal);
  }

  return true;
}

nsresult InitClassesWithNewWrappedGlobal(JSContext* aJSContext,
                                         nsISupports* aCOMObj,
                                         nsIPrincipal* aPrincipal,
                                         uint32_t aFlags,
                                         JS::RealmOptions& aOptions,
                                         MutableHandleObject aNewGlobal) {
  MOZ_ASSERT(aJSContext, "bad param");
  MOZ_ASSERT(aCOMObj, "bad param");

  // We pass null for the 'extra' pointer during global object creation, so
  // we need to have a principal.
  MOZ_ASSERT(aPrincipal);
  // All uses (at time of writing) were System Principal, meaning
  // aShouldResistFingerprinting can be hardcoded to false.
  // If this changes, ShouldRFP needs to be updated accordingly.
  MOZ_RELEASE_ASSERT(aPrincipal->IsSystemPrincipal());

  // Similarly we can thus hardcode the RTPCallerType.
  aOptions.behaviors().setReduceTimerPrecisionCallerType(
      RTPCallerTypeToToken(RTPCallerType::SystemPrincipal));

  InitGlobalObjectOptions(aOptions, /* aSystemPrincipal */ true,
                          /* aSecureContext */ true,
                          /* aForceUTC */ false, /* aAlwaysUseFdlibm */ false,
                          /* aLocaleEnUS */ false);

  // Call into XPCWrappedNative to make a new global object, scope, and global
  // prototype.
  xpcObjectHelper helper(aCOMObj);
  MOZ_ASSERT(helper.GetScriptableFlags() & XPC_SCRIPTABLE_IS_GLOBAL_OBJECT);
  RefPtr<XPCWrappedNative> wrappedGlobal;
  nsresult rv = XPCWrappedNative::WrapNewGlobal(
      aJSContext, helper, aPrincipal, aOptions, getter_AddRefs(wrappedGlobal));
  NS_ENSURE_SUCCESS(rv, rv);

  // Grab a copy of the global and enter its compartment.
  RootedObject global(aJSContext, wrappedGlobal->GetFlatJSObject());
  MOZ_ASSERT(JS_IsGlobalObject(global));

  if (!InitGlobalObject(aJSContext, global, aFlags)) {
    return UnexpectedFailure(NS_ERROR_FAILURE);
  }

  {  // Scope for JSAutoRealm
    JSAutoRealm ar(aJSContext, global);
    if (!JS_DefineProfilingFunctions(aJSContext, global)) {
      return UnexpectedFailure(NS_ERROR_OUT_OF_MEMORY);
    }
    if (aPrincipal->IsSystemPrincipal()) {
      if (!glean::Glean::DefineGlean(aJSContext, global) ||
          !glean::GleanPings::DefineGleanPings(aJSContext, global)) {
        return UnexpectedFailure(NS_ERROR_FAILURE);
      }
    }
  }

  aNewGlobal.set(global);
  return NS_OK;
}

nsCString GetFunctionName(JSContext* cx, HandleObject obj) {
  RootedObject inner(cx, js::UncheckedUnwrap(obj));
  JSAutoRealm ar(cx, inner);

  RootedFunction fun(cx, JS_GetObjectFunction(inner));
  if (!fun) {
    // If the object isn't a function, it's likely that it has a single
    // function property (for things like nsITimerCallback). In this case,
    // return the name of that function property.

    Rooted<IdVector> idArray(cx, IdVector(cx));
    if (!JS_Enumerate(cx, inner, &idArray)) {
      JS_ClearPendingException(cx);
      return nsCString("error");
    }

    if (idArray.length() != 1) {
      return nsCString("nonfunction");
    }

    RootedId id(cx, idArray[0]);
    RootedValue v(cx);
    if (!JS_GetPropertyById(cx, inner, id, &v)) {
      JS_ClearPendingException(cx);
      return nsCString("nonfunction");
    }

    if (!v.isObject()) {
      return nsCString("nonfunction");
    }

    RootedObject vobj(cx, &v.toObject());
    return GetFunctionName(cx, vobj);
  }

  RootedString funName(cx, JS_GetMaybePartialFunctionDisplayId(fun));
  RootedScript script(cx, JS_GetFunctionScript(cx, fun));
  const char* filename = script ? JS_GetScriptFilename(script) : "anonymous";
  const char* filenameSuffix = strrchr(filename, '/');

  if (filenameSuffix) {
    filenameSuffix++;
  } else {
    filenameSuffix = filename;
  }

  nsCString displayName("anonymous");
  if (funName) {
    RootedValue funNameVal(cx, StringValue(funName));
    if (!XPCConvert::JSData2Native(cx, &displayName, funNameVal,
                                   {nsXPTType::T_UTF8STRING}, nullptr, 0,
                                   nullptr)) {
      JS_ClearPendingException(cx);
      return nsCString("anonymous");
    }
  }

  displayName.Append('[');
  displayName.Append(filenameSuffix, strlen(filenameSuffix));
  displayName.Append(']');
  return displayName;
}

}  // namespace xpc

static nsresult NativeInterface2JSObject(JSContext* aCx, HandleObject aScope,
                                         nsISupports* aCOMObj,
                                         nsWrapperCache* aCache,
                                         const nsIID* aIID, bool aAllowWrapping,
                                         MutableHandleValue aVal) {
  JSAutoRealm ar(aCx, aScope);

  nsresult rv;
  xpcObjectHelper helper(aCOMObj, aCache);
  if (!XPCConvert::NativeInterface2JSObject(aCx, aVal, helper, aIID,
                                            aAllowWrapping, &rv)) {
    return rv;
  }

  MOZ_ASSERT(
      aAllowWrapping || !xpc::WrapperFactory::IsXrayWrapper(&aVal.toObject()),
      "Shouldn't be returning a xray wrapper here");

  return NS_OK;
}

nsresult nsIXPConnect::WrapNative(JSContext* aJSContext, JSObject* aScopeArg,
                                  nsISupports* aCOMObj, const nsIID& aIID,
                                  JSObject** aRetVal) {
  MOZ_ASSERT(aJSContext, "bad param");
  MOZ_ASSERT(aScopeArg, "bad param");
  MOZ_ASSERT(aCOMObj, "bad param");

  RootedObject aScope(aJSContext, aScopeArg);
  RootedValue v(aJSContext);
  nsresult rv = NativeInterface2JSObject(aJSContext, aScope, aCOMObj, nullptr,
                                         &aIID, true, &v);
  if (NS_FAILED(rv)) {
    return rv;
  }

  if (!v.isObjectOrNull()) {
    return NS_ERROR_FAILURE;
  }

  *aRetVal = v.toObjectOrNull();
  return NS_OK;
}

nsresult nsIXPConnect::WrapNativeToJSVal(JSContext* aJSContext,
                                         JSObject* aScopeArg,
                                         nsISupports* aCOMObj,
                                         nsWrapperCache* aCache,
                                         const nsIID* aIID, bool aAllowWrapping,
                                         MutableHandleValue aVal) {
  MOZ_ASSERT(aJSContext, "bad param");
  MOZ_ASSERT(aScopeArg, "bad param");
  MOZ_ASSERT(aCOMObj, "bad param");

  RootedObject aScope(aJSContext, aScopeArg);
  return NativeInterface2JSObject(aJSContext, aScope, aCOMObj, aCache, aIID,
                                  aAllowWrapping, aVal);
}

nsresult nsIXPConnect::WrapJS(JSContext* aJSContext, JSObject* aJSObjArg,
                              const nsIID& aIID, void** result) {
  MOZ_ASSERT(aJSContext, "bad param");
  MOZ_ASSERT(aJSObjArg, "bad param");
  MOZ_ASSERT(result, "bad param");

  *result = nullptr;

  RootedObject aJSObj(aJSContext, aJSObjArg);

  nsresult rv = NS_ERROR_UNEXPECTED;
  if (!XPCConvert::JSObject2NativeInterface(aJSContext, result, aJSObj, &aIID,
                                            nullptr, &rv))
    return rv;
  return NS_OK;
}

nsresult nsIXPConnect::JSValToVariant(JSContext* cx, HandleValue aJSVal,
                                      nsIVariant** aResult) {
  MOZ_ASSERT(aResult, "bad param");

  RefPtr<XPCVariant> variant = XPCVariant::newVariant(cx, aJSVal);
  variant.forget(aResult);
  NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);

  return NS_OK;
}

nsresult nsIXPConnect::WrapJSAggregatedToNative(nsISupports* aOuter,
                                                JSContext* aJSContext,
                                                JSObject* aJSObjArg,
                                                const nsIID& aIID,
                                                void** result) {
  MOZ_ASSERT(aOuter, "bad param");
  MOZ_ASSERT(aJSContext, "bad param");
  MOZ_ASSERT(aJSObjArg, "bad param");
  MOZ_ASSERT(result, "bad param");

  *result = nullptr;

  RootedObject aJSObj(aJSContext, aJSObjArg);
  nsresult rv;
  if (!XPCConvert::JSObject2NativeInterface(aJSContext, result, aJSObj, &aIID,
                                            aOuter, &rv))
    return rv;
  return NS_OK;
}

nsresult nsIXPConnect::GetWrappedNativeOfJSObject(
    JSContext* aJSContext, JSObject* aJSObjArg,
    nsIXPConnectWrappedNative** _retval) {
  MOZ_ASSERT(aJSContext, "bad param");
  MOZ_ASSERT(aJSObjArg, "bad param");
  MOZ_ASSERT(_retval, "bad param");

  RootedObject aJSObj(aJSContext, aJSObjArg);
  aJSObj = js::CheckedUnwrapDynamic(aJSObj, aJSContext,
                                    /* stopAtWindowProxy = */ false);
  if (!aJSObj || !IsWrappedNativeReflector(aJSObj)) {
    *_retval = nullptr;
    return NS_ERROR_FAILURE;
  }

  RefPtr<XPCWrappedNative> temp = XPCWrappedNative::Get(aJSObj);
  temp.forget(_retval);
  return NS_OK;
}

static already_AddRefed<nsISupports> ReflectorToISupports(JSObject* reflector) {
  if (!reflector) {
    return nullptr;
  }

  // Try XPCWrappedNatives.
  if (IsWrappedNativeReflector(reflector)) {
    XPCWrappedNative* wn = XPCWrappedNative::Get(reflector);
    if (!wn) {
      return nullptr;
    }
    nsCOMPtr<nsISupports> native = wn->Native();
    return native.forget();
  }

  // Try DOM objects.  This QI without taking a ref first is safe, because
  // this if non-null our thing will definitely be a DOM object, and we know
  // their QI to nsISupports doesn't do anything weird.
  nsCOMPtr<nsISupports> canonical =
      do_QueryInterface(mozilla::dom::UnwrapDOMObjectToISupports(reflector));
  return canonical.forget();
}

already_AddRefed<nsISupports> xpc::ReflectorToISupportsStatic(
    JSObject* reflector) {
  // Unwrap security wrappers, if allowed.
  return ReflectorToISupports(js::CheckedUnwrapStatic(reflector));
}

already_AddRefed<nsISupports> xpc::ReflectorToISupportsDynamic(
    JSObject* reflector, JSContext* cx) {
  // Unwrap security wrappers, if allowed.
  return ReflectorToISupports(
      js::CheckedUnwrapDynamic(reflector, cx,
                               /* stopAtWindowProxy = */ false));
}

nsresult nsIXPConnect::CreateSandbox(JSContext* cx, nsIPrincipal* principal,
                                     JSObject** _retval) {
  *_retval = nullptr;

  RootedValue rval(cx);
  SandboxOptions options;
  nsresult rv = CreateSandboxObject(cx, &rval, principal, options);
  MOZ_ASSERT(NS_FAILED(rv) || !rval.isPrimitive(),
             "Bad return value from xpc_CreateSandboxObject()!");

  if (NS_SUCCEEDED(rv) && !rval.isPrimitive()) {
    *_retval = rval.toObjectOrNull();
  }

  return rv;
}

nsresult nsIXPConnect::EvalInSandboxObject(const nsAString& source,
                                           const char* filename, JSContext* cx,
                                           JSObject* sandboxArg,
                                           MutableHandleValue rval) {
  if (!sandboxArg) {
    return NS_ERROR_INVALID_ARG;
  }

  RootedObject sandbox(cx, sandboxArg);
  nsCString filenameStr;
  if (filename) {
    filenameStr.Assign(filename);
  } else {
    filenameStr = "x-bogus://XPConnect/Sandbox"_ns;
  }
  return EvalInSandbox(cx, sandbox, source, filenameStr, 1,
                       /* enforceFilenameRestrictions */ true, rval);
}

nsresult nsIXPConnect::DebugDump(int16_t depth) {
#ifdef DEBUG
  auto* self = static_cast<nsXPConnect*>(this);

  depth--;
  XPC_LOG_ALWAYS(
      ("nsXPConnect @ %p with mRefCnt = %" PRIuPTR, self, self->mRefCnt.get()));
  XPC_LOG_INDENT();
  XPC_LOG_ALWAYS(("gSelf @ %p", self->gSelf));
  XPC_LOG_ALWAYS(("gOnceAliveNowDead is %d", (int)self->gOnceAliveNowDead));
  XPCWrappedNativeScope::DebugDumpAllScopes(depth);
  XPC_LOG_OUTDENT();
#endif
  return NS_OK;
}

nsresult nsIXPConnect::DebugDumpObject(nsISupports* aCOMObj, int16_t depth) {
#ifdef DEBUG
  if (!depth) {
    return NS_OK;
  }
  if (!aCOMObj) {
    XPC_LOG_ALWAYS(("*** Cound not dump object with NULL address"));
    return NS_OK;
  }

  nsCOMPtr<nsIXPConnect> xpc;
  nsCOMPtr<nsIXPConnectWrappedNative> wn;
  nsCOMPtr<nsIXPConnectWrappedJS> wjs;

  if (NS_SUCCEEDED(aCOMObj->QueryInterface(NS_GET_IID(nsIXPConnect),
                                           getter_AddRefs(xpc)))) {
    XPC_LOG_ALWAYS(("Dumping a nsIXPConnect..."));
    xpc->DebugDump(depth);
  } else if (NS_SUCCEEDED(aCOMObj->QueryInterface(
                 NS_GET_IID(nsIXPConnectWrappedNative), getter_AddRefs(wn)))) {
    XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedNative..."));
    wn->DebugDump(depth);
  } else if (NS_SUCCEEDED(aCOMObj->QueryInterface(
                 NS_GET_IID(nsIXPConnectWrappedJS), getter_AddRefs(wjs)))) {
    XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedJS..."));
    wjs->DebugDump(depth);
  } else {
    XPC_LOG_ALWAYS(("*** Could not dump the nsISupports @ %p", aCOMObj));
  }
#endif
  return NS_OK;
}

nsresult nsIXPConnect::DebugDumpJSStack(bool showArgs, bool showLocals,
                                        bool showThisProps) {
  xpc_DumpJSStack(showArgs, showLocals, showThisProps);

  return NS_OK;
}

nsresult nsIXPConnect::VariantToJS(JSContext* ctx, JSObject* scopeArg,
                                   nsIVariant* value,
                                   MutableHandleValue _retval) {
  MOZ_ASSERT(ctx, "bad param");
  MOZ_ASSERT(scopeArg, "bad param");
  MOZ_ASSERT(value, "bad param");

  RootedObject scope(ctx, scopeArg);
  MOZ_ASSERT(js::IsObjectInContextCompartment(scope, ctx));

  nsresult rv = NS_OK;
  if (!XPCVariant::VariantDataToJS(ctx, value, &rv, _retval)) {
    if (NS_FAILED(rv)) {
      return rv;
    }

    return NS_ERROR_FAILURE;
  }
  return NS_OK;
}

nsresult nsIXPConnect::JSToVariant(JSContext* ctx, HandleValue value,
                                   nsIVariant** _retval) {
  MOZ_ASSERT(ctx, "bad param");
  MOZ_ASSERT(_retval, "bad param");

  RefPtr<XPCVariant> variant = XPCVariant::newVariant(ctx, value);
  variant.forget(_retval);
  if (!(*_retval)) {
    return NS_ERROR_FAILURE;
  }

  return NS_OK;
}

namespace xpc {

bool Base64Encode(JSContext* cx, HandleValue val, MutableHandleValue out) {
  MOZ_ASSERT(cx);

  nsAutoCString encodedString;
  BindingCallContext callCx(cx, "Base64Encode");
  if (!ConvertJSValueToByteString(callCx, val, false"value", encodedString)) {
    return false;
  }

  nsAutoCString result;
  if (NS_FAILED(mozilla::Base64Encode(encodedString, result))) {
    JS_ReportErrorASCII(cx, "Failed to encode base64 data!");
    return false;
  }

  JSString* str = JS_NewStringCopyN(cx, result.get(), result.Length());
  if (!str) {
    return false;
  }

  out.setString(str);
  return true;
}

bool Base64Decode(JSContext* cx, HandleValue val, MutableHandleValue out) {
  MOZ_ASSERT(cx);

  nsAutoCString encodedString;
  BindingCallContext callCx(cx, "Base64Decode");
  if (!ConvertJSValueToByteString(callCx, val, false"value", encodedString)) {
    return false;
  }

  nsAutoCString result;
  if (NS_FAILED(mozilla::Base64Decode(encodedString, result))) {
    JS_ReportErrorASCII(cx, "Failed to decode base64 string!");
    return false;
  }

  JSString* str = JS_NewStringCopyN(cx, result.get(), result.Length());
  if (!str) {
    return false;
  }

  out.setString(str);
  return true;
}

void SetLocationForGlobal(JSObject* global, const nsACString& location) {
  MOZ_ASSERT(global);
  RealmPrivate::Get(global)->SetLocation(location);
}

void SetLocationForGlobal(JSObject* global, nsIURI* locationURI) {
  MOZ_ASSERT(global);
  RealmPrivate::Get(global)->SetLocationURI(locationURI);
}

}  // namespace xpc

// static
nsIXPConnect* nsIXPConnect::XPConnect() {
  // Do a release-mode assert that we're not doing anything significant in
  // XPConnect off the main thread. If you're an extension developer hitting
  // this, you need to change your code. See bug 716167.
  if (!MOZ_LIKELY(NS_IsMainThread())) {
    MOZ_CRASH();
  }

  return nsXPConnect::gSelf;
}

/* These are here to be callable from a debugger */
extern "C" {

MOZ_EXPORT void DumpJSStack() { xpc_DumpJSStack(truetruefalse); }

MOZ_EXPORT void DumpCompleteHeap() {
  nsCOMPtr<nsICycleCollectorListener> listener =
      nsCycleCollector_createLogger();
  MOZ_ASSERT(listener);

  nsCOMPtr<nsICycleCollectorListener> alltracesListener;
  listener->AllTraces(getter_AddRefs(alltracesListener));
  if (!alltracesListener) {
    NS_WARNING("Failed to get all traces logger");
    return;
  }

  nsJSContext::CycleCollectNow(CCReason::DUMP_HEAP, alltracesListener);
}

}  // extern "C"

namespace xpc {

bool Atob(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  if (!args.length()) {
    return true;
  }

  return xpc::Base64Decode(cx, args[0], args.rval());
}

bool Btoa(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  if (!args.length()) {
    return true;
  }

  return xpc::Base64Encode(cx, args[0], args.rval());
}

bool IsXrayWrapper(JSObject* obj) { return WrapperFactory::IsXrayWrapper(obj); }

}  // namespace xpc

namespace mozilla {
namespace dom {

bool IsChromeOrUAWidget(JSContext* cx, JSObject* /* unused */) {
  MOZ_ASSERT(NS_IsMainThread());
  JS::Realm* realm = JS::GetCurrentRealmOrNull(cx);
  MOZ_ASSERT(realm);
  JS::Compartment* c = JS::GetCompartmentForRealm(realm);

  return AccessCheck::isChrome(c) || IsUAWidgetCompartment(c);
}

bool IsNotUAWidget(JSContext* cx, JSObject* /* unused */) {
  MOZ_ASSERT(NS_IsMainThread());
  JS::Realm* realm = JS::GetCurrentRealmOrNull(cx);
  MOZ_ASSERT(realm);
  JS::Compartment* c = JS::GetCompartmentForRealm(realm);

  return !IsUAWidgetCompartment(c);
}

extern bool IsCurrentThreadRunningChromeWorker();

bool ThreadSafeIsChromeOrUAWidget(JSContext* cx, JSObject* obj) {
  if (NS_IsMainThread()) {
    return IsChromeOrUAWidget(cx, obj);
  }
  return IsCurrentThreadRunningChromeWorker();
}

}  // namespace dom
}  // namespace mozilla

#ifdef MOZ_TSAN
ReadOnlyPage ReadOnlyPage::sInstance;
#else
constexpr const volatile ReadOnlyPage ReadOnlyPage::sInstance;
#endif

void xpc::ReadOnlyPage::Write(const volatile bool* aPtr, bool aValue) {
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
  if (*aPtr == aValue) return;
  // Please modify the definition of kAutomationPageSize if a new platform
  // is running in automation and hits this assertion.
  MOZ_RELEASE_ASSERT(PR_GetPageSize() == alignof(ReadOnlyPage));
  MOZ_RELEASE_ASSERT(
      reinterpret_cast<uintptr_t>(&sInstance) % alignof(ReadOnlyPage) == 0);
#ifdef XP_WIN
  AutoVirtualProtect prot(const_cast<ReadOnlyPage*>(&sInstance),
                          alignof(ReadOnlyPage), PAGE_READWRITE);
  MOZ_RELEASE_ASSERT(prot && (prot.PrevProt() & 0xFF) == PAGE_READONLY);
#else
  int ret = mprotect(const_cast<ReadOnlyPage*>(&sInstance),
                     alignof(ReadOnlyPage), PROT_READ | PROT_WRITE);
  MOZ_RELEASE_ASSERT(ret == 0);
#endif
  MOZ_RELEASE_ASSERT(aPtr == &sInstance.mNonLocalConnectionsDisabled ||
                     aPtr == &sInstance.mTurnOffAllSecurityPref);
#ifdef XP_WIN
  BOOL ret = WriteProcessMemory(GetCurrentProcess(), const_cast<bool*>(aPtr),
                                &aValue, sizeof(bool), nullptr);
  MOZ_RELEASE_ASSERT(ret);
#else
  *const_cast<volatile bool*>(aPtr) = aValue;
  ret = mprotect(const_cast<ReadOnlyPage*>(&sInstance), alignof(ReadOnlyPage),
                 PROT_READ);
  MOZ_RELEASE_ASSERT(ret == 0);
#endif
}

void xpc::ReadOnlyPage::Init() {
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
  static_assert(alignof(ReadOnlyPage) == kAutomationPageSize);
  static_assert(sizeof(sInstance) == alignof(ReadOnlyPage));

  // Make sure that initialization is not too late.
  MOZ_DIAGNOSTIC_ASSERT(!net::gIOService);
  char* s = getenv("MOZ_DISABLE_NONLOCAL_CONNECTIONS");
  const bool disabled = s && *s != '0';
  Write(&sInstance.mNonLocalConnectionsDisabled, disabled);
  if (!disabled) {
    // not bothered to check automation prefs.
    return;
  }

  // The obvious thing is to make this pref a static pref. But then it would
  // always be defined and always show up in about:config, and users could flip
  // it, which we don't want. Instead we roll our own callback so that if the
  // pref is undefined (the normal case) then sAutomationPrefIsSet is false and
  // nothing shows up in about:config.
  nsresult rv = Preferences::RegisterCallbackAndCall(
      [](const char* aPrefName, void/* aClosure */) {
        Write(&sInstance.mTurnOffAllSecurityPref,
              Preferences::GetBool(aPrefName, /* aFallback */ false));
      },
      "security."
      "turn_off_all_security_so_that_viruses_can_take_over_this_computer");
  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
}

Messung V0.5
C=87 H=96 G=91

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge