tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

XPCThrower.cpp (4492B)


      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 /* Code for throwing errors into JavaScript. */
      8 
      9 #include "xpcprivate.h"
     10 #include "XPCWrapper.h"
     11 #include "js/CharacterEncoding.h"
     12 #include "js/Printf.h"
     13 #include "mozilla/dom/BindingUtils.h"
     14 #include "mozilla/dom/DOMException.h"
     15 #include "mozilla/dom/Exceptions.h"
     16 #include "nsString.h"
     17 
     18 using namespace mozilla;
     19 using namespace mozilla::dom;
     20 
     21 bool XPCThrower::sVerbose = true;
     22 
     23 // static
     24 void XPCThrower::Throw(nsresult rv, JSContext* cx) {
     25  const char* format;
     26  if (JS_IsExceptionPending(cx)) {
     27    return;
     28  }
     29  if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) {
     30    format = "";
     31  }
     32  dom::Throw(cx, rv, nsDependentCString(format));
     33 }
     34 
     35 namespace xpc {
     36 
     37 bool Throw(JSContext* cx, nsresult rv) {
     38  XPCThrower::Throw(rv, cx);
     39  return false;
     40 }
     41 
     42 }  // namespace xpc
     43 
     44 /*
     45 * If there has already been an exception thrown, see if we're throwing the
     46 * same sort of exception, and if we are, don't clobber the old one. ccx
     47 * should be the current call context.
     48 */
     49 // static
     50 bool XPCThrower::CheckForPendingException(nsresult result, JSContext* cx) {
     51  RefPtr<Exception> e = XPCJSContext::Get()->GetPendingException();
     52  if (!e) {
     53    return false;
     54  }
     55  XPCJSContext::Get()->SetPendingException(nullptr);
     56 
     57  if (e->GetResult() != result) {
     58    return false;
     59  }
     60 
     61  ThrowExceptionObject(cx, e);
     62  return true;
     63 }
     64 
     65 // static
     66 void XPCThrower::Throw(nsresult rv, XPCCallContext& ccx) {
     67  char* sz;
     68  const char* format;
     69 
     70  if (CheckForPendingException(rv, ccx)) {
     71    return;
     72  }
     73 
     74  if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) {
     75    format = "";
     76  }
     77 
     78  sz = (char*)format;
     79  NS_ENSURE_TRUE_VOID(sz);
     80 
     81  if (sz && sVerbose) {
     82    Verbosify(ccx, &sz, false);
     83  }
     84 
     85  dom::Throw(ccx, rv, nsDependentCString(sz));
     86 
     87  if (sz && sz != format) {
     88    js_free(sz);
     89  }
     90 }
     91 
     92 // static
     93 void XPCThrower::ThrowBadResult(nsresult rv, nsresult result,
     94                                XPCCallContext& ccx) {
     95  char* sz;
     96  const char* format;
     97  const char* name;
     98 
     99  /*
    100   *  If there is a pending exception when the native call returns and
    101   *  it has the same error result as returned by the native call, then
    102   *  the native call may be passing through an error from a previous JS
    103   *  call. So we'll just throw that exception into our JS.  Note that
    104   *  we don't need to worry about NS_ERROR_UNCATCHABLE_EXCEPTION,
    105   *  because presumably there would be no pending exception for that
    106   *  nsresult!
    107   */
    108 
    109  if (CheckForPendingException(result, ccx)) {
    110    return;
    111  }
    112 
    113  // else...
    114 
    115  if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format) ||
    116      !format) {
    117    format = "";
    118  }
    119 
    120  if (nsXPCException::NameAndFormatForNSResult(result, &name, nullptr) &&
    121      name) {
    122    sz = JS_smprintf("%s 0x%x (%s)", format, (unsigned)result, name).release();
    123  } else {
    124    sz = JS_smprintf("%s 0x%x", format, (unsigned)result).release();
    125  }
    126  NS_ENSURE_TRUE_VOID(sz);
    127 
    128  if (sz && sVerbose) {
    129    Verbosify(ccx, &sz, true);
    130  }
    131 
    132  dom::Throw(ccx, result, nsDependentCString(sz));
    133 
    134  if (sz) {
    135    js_free(sz);
    136  }
    137 }
    138 
    139 // static
    140 void XPCThrower::ThrowBadParam(nsresult rv, unsigned paramNum,
    141                               XPCCallContext& ccx) {
    142  char* sz;
    143  const char* format;
    144 
    145  if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) {
    146    format = "";
    147  }
    148 
    149  sz = JS_smprintf("%s arg %d", format, paramNum).release();
    150  NS_ENSURE_TRUE_VOID(sz);
    151 
    152  if (sz && sVerbose) {
    153    Verbosify(ccx, &sz, true);
    154  }
    155 
    156  dom::Throw(ccx, rv, nsDependentCString(sz));
    157 
    158  if (sz) {
    159    js_free(sz);
    160  }
    161 }
    162 
    163 // static
    164 void XPCThrower::Verbosify(XPCCallContext& ccx, char** psz, bool own) {
    165  char* sz = nullptr;
    166 
    167  if (ccx.HasInterfaceAndMember()) {
    168    XPCNativeInterface* iface = ccx.GetInterface();
    169    jsid id = ccx.GetMember()->GetName();
    170    const char* name;
    171    JS::UniqueChars bytes;
    172    if (!id.isVoid()) {
    173      bytes = JS_EncodeStringToLatin1(ccx, id.toString());
    174      name = bytes ? bytes.get() : "";
    175    } else {
    176      name = "Unknown";
    177    }
    178    sz =
    179        JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name).release();
    180  }
    181 
    182  if (sz) {
    183    if (own) {
    184      js_free(*psz);
    185    }
    186    *psz = sz;
    187  }
    188 }