Example #1
0
int main(int argc, char** argv)
{
	constexpr const Uint PRINT_TIMES = 10;
	
	if( argc < 2 ) {
		fprintf(stderr, "usage: %s <word>\n", argv[0]);
		return -1;
	}

	const char* const word = argv[1];
	const Uint word_len = strlen(word);
	char* const buffer = static_cast<char*>( malloc(sizeof(char) * ( word_len + 1 )) );

	if(buffer == NULL) {
		perror("Failed to allocate memory: ");
		return -1;
	}

	const auto buffer_cleanup = MakeScopeExit([buffer] { 
		free(buffer);
		printf("buffer freed\n");
	});

	cpy_reverse(buffer, argv[1], word_len);
	buffer[word_len] = '\0';

	for(Uint i = 0; i < PRINT_TIMES; ++i) 
	{
		if( puts(buffer) == EOF ) {
			perror("puts failed: ");
			break;
		}
	}

	FILE* const file = fopen("savefile.txt", "w");
	
	if(file == nullptr) {
		perror("failed to create savefile.txt: ");
		return -1;
	}

	const auto close_file = MakeScopeExit([file] {
		fclose(file);
		printf("file closed\n");
	});

	fwrite(buffer, sizeof(char), word_len, file);
	if(ferror(file)) {
		perror("fwrite failed: ");
		return -1;
	}


	return 0;
}
Example #2
0
Result<bool, nsresult> FrameParser::VBRHeader::ParseVBRI(
    BufferReader* aReader) {
  static const uint32_t TAG = BigEndian::readUint32("VBRI");
  static const uint32_t OFFSET = 32 + FrameParser::FrameHeader::SIZE;
  static const uint32_t FRAME_COUNT_OFFSET = OFFSET + 14;
  static const uint32_t MIN_FRAME_SIZE = OFFSET + 26;

  MOZ_ASSERT(aReader);
  // ParseVBRI assumes that the ByteReader offset points to the beginning of a
  // frame, therefore as a simple check, we look for the presence of a frame
  // sync at that position.
  auto sync = aReader->PeekU16();
  if (sync.isOk()) {  // To avoid compiler complains 'set but unused'.
    MOZ_ASSERT((sync.unwrap() & 0xFFE0) == 0xFFE0);
  }

  // Seek backward to the original position before leaving this scope.
  const size_t prevReaderOffset = aReader->Offset();
  auto scopeExit = MakeScopeExit([&] { aReader->Seek(prevReaderOffset); });

  // VBRI have a fixed relative position, so let's check for it there.
  if (aReader->Remaining() > MIN_FRAME_SIZE) {
    aReader->Seek(prevReaderOffset + OFFSET);
    uint32_t tag, frames;
    MOZ_TRY_VAR(tag, aReader->ReadU32());
    if (tag == TAG) {
      aReader->Seek(prevReaderOffset + FRAME_COUNT_OFFSET);
      MOZ_TRY_VAR(frames, aReader->ReadU32());
      mNumAudioFrames = Some(frames);
      mType = VBRI;
      return true;
    }
  }
  return false;
}
Example #3
0
Result<Ok, nsresult> MemMapSnapshot::Freeze(AutoMemMap& aMem) {
  // Delete the shm file after we're done here, whether we succeed or not. The
  // open file descriptor will keep it alive until all remaining references
  // are closed, at which point it will be automatically freed.
  auto cleanup = MakeScopeExit([&]() { PR_Delete(mPath.get()); });

  // Make the shm file readonly. This doesn't make a difference in practice,
  // since we open and share a read-only file descriptor, and then delete the
  // file. But it doesn't hurt, either.
  chmod(mPath.get(), 0400);

  nsCOMPtr<nsIFile> file;
  MOZ_TRY(NS_NewNativeLocalFile(mPath, /* followLinks = */ false,
                                getter_AddRefs(file)));

  return aMem.init(file);
}
void
GetAddrInfoOperator::Reply(DNSServiceRef aSdRef,
                           DNSServiceFlags aFlags,
                           uint32_t aInterfaceIndex,
                           DNSServiceErrorType aErrorCode,
                           const nsACString& aHostName,
                           const NetAddr& aAddress,
                           uint32_t aTTL)
{
  MOZ_ASSERT(GetThread() == NS_GetCurrentThread());

  auto guard = MakeScopeExit([&] {
    Unused << NS_WARN_IF(NS_FAILED(Stop()));
  });

  if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) {
    LOG_E("GetAddrInfoOperator::Reply (%d)", aErrorCode);
    return;
  }

  if (!mListener) { return; }

  NetAddr addr = aAddress;
  nsCOMPtr<nsINetAddr> address = new nsNetAddr(&addr);
  nsCString addressStr;
  if (NS_WARN_IF(NS_FAILED(address->GetAddress(addressStr)))) { return; }

  nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(mServiceInfo);
  if (NS_WARN_IF(NS_FAILED(info->SetAddress(addressStr)))) { return; }

  /**
   * |kDNSServiceFlagsMoreComing| means this callback will be one or more
   * callback events later, so this instance should be kept alive until all
   * follow-up events are processed.
   */
  if (aFlags & kDNSServiceFlagsMoreComing) {
    guard.release();
  }

  if (kDNSServiceErr_NoError == aErrorCode) {
    mListener->OnServiceResolved(info);
  } else {
    mListener->OnResolveFailed(info, aErrorCode);
  }
}
nsresult
DoListAddresses(AddrMapType& aAddrMap)
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        return NS_ERROR_FAILURE;
    }

    auto autoCloseSocket = MakeScopeExit([&] {
      close(fd);
    });

    struct ifconf ifconf;
    /* 16k of space should be enough to list all interfaces.  Worst case, if it's
     * not then we will error out and fail to list addresses.  This should only
     * happen on pathological machines with way too many interfaces.
     */
    char buf[16384];

    ifconf.ifc_len = sizeof(buf);
    ifconf.ifc_buf = buf;
    if (ioctl(fd, SIOCGIFCONF, &ifconf) != 0) {
        return NS_ERROR_FAILURE;
    }

    struct ifreq* ifreq = ifconf.ifc_req;
    int i = 0;
    while (i < ifconf.ifc_len) {
        size_t len = sizeof(struct ifreq);

        DebugOnly<nsresult> rv =
          ListInterfaceAddresses(fd, ifreq->ifr_name, aAddrMap);
        NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ListInterfaceAddresses failed");

        ifreq = (struct ifreq*) ((char*)ifreq + len);
        i += len;
    }

    autoCloseSocket.release();
    return NS_OK;
}
Example #6
0
int main(int argc, char** argv)
{
	constexpr const Uint PRINT_TIMES = 10;
	
	if( argc < 2 ) {
		fprintf(stderr, "usage: %s <word>\n", argv[0]);
		return -1;
	}

	const Uint word_len = mystrlen(argv[1]);
	char* const buffer = static_cast<char*>( malloc(sizeof(char) * ( word_len + 1 )) );

	if(buffer == NULL) {
		perror("Failed to allocate memory: ");
		return -1;
	}

	const auto buffer_cleanup = MakeScopeExit([=] {
		puts("WRITING BUFFER TO STDOUT");
		fwrite(buffer, sizeof(char), word_len, stdout);
		putchar('\n');
		free(buffer); 
	});


	cpyback(buffer, argv[1], word_len);
	buffer[word_len] = '\0';

	for(Uint i = 0; i < PRINT_TIMES; ++i) 
	{
		if( puts(buffer) == EOF ) 
		{
			perror("puts failed: ");
			return -1;
		}
	}


	return 0;
}
Maybe<bool>
Compatibility::OnUIAMessage(WPARAM aWParam, LPARAM aLParam)
{
  auto clearUiaRemotePid = MakeScopeExit([]() {
    sUiaRemotePid = Nothing();
  });

  Telemetry::AutoTimer<Telemetry::A11Y_UIA_DETECTION_TIMING_MS> timer;

  // UIA creates a section containing the substring "HOOK_SHMEM_"
  NS_NAMED_LITERAL_STRING(kStrHookShmem, "HOOK_SHMEM_");

  // The section name always ends with this suffix, which is derived from the
  // current thread id and the UIA message's WPARAM and LPARAM.
  nsAutoString partialSectionSuffix;
  partialSectionSuffix.AppendPrintf("_%08x_%08x_%08x", ::GetCurrentThreadId(),
                                    static_cast<DWORD>(aLParam), aWParam);

  // Find any named Section that matches the naming convention of the UIA shared
  // memory.
  nsAutoHandle section;
  auto comparator = [&](const nsDependentSubstring& aName,
                        const nsDependentSubstring& aType) -> bool {
    if (aType.Equals(NS_LITERAL_STRING("Section")) &&
        FindInReadable(kStrHookShmem, aName) &&
        StringEndsWith(aName, partialSectionSuffix)) {
      section.own(::OpenFileMapping(GENERIC_READ, FALSE,
                                    PromiseFlatString(aName).get()));
      return false;
    }

    return true;
  };

  if (!FindNamedObject(comparator) || !section) {
    return Nothing();
  }

  NTSTATUS ntStatus;

  // First we must query for a list of all the open handles in the system.
  UniquePtr<char[]> handleInfoBuf;
  ULONG handleInfoBufLen = sizeof(SYSTEM_HANDLE_INFORMATION_EX) +
                           1024 * sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);

  // We must query for handle information in a loop, since we are effectively
  // asking the kernel to take a snapshot of all the handles on the system;
  // the size of the required buffer may fluctuate between successive calls.
  while (true) {
    // These allocations can be hundreds of megabytes on some computers, so
    // we should use fallible new here.
    handleInfoBuf = MakeUniqueFallible<char[]>(handleInfoBufLen);
    if (!handleInfoBuf) {
      return Nothing();
    }

    ntStatus = ::NtQuerySystemInformation(
                 (SYSTEM_INFORMATION_CLASS) SystemExtendedHandleInformation,
                 handleInfoBuf.get(), handleInfoBufLen, &handleInfoBufLen);
    if (ntStatus == STATUS_INFO_LENGTH_MISMATCH) {
      continue;
    }

    if (!NT_SUCCESS(ntStatus)) {
      return Nothing();
    }

    break;
  }

  const DWORD ourPid = ::GetCurrentProcessId();
  Maybe<PVOID> kernelObject;
  static Maybe<USHORT> sectionObjTypeIndex;
  nsTHashtable<nsUint32HashKey> nonSectionObjTypes;
  nsDataHashtable<nsVoidPtrHashKey, DWORD> objMap;

  auto handleInfo = reinterpret_cast<SYSTEM_HANDLE_INFORMATION_EX*>(handleInfoBuf.get());

  for (ULONG index = 0; index < handleInfo->mHandleCount; ++index) {
    SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX& curHandle = handleInfo->mHandles[index];

    HANDLE handle = reinterpret_cast<HANDLE>(curHandle.mHandle);

    // The mapping of the curHandle.mObjectTypeIndex field depends on the
    // underlying OS kernel. As we scan through the handle list, we record the
    // type indices such that we may use those values to skip over handles that
    // refer to non-section objects.
    if (sectionObjTypeIndex) {
      // If we know the type index for Sections, that's the fastest check...
      if (sectionObjTypeIndex.value() != curHandle.mObjectTypeIndex) {
        // Not a section
        continue;
      }
    } else if (nonSectionObjTypes.Contains(static_cast<uint32_t>(
                                             curHandle.mObjectTypeIndex))) {
      // Otherwise we check whether or not the object type is definitely _not_
      // a Section...
      continue;
    } else if (ourPid == curHandle.mPid) {
      // Otherwise we need to issue some system calls to find out the object
      // type corresponding to the current handle's type index.
      ULONG objTypeBufLen;
      ntStatus = ::NtQueryObject(handle, ObjectTypeInformation,
                                 nullptr, 0, &objTypeBufLen);
      if (ntStatus != STATUS_INFO_LENGTH_MISMATCH) {
        continue;
      }

      auto objTypeBuf = MakeUnique<char[]>(objTypeBufLen);
      ntStatus = ::NtQueryObject(handle, ObjectTypeInformation, objTypeBuf.get(),
                                 objTypeBufLen, &objTypeBufLen);
      if (!NT_SUCCESS(ntStatus)) {
        continue;
      }

      auto objType =
        reinterpret_cast<PUBLIC_OBJECT_TYPE_INFORMATION*>(objTypeBuf.get());

      // Now we check whether the object's type name matches "Section"
      nsDependentSubstring objTypeName(objType->TypeName.Buffer,
                                       objType->TypeName.Length / sizeof(wchar_t));
      if (!objTypeName.Equals(NS_LITERAL_STRING("Section"))) {
        nonSectionObjTypes.PutEntry(static_cast<uint32_t>(curHandle.mObjectTypeIndex));
        continue;
      }

      sectionObjTypeIndex = Some(curHandle.mObjectTypeIndex);
    }

    // At this point we know that curHandle references a Section object.
    // Now we can do some actual tests on it.

    if (ourPid != curHandle.mPid) {
      if (kernelObject && kernelObject.value() == curHandle.mObject) {
        // The kernel objects match -- we have found the remote pid!
        sUiaRemotePid = Some(curHandle.mPid);
        break;
      }

      // An object that is not ours. Since we do not yet know which kernel
      // object we're interested in, we'll save the current object for later.
      objMap.Put(curHandle.mObject, curHandle.mPid);
    } else if (handle == section.get()) {
      // This is the file mapping that we opened above. We save this mObject
      // in order to compare to Section objects opened by other processes.
      kernelObject = Some(curHandle.mObject);
    }
  }

  if (!kernelObject) {
    return Nothing();
  }

  if (!sUiaRemotePid) {
    // We found kernelObject *after* we saw the remote process's copy. Now we
    // must look it up in objMap.
    DWORD pid;
    if (objMap.Get(kernelObject.value(), &pid)) {
      sUiaRemotePid = Some(pid);
    }
  }

  if (!sUiaRemotePid) {
    return Nothing();
  }

  a11y::SetInstantiator(sUiaRemotePid.value());

  // Block if necessary
  nsCOMPtr<nsIFile> instantiator;
  if (a11y::GetInstantiator(getter_AddRefs(instantiator)) &&
      ShouldBlockUIAClient(instantiator)) {
    return Some(false);
  }

  return Some(true);
}
Example #8
0
/* static */
void PrioEncoder::Encode(GlobalObject& aGlobal, const nsCString& aBatchID,
                         const PrioParams& aPrioParams,
                         RootedDictionary<PrioEncodedData>& aData,
                         ErrorResult& aRv) {
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
  if (!global) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }

  SECStatus prio_rv = SECSuccess;

  if (!sSingleton) {
    nsresult rv;

    nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyA;
    rv = Preferences::GetCString("prio.publicKeyA", prioKeyA);
    if (NS_FAILED(rv)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return;
    }

    nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyB;
    rv = Preferences::GetCString("prio.publicKeyB", prioKeyB);
    if (NS_FAILED(rv)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return;
    }

    // Check that both public keys are of the right length
    // and contain only hex digits 0-9a-fA-f
    if (!PrioEncoder::IsValidHexPublicKey(prioKeyA) ||
        !PrioEncoder::IsValidHexPublicKey(prioKeyB)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return;
    }

    prio_rv = Prio_init();

    if (prio_rv != SECSuccess) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return;
    }

    prio_rv = PublicKey_import_hex(
        &sPublicKeyA,
        reinterpret_cast<const unsigned char*>(prioKeyA.BeginReading()),
        CURVE25519_KEY_LEN_HEX);
    if (prio_rv != SECSuccess) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return;
    }

    prio_rv = PublicKey_import_hex(
        &sPublicKeyB,
        reinterpret_cast<const unsigned char*>(prioKeyB.BeginReading()),
        CURVE25519_KEY_LEN_HEX);
    if (prio_rv != SECSuccess) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return;
    }

    sSingleton = new PrioEncoder();
    ClearOnShutdown(&sSingleton);
  }

  nsTArray<bool> dataItems = aPrioParams.mBooleans;
  if (dataItems.Length() > gNumBooleans) {
    aRv.ThrowRangeError<MSG_VALUE_OUT_OF_RANGE>(
        NS_LITERAL_STRING("Maximum boolean value exceeded"));
    return;
  }

  PrioConfig prioConfig = PrioConfig_new(
      dataItems.Length(), sPublicKeyA, sPublicKeyB,
      reinterpret_cast<const unsigned char*>(aBatchID.BeginReading()),
      aBatchID.Length());

  if (!prioConfig) {
    aRv.Throw(NS_ERROR_FAILURE);
    return;
  }

  auto configGuard = MakeScopeExit([&] { PrioConfig_clear(prioConfig); });

  unsigned char* forServerA = nullptr;
  unsigned int lenA = 0;
  unsigned char* forServerB = nullptr;
  unsigned int lenB = 0;

  prio_rv = PrioClient_encode(prioConfig, dataItems.Elements(), &forServerA,
                              &lenA, &forServerB, &lenB);

  nsTArray<uint8_t> arrayForServerA;
  nsTArray<uint8_t> arrayForServerB;

  if (!arrayForServerA.AppendElements(reinterpret_cast<uint8_t*>(forServerA),
                                      lenA, fallible)) {
    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    return;
  }

  free(forServerA);

  if (!arrayForServerB.AppendElements(reinterpret_cast<uint8_t*>(forServerB),
                                      lenB, fallible)) {
    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    return;
  }

  free(forServerB);

  if (prio_rv != SECSuccess) {
    aRv.Throw(NS_ERROR_FAILURE);
    return;
  }

  JS::Rooted<JS::Value> valueA(aGlobal.Context());
  if (!ToJSValue(aGlobal.Context(),
                 TypedArrayCreator<Uint8Array>(arrayForServerA), &valueA)) {
    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    return;
  }

  aData.mA.Construct().Init(&valueA.toObject());

  JS::Rooted<JS::Value> valueB(aGlobal.Context());
  if (!ToJSValue(aGlobal.Context(),
                 TypedArrayCreator<Uint8Array>(arrayForServerB), &valueB)) {
    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    return;
  }

  aData.mB.Construct().Init(&valueB.toObject());
}
void
ResolveOperator::Reply(DNSServiceRef aSdRef,
                       DNSServiceFlags aFlags,
                       uint32_t aInterfaceIndex,
                       DNSServiceErrorType aErrorCode,
                       const nsACString& aFullName,
                       const nsACString& aHostTarget,
                       uint16_t aPort,
                       uint16_t aTxtLen,
                       const unsigned char* aTxtRecord)
{
  MOZ_ASSERT(GetThread() == NS_GetCurrentThread());

  auto guard = MakeScopeExit([&] {
    Unused << NS_WARN_IF(NS_FAILED(Stop()));
  });

  if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) {
    LOG_E("ResolveOperator::Reply (%d)", aErrorCode);
    return;
  }

  // Resolve TXT record
  int count = TXTRecordGetCount(aTxtLen, aTxtRecord);
  LOG_I("resolve: txt count = %d, len = %d", count, aTxtLen);
  nsCOMPtr<nsIWritablePropertyBag2> attributes = new nsHashPropertyBag();
  if (NS_WARN_IF(!attributes)) {
    return;
  }
  if (count) {
    for (int i = 0; i < count; ++i) {
      char key[TXT_BUFFER_SIZE] = { '\0' };
      uint8_t vSize = 0;
      const void* value = nullptr;
      if (kDNSServiceErr_NoError !=
          TXTRecordGetItemAtIndex(aTxtLen,
                                  aTxtRecord,
                                  i,
                                  TXT_BUFFER_SIZE,
                                  key,
                                  &vSize,
                                  &value)) {
        break;
      }

      nsAutoCString str(reinterpret_cast<const char*>(value), vSize);
      LOG_I("resolve TXT: (%d) %s=%s", vSize, key, str.get());

      if (NS_WARN_IF(NS_FAILED(attributes->SetPropertyAsACString(
          /* it's safe to convert because key name is ASCII only. */
          NS_ConvertASCIItoUTF16(key),
          str)))) {
        break;
      }
    }
  }

  if (!mListener) { return; }
  nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(mServiceInfo);
  if (NS_WARN_IF(NS_FAILED(info->SetHost(aHostTarget)))) { return; }
  if (NS_WARN_IF(NS_FAILED(info->SetPort(aPort)))) { return; }
  if (NS_WARN_IF(NS_FAILED(info->SetAttributes(attributes)))) { return; }

  if (kDNSServiceErr_NoError == aErrorCode) {
    GetAddrInfor(info);
  }
  else {
    mListener->OnResolveFailed(info, aErrorCode);
    Unused << NS_WARN_IF(NS_FAILED(Stop()));
  }
}
Example #10
0
Result<bool, nsresult> FrameParser::VBRHeader::ParseXing(
    BufferReader* aReader) {
  static const uint32_t XING_TAG = BigEndian::readUint32("Xing");
  static const uint32_t INFO_TAG = BigEndian::readUint32("Info");

  enum Flags {
    NUM_FRAMES = 0x01,
    NUM_BYTES = 0x02,
    TOC = 0x04,
    VBR_SCALE = 0x08
  };

  MOZ_ASSERT(aReader);

  // Seek backward to the original position before leaving this scope.
  const size_t prevReaderOffset = aReader->Offset();
  auto scopeExit = MakeScopeExit([&] { aReader->Seek(prevReaderOffset); });

  // We have to search for the Xing header as its position can change.
  for (auto res = aReader->PeekU32();
       res.isOk() && res.unwrap() != XING_TAG && res.unwrap() != INFO_TAG;) {
    aReader->Read(1);
    res = aReader->PeekU32();
  }

  // Skip across the VBR header ID tag.
  MOZ_TRY(aReader->ReadU32());
  mType = XING;

  uint32_t flags;
  MOZ_TRY_VAR(flags, aReader->ReadU32());

  if (flags & NUM_FRAMES) {
    uint32_t frames;
    MOZ_TRY_VAR(frames, aReader->ReadU32());
    mNumAudioFrames = Some(frames);
  }
  if (flags & NUM_BYTES) {
    uint32_t bytes;
    MOZ_TRY_VAR(bytes, aReader->ReadU32());
    mNumBytes = Some(bytes);
  }
  if (flags & TOC && aReader->Remaining() >= vbr_header::TOC_SIZE) {
    if (!mNumBytes) {
      // We don't have the stream size to calculate offsets, skip the TOC.
      aReader->Read(vbr_header::TOC_SIZE);
    } else {
      mTOC.clear();
      mTOC.reserve(vbr_header::TOC_SIZE);
      uint8_t data;
      for (size_t i = 0; i < vbr_header::TOC_SIZE; ++i) {
        MOZ_TRY_VAR(data, aReader->ReadU8());
        mTOC.push_back(1.0f / 256.0f * data * mNumBytes.value());
      }
    }
  }
  if (flags & VBR_SCALE) {
    uint32_t scale;
    MOZ_TRY_VAR(scale, aReader->ReadU32());
    mScale = Some(scale);
  }

  return mType == XING;
}
Example #11
0
ProxyStream::ProxyStream(REFIID aIID, IUnknown* aObject, Environment* aEnv,
                         ProxyStreamFlags aFlags)
  : mGlobalLockedBuf(nullptr)
  , mHGlobal(nullptr)
  , mBufSize(0)
  , mPreserveStream(aFlags & ProxyStreamFlags::ePreservable)
{
  if (!aObject) {
    return;
  }

  RefPtr<IStream> stream;
  HGLOBAL hglobal = NULL;
  int streamSize = 0;
  DWORD mshlFlags = mPreserveStream ? MSHLFLAGS_TABLESTRONG : MSHLFLAGS_NORMAL;

  HRESULT createStreamResult = S_OK;
  HRESULT marshalResult = S_OK;
  HRESULT statResult = S_OK;
  HRESULT getHGlobalResult = S_OK;

  nsAutoString manifestPath;

  auto marshalFn = [this, &aIID, aObject, mshlFlags, &stream, &streamSize,
                    &hglobal, &createStreamResult, &marshalResult, &statResult,
                    &getHGlobalResult, aEnv, &manifestPath]() -> void
  {
    if (aEnv) {
      bool pushOk = aEnv->Push();
      MOZ_DIAGNOSTIC_ASSERT(pushOk);
      if (!pushOk) {
        return;
      }
    }

    auto popEnv = MakeScopeExit([aEnv]() -> void {
      if (!aEnv) {
        return;
      }

      bool popOk = aEnv->Pop();
      MOZ_DIAGNOSTIC_ASSERT(popOk);
    });

    createStreamResult = ::CreateStreamOnHGlobal(nullptr, TRUE,
                                                 getter_AddRefs(stream));
    if (FAILED(createStreamResult)) {
      return;
    }

#if defined(ACCESSIBILITY)
    ActivationContext::GetCurrentManifestPath(manifestPath);
#endif // defined(ACCESSIBILITY)

    marshalResult = ::CoMarshalInterface(stream, aIID, aObject, MSHCTX_LOCAL,
                                         nullptr, mshlFlags);
#if !defined(MOZ_DEV_EDITION)
    MOZ_DIAGNOSTIC_ASSERT(marshalResult != E_INVALIDARG);
#endif // !defined(MOZ_DEV_EDITION)
    if (FAILED(marshalResult)) {
      return;
    }

    STATSTG statstg;
    statResult = stream->Stat(&statstg, STATFLAG_NONAME);
    if (SUCCEEDED(statResult)) {
      streamSize = static_cast<int>(statstg.cbSize.LowPart);
    } else {
      return;
    }

    getHGlobalResult = ::GetHGlobalFromStream(stream, &hglobal);
    MOZ_ASSERT(SUCCEEDED(getHGlobalResult));
  };

  if (XRE_IsParentProcess()) {
    // We'll marshal this stuff directly using the current thread, therefore its
    // stub will reside in the same apartment as the current thread.
    marshalFn();
  } else {
    // When marshaling in child processes, we want to force the MTA.
    EnsureMTA mta(marshalFn);
  }

  if (FAILED(createStreamResult)) {
    nsPrintfCString hrAsStr("0x%08X", createStreamResult);
    CrashReporter::AnnotateCrashReport(
        NS_LITERAL_CSTRING("CreateStreamOnHGlobalFailure"),
        hrAsStr);
  }

  if (FAILED(marshalResult)) {
    AnnotateInterfaceRegistration(aIID);
    nsPrintfCString hrAsStr("0x%08X", marshalResult);
    CrashReporter::AnnotateCrashReport(
        NS_LITERAL_CSTRING("CoMarshalInterfaceFailure"), hrAsStr);
    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("MarshalActCtxManifestPath"),
                                       NS_ConvertUTF16toUTF8(manifestPath));
  }

  if (FAILED(statResult)) {
    nsPrintfCString hrAsStr("0x%08X", statResult);
    CrashReporter::AnnotateCrashReport(
        NS_LITERAL_CSTRING("StatFailure"),
        hrAsStr);
  }

  if (FAILED(getHGlobalResult)) {
    nsPrintfCString hrAsStr("0x%08X", getHGlobalResult);
    CrashReporter::AnnotateCrashReport(
        NS_LITERAL_CSTRING("GetHGlobalFromStreamFailure"),
        hrAsStr);
  }

  mStream = mozilla::Move(stream);

  if (streamSize) {
    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamSizeFrom"),
                                       NS_LITERAL_CSTRING("IStream::Stat"));
    mBufSize = streamSize;
  }

  if (!hglobal) {
    return;
  }

  mGlobalLockedBuf = reinterpret_cast<BYTE*>(::GlobalLock(hglobal));
  mHGlobal = hglobal;

  // If we couldn't get the stream size directly from mStream, we may use
  // the size of the memory block allocated by the HGLOBAL, though it might
  // be larger than the actual stream size.
  if (!streamSize) {
    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamSizeFrom"),
                                       NS_LITERAL_CSTRING("GlobalSize"));
    mBufSize = static_cast<int>(::GlobalSize(hglobal));
  }

  nsAutoCString strBufSize;
  strBufSize.AppendInt(mBufSize);

  CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamSize"),
                                     strBufSize);
}