зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central a=merge
This commit is contained in:
Коммит
edbf2c0099
|
@ -62,18 +62,19 @@ if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
|
|||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
RCINCLUDE = 'splash.rc'
|
||||
DEFINES['MOZ_PHOENIX'] = True
|
||||
SOURCES += [
|
||||
'LauncherProcessWin.cpp',
|
||||
'LaunchUnelevated.cpp',
|
||||
DIRS += [
|
||||
'winlauncher',
|
||||
]
|
||||
USE_LIBS += [
|
||||
'winlauncher',
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
'/browser/app/winlauncher',
|
||||
]
|
||||
DELAYLOAD_DLLS += [
|
||||
'oleaut32.dll',
|
||||
'ole32.dll',
|
||||
]
|
||||
OS_LIBS += [
|
||||
'oleaut32',
|
||||
'ole32',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
|
||||
# For sandbox includes and the include dependencies those have
|
||||
|
|
|
@ -254,6 +254,11 @@ InitXPCOMGlue()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef HAS_DLL_BLOCKLIST
|
||||
// NB: This must be extern, as this value is checked elsewhere
|
||||
uint32_t gBlocklistInitFlags = eDllBlocklistInitFlagDefault;
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[], char* envp[])
|
||||
{
|
||||
mozilla::TimeStamp start = mozilla::TimeStamp::Now();
|
||||
|
@ -289,7 +294,7 @@ int main(int argc, char* argv[], char* envp[])
|
|||
#endif
|
||||
|
||||
#ifdef HAS_DLL_BLOCKLIST
|
||||
DllBlocklist_Initialize();
|
||||
DllBlocklist_Initialize(gBlocklistInitFlags);
|
||||
#endif
|
||||
|
||||
nsresult rv = InitXPCOMGlue();
|
||||
|
|
|
@ -0,0 +1,431 @@
|
|||
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "NativeNt.h"
|
||||
#include "nsWindowsDllInterceptor.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
#define DLL_BLOCKLIST_ENTRY(name, ...) \
|
||||
{ L##name, __VA_ARGS__ },
|
||||
#define DLL_BLOCKLIST_CHAR_TYPE wchar_t
|
||||
|
||||
// Restrict the blocklist definitions to Nightly-only for now
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
#include "mozilla/WindowsDllBlocklistDefs.h"
|
||||
#else
|
||||
#include "mozilla/WindowsDllBlocklistCommon.h"
|
||||
DLL_BLOCKLIST_DEFINITIONS_BEGIN
|
||||
DLL_BLOCKLIST_DEFINITIONS_END
|
||||
#endif
|
||||
|
||||
extern uint32_t gBlocklistInitFlags;
|
||||
|
||||
static const HANDLE kCurrentProcess = reinterpret_cast<HANDLE>(-1);
|
||||
|
||||
class MOZ_STATIC_CLASS MOZ_TRIVIAL_CTOR_DTOR NativeNtBlockSet final
|
||||
{
|
||||
struct NativeNtBlockSetEntry
|
||||
{
|
||||
NativeNtBlockSetEntry() = default;
|
||||
~NativeNtBlockSetEntry() = default;
|
||||
NativeNtBlockSetEntry(const wchar_t* aName, uint64_t aVersion,
|
||||
NativeNtBlockSetEntry* aNext)
|
||||
: mName(aName)
|
||||
, mVersion(aVersion)
|
||||
, mNext(aNext)
|
||||
{}
|
||||
const wchar_t* mName;
|
||||
uint64_t mVersion;
|
||||
NativeNtBlockSetEntry* mNext;
|
||||
};
|
||||
|
||||
public:
|
||||
// Constructor and destructor MUST be trivial
|
||||
NativeNtBlockSet() = default;
|
||||
~NativeNtBlockSet() = default;
|
||||
|
||||
void Add(const wchar_t* aName, uint64_t aVersion);
|
||||
void Write(HANDLE aFile);
|
||||
|
||||
private:
|
||||
static NativeNtBlockSetEntry* NewEntry(const wchar_t* aName, uint64_t aVersion,
|
||||
NativeNtBlockSetEntry* aNextEntry);
|
||||
|
||||
private:
|
||||
NativeNtBlockSetEntry* mFirstEntry;
|
||||
// SRWLOCK_INIT == 0, so this is okay to use without any additional work as
|
||||
// long as NativeNtBlockSet is instantiated statically
|
||||
SRWLOCK mLock;
|
||||
};
|
||||
|
||||
NativeNtBlockSet::NativeNtBlockSetEntry*
|
||||
NativeNtBlockSet::NewEntry(const wchar_t* aName, uint64_t aVersion,
|
||||
NativeNtBlockSet::NativeNtBlockSetEntry* aNextEntry)
|
||||
{
|
||||
HANDLE processHeap = mozilla::nt::RtlGetProcessHeap();
|
||||
if (!processHeap) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PVOID memory = ::RtlAllocateHeap(processHeap, 0, sizeof(NativeNtBlockSetEntry));
|
||||
if (!memory) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new (memory) NativeNtBlockSetEntry(aName, aVersion, aNextEntry);
|
||||
}
|
||||
|
||||
void
|
||||
NativeNtBlockSet::Add(const wchar_t* aName, uint64_t aVersion)
|
||||
{
|
||||
::RtlAcquireSRWLockExclusive(&mLock);
|
||||
|
||||
for (NativeNtBlockSetEntry* entry = mFirstEntry; entry; entry = entry->mNext) {
|
||||
// We just need to compare the string pointers, not the strings themselves,
|
||||
// as we always pass in the strings statically defined in the blocklist.
|
||||
if (aName == entry->mName && aVersion == entry->mVersion) {
|
||||
::RtlReleaseSRWLockExclusive(&mLock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Not present, add it
|
||||
NativeNtBlockSetEntry* newEntry = NewEntry(aName, aVersion, mFirstEntry);
|
||||
mFirstEntry = newEntry;
|
||||
|
||||
::RtlReleaseSRWLockExclusive(&mLock);
|
||||
}
|
||||
|
||||
void
|
||||
NativeNtBlockSet::Write(HANDLE aFile)
|
||||
{
|
||||
// NB: If this function is called, it is long after kernel32 is initialized,
|
||||
// so it is safe to use Win32 calls here.
|
||||
DWORD nBytes;
|
||||
char buf[MAX_PATH];
|
||||
|
||||
// It would be nicer to use RAII here. However, its destructor
|
||||
// might not run if an exception occurs, in which case we would never release
|
||||
// the lock (MSVC warns about this possibility). So we acquire and release
|
||||
// manually.
|
||||
::AcquireSRWLockExclusive(&mLock);
|
||||
|
||||
MOZ_SEH_TRY {
|
||||
for (auto entry = mFirstEntry; entry; entry = entry->mNext) {
|
||||
int convOk = ::WideCharToMultiByte(CP_UTF8, 0, entry->mName, -1, buf,
|
||||
sizeof(buf), nullptr, nullptr);
|
||||
if (!convOk) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// write name[,v.v.v.v];
|
||||
if (!WriteFile(aFile, buf, convOk, &nBytes, nullptr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry->mVersion != ALL_VERSIONS) {
|
||||
WriteFile(aFile, ",", 1, &nBytes, nullptr);
|
||||
uint16_t parts[4];
|
||||
parts[0] = entry->mVersion >> 48;
|
||||
parts[1] = (entry->mVersion >> 32) & 0xFFFF;
|
||||
parts[2] = (entry->mVersion >> 16) & 0xFFFF;
|
||||
parts[3] = entry->mVersion & 0xFFFF;
|
||||
for (size_t p = 0; p < mozilla::ArrayLength(parts); ++p) {
|
||||
ltoa(parts[p], buf, 10);
|
||||
WriteFile(aFile, buf, strlen(buf), &nBytes, nullptr);
|
||||
if (p != mozilla::ArrayLength(parts) - 1) {
|
||||
WriteFile(aFile, ".", 1, &nBytes, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteFile(aFile, ";", 1, &nBytes, nullptr);
|
||||
}
|
||||
}
|
||||
MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
}
|
||||
|
||||
::ReleaseSRWLockExclusive(&mLock);
|
||||
}
|
||||
|
||||
static NativeNtBlockSet gBlockSet;
|
||||
|
||||
extern "C" void MOZ_EXPORT
|
||||
NativeNtBlockSet_Write(HANDLE aHandle)
|
||||
{
|
||||
gBlockSet.Write(aHandle);
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckBlockInfo(const DllBlockInfo* aInfo, void* aBaseAddress, uint64_t& aVersion)
|
||||
{
|
||||
aVersion = ALL_VERSIONS;
|
||||
|
||||
if (aInfo->flags & (DllBlockInfo::BLOCK_WIN8PLUS_ONLY | DllBlockInfo::BLOCK_WIN8_ONLY)) {
|
||||
RTL_OSVERSIONINFOW osv;
|
||||
NTSTATUS ntStatus = ::RtlGetVersion(&osv);
|
||||
if (!NT_SUCCESS(ntStatus)) {
|
||||
// huh?
|
||||
return false;
|
||||
}
|
||||
|
||||
if (osv.dwMajorVersion < 8) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((aInfo->flags & DllBlockInfo::BLOCK_WIN8_ONLY) && (osv.dwMajorVersion > 8 ||
|
||||
(osv.dwMajorVersion == 8 && osv.dwMinorVersion > 0))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// We're not bootstrapping child processes at this time, so this case is
|
||||
// always true.
|
||||
if (aInfo->flags & DllBlockInfo::CHILD_PROCESSES_ONLY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aInfo->maxVersion == ALL_VERSIONS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::nt::PEHeaders headers(aBaseAddress);
|
||||
if (!headers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aInfo->flags & DllBlockInfo::USE_TIMESTAMP) {
|
||||
DWORD timestamp;
|
||||
if (!headers.GetTimeStamp(timestamp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return timestamp > aInfo->maxVersion;
|
||||
}
|
||||
|
||||
// Else we try to get the file version information. Note that we don't have
|
||||
// access to GetFileVersionInfo* APIs.
|
||||
if (!headers.GetVersionInfo(aVersion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return aVersion > aInfo->maxVersion;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsDllAllowed(const UNICODE_STRING& aLeafName, void* aBaseAddress)
|
||||
{
|
||||
if (mozilla::nt::Contains12DigitHexString(aLeafName) ||
|
||||
mozilla::nt::IsFileNameAtLeast16HexDigits(aLeafName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UNICODE_STRING testStr;
|
||||
DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(info);
|
||||
while (info->name) {
|
||||
::RtlInitUnicodeString(&testStr, info->name);
|
||||
if (::RtlEqualUnicodeString(&aLeafName, &testStr, TRUE)) {
|
||||
break;
|
||||
}
|
||||
|
||||
++info;
|
||||
}
|
||||
|
||||
uint64_t version;
|
||||
if (info->name && !CheckBlockInfo(info, aBaseAddress, version)) {
|
||||
gBlockSet.Add(info->name, version);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef decltype(&NtMapViewOfSection) NtMapViewOfSection_func;
|
||||
static NtMapViewOfSection_func stub_NtMapViewOfSection;
|
||||
|
||||
static NTSTATUS NTAPI
|
||||
patched_NtMapViewOfSection(HANDLE aSection, HANDLE aProcess, PVOID* aBaseAddress,
|
||||
ULONG_PTR aZeroBits, SIZE_T aCommitSize,
|
||||
PLARGE_INTEGER aSectionOffset, PSIZE_T aViewSize,
|
||||
SECTION_INHERIT aInheritDisposition,
|
||||
ULONG aAllocationType, ULONG aProtectionFlags)
|
||||
{
|
||||
// We always map first, then we check for additional info after.
|
||||
NTSTATUS stubStatus = stub_NtMapViewOfSection(aSection, aProcess, aBaseAddress,
|
||||
aZeroBits, aCommitSize,
|
||||
aSectionOffset, aViewSize,
|
||||
aInheritDisposition,
|
||||
aAllocationType, aProtectionFlags);
|
||||
if (!NT_SUCCESS(stubStatus)) {
|
||||
return stubStatus;
|
||||
}
|
||||
|
||||
if (aProcess != kCurrentProcess) {
|
||||
// We're only interested in mapping for the current process.
|
||||
return stubStatus;
|
||||
}
|
||||
|
||||
// Do a query to see if the memory is MEM_IMAGE. If not, continue
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
NTSTATUS ntStatus = ::NtQueryVirtualMemory(aProcess, *aBaseAddress,
|
||||
MemoryBasicInformation, &mbi,
|
||||
sizeof(mbi), nullptr);
|
||||
if (!NT_SUCCESS(ntStatus)) {
|
||||
::NtUnmapViewOfSection(aProcess, *aBaseAddress);
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
// We don't care about mappings that aren't MEM_IMAGE
|
||||
if (!(mbi.Type & MEM_IMAGE)) {
|
||||
return stubStatus;
|
||||
}
|
||||
|
||||
// Get the section name
|
||||
mozilla::nt::MemorySectionNameBuf buf;
|
||||
|
||||
ntStatus = ::NtQueryVirtualMemory(aProcess, *aBaseAddress, MemorySectionName,
|
||||
&buf, sizeof(buf), nullptr);
|
||||
if (!NT_SUCCESS(ntStatus)) {
|
||||
::NtUnmapViewOfSection(aProcess, *aBaseAddress);
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
// Find the leaf name
|
||||
UNICODE_STRING leaf;
|
||||
mozilla::nt::GetLeafName(&leaf, &buf.mSectionFileName);
|
||||
|
||||
// Check blocklist
|
||||
if (IsDllAllowed(leaf, *aBaseAddress)) {
|
||||
return stubStatus;
|
||||
}
|
||||
|
||||
::NtUnmapViewOfSection(aProcess, *aBaseAddress);
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MOZ_RAII AutoVirtualProtect final
|
||||
{
|
||||
public:
|
||||
AutoVirtualProtect(void* aAddress, size_t aLength, DWORD aProtFlags,
|
||||
HANDLE aTargetProcess = nullptr)
|
||||
: mAddress(aAddress)
|
||||
, mLength(aLength)
|
||||
, mTargetProcess(aTargetProcess)
|
||||
, mPrevProt(0)
|
||||
{
|
||||
::VirtualProtectEx(aTargetProcess, aAddress, aLength, aProtFlags,
|
||||
&mPrevProt);
|
||||
}
|
||||
|
||||
~AutoVirtualProtect()
|
||||
{
|
||||
if (!mPrevProt) {
|
||||
return;
|
||||
}
|
||||
|
||||
::VirtualProtectEx(mTargetProcess, mAddress, mLength, mPrevProt,
|
||||
&mPrevProt);
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return !!mPrevProt;
|
||||
}
|
||||
|
||||
AutoVirtualProtect(const AutoVirtualProtect&) = delete;
|
||||
AutoVirtualProtect(AutoVirtualProtect&&) = delete;
|
||||
AutoVirtualProtect& operator=(const AutoVirtualProtect&) = delete;
|
||||
AutoVirtualProtect& operator=(AutoVirtualProtect&&) = delete;
|
||||
|
||||
private:
|
||||
void* mAddress;
|
||||
size_t mLength;
|
||||
HANDLE mTargetProcess;
|
||||
DWORD mPrevProt;
|
||||
};
|
||||
|
||||
bool
|
||||
InitializeDllBlocklistOOP(HANDLE aChildProcess)
|
||||
{
|
||||
mozilla::CrossProcessDllInterceptor intcpt(aChildProcess);
|
||||
intcpt.Init(L"ntdll.dll");
|
||||
bool ok = intcpt.AddDetour("NtMapViewOfSection",
|
||||
reinterpret_cast<intptr_t>(&patched_NtMapViewOfSection),
|
||||
(void**) &stub_NtMapViewOfSection);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the child process's copy of stub_NtMapViewOfSection
|
||||
SIZE_T bytesWritten;
|
||||
ok = !!::WriteProcessMemory(aChildProcess, &stub_NtMapViewOfSection,
|
||||
&stub_NtMapViewOfSection,
|
||||
sizeof(stub_NtMapViewOfSection), &bytesWritten);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Because aChildProcess has just been created in a suspended state, its
|
||||
// dynamic linker has not yet been initialized, thus its executable has
|
||||
// not yet been linked with ntdll.dll. If the blocklist hook intercepts a
|
||||
// library load prior to the link, the hook will be unable to invoke any
|
||||
// ntdll.dll functions.
|
||||
//
|
||||
// We know that the executable for our *current* process's binary is already
|
||||
// linked into ntdll, so we obtain the IAT from our own executable and graft
|
||||
// it onto the child process's IAT, thus enabling the child process's hook to
|
||||
// safely make its ntdll calls.
|
||||
mozilla::nt::PEHeaders ourExeImage(::GetModuleHandleW(nullptr));
|
||||
if (!ourExeImage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PIMAGE_IMPORT_DESCRIPTOR impDesc = ourExeImage.GetIATForModule("ntdll.dll");
|
||||
if (!impDesc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is the pointer we need to write
|
||||
auto firstIatThunk = ourExeImage.template
|
||||
RVAToPtr<PIMAGE_THUNK_DATA>(impDesc->FirstThunk);
|
||||
if (!firstIatThunk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the length by iterating through the table until we find a null entry
|
||||
PIMAGE_THUNK_DATA curIatThunk = firstIatThunk;
|
||||
while (mozilla::nt::PEHeaders::IsValid(curIatThunk)) {
|
||||
++curIatThunk;
|
||||
}
|
||||
|
||||
ptrdiff_t iatLength = (curIatThunk - firstIatThunk) * sizeof(IMAGE_THUNK_DATA);
|
||||
|
||||
{ // Scope for prot
|
||||
AutoVirtualProtect prot(firstIatThunk, iatLength, PAGE_READWRITE,
|
||||
aChildProcess);
|
||||
if (!prot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ok = !!::WriteProcessMemory(aChildProcess, firstIatThunk, firstIatThunk,
|
||||
iatLength, &bytesWritten);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the mozglue blocklist that we have bootstrapped
|
||||
uint32_t newFlags = eDllBlocklistInitFlagWasBootstrapped;
|
||||
ok = !!::WriteProcessMemory(aChildProcess, &gBlocklistInitFlags, &newFlags,
|
||||
sizeof(newFlags), &bytesWritten);
|
||||
return ok;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,18 @@
|
|||
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_DllBlocklistWin_h
|
||||
#define mozilla_DllBlocklistWin_h
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
bool InitializeDllBlocklistOOP(HANDLE aChildProcess);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_DllBlocklistWin_h
|
|
@ -21,6 +21,7 @@
|
|||
#include <windows.h>
|
||||
#include <processthreadsapi.h>
|
||||
|
||||
#include "DllBlocklistWin.h"
|
||||
#include "LaunchUnelevated.h"
|
||||
#include "ProcThreadAttributes.h"
|
||||
|
||||
|
@ -34,7 +35,7 @@ static bool
|
|||
PostCreationSetup(HANDLE aChildProcess, HANDLE aChildMainThread,
|
||||
const bool aIsSafeMode)
|
||||
{
|
||||
return true;
|
||||
return mozilla::InitializeDllBlocklistOOP(aChildProcess);
|
||||
}
|
||||
|
||||
#if !defined(PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON)
|
|
@ -0,0 +1,546 @@
|
|||
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_NativeNt_h
|
||||
#define mozilla_NativeNt_h
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
#error "This header is for initial process initialization. You don't want to be including this here."
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
#include <winnt.h>
|
||||
#include <winternl.h>
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
#if !defined(STATUS_ACCESS_DENIED)
|
||||
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
|
||||
#endif // !defined(STATUS_ACCESS_DENIED)
|
||||
|
||||
#if !defined(STATUS_DLL_NOT_FOUND)
|
||||
#define STATUS_DLL_NOT_FOUND ((NTSTATUS)0xC0000135L)
|
||||
#endif // !defined(STATUS_DLL_NOT_FOUND)
|
||||
|
||||
enum SECTION_INHERIT
|
||||
{
|
||||
ViewShare = 1,
|
||||
ViewUnmap = 2
|
||||
};
|
||||
|
||||
NTSTATUS NTAPI
|
||||
NtMapViewOfSection(HANDLE aSection, HANDLE aProcess, PVOID* aBaseAddress,
|
||||
ULONG_PTR aZeroBits, SIZE_T aCommitSize,
|
||||
PLARGE_INTEGER aSectionOffset, PSIZE_T aViewSize,
|
||||
SECTION_INHERIT aInheritDisposition, ULONG aAllocationType,
|
||||
ULONG aProtectionFlags);
|
||||
|
||||
NTSTATUS NTAPI
|
||||
NtUnmapViewOfSection(HANDLE aProcess, PVOID aBaseAddress);
|
||||
|
||||
enum MEMORY_INFORMATION_CLASS
|
||||
{
|
||||
MemoryBasicInformation = 0,
|
||||
MemorySectionName = 2
|
||||
};
|
||||
|
||||
// NB: When allocating, space for the buffer must also be included
|
||||
typedef struct _MEMORY_SECTION_NAME
|
||||
{
|
||||
UNICODE_STRING mSectionFileName;
|
||||
} MEMORY_SECTION_NAME, *PMEMORY_SECTION_NAME;
|
||||
|
||||
NTSTATUS NTAPI
|
||||
NtQueryVirtualMemory(HANDLE aProcess, PVOID aBaseAddress,
|
||||
MEMORY_INFORMATION_CLASS aMemInfoClass, PVOID aMemInfo,
|
||||
SIZE_T aMemInfoLen, PSIZE_T aReturnLen);
|
||||
|
||||
LONG NTAPI
|
||||
RtlCompareUnicodeString(PCUNICODE_STRING aStr1, PCUNICODE_STRING aStr2,
|
||||
BOOLEAN aCaseInsensitive);
|
||||
|
||||
BOOLEAN NTAPI
|
||||
RtlEqualUnicodeString(PCUNICODE_STRING aStr1, PCUNICODE_STRING aStr2,
|
||||
BOOLEAN aCaseInsensitive);
|
||||
|
||||
NTSTATUS NTAPI
|
||||
RtlGetVersion(PRTL_OSVERSIONINFOW aOutVersionInformation);
|
||||
|
||||
PVOID NTAPI
|
||||
RtlAllocateHeap(PVOID aHeapHandle, ULONG aFlags, SIZE_T aSize);
|
||||
|
||||
PVOID NTAPI
|
||||
RtlReAllocateHeap(PVOID aHeapHandle, ULONG aFlags, LPVOID aMem, SIZE_T aNewSize);
|
||||
|
||||
BOOLEAN NTAPI
|
||||
RtlFreeHeap(PVOID aHeapHandle, ULONG aFlags, PVOID aHeapBase);
|
||||
|
||||
VOID NTAPI
|
||||
RtlAcquireSRWLockExclusive(PSRWLOCK aLock);
|
||||
|
||||
VOID NTAPI
|
||||
RtlReleaseSRWLockExclusive(PSRWLOCK aLock);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
namespace mozilla {
|
||||
namespace nt {
|
||||
|
||||
struct MemorySectionNameBuf : public _MEMORY_SECTION_NAME
|
||||
{
|
||||
MemorySectionNameBuf()
|
||||
{
|
||||
mSectionFileName.Length = 0;
|
||||
mSectionFileName.MaximumLength = sizeof(mBuf);
|
||||
mSectionFileName.Buffer = mBuf;
|
||||
}
|
||||
|
||||
WCHAR mBuf[MAX_PATH];
|
||||
};
|
||||
|
||||
inline bool
|
||||
FindCharInUnicodeString(const UNICODE_STRING& aStr, WCHAR aChar, uint16_t& aPos,
|
||||
uint16_t aStartIndex = 0)
|
||||
{
|
||||
const uint16_t aMaxIndex = aStr.Length / sizeof(WCHAR);
|
||||
|
||||
for (uint16_t curIndex = aStartIndex; curIndex < aMaxIndex; ++curIndex) {
|
||||
if (aStr.Buffer[curIndex] == aChar) {
|
||||
aPos = curIndex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsHexDigit(WCHAR aChar)
|
||||
{
|
||||
return aChar >= L'0' && aChar <= L'9' ||
|
||||
aChar >= L'A' && aChar <= L'F' ||
|
||||
aChar >= L'a' && aChar <= L'f';
|
||||
}
|
||||
|
||||
inline bool
|
||||
MatchUnicodeString(const UNICODE_STRING& aStr, bool (*aPredicate)(WCHAR))
|
||||
{
|
||||
WCHAR* cur = aStr.Buffer;
|
||||
WCHAR* end = &aStr.Buffer[aStr.Length / sizeof(WCHAR)];
|
||||
while (cur < end) {
|
||||
if (!aPredicate(*cur)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++cur;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Contains12DigitHexString(const UNICODE_STRING& aLeafName)
|
||||
{
|
||||
uint16_t start, end;
|
||||
if (!FindCharInUnicodeString(aLeafName, L'.', start)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++start;
|
||||
if (!FindCharInUnicodeString(aLeafName, L'.', end, start)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (end - start != 12) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UNICODE_STRING test;
|
||||
test.Buffer = &aLeafName.Buffer[start];
|
||||
test.Length = (end - start) * sizeof(WCHAR);
|
||||
test.MaximumLength = test.Length;
|
||||
|
||||
return MatchUnicodeString(test, &IsHexDigit);
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsFileNameAtLeast16HexDigits(const UNICODE_STRING& aLeafName)
|
||||
{
|
||||
uint16_t dotIndex;
|
||||
if (!FindCharInUnicodeString(aLeafName, L'.', dotIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dotIndex < 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UNICODE_STRING test;
|
||||
test.Buffer = aLeafName.Buffer;
|
||||
test.Length = dotIndex * sizeof(WCHAR);
|
||||
test.MaximumLength = aLeafName.MaximumLength;
|
||||
|
||||
return MatchUnicodeString(test, &IsHexDigit);
|
||||
}
|
||||
|
||||
inline void
|
||||
GetLeafName(PUNICODE_STRING aDestString, PCUNICODE_STRING aSrcString)
|
||||
{
|
||||
WCHAR* buf = aSrcString->Buffer;
|
||||
WCHAR* end = &aSrcString->Buffer[(aSrcString->Length / sizeof(WCHAR)) - 1];
|
||||
WCHAR* cur = end;
|
||||
while (cur >= buf) {
|
||||
if (*cur == L'\\') {
|
||||
break;
|
||||
}
|
||||
|
||||
--cur;
|
||||
}
|
||||
|
||||
// At this point, either cur points to the final backslash, or it points to
|
||||
// buf - 1. Either way, we're interested in cur + 1 as the desired buffer.
|
||||
aDestString->Buffer = cur + 1;
|
||||
aDestString->Length = (end - aDestString->Buffer + 1) * sizeof(WCHAR);
|
||||
aDestString->MaximumLength = aDestString->Length;
|
||||
}
|
||||
|
||||
inline char
|
||||
EnsureLowerCaseASCII(char aChar)
|
||||
{
|
||||
if (aChar >= 'A' && aChar <= 'Z') {
|
||||
aChar -= 'A' - 'a';
|
||||
}
|
||||
|
||||
return aChar;
|
||||
}
|
||||
|
||||
inline int
|
||||
StricmpASCII(const char* aLeft, const char* aRight)
|
||||
{
|
||||
char curLeft, curRight;
|
||||
|
||||
do {
|
||||
curLeft = EnsureLowerCaseASCII(*(aLeft++));
|
||||
curRight = EnsureLowerCaseASCII(*(aRight++));
|
||||
} while(curLeft && curLeft == curRight);
|
||||
|
||||
return curLeft - curRight;
|
||||
}
|
||||
|
||||
class MOZ_RAII PEHeaders final
|
||||
{
|
||||
/**
|
||||
* This structure is documented on MSDN as VS_VERSIONINFO, but is not present
|
||||
* in SDK headers because it cannot be specified as a C struct. The following
|
||||
* structure contains the fixed-length fields at the beginning of
|
||||
* VS_VERSIONINFO.
|
||||
*/
|
||||
struct VS_VERSIONINFO_HEADER
|
||||
{
|
||||
WORD wLength;
|
||||
WORD wValueLength;
|
||||
WORD wType;
|
||||
WCHAR szKey[16]; // ArrayLength(L"VS_VERSION_INFO")
|
||||
// Additional data goes here, aligned on a 4-byte boundary
|
||||
};
|
||||
|
||||
public:
|
||||
explicit PEHeaders(void* aBaseAddress)
|
||||
: PEHeaders(reinterpret_cast<PIMAGE_DOS_HEADER>(aBaseAddress))
|
||||
{
|
||||
}
|
||||
|
||||
// The lowest two bits of an HMODULE are used as flags. Stripping those bits
|
||||
// from the HMODULE yields the base address of the binary's memory mapping.
|
||||
// (See LoadLibraryEx docs on MSDN)
|
||||
explicit PEHeaders(HMODULE aModule)
|
||||
: PEHeaders(reinterpret_cast<PIMAGE_DOS_HEADER>(
|
||||
reinterpret_cast<uintptr_t>(aModule) & ~uintptr_t(3)))
|
||||
{
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return !!mImageLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload computes absolute virtual addresses relative to the base
|
||||
* address of the binary.
|
||||
*/
|
||||
template <typename T, typename R>
|
||||
T RVAToPtr(R aRva)
|
||||
{
|
||||
return RVAToPtr<T>(mMzHeader, aRva);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload computes a result by adding aRva to aBase, but also ensures
|
||||
* that the resulting pointer falls within the bounds of this binary's memory
|
||||
* mapping.
|
||||
*/
|
||||
template <typename T, typename R>
|
||||
T RVAToPtr(void* aBase, R aRva)
|
||||
{
|
||||
if (!mImageLimit) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* absAddress = reinterpret_cast<char*>(aBase) + aRva;
|
||||
if (absAddress < reinterpret_cast<char*>(mMzHeader) ||
|
||||
absAddress > reinterpret_cast<char*>(mImageLimit)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<T>(absAddress);
|
||||
}
|
||||
|
||||
PIMAGE_IMPORT_DESCRIPTOR GetImportDirectory()
|
||||
{
|
||||
return GetImageDirectoryEntry<PIMAGE_IMPORT_DESCRIPTOR>(
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT);
|
||||
}
|
||||
|
||||
PIMAGE_RESOURCE_DIRECTORY GetResourceTable()
|
||||
{
|
||||
return GetImageDirectoryEntry<PIMAGE_RESOURCE_DIRECTORY>(
|
||||
IMAGE_DIRECTORY_ENTRY_RESOURCE);
|
||||
}
|
||||
|
||||
bool
|
||||
GetVersionInfo(uint64_t& aOutVersion)
|
||||
{
|
||||
// RT_VERSION == 16
|
||||
// Version resources require an id of 1
|
||||
auto root = FindResourceLeaf<VS_VERSIONINFO_HEADER*>(16, 1);
|
||||
if (!root) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VS_FIXEDFILEINFO* fixedInfo = GetFixedFileInfo(root);
|
||||
if (!fixedInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aOutVersion = ((static_cast<uint64_t>(fixedInfo->dwFileVersionMS) << 32) |
|
||||
static_cast<uint64_t>(fixedInfo->dwFileVersionLS));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetTimeStamp(DWORD& aResult)
|
||||
{
|
||||
if (!(*this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aResult = mPeHeader->FileHeader.TimeDateStamp;
|
||||
return true;
|
||||
}
|
||||
|
||||
PIMAGE_IMPORT_DESCRIPTOR
|
||||
GetIATForModule(const char* aModuleNameASCII)
|
||||
{
|
||||
for (PIMAGE_IMPORT_DESCRIPTOR curImpDesc = GetImportDirectory();
|
||||
IsValid(curImpDesc); ++curImpDesc) {
|
||||
auto curName = RVAToPtr<const char*>(curImpDesc->Name);
|
||||
if (!curName) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (StricmpASCII(aModuleNameASCII, curName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// curImpDesc now points to the IAT for the module we're interested in
|
||||
return curImpDesc;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resources are stored in a three-level tree. To locate a particular entry,
|
||||
* you must supply a resource type, the resource id, and then the language id.
|
||||
* If aLangId == 0, we just resolve the first entry regardless of language.
|
||||
*/
|
||||
template <typename T> T
|
||||
FindResourceLeaf(WORD aType, WORD aResId, WORD aLangId = 0)
|
||||
{
|
||||
PIMAGE_RESOURCE_DIRECTORY topLevel = GetResourceTable();
|
||||
if (!topLevel) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PIMAGE_RESOURCE_DIRECTORY_ENTRY typeEntry = FindResourceEntry(topLevel,
|
||||
aType);
|
||||
if (!typeEntry || !typeEntry->DataIsDirectory) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto idDir = RVAToPtr<PIMAGE_RESOURCE_DIRECTORY>(topLevel,
|
||||
typeEntry->OffsetToDirectory);
|
||||
PIMAGE_RESOURCE_DIRECTORY_ENTRY idEntry = FindResourceEntry(idDir, aResId);
|
||||
if (!idEntry || !idEntry->DataIsDirectory) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto langDir = RVAToPtr<PIMAGE_RESOURCE_DIRECTORY>(topLevel,
|
||||
idEntry->OffsetToDirectory);
|
||||
PIMAGE_RESOURCE_DIRECTORY_ENTRY langEntry;
|
||||
if (aLangId) {
|
||||
langEntry = FindResourceEntry(langDir, aLangId);
|
||||
} else {
|
||||
langEntry = FindFirstResourceEntry(langDir);
|
||||
}
|
||||
|
||||
if (!langEntry || langEntry->DataIsDirectory) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto dataEntry = RVAToPtr<PIMAGE_RESOURCE_DATA_ENTRY>(topLevel,
|
||||
langEntry->OffsetToData);
|
||||
return RVAToPtr<T>(dataEntry->OffsetToData);
|
||||
}
|
||||
|
||||
static bool IsValid(PIMAGE_IMPORT_DESCRIPTOR aImpDesc)
|
||||
{
|
||||
return aImpDesc && aImpDesc->OriginalFirstThunk != 0;
|
||||
}
|
||||
|
||||
static bool IsValid(PIMAGE_THUNK_DATA aImgThunk)
|
||||
{
|
||||
return aImgThunk && aImgThunk->u1.Ordinal != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit PEHeaders(PIMAGE_DOS_HEADER aMzHeader)
|
||||
: mMzHeader(aMzHeader)
|
||||
, mPeHeader(nullptr)
|
||||
, mImageLimit(nullptr)
|
||||
{
|
||||
if (!mMzHeader || mMzHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
mPeHeader = RVAToPtrUnchecked<PIMAGE_NT_HEADERS>(mMzHeader->e_lfanew);
|
||||
if (!mPeHeader || mPeHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
mImageLimit =
|
||||
RVAToPtrUnchecked<void*>(mPeHeader->OptionalHeader.SizeOfImage - 1UL);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T GetImageDirectoryEntry(unsigned int aDirectoryIndex)
|
||||
{
|
||||
if (aDirectoryIndex >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IMAGE_DATA_DIRECTORY& dirEntry =
|
||||
mPeHeader->OptionalHeader.DataDirectory[aDirectoryIndex];
|
||||
return RVAToPtr<T>(dirEntry.VirtualAddress);
|
||||
}
|
||||
|
||||
// This private overload does not have bounds checks, because we need to be
|
||||
// able to resolve the bounds themselves.
|
||||
template <typename T, typename R>
|
||||
T RVAToPtrUnchecked(R aRva)
|
||||
{
|
||||
return reinterpret_cast<T>(reinterpret_cast<char*>(mMzHeader) + aRva);
|
||||
}
|
||||
|
||||
PIMAGE_RESOURCE_DIRECTORY_ENTRY
|
||||
FindResourceEntry(PIMAGE_RESOURCE_DIRECTORY aCurLevel, WORD aId)
|
||||
{
|
||||
// Immediately after the IMAGE_RESOURCE_DIRECTORY structure is an array
|
||||
// of IMAGE_RESOURCE_DIRECTORY_ENTRY structures. Since this function
|
||||
// searches by ID, we need to skip past any named entries before iterating.
|
||||
auto dirEnt =
|
||||
reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(aCurLevel + 1) +
|
||||
aCurLevel->NumberOfNamedEntries;
|
||||
for (WORD i = 0; i < aCurLevel->NumberOfIdEntries; ++i) {
|
||||
if (dirEnt[i].Id == aId) {
|
||||
return &dirEnt[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PIMAGE_RESOURCE_DIRECTORY_ENTRY
|
||||
FindFirstResourceEntry(PIMAGE_RESOURCE_DIRECTORY aCurLevel)
|
||||
{
|
||||
// Immediately after the IMAGE_RESOURCE_DIRECTORY structure is an array
|
||||
// of IMAGE_RESOURCE_DIRECTORY_ENTRY structures. We just return the first
|
||||
// entry, regardless of whether it is indexed by name or by id.
|
||||
auto dirEnt = reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(aCurLevel + 1);
|
||||
WORD numEntries = aCurLevel->NumberOfNamedEntries +
|
||||
aCurLevel->NumberOfIdEntries;
|
||||
if (!numEntries) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return dirEnt;
|
||||
}
|
||||
|
||||
VS_FIXEDFILEINFO*
|
||||
GetFixedFileInfo(VS_VERSIONINFO_HEADER* aVerInfo)
|
||||
{
|
||||
WORD length = aVerInfo->wLength;
|
||||
WORD offset = sizeof(VS_VERSIONINFO_HEADER);
|
||||
if (!offset) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const wchar_t kVersionInfoKey[] = L"VS_VERSION_INFO";
|
||||
if (::RtlCompareMemory(aVerInfo->szKey, kVersionInfoKey,
|
||||
ArrayLength(kVersionInfoKey)) !=
|
||||
ArrayLength(kVersionInfoKey)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uintptr_t base = reinterpret_cast<uintptr_t>(aVerInfo);
|
||||
// Align up to 4-byte boundary
|
||||
#pragma warning(suppress: 4146)
|
||||
offset += (-(base + offset) & 3);
|
||||
|
||||
if (offset > length) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto result = reinterpret_cast<VS_FIXEDFILEINFO*>(base + offset);
|
||||
if (result->dwSignature != 0xFEEF04BD) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
PIMAGE_DOS_HEADER mMzHeader;
|
||||
PIMAGE_NT_HEADERS mPeHeader;
|
||||
void* mImageLimit;
|
||||
};
|
||||
|
||||
inline HANDLE
|
||||
RtlGetProcessHeap()
|
||||
{
|
||||
PTEB teb = ::NtCurrentTeb();
|
||||
PPEB peb = teb->ProcessEnvironmentBlock;
|
||||
return peb->Reserved4[1];
|
||||
}
|
||||
|
||||
} // namespace nt
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_NativeNt_h
|
|
@ -0,0 +1,27 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
Library('winlauncher')
|
||||
|
||||
FORCE_STATIC_LIB = True
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'DllBlocklistWin.cpp',
|
||||
'LauncherProcessWin.cpp',
|
||||
'LaunchUnelevated.cpp',
|
||||
]
|
||||
|
||||
OS_LIBS += [
|
||||
'ntdll',
|
||||
'oleaut32',
|
||||
'ole32',
|
||||
]
|
||||
|
||||
TEST_DIRS += [
|
||||
'test',
|
||||
]
|
||||
|
||||
DisableStlWrapping()
|
|
@ -0,0 +1,97 @@
|
|||
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "NativeNt.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
const wchar_t kNormal[] = L"Foo.dll";
|
||||
const wchar_t kHex12[] = L"Foo.ABCDEF012345.dll";
|
||||
const wchar_t kHex15[] = L"ABCDEF012345678.dll";
|
||||
const wchar_t kHex16[] = L"ABCDEF0123456789.dll";
|
||||
const wchar_t kHex17[] = L"ABCDEF0123456789a.dll";
|
||||
const wchar_t kHex24[] = L"ABCDEF0123456789cdabef98.dll";
|
||||
const wchar_t kHex8[] = L"01234567.dll";
|
||||
const wchar_t kNonHex12[] = L"Foo.ABCDEFG12345.dll";
|
||||
const wchar_t kHex13[] = L"Foo.ABCDEF0123456.dll";
|
||||
const wchar_t kHex11[] = L"Foo.ABCDEF01234.dll";
|
||||
const wchar_t kPrefixedHex16[] = L"Pabcdef0123456789.dll";
|
||||
|
||||
const char kFailFmt[] = "TEST-FAILED | NativeNt | %s(%s) should have returned %s but did not\n";
|
||||
|
||||
#define RUN_TEST(fn, varName, expected) \
|
||||
if (fn(varName) == !expected) { \
|
||||
printf(kFailFmt, #fn, #varName, #expected); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define EXPECT_FAIL(fn, varName) \
|
||||
RUN_TEST(fn, varName, false) \
|
||||
|
||||
#define EXPECT_SUCCESS(fn, varName) \
|
||||
RUN_TEST(fn, varName, true)
|
||||
|
||||
using namespace mozilla::nt;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
UNICODE_STRING normal;
|
||||
::RtlInitUnicodeString(&normal, kNormal);
|
||||
|
||||
UNICODE_STRING hex12;
|
||||
::RtlInitUnicodeString(&hex12, kHex12);
|
||||
|
||||
UNICODE_STRING hex16;
|
||||
::RtlInitUnicodeString(&hex16, kHex16);
|
||||
|
||||
UNICODE_STRING hex24;
|
||||
::RtlInitUnicodeString(&hex24, kHex24);
|
||||
|
||||
UNICODE_STRING hex8;
|
||||
::RtlInitUnicodeString(&hex8, kHex8);
|
||||
|
||||
UNICODE_STRING nonHex12;
|
||||
::RtlInitUnicodeString(&nonHex12, kNonHex12);
|
||||
|
||||
UNICODE_STRING hex13;
|
||||
::RtlInitUnicodeString(&hex13, kHex13);
|
||||
|
||||
UNICODE_STRING hex11;
|
||||
::RtlInitUnicodeString(&hex11, kHex11);
|
||||
|
||||
UNICODE_STRING hex15;
|
||||
::RtlInitUnicodeString(&hex15, kHex15);
|
||||
|
||||
UNICODE_STRING hex17;
|
||||
::RtlInitUnicodeString(&hex17, kHex17);
|
||||
|
||||
UNICODE_STRING prefixedHex16;
|
||||
::RtlInitUnicodeString(&prefixedHex16, kPrefixedHex16);
|
||||
|
||||
EXPECT_FAIL(Contains12DigitHexString, normal);
|
||||
EXPECT_SUCCESS(Contains12DigitHexString, hex12);
|
||||
EXPECT_FAIL(Contains12DigitHexString, hex13);
|
||||
EXPECT_FAIL(Contains12DigitHexString, hex11);
|
||||
EXPECT_FAIL(Contains12DigitHexString, hex16);
|
||||
EXPECT_FAIL(Contains12DigitHexString, nonHex12);
|
||||
|
||||
EXPECT_FAIL(IsFileNameAtLeast16HexDigits, normal);
|
||||
EXPECT_FAIL(IsFileNameAtLeast16HexDigits, hex12);
|
||||
EXPECT_SUCCESS(IsFileNameAtLeast16HexDigits, hex24);
|
||||
EXPECT_SUCCESS(IsFileNameAtLeast16HexDigits, hex16);
|
||||
EXPECT_SUCCESS(IsFileNameAtLeast16HexDigits, hex17);
|
||||
EXPECT_FAIL(IsFileNameAtLeast16HexDigits, hex8);
|
||||
EXPECT_FAIL(IsFileNameAtLeast16HexDigits, hex15);
|
||||
EXPECT_FAIL(IsFileNameAtLeast16HexDigits, prefixedHex16);
|
||||
|
||||
if (RtlGetProcessHeap() != ::GetProcessHeap()) {
|
||||
printf("TEST-FAILED | NativeNt | RtlGetProcessHeap() is broken\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
DisableStlWrapping()
|
||||
|
||||
CppUnitTests(['TestNativeNt'])
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/browser/app/winlauncher',
|
||||
]
|
||||
|
||||
OS_LIBS += [
|
||||
'ntdll',
|
||||
]
|
|
@ -7,6 +7,7 @@
|
|||
* depend on the frame being contained in tabbrowser. */
|
||||
|
||||
/* eslint-env mozilla/frame-script */
|
||||
/* eslint no-unused-vars: ["error", {args: "none"}] */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
@ -15,31 +16,23 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
var global = this;
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
BlockedSiteContent: "resource:///modules/BlockedSiteContent.jsm",
|
||||
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
|
||||
ContentLinkHandler: "resource:///modules/ContentLinkHandler.jsm",
|
||||
ContentMetaHandler: "resource:///modules/ContentMetaHandler.jsm",
|
||||
ContentWebRTC: "resource:///modules/ContentWebRTC.jsm",
|
||||
InlineSpellCheckerContent: "resource://gre/modules/InlineSpellCheckerContent.jsm",
|
||||
LoginManagerContent: "resource://gre/modules/LoginManagerContent.jsm",
|
||||
LoginFormFactory: "resource://gre/modules/LoginManagerContent.jsm",
|
||||
InsecurePasswordUtils: "resource://gre/modules/InsecurePasswordUtils.jsm",
|
||||
PluginContent: "resource:///modules/PluginContent.jsm",
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
FormSubmitObserver: "resource:///modules/FormSubmitObserver.jsm",
|
||||
NetErrorContent: "resource:///modules/NetErrorContent.jsm",
|
||||
PageMetadata: "resource://gre/modules/PageMetadata.jsm",
|
||||
SafeBrowsing: "resource://gre/modules/SafeBrowsing.jsm",
|
||||
Utils: "resource://gre/modules/sessionstore/Utils.jsm",
|
||||
WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.jsm",
|
||||
ContextMenu: "resource:///modules/ContextMenu.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gPipNSSBundle", function() {
|
||||
return Services.strings.createBundle("chrome://pipnss/locale/pipnss.properties");
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "gNSSErrorsBundle", function() {
|
||||
return Services.strings.createBundle("chrome://pipnss/locale/nsserrors.properties");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyProxy(this, "contextMenu", () => {
|
||||
return new ContextMenu(global);
|
||||
});
|
||||
|
@ -88,74 +81,6 @@ addEventListener("blur", function(event) {
|
|||
LoginManagerContent.onUsernameInput(event);
|
||||
});
|
||||
|
||||
const SEC_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE;
|
||||
const MOZILLA_PKIX_ERROR_BASE = Ci.nsINSSErrorsService.MOZILLA_PKIX_ERROR_BASE;
|
||||
|
||||
const SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11;
|
||||
const SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
|
||||
const SEC_ERROR_UNTRUSTED_ISSUER = SEC_ERROR_BASE + 20;
|
||||
const SEC_ERROR_UNTRUSTED_CERT = SEC_ERROR_BASE + 21;
|
||||
const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE = SEC_ERROR_BASE + 30;
|
||||
const SEC_ERROR_CA_CERT_INVALID = SEC_ERROR_BASE + 36;
|
||||
const SEC_ERROR_OCSP_FUTURE_RESPONSE = SEC_ERROR_BASE + 131;
|
||||
const SEC_ERROR_OCSP_OLD_RESPONSE = SEC_ERROR_BASE + 132;
|
||||
const SEC_ERROR_REUSED_ISSUER_AND_SERIAL = SEC_ERROR_BASE + 138;
|
||||
const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176;
|
||||
const MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE = MOZILLA_PKIX_ERROR_BASE + 5;
|
||||
const MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE = MOZILLA_PKIX_ERROR_BASE + 6;
|
||||
const MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT = MOZILLA_PKIX_ERROR_BASE + 14;
|
||||
const MOZILLA_PKIX_ERROR_MITM_DETECTED = MOZILLA_PKIX_ERROR_BASE + 15;
|
||||
|
||||
|
||||
const SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE;
|
||||
const SSL_ERROR_SSL_DISABLED = SSL_ERROR_BASE + 20;
|
||||
const SSL_ERROR_SSL2_DISABLED = SSL_ERROR_BASE + 14;
|
||||
|
||||
const PREF_SERVICES_SETTINGS_CLOCK_SKEW_SECONDS = "services.settings.clock_skew_seconds";
|
||||
const PREF_SERVICES_SETTINGS_LAST_FETCHED = "services.settings.last_update_seconds";
|
||||
|
||||
const PREF_SSL_IMPACT_ROOTS = ["security.tls.version.", "security.ssl3."];
|
||||
|
||||
|
||||
function getSerializedSecurityInfo(docShell) {
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
|
||||
let securityInfo = docShell.failedChannel && docShell.failedChannel.securityInfo;
|
||||
if (!securityInfo) {
|
||||
return "";
|
||||
}
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo)
|
||||
.QueryInterface(Ci.nsISerializable);
|
||||
|
||||
return serhelper.serializeToString(securityInfo);
|
||||
}
|
||||
|
||||
function getSiteBlockedErrorDetails(docShell) {
|
||||
let blockedInfo = {};
|
||||
if (docShell.failedChannel) {
|
||||
let classifiedChannel = docShell.failedChannel.
|
||||
QueryInterface(Ci.nsIClassifiedChannel);
|
||||
if (classifiedChannel) {
|
||||
let httpChannel = docShell.failedChannel.QueryInterface(Ci.nsIHttpChannel);
|
||||
|
||||
let reportUri = httpChannel.URI.clone();
|
||||
|
||||
// Remove the query to avoid leaking sensitive data
|
||||
if (reportUri instanceof Ci.nsIURL) {
|
||||
reportUri = reportUri.mutate()
|
||||
.setQuery("")
|
||||
.finalize();
|
||||
}
|
||||
|
||||
blockedInfo = { list: classifiedChannel.matchedList,
|
||||
provider: classifiedChannel.matchedProvider,
|
||||
uri: reportUri.asciiSpec };
|
||||
}
|
||||
}
|
||||
return blockedInfo;
|
||||
}
|
||||
|
||||
var AboutBlockedSiteListener = {
|
||||
init(chromeGlobal) {
|
||||
addMessageListener("DeceptiveBlockedDetails", this);
|
||||
|
@ -171,11 +96,7 @@ var AboutBlockedSiteListener = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (msg.name == "DeceptiveBlockedDetails") {
|
||||
sendAsyncMessage("DeceptiveBlockedDetails:Result", {
|
||||
blockedInfo: getSiteBlockedErrorDetails(docShell),
|
||||
});
|
||||
}
|
||||
BlockedSiteContent.receiveMessage(global, msg);
|
||||
},
|
||||
|
||||
handleEvent(aEvent) {
|
||||
|
@ -187,77 +108,10 @@ var AboutBlockedSiteListener = {
|
|||
return;
|
||||
}
|
||||
|
||||
let blockedInfo = getSiteBlockedErrorDetails(docShell);
|
||||
let provider = blockedInfo.provider || "";
|
||||
|
||||
let doc = content.document;
|
||||
|
||||
/**
|
||||
* Set error description link in error details.
|
||||
* For example, the "reported as a deceptive site" link for
|
||||
* blocked phishing pages.
|
||||
*/
|
||||
let desc = Services.prefs.getCharPref(
|
||||
"browser.safebrowsing.provider." + provider + ".reportURL", "");
|
||||
if (desc) {
|
||||
doc.getElementById("error_desc_link").setAttribute("href", desc + aEvent.detail.url);
|
||||
}
|
||||
|
||||
// Set other links in error details.
|
||||
switch (aEvent.detail.err) {
|
||||
case "malware":
|
||||
doc.getElementById("report_detection").setAttribute("href",
|
||||
(SafeBrowsing.getReportURL("MalwareMistake", blockedInfo) ||
|
||||
"https://www.stopbadware.org/firefox"));
|
||||
doc.getElementById("learn_more_link").setAttribute("href",
|
||||
"https://www.stopbadware.org/firefox");
|
||||
break;
|
||||
case "unwanted":
|
||||
doc.getElementById("learn_more_link").setAttribute("href",
|
||||
"https://www.google.com/about/unwanted-software-policy.html");
|
||||
break;
|
||||
case "phishing":
|
||||
doc.getElementById("report_detection").setAttribute("href",
|
||||
(SafeBrowsing.getReportURL("PhishMistake", blockedInfo) ||
|
||||
"https://safebrowsing.google.com/safebrowsing/report_error/?tpl=mozilla"));
|
||||
doc.getElementById("learn_more_link").setAttribute("href",
|
||||
"https://www.antiphishing.org//");
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the firefox support url.
|
||||
doc.getElementById("firefox_support").setAttribute("href",
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") + "phishing-malware");
|
||||
|
||||
// Show safe browsing details on load if the pref is set to true.
|
||||
let showDetails = Services.prefs.getBoolPref("browser.xul.error_pages.show_safe_browsing_details_on_load");
|
||||
if (showDetails) {
|
||||
let details = content.document.getElementById("errorDescriptionContainer");
|
||||
details.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
// Set safe browsing advisory link.
|
||||
let advisoryUrl = Services.prefs.getCharPref(
|
||||
"browser.safebrowsing.provider." + provider + ".advisoryURL", "");
|
||||
if (!advisoryUrl) {
|
||||
let el = content.document.getElementById("advisoryDesc");
|
||||
el.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
let advisoryLinkText = Services.prefs.getCharPref(
|
||||
"browser.safebrowsing.provider." + provider + ".advisoryName", "");
|
||||
if (!advisoryLinkText) {
|
||||
let el = content.document.getElementById("advisoryDesc");
|
||||
el.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
let anchorEl = content.document.getElementById("advisory_provider");
|
||||
anchorEl.setAttribute("href", advisoryUrl);
|
||||
anchorEl.textContent = advisoryLinkText;
|
||||
BlockedSiteContent.handleEvent(global, aEvent);
|
||||
},
|
||||
};
|
||||
AboutBlockedSiteListener.init(this);
|
||||
|
||||
var AboutNetAndCertErrorListener = {
|
||||
init(chromeGlobal) {
|
||||
|
@ -286,7 +140,7 @@ var AboutNetAndCertErrorListener = {
|
|||
return;
|
||||
}
|
||||
|
||||
this.onCertErrorDetails(msg, frameDocShell);
|
||||
NetErrorContent.onCertErrorDetails(global, msg, frameDocShell);
|
||||
} else if (msg.name == "Browser:CaptivePortalFreed") {
|
||||
// TODO: This check is not correct for frames.
|
||||
if (!this.isAboutCertError(content.document)) {
|
||||
|
@ -297,291 +151,6 @@ var AboutNetAndCertErrorListener = {
|
|||
}
|
||||
},
|
||||
|
||||
_getCertValidityRange(docShell) {
|
||||
let {securityInfo} = docShell.failedChannel;
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
let certs = securityInfo.failedCertChain.getEnumerator();
|
||||
let notBefore = 0;
|
||||
let notAfter = Number.MAX_SAFE_INTEGER;
|
||||
while (certs.hasMoreElements()) {
|
||||
let cert = certs.getNext();
|
||||
cert.QueryInterface(Ci.nsIX509Cert);
|
||||
notBefore = Math.max(notBefore, cert.validity.notBefore);
|
||||
notAfter = Math.min(notAfter, cert.validity.notAfter);
|
||||
}
|
||||
// nsIX509Cert reports in PR_Date terms, which uses microseconds. Convert:
|
||||
notBefore /= 1000;
|
||||
notAfter /= 1000;
|
||||
return {notBefore, notAfter};
|
||||
},
|
||||
|
||||
_setTechDetails(input, doc) {
|
||||
// CSS class and error code are set from nsDocShell.
|
||||
let searchParams = new URLSearchParams(doc.documentURI.split("?")[1]);
|
||||
let cssClass = searchParams.get("s");
|
||||
let error = searchParams.get("e");
|
||||
let technicalInfo = doc.getElementById("badCertTechnicalInfo");
|
||||
technicalInfo.textContent = "";
|
||||
|
||||
let uri = Services.io.newURI(input.data.url);
|
||||
let hostString = uri.host;
|
||||
if (uri.port != 443 && uri.port != -1) {
|
||||
hostString = uri.hostPort;
|
||||
}
|
||||
|
||||
let msg1 = gPipNSSBundle.formatStringFromName("certErrorIntro",
|
||||
[hostString], 1);
|
||||
msg1 += "\n\n";
|
||||
|
||||
if (input.data.certIsUntrusted) {
|
||||
switch (input.data.code) {
|
||||
// We only want to measure MitM rates for now. Treat it as unkown issuer.
|
||||
case MOZILLA_PKIX_ERROR_MITM_DETECTED:
|
||||
case SEC_ERROR_UNKNOWN_ISSUER:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_UnknownIssuer") + "\n";
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_UnknownIssuer2") + "\n";
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_UnknownIssuer3") + "\n";
|
||||
break;
|
||||
case SEC_ERROR_CA_CERT_INVALID:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_CaInvalid") + "\n";
|
||||
break;
|
||||
case SEC_ERROR_UNTRUSTED_ISSUER:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_Issuer") + "\n";
|
||||
break;
|
||||
case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_SignatureAlgorithmDisabled") + "\n";
|
||||
break;
|
||||
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_ExpiredIssuer") + "\n";
|
||||
break;
|
||||
case MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_SelfSigned") + "\n";
|
||||
break;
|
||||
default:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_Untrusted") + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
technicalInfo.appendChild(doc.createTextNode(msg1));
|
||||
|
||||
if (input.data.isDomainMismatch) {
|
||||
let subjectAltNames = input.data.certSubjectAltNames.split(",");
|
||||
let numSubjectAltNames = subjectAltNames.length;
|
||||
let msgPrefix = "";
|
||||
if (numSubjectAltNames != 0) {
|
||||
if (numSubjectAltNames == 1) {
|
||||
msgPrefix = gPipNSSBundle.GetStringFromName("certErrorMismatchSinglePrefix");
|
||||
|
||||
// Let's check if we want to make this a link.
|
||||
let okHost = input.data.certSubjectAltNames;
|
||||
let href = "";
|
||||
let thisHost = doc.location.hostname;
|
||||
let proto = doc.location.protocol + "//";
|
||||
// If okHost is a wildcard domain ("*.example.com") let's
|
||||
// use "www" instead. "*.example.com" isn't going to
|
||||
// get anyone anywhere useful. bug 432491
|
||||
okHost = okHost.replace(/^\*\./, "www.");
|
||||
/* case #1:
|
||||
* example.com uses an invalid security certificate.
|
||||
*
|
||||
* The certificate is only valid for www.example.com
|
||||
*
|
||||
* Make sure to include the "." ahead of thisHost so that
|
||||
* a MitM attack on paypal.com doesn't hyperlink to "notpaypal.com"
|
||||
*
|
||||
* We'd normally just use a RegExp here except that we lack a
|
||||
* library function to escape them properly (bug 248062), and
|
||||
* domain names are famous for having '.' characters in them,
|
||||
* which would allow spurious and possibly hostile matches.
|
||||
*/
|
||||
if (okHost.endsWith("." + thisHost)) {
|
||||
href = proto + okHost;
|
||||
}
|
||||
/* case #2:
|
||||
* browser.garage.maemo.org uses an invalid security certificate.
|
||||
*
|
||||
* The certificate is only valid for garage.maemo.org
|
||||
*/
|
||||
if (thisHost.endsWith("." + okHost)) {
|
||||
href = proto + okHost;
|
||||
}
|
||||
|
||||
// If we set a link, meaning there's something helpful for
|
||||
// the user here, expand the section by default
|
||||
if (href && cssClass != "expertBadCert") {
|
||||
doc.getElementById("badCertAdvancedPanel").style.display = "block";
|
||||
if (error == "nssBadCert") {
|
||||
// Toggling the advanced panel must ensure that the debugging
|
||||
// information panel is hidden as well, since it's opened by the
|
||||
// error code link in the advanced panel.
|
||||
var div = doc.getElementById("certificateErrorDebugInformation");
|
||||
div.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
// Set the link if we want it.
|
||||
if (href) {
|
||||
let referrerlink = doc.createElement("a");
|
||||
referrerlink.append(input.data.certSubjectAltNames);
|
||||
referrerlink.title = input.data.certSubjectAltNames;
|
||||
referrerlink.id = "cert_domain_link";
|
||||
referrerlink.href = href;
|
||||
let fragment = BrowserUtils.getLocalizedFragment(doc, msgPrefix,
|
||||
referrerlink);
|
||||
technicalInfo.appendChild(fragment);
|
||||
} else {
|
||||
let fragment = BrowserUtils.getLocalizedFragment(doc,
|
||||
msgPrefix,
|
||||
input.data.certSubjectAltNames);
|
||||
technicalInfo.appendChild(fragment);
|
||||
}
|
||||
technicalInfo.append("\n");
|
||||
} else {
|
||||
let msg = gPipNSSBundle.GetStringFromName("certErrorMismatchMultiple") + "\n";
|
||||
for (let i = 0; i < numSubjectAltNames; i++) {
|
||||
msg += subjectAltNames[i];
|
||||
if (i != (numSubjectAltNames - 1)) {
|
||||
msg += ", ";
|
||||
}
|
||||
}
|
||||
technicalInfo.append(msg + "\n");
|
||||
}
|
||||
} else {
|
||||
let msg = gPipNSSBundle.formatStringFromName("certErrorMismatch",
|
||||
[hostString], 1);
|
||||
technicalInfo.append(msg + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (input.data.isNotValidAtThisTime) {
|
||||
let nowTime = new Date().getTime() * 1000;
|
||||
let dateOptions = { year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "numeric" };
|
||||
let now = new Services.intl.DateTimeFormat(undefined, dateOptions).format(new Date());
|
||||
let msg = "";
|
||||
if (input.data.validity.notBefore) {
|
||||
if (nowTime > input.data.validity.notAfter) {
|
||||
msg += gPipNSSBundle.formatStringFromName("certErrorExpiredNow",
|
||||
[input.data.validity.notAfterLocalTime, now], 2) + "\n";
|
||||
} else {
|
||||
msg += gPipNSSBundle.formatStringFromName("certErrorNotYetValidNow",
|
||||
[input.data.validity.notBeforeLocalTime, now], 2) + "\n";
|
||||
}
|
||||
} else {
|
||||
// If something goes wrong, we assume the cert expired.
|
||||
msg += gPipNSSBundle.formatStringFromName("certErrorExpiredNow",
|
||||
["", now], 2) + "\n";
|
||||
}
|
||||
technicalInfo.append(msg);
|
||||
}
|
||||
technicalInfo.append("\n");
|
||||
|
||||
// Add link to certificate and error message.
|
||||
let linkPrefix = gPipNSSBundle.GetStringFromName("certErrorCodePrefix3");
|
||||
let detailLink = doc.createElement("a");
|
||||
detailLink.append(input.data.codeString);
|
||||
detailLink.title = input.data.codeString;
|
||||
detailLink.id = "errorCode";
|
||||
let fragment = BrowserUtils.getLocalizedFragment(doc, linkPrefix, detailLink);
|
||||
technicalInfo.appendChild(fragment);
|
||||
var errorCode = doc.getElementById("errorCode");
|
||||
if (errorCode) {
|
||||
errorCode.href = "javascript:void(0)";
|
||||
errorCode.addEventListener("click", () => {
|
||||
let debugInfo = doc.getElementById("certificateErrorDebugInformation");
|
||||
debugInfo.style.display = "block";
|
||||
debugInfo.scrollIntoView({block: "start", behavior: "smooth"});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onCertErrorDetails(msg, docShell) {
|
||||
let doc = docShell.document;
|
||||
|
||||
let div = doc.getElementById("certificateErrorText");
|
||||
div.textContent = msg.data.info;
|
||||
this._setTechDetails(msg, doc);
|
||||
let learnMoreLink = doc.getElementById("learnMoreLink");
|
||||
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
|
||||
|
||||
switch (msg.data.code) {
|
||||
case SEC_ERROR_UNKNOWN_ISSUER:
|
||||
case MOZILLA_PKIX_ERROR_MITM_DETECTED:
|
||||
case MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
|
||||
learnMoreLink.href = baseURL + "security-error";
|
||||
break;
|
||||
|
||||
// In case the certificate expired we make sure the system clock
|
||||
// matches the remote-settings service (blocklist via Kinto) ping time
|
||||
// and is not before the build date.
|
||||
case SEC_ERROR_EXPIRED_CERTIFICATE:
|
||||
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
|
||||
case SEC_ERROR_OCSP_FUTURE_RESPONSE:
|
||||
case SEC_ERROR_OCSP_OLD_RESPONSE:
|
||||
case MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
|
||||
case MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
|
||||
|
||||
// We check against the remote-settings server time first if available, because that allows us
|
||||
// to give the user an approximation of what the correct time is.
|
||||
let difference = Services.prefs.getIntPref(PREF_SERVICES_SETTINGS_CLOCK_SKEW_SECONDS, 0);
|
||||
let lastFetched = Services.prefs.getIntPref(PREF_SERVICES_SETTINGS_LAST_FETCHED, 0) * 1000;
|
||||
|
||||
let now = Date.now();
|
||||
let certRange = this._getCertValidityRange(docShell);
|
||||
|
||||
let approximateDate = now - difference * 1000;
|
||||
// If the difference is more than a day, we last fetched the date in the last 5 days,
|
||||
// and adjusting the date per the interval would make the cert valid, warn the user:
|
||||
if (Math.abs(difference) > 60 * 60 * 24 && (now - lastFetched) <= 60 * 60 * 24 * 5 &&
|
||||
certRange.notBefore < approximateDate && certRange.notAfter > approximateDate) {
|
||||
let formatter = new Services.intl.DateTimeFormat(undefined, {
|
||||
dateStyle: "short"
|
||||
});
|
||||
let systemDate = formatter.format(new Date());
|
||||
// negative difference means local time is behind server time
|
||||
approximateDate = formatter.format(new Date(approximateDate));
|
||||
|
||||
doc.getElementById("wrongSystemTime_URL").textContent = doc.location.hostname;
|
||||
doc.getElementById("wrongSystemTime_systemDate").textContent = systemDate;
|
||||
doc.getElementById("wrongSystemTime_actualDate").textContent = approximateDate;
|
||||
|
||||
doc.getElementById("errorShortDesc").style.display = "none";
|
||||
doc.getElementById("wrongSystemTimePanel").style.display = "block";
|
||||
|
||||
// If there is no clock skew with Kinto servers, check against the build date.
|
||||
// (The Kinto ping could have happened when the time was still right, or not at all)
|
||||
} else {
|
||||
let appBuildID = Services.appinfo.appBuildID;
|
||||
|
||||
let year = parseInt(appBuildID.substr(0, 4), 10);
|
||||
let month = parseInt(appBuildID.substr(4, 2), 10) - 1;
|
||||
let day = parseInt(appBuildID.substr(6, 2), 10);
|
||||
|
||||
let buildDate = new Date(year, month, day);
|
||||
let systemDate = new Date();
|
||||
|
||||
// We don't check the notBefore of the cert with the build date,
|
||||
// as it is of course almost certain that it is now later than the build date,
|
||||
// so we shouldn't exclude the possibility that the cert has become valid
|
||||
// since the build date.
|
||||
if (buildDate > systemDate && new Date(certRange.notAfter) > buildDate) {
|
||||
let formatter = new Services.intl.DateTimeFormat(undefined, {
|
||||
dateStyle: "short"
|
||||
});
|
||||
|
||||
doc.getElementById("wrongSystemTimeWithoutReference_URL")
|
||||
.textContent = doc.location.hostname;
|
||||
doc.getElementById("wrongSystemTimeWithoutReference_systemDate")
|
||||
.textContent = formatter.format(systemDate);
|
||||
|
||||
doc.getElementById("errorShortDesc").style.display = "none";
|
||||
doc.getElementById("wrongSystemTimeWithoutReferencePanel").style.display = "block";
|
||||
}
|
||||
}
|
||||
learnMoreLink.href = baseURL + "time-errors";
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onCaptivePortalFreed(msg) {
|
||||
content.dispatchEvent(new content.CustomEvent("AboutNetErrorCaptivePortalFreed"));
|
||||
},
|
||||
|
@ -594,149 +163,10 @@ var AboutNetAndCertErrorListener = {
|
|||
return;
|
||||
}
|
||||
|
||||
switch (aEvent.type) {
|
||||
case "AboutNetErrorLoad":
|
||||
this.onPageLoad(aEvent.originalTarget, doc.defaultView);
|
||||
break;
|
||||
case "AboutNetErrorOpenCaptivePortal":
|
||||
this.openCaptivePortalPage(aEvent);
|
||||
break;
|
||||
case "AboutNetErrorSetAutomatic":
|
||||
this.onSetAutomatic(aEvent);
|
||||
break;
|
||||
case "AboutNetErrorResetPreferences":
|
||||
this.onResetPreferences(aEvent);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
changedCertPrefs() {
|
||||
let prefSSLImpact = PREF_SSL_IMPACT_ROOTS.reduce((prefs, root) => {
|
||||
return prefs.concat(Services.prefs.getChildList(root));
|
||||
}, []);
|
||||
for (let prefName of prefSSLImpact) {
|
||||
if (Services.prefs.prefHasUserValue(prefName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_getErrorMessageFromCode(securityInfo, doc) {
|
||||
let uri = Services.io.newURI(doc.location);
|
||||
let hostString = uri.host;
|
||||
if (uri.port != 443 && uri.port != -1) {
|
||||
hostString = uri.hostPort;
|
||||
}
|
||||
|
||||
let id_str = "";
|
||||
switch (securityInfo.errorCode) {
|
||||
case SSL_ERROR_SSL_DISABLED:
|
||||
id_str = "PSMERR_SSL_Disabled";
|
||||
break;
|
||||
case SSL_ERROR_SSL2_DISABLED:
|
||||
id_str = "PSMERR_SSL2_Disabled";
|
||||
break;
|
||||
case SEC_ERROR_REUSED_ISSUER_AND_SERIAL:
|
||||
id_str = "PSMERR_HostReusedIssuerSerial";
|
||||
break;
|
||||
}
|
||||
let nss_error_id_str = securityInfo.errorCodeString;
|
||||
let msg2 = "";
|
||||
if (id_str) {
|
||||
msg2 = gPipNSSBundle.GetStringFromName(id_str) + "\n";
|
||||
} else if (nss_error_id_str) {
|
||||
msg2 = gNSSErrorsBundle.GetStringFromName(nss_error_id_str) + "\n";
|
||||
}
|
||||
|
||||
if (!msg2) {
|
||||
// We couldn't get an error message. Use the error string.
|
||||
// Note that this is different from before where we used PR_ErrorToString.
|
||||
msg2 = nss_error_id_str;
|
||||
}
|
||||
let msg = gPipNSSBundle.formatStringFromName("SSLConnectionErrorPrefix2",
|
||||
[hostString, msg2], 2);
|
||||
|
||||
if (nss_error_id_str) {
|
||||
msg += gPipNSSBundle.formatStringFromName("certErrorCodePrefix3",
|
||||
[nss_error_id_str], 1) + "\n";
|
||||
}
|
||||
return msg;
|
||||
},
|
||||
|
||||
onPageLoad(originalTarget, win) {
|
||||
// Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json
|
||||
const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0;
|
||||
|
||||
let hideAddExceptionButton = false;
|
||||
|
||||
if (this.isAboutCertError(win.document)) {
|
||||
ClickEventHandler.onCertError(originalTarget, win);
|
||||
hideAddExceptionButton =
|
||||
Services.prefs.getBoolPref("security.certerror.hideAddException", false);
|
||||
}
|
||||
if (this.isAboutNetError(win.document)) {
|
||||
let docShell = win.document.docShell;
|
||||
if (docShell) {
|
||||
let {securityInfo} = docShell.failedChannel;
|
||||
// We don't have a securityInfo when this is for example a DNS error.
|
||||
if (securityInfo) {
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
let msg = this._getErrorMessageFromCode(securityInfo,
|
||||
win.document);
|
||||
let id = win.document.getElementById("errorShortDescText");
|
||||
id.textContent = msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
|
||||
win.dispatchEvent(new win.CustomEvent("AboutNetErrorOptions", {
|
||||
detail: JSON.stringify({
|
||||
enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
|
||||
changedCertPrefs: this.changedCertPrefs(),
|
||||
automatic,
|
||||
hideAddExceptionButton,
|
||||
})
|
||||
}));
|
||||
|
||||
sendAsyncMessage("Browser:SSLErrorReportTelemetry",
|
||||
{reportStatus: TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN});
|
||||
},
|
||||
|
||||
openCaptivePortalPage(evt) {
|
||||
sendAsyncMessage("Browser:OpenCaptivePortalPage");
|
||||
},
|
||||
|
||||
|
||||
onResetPreferences(evt) {
|
||||
sendAsyncMessage("Browser:ResetSSLPreferences");
|
||||
},
|
||||
|
||||
onSetAutomatic(evt) {
|
||||
sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
|
||||
automatic: evt.detail
|
||||
});
|
||||
|
||||
// If we're enabling reports, send a report for this failure.
|
||||
if (evt.detail) {
|
||||
let win = evt.originalTarget.ownerGlobal;
|
||||
let docShell = win.document.docShell;
|
||||
|
||||
let {securityInfo} = docShell.failedChannel;
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
let {host, port} = win.document.mozDocumentURIIfNotForErrorPages;
|
||||
|
||||
let errorReporter = Cc["@mozilla.org/securityreporter;1"]
|
||||
.getService(Ci.nsISecurityReporter);
|
||||
errorReporter.reportTLSError(securityInfo, host, port);
|
||||
}
|
||||
NetErrorContent.handleEvent(global, aEvent);
|
||||
},
|
||||
};
|
||||
|
||||
AboutNetAndCertErrorListener.init(this);
|
||||
AboutBlockedSiteListener.init(this);
|
||||
|
||||
var ClickEventHandler = {
|
||||
init: function init() {
|
||||
|
@ -757,13 +187,13 @@ var ClickEventHandler = {
|
|||
// Handle click events from about pages
|
||||
if (event.button == 0) {
|
||||
if (AboutNetAndCertErrorListener.isAboutCertError(ownerDoc)) {
|
||||
this.onCertError(originalTarget, ownerDoc.defaultView);
|
||||
NetErrorContent.onCertError(global, originalTarget, ownerDoc.defaultView);
|
||||
return;
|
||||
} else if (ownerDoc.documentURI.startsWith("about:blocked")) {
|
||||
this.onAboutBlocked(originalTarget, ownerDoc);
|
||||
BlockedSiteContent.onAboutBlocked(global, originalTarget, ownerDoc);
|
||||
return;
|
||||
} else if (AboutNetAndCertErrorListener.isAboutNetError(ownerDoc)) {
|
||||
this.onAboutNetError(event, ownerDoc.documentURI);
|
||||
NetErrorContent.onAboutNetError(global, event, ownerDoc.documentURI);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -838,58 +268,6 @@ var ClickEventHandler = {
|
|||
}
|
||||
},
|
||||
|
||||
onCertError(targetElement, win) {
|
||||
let docShell = win.document.docShell;
|
||||
sendAsyncMessage("Browser:CertExceptionError", {
|
||||
frameId: WebNavigationFrames.getFrameId(win),
|
||||
location: win.document.location.href,
|
||||
elementId: targetElement.getAttribute("id"),
|
||||
isTopFrame: (win.parent === win),
|
||||
securityInfoAsString: getSerializedSecurityInfo(docShell),
|
||||
});
|
||||
},
|
||||
|
||||
onAboutBlocked(targetElement, ownerDoc) {
|
||||
var reason = "phishing";
|
||||
if (/e=malwareBlocked/.test(ownerDoc.documentURI)) {
|
||||
reason = "malware";
|
||||
} else if (/e=unwantedBlocked/.test(ownerDoc.documentURI)) {
|
||||
reason = "unwanted";
|
||||
} else if (/e=harmfulBlocked/.test(ownerDoc.documentURI)) {
|
||||
reason = "harmful";
|
||||
}
|
||||
|
||||
let docShell = ownerDoc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
|
||||
sendAsyncMessage("Browser:SiteBlockedError", {
|
||||
location: ownerDoc.location.href,
|
||||
reason,
|
||||
elementId: targetElement.getAttribute("id"),
|
||||
isTopFrame: (ownerDoc.defaultView.parent === ownerDoc.defaultView),
|
||||
blockedInfo: getSiteBlockedErrorDetails(docShell),
|
||||
});
|
||||
},
|
||||
|
||||
onAboutNetError(event, documentURI) {
|
||||
let elmId = event.originalTarget.getAttribute("id");
|
||||
if (elmId == "returnButton") {
|
||||
sendAsyncMessage("Browser:SSLErrorGoBack", {});
|
||||
return;
|
||||
}
|
||||
if (elmId != "errorTryAgain" || !/e=netOffline/.test(documentURI)) {
|
||||
return;
|
||||
}
|
||||
// browser front end will handle clearing offline mode and refreshing
|
||||
// the page *if* we're in offline mode now. Otherwise let the error page
|
||||
// handle the click.
|
||||
if (Services.io.offline) {
|
||||
event.preventDefault();
|
||||
sendAsyncMessage("Browser:EnableOnlineMode", {});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Extracts linkNode and href for the current click target.
|
||||
*
|
||||
|
@ -947,7 +325,7 @@ ContentLinkHandler.init(this);
|
|||
ContentMetaHandler.init(this);
|
||||
|
||||
// TODO: Load this lazily so the JSM is run only if a relevant event/message fires.
|
||||
var pluginContent = new PluginContent(global);
|
||||
void new PluginContent(global);
|
||||
|
||||
addEventListener("DOMWindowFocus", function(event) {
|
||||
sendAsyncMessage("DOMWindowFocus", {});
|
||||
|
|
|
@ -27,7 +27,7 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["CSS"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["CSS"]);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "DragPositionManager",
|
||||
"resource:///modules/DragPositionManager.jsm");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
const PREF_LOGLEVEL = "browser.policies.loglevel";
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ var {
|
|||
StartupCache,
|
||||
} = ExtensionParent;
|
||||
|
||||
Cu.importGlobalProperties(["InspectorUtils"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["InspectorUtils"]);
|
||||
|
||||
const POPUP_PRELOAD_TIMEOUT_MS = 200;
|
||||
const POPUP_OPEN_MS_HISTOGRAM = "WEBEXT_BROWSERACTION_POPUP_OPEN_MS";
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
Cu.importGlobalProperties(["TextEncoder", "TextDecoder"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["TextEncoder", "TextDecoder"]);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Subprocess", "resource://gre/modules/Subprocess.jsm");
|
||||
|
|
|
@ -16,7 +16,7 @@ ChromeUtils.defineModuleGetter(this, "PlacesUtils",
|
|||
ChromeUtils.defineModuleGetter(this, "Sqlite",
|
||||
"resource://gre/modules/Sqlite.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
const kBookmarksFileName = "360sefav.db";
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
|
|||
return Services.strings.createBundle(kBrandBundle);
|
||||
});
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "kUndoStateFullPath", function() {
|
||||
return OS.Path.join(OS.Constants.Path.profileDir, "initialMigrationMetadata.jsonlz4");
|
||||
|
|
|
@ -15,7 +15,7 @@ ChromeUtils.defineModuleGetter(this, "PlacesUtils",
|
|||
ChromeUtils.defineModuleGetter(this, "ESEDBReader",
|
||||
"resource:///modules/ESEDBReader.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
const kEdgeRegistryRoot = "SOFTWARE\\Classes\\Local Settings\\Software\\" +
|
||||
"Microsoft\\Windows\\CurrentVersion\\AppContainer\\Storage\\" +
|
||||
|
|
|
@ -21,7 +21,7 @@ ChromeUtils.defineModuleGetter(this, "PlacesUtils",
|
|||
ChromeUtils.defineModuleGetter(this, "OSCrypto",
|
||||
"resource://gre/modules/OSCrypto.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
// Resources
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource:///modules/MigrationUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["FileReader"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["FileReader"]);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
|
@ -35,7 +35,7 @@ const WEB_CREDENTIALS_VAULT_ID = [0x4BF4C442,
|
|||
0x4ADD80B3,
|
||||
0x28DB4D70];
|
||||
|
||||
Cu.importGlobalProperties(["File"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["File"]);
|
||||
|
||||
const wintypes = {
|
||||
BOOL: ctypes.int,
|
||||
|
|
|
@ -14,7 +14,7 @@ ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "AutoMigrate",
|
||||
"resource:///modules/AutoMigrate.jsm");
|
||||
|
|
|
@ -18,7 +18,7 @@ ChromeUtils.defineModuleGetter(this, "PlacesUtils",
|
|||
ChromeUtils.defineModuleGetter(this, "FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
function Bookmarks(aBookmarksFile) {
|
||||
this._file = aBookmarksFile;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
/* exported gProfD, promiseMigration, registerFakePath */
|
||||
|
||||
Cu.importGlobalProperties([ "URL" ]);
|
||||
/* exported gProfD, promiseMigration, registerFakePath, URL */
|
||||
|
||||
ChromeUtils.import("resource:///modules/MigrationUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/LoginHelper.jsm");
|
||||
|
@ -15,6 +13,8 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
ChromeUtils.import("resource://testing-common/TestUtils.jsm");
|
||||
ChromeUtils.import("resource://testing-common/PlacesTestUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, [ "URL" ]);
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
ChromeUtils.defineModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
|
|
|
@ -76,7 +76,7 @@ ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
|||
TelemetryTimestamps.add("blankWindowShown");
|
||||
})();
|
||||
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetters(this, {
|
||||
WindowsUIUtils: ["@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils"],
|
||||
|
|
|
@ -9,7 +9,7 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["Element"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["Element"]);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AppConstants: "resource://gre/modules/AppConstants.jsm",
|
||||
|
|
|
@ -15,10 +15,8 @@ if (commonFile) {
|
|||
|
||||
// Put any other stuff relative to this test folder below.
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "PlacesUIUtils", function() {
|
||||
ChromeUtils.import("resource:///modules/PlacesUIUtils.jsm");
|
||||
return PlacesUIUtils;
|
||||
});
|
||||
ChromeUtils.defineModuleGetter(this, "PlacesUIUtils",
|
||||
"resource:///modules/PlacesUIUtils.jsm");
|
||||
|
||||
// Needed by some test that relies on having an app registered.
|
||||
ChromeUtils.import("resource://testing-common/AppInfo.jsm", this);
|
||||
|
|
|
@ -6,8 +6,6 @@ Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js",
|
|||
/* globals sinon */
|
||||
// ================================================
|
||||
|
||||
ChromeUtils.import("resource:///modules/PlacesUIUtils.jsm");
|
||||
|
||||
/* eslint-disable mozilla/use-chromeutils-generateqi */
|
||||
|
||||
add_task(async function test_no_result_node() {
|
||||
|
|
|
@ -11,8 +11,9 @@ ChromeUtils.import("resource://gre/modules/Log.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm");
|
||||
ChromeUtils.import("resource://services-common/async.js");
|
||||
ChromeUtils.import("resource://gre/modules/Http.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["XMLHttpRequest"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
|
||||
|
||||
// The maximum amount of net data allowed per request on Bing's API.
|
||||
const MAX_REQUEST_DATA = 5000; // Documentation says 10000 but anywhere
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
var EXPORTED_SYMBOLS = [ "TranslationDocument" ];
|
||||
|
||||
ChromeUtils.import("resource://services-common/async.js");
|
||||
Cu.importGlobalProperties(["DOMParser"]);
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["DOMParser"]);
|
||||
|
||||
/**
|
||||
* This class represents a document that is being translated,
|
||||
|
|
|
@ -11,8 +11,9 @@ ChromeUtils.import("resource://gre/modules/Log.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm");
|
||||
ChromeUtils.import("resource://services-common/async.js");
|
||||
ChromeUtils.import("resource://gre/modules/Http.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["XMLHttpRequest"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
|
||||
|
||||
// The maximum amount of net data allowed per request on Bing's API.
|
||||
const MAX_REQUEST_DATA = 5000; // Documentation says 10000 but anywhere
|
||||
|
|
|
@ -12,7 +12,7 @@ ChromeUtils.import("resource://gre/modules/TelemetryController.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "BrowserUITelemetry",
|
||||
"resource:///modules/BrowserUITelemetry.jsm");
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
const {ASRouterActions: ra} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
|
||||
const {OnboardingMessageProvider} = ChromeUtils.import("resource://activity-stream/lib/OnboardingMessageProvider.jsm", {});
|
||||
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
|
||||
const {actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
|
||||
const PREFERENCES_LOADED_EVENT = "home-pane-loaded";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
const {actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["fetch", "URL"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
|
||||
const {actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
|
||||
const {PersistentCache} = ChromeUtils.import("resource://activity-stream/lib/PersistentCache.jsm", {});
|
||||
|
|
|
@ -3,7 +3,7 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "IDNService", "@mozilla.org/network/idn-service;1", "nsIIDNService");
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
/**
|
||||
* Properly convert internationalized domain names.
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
* 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/. */
|
||||
|
||||
Cu.importGlobalProperties(["fetch", "URL"]);
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch", "URL"]);
|
||||
|
||||
const TIPPYTOP_JSON_PATH = "resource://activity-stream/data/content/tippytop/top_sites.json";
|
||||
const TIPPYTOP_URL_PREFIX = "resource://activity-stream/data/content/tippytop/images/";
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/NewTabUtils.jsm");
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
|
||||
const {actionTypes: at, actionCreators: ac} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
|
||||
const {Prefs} = ChromeUtils.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm", {});
|
||||
|
|
|
@ -14,7 +14,7 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
|
||||
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["TextDecoder", "XMLHttpRequest"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["TextDecoder", "XMLHttpRequest"]);
|
||||
|
||||
// Define our prefs
|
||||
const PREF_CLIENT_ID = "asanreporter.clientid";
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.importGlobalProperties(["URLSearchParams"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URLSearchParams"]);
|
||||
|
||||
const kExtensionID = "followonsearch@mozilla.com";
|
||||
const kSaveTelemetryMsg = `${kExtensionID}:save-telemetry`;
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
ChromeUtils.import("resource://gre/modules/ctypes.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://ppapi.js/opengles2-utils.jsm");
|
||||
Cu.importGlobalProperties(['URL']);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ['URL']);
|
||||
|
||||
const PP_OK = 0;
|
||||
const PP_OK_COMPLETIONPENDING = -1;
|
||||
|
|
|
@ -42,7 +42,7 @@ ChromeUtils.defineModuleGetter(this, "PdfJsTelemetry",
|
|||
ChromeUtils.defineModuleGetter(this, "PdfjsContentUtils",
|
||||
"resource://pdf.js/PdfjsContentUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["XMLHttpRequest"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
|
||||
|
||||
var Svc = {};
|
||||
XPCOMUtils.defineLazyServiceGetter(Svc, "mime",
|
||||
|
|
|
@ -47,7 +47,7 @@ var EXPORTED_SYMBOLS = ["pktApi"];
|
|||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["XMLHttpRequest"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
|
||||
|
||||
var pktApi = (function() {
|
||||
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["BlockedSiteContent"];
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "SafeBrowsing",
|
||||
"resource://gre/modules/SafeBrowsing.jsm");
|
||||
|
||||
function getSiteBlockedErrorDetails(docShell) {
|
||||
let blockedInfo = {};
|
||||
if (docShell.failedChannel) {
|
||||
let classifiedChannel = docShell.failedChannel.
|
||||
QueryInterface(Ci.nsIClassifiedChannel);
|
||||
if (classifiedChannel) {
|
||||
let httpChannel = docShell.failedChannel.QueryInterface(Ci.nsIHttpChannel);
|
||||
|
||||
let reportUri = httpChannel.URI.clone();
|
||||
|
||||
// Remove the query to avoid leaking sensitive data
|
||||
if (reportUri instanceof Ci.nsIURL) {
|
||||
reportUri = reportUri.mutate()
|
||||
.setQuery("")
|
||||
.finalize();
|
||||
}
|
||||
|
||||
blockedInfo = { list: classifiedChannel.matchedList,
|
||||
provider: classifiedChannel.matchedProvider,
|
||||
uri: reportUri.asciiSpec };
|
||||
}
|
||||
}
|
||||
return blockedInfo;
|
||||
}
|
||||
|
||||
var BlockedSiteContent = {
|
||||
receiveMessage(global, msg) {
|
||||
if (msg.name == "DeceptiveBlockedDetails") {
|
||||
global.sendAsyncMessage("DeceptiveBlockedDetails:Result", {
|
||||
blockedInfo: getSiteBlockedErrorDetails(global.docShell),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent(global, aEvent) {
|
||||
if (aEvent.type != "AboutBlockedLoaded") {
|
||||
return;
|
||||
}
|
||||
|
||||
let {content} = global;
|
||||
|
||||
let blockedInfo = getSiteBlockedErrorDetails(global.docShell);
|
||||
let provider = blockedInfo.provider || "";
|
||||
|
||||
let doc = content.document;
|
||||
|
||||
/**
|
||||
* Set error description link in error details.
|
||||
* For example, the "reported as a deceptive site" link for
|
||||
* blocked phishing pages.
|
||||
*/
|
||||
let desc = Services.prefs.getCharPref(
|
||||
"browser.safebrowsing.provider." + provider + ".reportURL", "");
|
||||
if (desc) {
|
||||
doc.getElementById("error_desc_link").setAttribute("href", desc + aEvent.detail.url);
|
||||
}
|
||||
|
||||
// Set other links in error details.
|
||||
switch (aEvent.detail.err) {
|
||||
case "malware":
|
||||
doc.getElementById("report_detection").setAttribute("href",
|
||||
(SafeBrowsing.getReportURL("MalwareMistake", blockedInfo) ||
|
||||
"https://www.stopbadware.org/firefox"));
|
||||
doc.getElementById("learn_more_link").setAttribute("href",
|
||||
"https://www.stopbadware.org/firefox");
|
||||
break;
|
||||
case "unwanted":
|
||||
doc.getElementById("learn_more_link").setAttribute("href",
|
||||
"https://www.google.com/about/unwanted-software-policy.html");
|
||||
break;
|
||||
case "phishing":
|
||||
doc.getElementById("report_detection").setAttribute("href",
|
||||
(SafeBrowsing.getReportURL("PhishMistake", blockedInfo) ||
|
||||
"https://safebrowsing.google.com/safebrowsing/report_error/?tpl=mozilla"));
|
||||
doc.getElementById("learn_more_link").setAttribute("href",
|
||||
"https://www.antiphishing.org//");
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the firefox support url.
|
||||
doc.getElementById("firefox_support").setAttribute("href",
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") + "phishing-malware");
|
||||
|
||||
// Show safe browsing details on load if the pref is set to true.
|
||||
let showDetails = Services.prefs.getBoolPref("browser.xul.error_pages.show_safe_browsing_details_on_load");
|
||||
if (showDetails) {
|
||||
let details = content.document.getElementById("errorDescriptionContainer");
|
||||
details.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
// Set safe browsing advisory link.
|
||||
let advisoryUrl = Services.prefs.getCharPref(
|
||||
"browser.safebrowsing.provider." + provider + ".advisoryURL", "");
|
||||
if (!advisoryUrl) {
|
||||
let el = content.document.getElementById("advisoryDesc");
|
||||
el.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
let advisoryLinkText = Services.prefs.getCharPref(
|
||||
"browser.safebrowsing.provider." + provider + ".advisoryName", "");
|
||||
if (!advisoryLinkText) {
|
||||
let el = content.document.getElementById("advisoryDesc");
|
||||
el.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
let anchorEl = content.document.getElementById("advisory_provider");
|
||||
anchorEl.setAttribute("href", advisoryUrl);
|
||||
anchorEl.textContent = advisoryLinkText;
|
||||
},
|
||||
|
||||
onAboutBlocked(global, targetElement, ownerDoc) {
|
||||
var reason = "phishing";
|
||||
if (/e=malwareBlocked/.test(ownerDoc.documentURI)) {
|
||||
reason = "malware";
|
||||
} else if (/e=unwantedBlocked/.test(ownerDoc.documentURI)) {
|
||||
reason = "unwanted";
|
||||
} else if (/e=harmfulBlocked/.test(ownerDoc.documentURI)) {
|
||||
reason = "harmful";
|
||||
}
|
||||
|
||||
let docShell = ownerDoc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
|
||||
global.sendAsyncMessage("Browser:SiteBlockedError", {
|
||||
location: ownerDoc.location.href,
|
||||
reason,
|
||||
elementId: targetElement.getAttribute("id"),
|
||||
isTopFrame: (ownerDoc.defaultView.parent === ownerDoc.defaultView),
|
||||
blockedInfo: getSiteBlockedErrorDetails(docShell),
|
||||
});
|
||||
},
|
||||
};
|
|
@ -10,7 +10,7 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
ChromeUtils.defineModuleGetter(this, "Log", "resource://gre/modules/Log.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "UpdateUtils", "resource://gre/modules/UpdateUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["fetch", "URL"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch", "URL"]);
|
||||
|
||||
var EXPORTED_SYMBOLS = ["BrowserErrorReporter"];
|
||||
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
// Debounce time in milliseconds - this should be long enough to account for
|
||||
// sync script tags that could appear between desired meta tags
|
||||
|
|
|
@ -10,7 +10,7 @@ var EXPORTED_SYMBOLS = [
|
|||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["XMLHttpRequest"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm");
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["ContextMenu"];
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
E10SUtils: "resource://gre/modules/E10SUtils.jsm",
|
||||
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
|
||||
|
|
|
@ -0,0 +1,532 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
var EXPORTED_SYMBOLS = ["NetErrorContent"];
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "BrowserUtils",
|
||||
"resource://gre/modules/BrowserUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "WebNavigationFrames",
|
||||
"resource://gre/modules/WebNavigationFrames.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gPipNSSBundle", function() {
|
||||
return Services.strings.createBundle("chrome://pipnss/locale/pipnss.properties");
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "gNSSErrorsBundle", function() {
|
||||
return Services.strings.createBundle("chrome://pipnss/locale/nsserrors.properties");
|
||||
});
|
||||
|
||||
|
||||
const SEC_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE;
|
||||
const MOZILLA_PKIX_ERROR_BASE = Ci.nsINSSErrorsService.MOZILLA_PKIX_ERROR_BASE;
|
||||
|
||||
const SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11;
|
||||
const SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
|
||||
const SEC_ERROR_UNTRUSTED_ISSUER = SEC_ERROR_BASE + 20;
|
||||
const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE = SEC_ERROR_BASE + 30;
|
||||
const SEC_ERROR_CA_CERT_INVALID = SEC_ERROR_BASE + 36;
|
||||
const SEC_ERROR_OCSP_FUTURE_RESPONSE = SEC_ERROR_BASE + 131;
|
||||
const SEC_ERROR_OCSP_OLD_RESPONSE = SEC_ERROR_BASE + 132;
|
||||
const SEC_ERROR_REUSED_ISSUER_AND_SERIAL = SEC_ERROR_BASE + 138;
|
||||
const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176;
|
||||
const MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE = MOZILLA_PKIX_ERROR_BASE + 5;
|
||||
const MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE = MOZILLA_PKIX_ERROR_BASE + 6;
|
||||
const MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT = MOZILLA_PKIX_ERROR_BASE + 14;
|
||||
const MOZILLA_PKIX_ERROR_MITM_DETECTED = MOZILLA_PKIX_ERROR_BASE + 15;
|
||||
|
||||
|
||||
const SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE;
|
||||
const SSL_ERROR_SSL_DISABLED = SSL_ERROR_BASE + 20;
|
||||
const SSL_ERROR_SSL2_DISABLED = SSL_ERROR_BASE + 14;
|
||||
|
||||
const PREF_SERVICES_SETTINGS_CLOCK_SKEW_SECONDS = "services.settings.clock_skew_seconds";
|
||||
const PREF_SERVICES_SETTINGS_LAST_FETCHED = "services.settings.last_update_seconds";
|
||||
|
||||
const PREF_SSL_IMPACT_ROOTS = ["security.tls.version.", "security.ssl3."];
|
||||
|
||||
|
||||
function getSerializedSecurityInfo(docShell) {
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
|
||||
let securityInfo = docShell.failedChannel && docShell.failedChannel.securityInfo;
|
||||
if (!securityInfo) {
|
||||
return "";
|
||||
}
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo)
|
||||
.QueryInterface(Ci.nsISerializable);
|
||||
|
||||
return serhelper.serializeToString(securityInfo);
|
||||
}
|
||||
|
||||
var NetErrorContent = {
|
||||
isAboutNetError(doc) {
|
||||
return doc.documentURI.startsWith("about:neterror");
|
||||
},
|
||||
|
||||
isAboutCertError(doc) {
|
||||
return doc.documentURI.startsWith("about:certerror");
|
||||
},
|
||||
|
||||
_getCertValidityRange(docShell) {
|
||||
let {securityInfo} = docShell.failedChannel;
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
let certs = securityInfo.failedCertChain.getEnumerator();
|
||||
let notBefore = 0;
|
||||
let notAfter = Number.MAX_SAFE_INTEGER;
|
||||
while (certs.hasMoreElements()) {
|
||||
let cert = certs.getNext();
|
||||
cert.QueryInterface(Ci.nsIX509Cert);
|
||||
notBefore = Math.max(notBefore, cert.validity.notBefore);
|
||||
notAfter = Math.min(notAfter, cert.validity.notAfter);
|
||||
}
|
||||
// nsIX509Cert reports in PR_Date terms, which uses microseconds. Convert:
|
||||
notBefore /= 1000;
|
||||
notAfter /= 1000;
|
||||
return {notBefore, notAfter};
|
||||
},
|
||||
|
||||
_setTechDetails(input, doc) {
|
||||
// CSS class and error code are set from nsDocShell.
|
||||
let searchParams = new URLSearchParams(doc.documentURI.split("?")[1]);
|
||||
let cssClass = searchParams.get("s");
|
||||
let error = searchParams.get("e");
|
||||
let technicalInfo = doc.getElementById("badCertTechnicalInfo");
|
||||
technicalInfo.textContent = "";
|
||||
|
||||
let uri = Services.io.newURI(input.data.url);
|
||||
let hostString = uri.host;
|
||||
if (uri.port != 443 && uri.port != -1) {
|
||||
hostString = uri.hostPort;
|
||||
}
|
||||
|
||||
let msg1 = gPipNSSBundle.formatStringFromName("certErrorIntro",
|
||||
[hostString], 1);
|
||||
msg1 += "\n\n";
|
||||
|
||||
if (input.data.certIsUntrusted) {
|
||||
switch (input.data.code) {
|
||||
// We only want to measure MitM rates for now. Treat it as unkown issuer.
|
||||
case MOZILLA_PKIX_ERROR_MITM_DETECTED:
|
||||
case SEC_ERROR_UNKNOWN_ISSUER:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_UnknownIssuer") + "\n";
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_UnknownIssuer2") + "\n";
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_UnknownIssuer3") + "\n";
|
||||
break;
|
||||
case SEC_ERROR_CA_CERT_INVALID:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_CaInvalid") + "\n";
|
||||
break;
|
||||
case SEC_ERROR_UNTRUSTED_ISSUER:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_Issuer") + "\n";
|
||||
break;
|
||||
case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_SignatureAlgorithmDisabled") + "\n";
|
||||
break;
|
||||
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_ExpiredIssuer") + "\n";
|
||||
break;
|
||||
case MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_SelfSigned") + "\n";
|
||||
break;
|
||||
default:
|
||||
msg1 += gPipNSSBundle.GetStringFromName("certErrorTrust_Untrusted") + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
technicalInfo.appendChild(doc.createTextNode(msg1));
|
||||
|
||||
if (input.data.isDomainMismatch) {
|
||||
let subjectAltNames = input.data.certSubjectAltNames.split(",");
|
||||
let numSubjectAltNames = subjectAltNames.length;
|
||||
let msgPrefix = "";
|
||||
if (numSubjectAltNames != 0) {
|
||||
if (numSubjectAltNames == 1) {
|
||||
msgPrefix = gPipNSSBundle.GetStringFromName("certErrorMismatchSinglePrefix");
|
||||
|
||||
// Let's check if we want to make this a link.
|
||||
let okHost = input.data.certSubjectAltNames;
|
||||
let href = "";
|
||||
let thisHost = doc.location.hostname;
|
||||
let proto = doc.location.protocol + "//";
|
||||
// If okHost is a wildcard domain ("*.example.com") let's
|
||||
// use "www" instead. "*.example.com" isn't going to
|
||||
// get anyone anywhere useful. bug 432491
|
||||
okHost = okHost.replace(/^\*\./, "www.");
|
||||
/* case #1:
|
||||
* example.com uses an invalid security certificate.
|
||||
*
|
||||
* The certificate is only valid for www.example.com
|
||||
*
|
||||
* Make sure to include the "." ahead of thisHost so that
|
||||
* a MitM attack on paypal.com doesn't hyperlink to "notpaypal.com"
|
||||
*
|
||||
* We'd normally just use a RegExp here except that we lack a
|
||||
* library function to escape them properly (bug 248062), and
|
||||
* domain names are famous for having '.' characters in them,
|
||||
* which would allow spurious and possibly hostile matches.
|
||||
*/
|
||||
if (okHost.endsWith("." + thisHost)) {
|
||||
href = proto + okHost;
|
||||
}
|
||||
/* case #2:
|
||||
* browser.garage.maemo.org uses an invalid security certificate.
|
||||
*
|
||||
* The certificate is only valid for garage.maemo.org
|
||||
*/
|
||||
if (thisHost.endsWith("." + okHost)) {
|
||||
href = proto + okHost;
|
||||
}
|
||||
|
||||
// If we set a link, meaning there's something helpful for
|
||||
// the user here, expand the section by default
|
||||
if (href && cssClass != "expertBadCert") {
|
||||
doc.getElementById("badCertAdvancedPanel").style.display = "block";
|
||||
if (error == "nssBadCert") {
|
||||
// Toggling the advanced panel must ensure that the debugging
|
||||
// information panel is hidden as well, since it's opened by the
|
||||
// error code link in the advanced panel.
|
||||
var div = doc.getElementById("certificateErrorDebugInformation");
|
||||
div.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
// Set the link if we want it.
|
||||
if (href) {
|
||||
let referrerlink = doc.createElement("a");
|
||||
referrerlink.append(input.data.certSubjectAltNames);
|
||||
referrerlink.title = input.data.certSubjectAltNames;
|
||||
referrerlink.id = "cert_domain_link";
|
||||
referrerlink.href = href;
|
||||
let fragment = BrowserUtils.getLocalizedFragment(doc, msgPrefix,
|
||||
referrerlink);
|
||||
technicalInfo.appendChild(fragment);
|
||||
} else {
|
||||
let fragment = BrowserUtils.getLocalizedFragment(doc,
|
||||
msgPrefix,
|
||||
input.data.certSubjectAltNames);
|
||||
technicalInfo.appendChild(fragment);
|
||||
}
|
||||
technicalInfo.append("\n");
|
||||
} else {
|
||||
let msg = gPipNSSBundle.GetStringFromName("certErrorMismatchMultiple") + "\n";
|
||||
for (let i = 0; i < numSubjectAltNames; i++) {
|
||||
msg += subjectAltNames[i];
|
||||
if (i != (numSubjectAltNames - 1)) {
|
||||
msg += ", ";
|
||||
}
|
||||
}
|
||||
technicalInfo.append(msg + "\n");
|
||||
}
|
||||
} else {
|
||||
let msg = gPipNSSBundle.formatStringFromName("certErrorMismatch",
|
||||
[hostString], 1);
|
||||
technicalInfo.append(msg + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (input.data.isNotValidAtThisTime) {
|
||||
let nowTime = new Date().getTime() * 1000;
|
||||
let dateOptions = { year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "numeric" };
|
||||
let now = new Services.intl.DateTimeFormat(undefined, dateOptions).format(new Date());
|
||||
let msg = "";
|
||||
if (input.data.validity.notBefore) {
|
||||
if (nowTime > input.data.validity.notAfter) {
|
||||
msg += gPipNSSBundle.formatStringFromName("certErrorExpiredNow",
|
||||
[input.data.validity.notAfterLocalTime, now], 2) + "\n";
|
||||
} else {
|
||||
msg += gPipNSSBundle.formatStringFromName("certErrorNotYetValidNow",
|
||||
[input.data.validity.notBeforeLocalTime, now], 2) + "\n";
|
||||
}
|
||||
} else {
|
||||
// If something goes wrong, we assume the cert expired.
|
||||
msg += gPipNSSBundle.formatStringFromName("certErrorExpiredNow",
|
||||
["", now], 2) + "\n";
|
||||
}
|
||||
technicalInfo.append(msg);
|
||||
}
|
||||
technicalInfo.append("\n");
|
||||
|
||||
// Add link to certificate and error message.
|
||||
let linkPrefix = gPipNSSBundle.GetStringFromName("certErrorCodePrefix3");
|
||||
let detailLink = doc.createElement("a");
|
||||
detailLink.append(input.data.codeString);
|
||||
detailLink.title = input.data.codeString;
|
||||
detailLink.id = "errorCode";
|
||||
let fragment = BrowserUtils.getLocalizedFragment(doc, linkPrefix, detailLink);
|
||||
technicalInfo.appendChild(fragment);
|
||||
var errorCode = doc.getElementById("errorCode");
|
||||
if (errorCode) {
|
||||
errorCode.href = "javascript:void(0)";
|
||||
errorCode.addEventListener("click", () => {
|
||||
let debugInfo = doc.getElementById("certificateErrorDebugInformation");
|
||||
debugInfo.style.display = "block";
|
||||
debugInfo.scrollIntoView({block: "start", behavior: "smooth"});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onCertErrorDetails(global, msg, docShell) {
|
||||
let doc = docShell.document;
|
||||
|
||||
let div = doc.getElementById("certificateErrorText");
|
||||
div.textContent = msg.data.info;
|
||||
this._setTechDetails(msg, doc);
|
||||
let learnMoreLink = doc.getElementById("learnMoreLink");
|
||||
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
|
||||
|
||||
switch (msg.data.code) {
|
||||
case SEC_ERROR_UNKNOWN_ISSUER:
|
||||
case MOZILLA_PKIX_ERROR_MITM_DETECTED:
|
||||
case MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
|
||||
learnMoreLink.href = baseURL + "security-error";
|
||||
break;
|
||||
|
||||
// In case the certificate expired we make sure the system clock
|
||||
// matches the remote-settings service (blocklist via Kinto) ping time
|
||||
// and is not before the build date.
|
||||
case SEC_ERROR_EXPIRED_CERTIFICATE:
|
||||
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
|
||||
case SEC_ERROR_OCSP_FUTURE_RESPONSE:
|
||||
case SEC_ERROR_OCSP_OLD_RESPONSE:
|
||||
case MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
|
||||
case MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
|
||||
|
||||
// We check against the remote-settings server time first if available, because that allows us
|
||||
// to give the user an approximation of what the correct time is.
|
||||
let difference = Services.prefs.getIntPref(PREF_SERVICES_SETTINGS_CLOCK_SKEW_SECONDS, 0);
|
||||
let lastFetched = Services.prefs.getIntPref(PREF_SERVICES_SETTINGS_LAST_FETCHED, 0) * 1000;
|
||||
|
||||
let now = Date.now();
|
||||
let certRange = this._getCertValidityRange(docShell);
|
||||
|
||||
let approximateDate = now - difference * 1000;
|
||||
// If the difference is more than a day, we last fetched the date in the last 5 days,
|
||||
// and adjusting the date per the interval would make the cert valid, warn the user:
|
||||
if (Math.abs(difference) > 60 * 60 * 24 && (now - lastFetched) <= 60 * 60 * 24 * 5 &&
|
||||
certRange.notBefore < approximateDate && certRange.notAfter > approximateDate) {
|
||||
let formatter = new Services.intl.DateTimeFormat(undefined, {
|
||||
dateStyle: "short"
|
||||
});
|
||||
let systemDate = formatter.format(new Date());
|
||||
// negative difference means local time is behind server time
|
||||
approximateDate = formatter.format(new Date(approximateDate));
|
||||
|
||||
doc.getElementById("wrongSystemTime_URL").textContent = doc.location.hostname;
|
||||
doc.getElementById("wrongSystemTime_systemDate").textContent = systemDate;
|
||||
doc.getElementById("wrongSystemTime_actualDate").textContent = approximateDate;
|
||||
|
||||
doc.getElementById("errorShortDesc").style.display = "none";
|
||||
doc.getElementById("wrongSystemTimePanel").style.display = "block";
|
||||
|
||||
// If there is no clock skew with Kinto servers, check against the build date.
|
||||
// (The Kinto ping could have happened when the time was still right, or not at all)
|
||||
} else {
|
||||
let appBuildID = Services.appinfo.appBuildID;
|
||||
|
||||
let year = parseInt(appBuildID.substr(0, 4), 10);
|
||||
let month = parseInt(appBuildID.substr(4, 2), 10) - 1;
|
||||
let day = parseInt(appBuildID.substr(6, 2), 10);
|
||||
|
||||
let buildDate = new Date(year, month, day);
|
||||
let systemDate = new Date();
|
||||
|
||||
// We don't check the notBefore of the cert with the build date,
|
||||
// as it is of course almost certain that it is now later than the build date,
|
||||
// so we shouldn't exclude the possibility that the cert has become valid
|
||||
// since the build date.
|
||||
if (buildDate > systemDate && new Date(certRange.notAfter) > buildDate) {
|
||||
let formatter = new Services.intl.DateTimeFormat(undefined, {
|
||||
dateStyle: "short"
|
||||
});
|
||||
|
||||
doc.getElementById("wrongSystemTimeWithoutReference_URL")
|
||||
.textContent = doc.location.hostname;
|
||||
doc.getElementById("wrongSystemTimeWithoutReference_systemDate")
|
||||
.textContent = formatter.format(systemDate);
|
||||
|
||||
doc.getElementById("errorShortDesc").style.display = "none";
|
||||
doc.getElementById("wrongSystemTimeWithoutReferencePanel").style.display = "block";
|
||||
}
|
||||
}
|
||||
learnMoreLink.href = baseURL + "time-errors";
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent(aGlobal, aEvent) {
|
||||
// Documents have a null ownerDocument.
|
||||
let doc = aEvent.originalTarget.ownerDocument || aEvent.originalTarget;
|
||||
|
||||
switch (aEvent.type) {
|
||||
case "AboutNetErrorLoad":
|
||||
this.onPageLoad(aGlobal, aEvent.originalTarget, doc.defaultView);
|
||||
break;
|
||||
case "AboutNetErrorOpenCaptivePortal":
|
||||
this.openCaptivePortalPage(aGlobal, aEvent);
|
||||
break;
|
||||
case "AboutNetErrorSetAutomatic":
|
||||
this.onSetAutomatic(aGlobal, aEvent);
|
||||
break;
|
||||
case "AboutNetErrorResetPreferences":
|
||||
this.onResetPreferences(aGlobal, aEvent);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
changedCertPrefs() {
|
||||
let prefSSLImpact = PREF_SSL_IMPACT_ROOTS.reduce((prefs, root) => {
|
||||
return prefs.concat(Services.prefs.getChildList(root));
|
||||
}, []);
|
||||
for (let prefName of prefSSLImpact) {
|
||||
if (Services.prefs.prefHasUserValue(prefName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_getErrorMessageFromCode(securityInfo, doc) {
|
||||
let uri = Services.io.newURI(doc.location);
|
||||
let hostString = uri.host;
|
||||
if (uri.port != 443 && uri.port != -1) {
|
||||
hostString = uri.hostPort;
|
||||
}
|
||||
|
||||
let id_str = "";
|
||||
switch (securityInfo.errorCode) {
|
||||
case SSL_ERROR_SSL_DISABLED:
|
||||
id_str = "PSMERR_SSL_Disabled";
|
||||
break;
|
||||
case SSL_ERROR_SSL2_DISABLED:
|
||||
id_str = "PSMERR_SSL2_Disabled";
|
||||
break;
|
||||
case SEC_ERROR_REUSED_ISSUER_AND_SERIAL:
|
||||
id_str = "PSMERR_HostReusedIssuerSerial";
|
||||
break;
|
||||
}
|
||||
let nss_error_id_str = securityInfo.errorCodeString;
|
||||
let msg2 = "";
|
||||
if (id_str) {
|
||||
msg2 = gPipNSSBundle.GetStringFromName(id_str) + "\n";
|
||||
} else if (nss_error_id_str) {
|
||||
msg2 = gNSSErrorsBundle.GetStringFromName(nss_error_id_str) + "\n";
|
||||
}
|
||||
|
||||
if (!msg2) {
|
||||
// We couldn't get an error message. Use the error string.
|
||||
// Note that this is different from before where we used PR_ErrorToString.
|
||||
msg2 = nss_error_id_str;
|
||||
}
|
||||
let msg = gPipNSSBundle.formatStringFromName("SSLConnectionErrorPrefix2",
|
||||
[hostString, msg2], 2);
|
||||
|
||||
if (nss_error_id_str) {
|
||||
msg += gPipNSSBundle.formatStringFromName("certErrorCodePrefix3",
|
||||
[nss_error_id_str], 1) + "\n";
|
||||
}
|
||||
return msg;
|
||||
},
|
||||
|
||||
onPageLoad(global, originalTarget, win) {
|
||||
// Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json
|
||||
const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0;
|
||||
|
||||
let hideAddExceptionButton = false;
|
||||
|
||||
if (this.isAboutCertError(win.document)) {
|
||||
this.onCertError(global, originalTarget, win);
|
||||
hideAddExceptionButton =
|
||||
Services.prefs.getBoolPref("security.certerror.hideAddException", false);
|
||||
}
|
||||
if (this.isAboutNetError(win.document)) {
|
||||
let docShell = win.document.docShell;
|
||||
if (docShell) {
|
||||
let {securityInfo} = docShell.failedChannel;
|
||||
// We don't have a securityInfo when this is for example a DNS error.
|
||||
if (securityInfo) {
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
let msg = this._getErrorMessageFromCode(securityInfo,
|
||||
win.document);
|
||||
let id = win.document.getElementById("errorShortDescText");
|
||||
id.textContent = msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
|
||||
win.dispatchEvent(new win.CustomEvent("AboutNetErrorOptions", {
|
||||
detail: JSON.stringify({
|
||||
enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
|
||||
changedCertPrefs: this.changedCertPrefs(),
|
||||
automatic,
|
||||
hideAddExceptionButton,
|
||||
})
|
||||
}));
|
||||
|
||||
global.sendAsyncMessage("Browser:SSLErrorReportTelemetry",
|
||||
{reportStatus: TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN});
|
||||
},
|
||||
|
||||
openCaptivePortalPage(global, evt) {
|
||||
global.sendAsyncMessage("Browser:OpenCaptivePortalPage");
|
||||
},
|
||||
|
||||
|
||||
onResetPreferences(global, evt) {
|
||||
global.sendAsyncMessage("Browser:ResetSSLPreferences");
|
||||
},
|
||||
|
||||
onSetAutomatic(global, evt) {
|
||||
global.sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
|
||||
automatic: evt.detail
|
||||
});
|
||||
|
||||
// If we're enabling reports, send a report for this failure.
|
||||
if (evt.detail) {
|
||||
let win = evt.originalTarget.ownerGlobal;
|
||||
let docShell = win.document.docShell;
|
||||
|
||||
let {securityInfo} = docShell.failedChannel;
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
let {host, port} = win.document.mozDocumentURIIfNotForErrorPages;
|
||||
|
||||
let errorReporter = Cc["@mozilla.org/securityreporter;1"]
|
||||
.getService(Ci.nsISecurityReporter);
|
||||
errorReporter.reportTLSError(securityInfo, host, port);
|
||||
}
|
||||
},
|
||||
|
||||
onCertError(global, targetElement, win) {
|
||||
let docShell = win.document.docShell;
|
||||
global.sendAsyncMessage("Browser:CertExceptionError", {
|
||||
frameId: WebNavigationFrames.getFrameId(win),
|
||||
location: win.document.location.href,
|
||||
elementId: targetElement.getAttribute("id"),
|
||||
isTopFrame: (win.parent === win),
|
||||
securityInfoAsString: getSerializedSecurityInfo(docShell),
|
||||
});
|
||||
},
|
||||
|
||||
onAboutNetError(global, event, documentURI) {
|
||||
let elmId = event.originalTarget.getAttribute("id");
|
||||
if (elmId == "returnButton") {
|
||||
global.sendAsyncMessage("Browser:SSLErrorGoBack", {});
|
||||
return;
|
||||
}
|
||||
if (elmId != "errorTryAgain" || !/e=netOffline/.test(documentURI)) {
|
||||
return;
|
||||
}
|
||||
// browser front end will handle clearing offline mode and refreshing
|
||||
// the page *if* we're in offline mode now. Otherwise let the error page
|
||||
// handle the click.
|
||||
if (Services.io.offline) {
|
||||
event.preventDefault();
|
||||
global.sendAsyncMessage("Browser:EnableOnlineMode", {});
|
||||
}
|
||||
},
|
||||
};
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
|
|
|
@ -11,8 +11,6 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/BrowserUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["InspectorUtils"]);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gNavigatorBundle", function() {
|
||||
const url = "chrome://browser/locale/browser.properties";
|
||||
return Services.strings.createBundle(url);
|
||||
|
|
|
@ -138,6 +138,7 @@ EXTRA_JS_MODULES += [
|
|||
'AboutNewTab.jsm',
|
||||
'AsyncTabSwitcher.jsm',
|
||||
'AttributionCode.jsm',
|
||||
'BlockedSiteContent.jsm',
|
||||
'BrowserErrorReporter.jsm',
|
||||
'BrowserUITelemetry.jsm',
|
||||
'BrowserUsageTelemetry.jsm',
|
||||
|
@ -156,6 +157,7 @@ EXTRA_JS_MODULES += [
|
|||
'FormValidationHandler.jsm',
|
||||
'LaterRun.jsm',
|
||||
'LightWeightThemeWebInstallListener.jsm',
|
||||
'NetErrorContent.jsm',
|
||||
'OpenInTabsUtils.jsm',
|
||||
'PageActions.jsm',
|
||||
'PageInfoListener.jsm',
|
||||
|
|
|
@ -12,10 +12,11 @@ const DEFAULT_FAVICON_TAB = `data:text/html,<meta%20charset="utf-8"><title>No%20
|
|||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://testing-common/TestUtils.jsm");
|
||||
ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["InspectorUtils"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["InspectorUtils"]);
|
||||
|
||||
var Tabs = {
|
||||
init(libDir) {},
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"llvm_revision": "317840",
|
||||
"llvm_revision": "326563",
|
||||
"stages": "3",
|
||||
"build_libcxx": true,
|
||||
"build_type": "Release",
|
||||
"assertions": false,
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
|
||||
"lld_repo": "https://llvm.org/svn/llvm-project/lld/trunk",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/trunk",
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_600/final",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_600/final",
|
||||
"lld_repo": "https://llvm.org/svn/llvm-project/lld/tags/RELEASE_600/final",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_600/final",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_600/final",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_600/final",
|
||||
"python_path": "/usr/bin/python2.7",
|
||||
"gcc_dir": "/builds/worker/workspace/build/src/gcc",
|
||||
"cc": "/builds/worker/workspace/build/src/gcc/bin/gcc",
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"llvm_revision": "317840",
|
||||
"llvm_revision": "326563",
|
||||
"stages": "1",
|
||||
"build_libcxx": true,
|
||||
"build_type": "Release",
|
||||
"assertions": false,
|
||||
"osx_cross_compile": true,
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/trunk",
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_600/final",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_600/final",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_600/final",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_600/final",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_600/final",
|
||||
"python_path": "/usr/bin/python2.7",
|
||||
"gcc_dir": "/builds/worker/workspace/build/src/gcc",
|
||||
"cc": "/builds/worker/workspace/build/src/clang/bin/clang",
|
||||
|
@ -21,7 +21,6 @@
|
|||
"ld": "/builds/worker/workspace/build/src/clang/bin/clang",
|
||||
"patches": [
|
||||
"compiler-rt-cross-compile.patch",
|
||||
"compiler-rt-no-codesign.patch",
|
||||
"r321543.patch"
|
||||
"compiler-rt-no-codesign.patch"
|
||||
]
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
From: Yi Kong <yikong@google.com>
|
||||
Date: Thu, 28 Dec 2017 23:06:24 +0000
|
||||
Subject: [PATCH] Ignore the DISPATCH_NOESCAPE if not defined
|
||||
|
||||
This macro is only defined after XCode 8, causing build breakage for
|
||||
build systems with prior versions. Ignore DISPATCH_NOESCAPE if not
|
||||
defined.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D41601
|
||||
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@321543 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
---
|
||||
lib/tsan/rtl/tsan_libdispatch_mac.cc | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/lib/tsan/rtl/tsan_libdispatch_mac.cc b/lib/tsan/rtl/tsan_libdispatch_mac.cc
|
||||
index eb22e4baa..d6c1ca662 100644
|
||||
--- a/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc
|
||||
+++ b/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc
|
||||
@@ -25,6 +25,11 @@
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <pthread.h>
|
||||
|
||||
+// DISPATCH_NOESCAPE is not defined prior to XCode 8.
|
||||
+#ifndef DISPATCH_NOESCAPE
|
||||
+#define DISPATCH_NOESCAPE
|
||||
+#endif
|
||||
+
|
||||
typedef long long_t; // NOLINT
|
||||
|
||||
namespace __tsan {
|
||||
|
|
@ -26,7 +26,9 @@ const {
|
|||
classes: Cc
|
||||
} = Components;
|
||||
|
||||
Cu.importGlobalProperties(['URL']);
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ['URL']);
|
||||
const netutil = Cc['@mozilla.org/network/util;1']
|
||||
.getService(Ci.nsINetUtil);
|
||||
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
const {
|
||||
utils: Cu
|
||||
} = Components;
|
||||
Cu.importGlobalProperties(['URL']);
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ['URL']);
|
||||
const displayModes = new Set(['fullscreen', 'standalone', 'minimal-ui',
|
||||
'browser'
|
||||
]);
|
||||
|
|
|
@ -13,7 +13,9 @@ const {
|
|||
utils: Cu
|
||||
} = Components;
|
||||
|
||||
Cu.importGlobalProperties(["InspectorUtils"]);
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["InspectorUtils"]);
|
||||
|
||||
function ValueExtractor(aConsole, aBundle) {
|
||||
this.console = aConsole;
|
||||
|
|
|
@ -11,7 +11,7 @@ ChromeUtils.import('resource://gre/modules/XPCOMUtils.jsm');
|
|||
XPCOMUtils.defineLazyGetter(this, 'gDOMBundle', () =>
|
||||
Services.strings.createBundle('chrome://global/locale/dom/dom.properties'));
|
||||
|
||||
Cu.importGlobalProperties(['crypto']);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ['crypto']);
|
||||
|
||||
var EXPORTED_SYMBOLS = ['PushCrypto', 'concatArray'];
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
ChromeUtils.import("resource://gre/modules/IndexedDBHelper.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.importGlobalProperties(["indexedDB"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["indexedDB"]);
|
||||
|
||||
var EXPORTED_SYMBOLS = ["PushDB"];
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["XMLHttpRequest"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
|
||||
|
||||
// PositionError has no interface object, so we can't use that here.
|
||||
const POSITION_UNAVAILABLE = 2;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef NSCOORD_H
|
||||
#define NSCOORD_H
|
||||
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nscore.h"
|
||||
#include "nsMathUtils.h"
|
||||
|
@ -30,21 +32,9 @@
|
|||
// want to eventually use floats.
|
||||
//#define NS_COORD_IS_FLOAT
|
||||
|
||||
inline float NS_IEEEPositiveInfinity() {
|
||||
union { uint32_t mPRUint32; float mFloat; } pun;
|
||||
pun.mPRUint32 = 0x7F800000;
|
||||
return pun.mFloat;
|
||||
}
|
||||
inline bool NS_IEEEIsNan(float aF) {
|
||||
union { uint32_t mBits; float mFloat; } pun;
|
||||
pun.mFloat = aF;
|
||||
return (pun.mBits & 0x7F800000) == 0x7F800000 &&
|
||||
(pun.mBits & 0x007FFFFF) != 0;
|
||||
}
|
||||
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
typedef float nscoord;
|
||||
#define nscoord_MAX NS_IEEEPositiveInfinity()
|
||||
#define nscoord_MAX (mozilla::PositiveInfinity<float>())
|
||||
#else
|
||||
typedef int32_t nscoord;
|
||||
#define nscoord_MAX nscoord((1 << 30) - 1)
|
||||
|
@ -238,7 +228,7 @@ NSCoordSaturatingSubtract(nscoord a, nscoord b,
|
|||
inline float NSCoordToFloat(nscoord aCoord) {
|
||||
VERIFY_COORD(aCoord);
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
NS_ASSERTION(!NS_IEEEIsNan(aCoord), "NaN encountered in float conversion");
|
||||
NS_ASSERTION(!mozilla::IsNaN(aCoord), "NaN encountered in float conversion");
|
||||
#endif
|
||||
return (float)aCoord;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm", {});
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
|
||||
const { MessageContext } = ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
|
||||
/**
|
||||
* L10nRegistry is a localization resource management system for Gecko.
|
||||
|
|
|
@ -13,10 +13,17 @@
|
|||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
||||
#if defined(XP_UNIX) && !defined(XP_DARWIN)
|
||||
#include <time.h>
|
||||
#else
|
||||
#include <chrono>
|
||||
#endif
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
|
@ -4998,6 +5005,56 @@ AflLoop(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
MonotonicNow(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
double now;
|
||||
|
||||
// The std::chrono symbols are too new to be present in STL on all platforms we
|
||||
// care about, so use raw POSIX clock APIs when it might be necessary.
|
||||
#if defined(XP_UNIX) && !defined(XP_DARWIN)
|
||||
auto ComputeNow = [](const timespec& ts) {
|
||||
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
};
|
||||
|
||||
timespec ts;
|
||||
if (false && clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
|
||||
// Use a monotonic clock if available.
|
||||
now = ComputeNow(ts);
|
||||
} else {
|
||||
// Use a realtime clock as fallback.
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
|
||||
// Fail if no clock is available.
|
||||
JS_ReportErrorASCII(cx, "can't retrieve system clock");
|
||||
return false;
|
||||
}
|
||||
|
||||
now = ComputeNow(ts);
|
||||
|
||||
// Manually enforce atomicity on a non-monotonic clock.
|
||||
{
|
||||
static mozilla::Atomic<bool, mozilla::ReleaseAcquire> spinLock;
|
||||
while (!spinLock.compareExchange(false, true))
|
||||
continue;
|
||||
|
||||
static double lastNow = -FLT_MAX;
|
||||
now = lastNow = std::max(now, lastNow);
|
||||
|
||||
spinLock = false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::milliseconds;
|
||||
using std::chrono::steady_clock;
|
||||
now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
#endif // XP_UNIX && !XP_DARWIN
|
||||
|
||||
args.rval().setNumber(now);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TimeSinceCreation(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -5895,6 +5952,11 @@ gc::ZealModeHelpText),
|
|||
" Call the __AFL_LOOP() runtime function (see AFL docs)\n"),
|
||||
#endif
|
||||
|
||||
JS_FN_HELP("monotonicNow", MonotonicNow, 0, 0,
|
||||
"monotonicNow()",
|
||||
" Return a timestamp reflecting the current elapsed system time.\n"
|
||||
" This is monotonically increasing.\n"),
|
||||
|
||||
JS_FN_HELP("timeSinceCreation", TimeSinceCreation, 0, 0,
|
||||
"TimeSinceCreation()",
|
||||
" Returns the time in milliseconds since process creation.\n"
|
||||
|
|
|
@ -1788,40 +1788,41 @@ FreshlyInitializeBindings(BindingName* cursor, const Vector<BindingName>& bindin
|
|||
Maybe<GlobalScope::Data*>
|
||||
NewGlobalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
|
||||
{
|
||||
|
||||
Vector<BindingName> funs(context);
|
||||
Vector<BindingName> vars(context);
|
||||
Vector<BindingName> lets(context);
|
||||
Vector<BindingName> consts(context);
|
||||
|
||||
bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
|
||||
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
|
||||
BindingName binding(bi.name(), allBindingsClosedOver || bi.closedOver());
|
||||
bool closedOver = allBindingsClosedOver || bi.closedOver();
|
||||
|
||||
switch (bi.kind()) {
|
||||
case BindingKind::Var:
|
||||
if (bi.declarationKind() == DeclarationKind::BodyLevelFunction) {
|
||||
if (!funs.append(binding))
|
||||
return Nothing();
|
||||
} else {
|
||||
if (!vars.append(binding))
|
||||
return Nothing();
|
||||
}
|
||||
case BindingKind::Var: {
|
||||
bool isTopLevelFunction = bi.declarationKind() == DeclarationKind::BodyLevelFunction;
|
||||
BindingName binding(bi.name(), closedOver, isTopLevelFunction);
|
||||
if (!vars.append(binding))
|
||||
return Nothing();
|
||||
break;
|
||||
case BindingKind::Let:
|
||||
}
|
||||
case BindingKind::Let: {
|
||||
BindingName binding(bi.name(), closedOver);
|
||||
if (!lets.append(binding))
|
||||
return Nothing();
|
||||
break;
|
||||
case BindingKind::Const:
|
||||
}
|
||||
case BindingKind::Const: {
|
||||
BindingName binding(bi.name(), closedOver);
|
||||
if (!consts.append(binding))
|
||||
return Nothing();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Bad global scope BindingKind");
|
||||
}
|
||||
}
|
||||
|
||||
GlobalScope::Data* bindings = nullptr;
|
||||
uint32_t numBindings = funs.length() + vars.length() + lets.length() + consts.length();
|
||||
uint32_t numBindings = vars.length() + lets.length() + consts.length();
|
||||
|
||||
if (numBindings > 0) {
|
||||
bindings = NewEmptyBindingData<GlobalScope>(context, alloc, numBindings);
|
||||
|
@ -1832,9 +1833,6 @@ NewGlobalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& al
|
|||
BindingName* start = bindings->trailingNames.start();
|
||||
BindingName* cursor = start;
|
||||
|
||||
cursor = FreshlyInitializeBindings(cursor, funs);
|
||||
|
||||
bindings->varStart = cursor - start;
|
||||
cursor = FreshlyInitializeBindings(cursor, vars);
|
||||
|
||||
bindings->letStart = cursor - start;
|
||||
|
@ -1928,25 +1926,20 @@ ParserBase::newModuleScopeData(ParseContext::Scope& scope)
|
|||
Maybe<EvalScope::Data*>
|
||||
NewEvalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
|
||||
{
|
||||
Vector<BindingName> funs(context);
|
||||
Vector<BindingName> vars(context);
|
||||
|
||||
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
|
||||
// Eval scopes only contain 'var' bindings. Make all bindings aliased
|
||||
// for now.
|
||||
MOZ_ASSERT(bi.kind() == BindingKind::Var);
|
||||
BindingName binding(bi.name(), true);
|
||||
if (bi.declarationKind() == DeclarationKind::BodyLevelFunction) {
|
||||
if (!funs.append(binding))
|
||||
return Nothing();
|
||||
} else {
|
||||
if (!vars.append(binding))
|
||||
return Nothing();
|
||||
}
|
||||
bool isTopLevelFunction = bi.declarationKind() == DeclarationKind::BodyLevelFunction;
|
||||
BindingName binding(bi.name(), true, isTopLevelFunction);
|
||||
if (!vars.append(binding))
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
EvalScope::Data* bindings = nullptr;
|
||||
uint32_t numBindings = funs.length() + vars.length();
|
||||
uint32_t numBindings = vars.length();
|
||||
|
||||
if (numBindings > 0) {
|
||||
bindings = NewEmptyBindingData<EvalScope>(context, alloc, numBindings);
|
||||
|
@ -1956,11 +1949,6 @@ NewEvalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& allo
|
|||
BindingName* start = bindings->trailingNames.start();
|
||||
BindingName* cursor = start;
|
||||
|
||||
// Keep track of what vars are functions. This is only used in BCE to omit
|
||||
// superfluous DEFVARs.
|
||||
cursor = FreshlyInitializeBindings(cursor, funs);
|
||||
|
||||
bindings->varStart = cursor - start;
|
||||
cursor = FreshlyInitializeBindings(cursor, vars);
|
||||
|
||||
bindings->length = numBindings;
|
||||
|
|
|
@ -37,10 +37,10 @@
|
|||
#include "vm/JSContext.h"
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::IsAscii;
|
||||
using mozilla::IsAsciiAlpha;
|
||||
using mozilla::IsAsciiDigit;
|
||||
using mozilla::MakeScopeExit;
|
||||
using mozilla::PodArrayZero;
|
||||
using mozilla::PodCopy;
|
||||
|
||||
struct ReservedWordInfo
|
||||
|
@ -420,18 +420,13 @@ TokenStreamAnyChars::TokenStreamAnyChars(JSContext* cx, const ReadOnlyCompileOpt
|
|||
mutedErrors(options.mutedErrors()),
|
||||
strictModeGetter(smg)
|
||||
{
|
||||
// Nb: the following tables could be static, but initializing them here is
|
||||
// much easier. Don't worry, the time to initialize them for each
|
||||
// TokenStream is trivial. See bug 639420.
|
||||
|
||||
// See Parser::assignExpr() for an explanation of isExprEnding[].
|
||||
PodArrayZero(isExprEnding);
|
||||
isExprEnding[size_t(TokenKind::Comma)] = 1;
|
||||
isExprEnding[size_t(TokenKind::Semi)] = 1;
|
||||
isExprEnding[size_t(TokenKind::Colon)] = 1;
|
||||
isExprEnding[size_t(TokenKind::Rp)] = 1;
|
||||
isExprEnding[size_t(TokenKind::Rb)] = 1;
|
||||
isExprEnding[size_t(TokenKind::Rc)] = 1;
|
||||
// |isExprEnding| was initially zeroed: overwrite the true entries here.
|
||||
isExprEnding[size_t(TokenKind::Comma)] = true;
|
||||
isExprEnding[size_t(TokenKind::Semi)] = true;
|
||||
isExprEnding[size_t(TokenKind::Colon)] = true;
|
||||
isExprEnding[size_t(TokenKind::Rp)] = true;
|
||||
isExprEnding[size_t(TokenKind::Rb)] = true;
|
||||
isExprEnding[size_t(TokenKind::Rc)] = true;
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
|
@ -494,10 +489,12 @@ TokenStreamAnyChars::updateFlagsForEOL()
|
|||
flags.isDirtyLine = false;
|
||||
}
|
||||
|
||||
// This gets the next char, normalizing all EOL sequences to '\n' as it goes.
|
||||
// This gets a full code point, starting from an already-consumed leading code
|
||||
// unit, normalizing EOL sequences to '\n', also updating line/column info as
|
||||
// needed.
|
||||
template<class AnyCharsAccess>
|
||||
bool
|
||||
TokenStreamChars<char16_t, AnyCharsAccess>::getChar(int32_t* cp)
|
||||
TokenStreamChars<char16_t, AnyCharsAccess>::getCodePoint(int32_t* cp)
|
||||
{
|
||||
TokenStreamAnyChars& anyChars = anyCharsAccess();
|
||||
|
||||
|
@ -536,14 +533,67 @@ TokenStreamChars<char16_t, AnyCharsAccess>::getChar(int32_t* cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
// This gets the next char. It does nothing special with EOL sequences, not
|
||||
// even updating the line counters. It can be used safely if (a) the
|
||||
// resulting char is guaranteed to be ungotten (by ungetCharIgnoreEOL()) if
|
||||
// it's an EOL, and (b) the line-related state (lineno, linebase) is not used
|
||||
// before it's ungotten.
|
||||
template<class AnyCharsAccess>
|
||||
bool
|
||||
TokenStreamChars<char16_t, AnyCharsAccess>::getNonAsciiCodePoint(char16_t lead, int32_t* codePoint)
|
||||
{
|
||||
MOZ_ASSERT(!isAsciiCodePoint(lead),
|
||||
"ASCII code unit/point must be handled separately");
|
||||
MOZ_ASSERT(lead == sourceUnits.previousCodeUnit(),
|
||||
"getNonAsciiCodePoint called incorrectly");
|
||||
|
||||
// The code point is usually |lead|: overwrite later if needed.
|
||||
*codePoint = lead;
|
||||
|
||||
// Dispense with single-unit code points ("code points", when a lone
|
||||
// trailing surrogate is encountered).
|
||||
if (MOZ_LIKELY(!unicode::IsLeadSurrogate(lead))) {
|
||||
if (MOZ_UNLIKELY(lead == unicode::LINE_SEPARATOR ||
|
||||
lead == unicode::PARA_SEPARATOR))
|
||||
{
|
||||
if (!updateLineInfoForEOL()) {
|
||||
#ifdef DEBUG
|
||||
*codePoint = EOF; // sentinel value to hopefully cause errors
|
||||
#endif
|
||||
MOZ_MAKE_MEM_UNDEFINED(codePoint, sizeof(*codePoint));
|
||||
return false;
|
||||
}
|
||||
|
||||
*codePoint = '\n';
|
||||
} else {
|
||||
MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there are no more units, or the next unit isn't a trailing surrogate,
|
||||
// it's also a "code point".
|
||||
if (MOZ_UNLIKELY(!sourceUnits.hasRawChars() ||
|
||||
!unicode::IsTrailSurrogate(sourceUnits.peekCodeUnit())))
|
||||
{
|
||||
MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise we have a multi-unit code point.
|
||||
*codePoint = unicode::UTF16Decode(lead, sourceUnits.getCodeUnit());
|
||||
MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
|
||||
return true;
|
||||
}
|
||||
|
||||
// This gets the next code unit -- the next numeric sub-unit of source text,
|
||||
// possibly smaller than a full code point. It is simple and stupid, and it
|
||||
// doesn't understand EOL, update line counters, or anything like that. If you
|
||||
// use it to consume an EOL sequence, line counters *will not* be correct for
|
||||
// subsequent code.
|
||||
//
|
||||
// Only use this if (a) the resulting code unit is guaranteed to be ungotten
|
||||
// (by ungetCodeUnit()) if it's an EOL, and (b) the line-related state (lineno,
|
||||
// linebase) is not used before it's ungotten.
|
||||
template<typename CharT, class AnyCharsAccess>
|
||||
int32_t
|
||||
GeneralTokenStreamChars<CharT, AnyCharsAccess>::getCharIgnoreEOL()
|
||||
GeneralTokenStreamChars<CharT, AnyCharsAccess>::getCodeUnit()
|
||||
{
|
||||
if (MOZ_LIKELY(sourceUnits.hasRawChars()))
|
||||
return sourceUnits.getCodeUnit();
|
||||
|
@ -559,7 +609,6 @@ GeneralTokenStreamChars<CharT, AnyCharsAccess>::ungetChar(int32_t c)
|
|||
if (c == EOF)
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(!sourceUnits.atStart());
|
||||
sourceUnits.ungetCodeUnit();
|
||||
if (c == '\n') {
|
||||
int32_t c2 = sourceUnits.peekCodeUnit();
|
||||
|
@ -577,12 +626,11 @@ GeneralTokenStreamChars<CharT, AnyCharsAccess>::ungetChar(int32_t c)
|
|||
|
||||
template<typename CharT>
|
||||
void
|
||||
TokenStreamCharsBase<CharT>::ungetCharIgnoreEOL(int32_t c)
|
||||
TokenStreamCharsBase<CharT>::ungetCodeUnit(int32_t c)
|
||||
{
|
||||
if (c == EOF)
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(!sourceUnits.atStart());
|
||||
sourceUnits.ungetCodeUnit();
|
||||
}
|
||||
|
||||
|
@ -599,7 +647,22 @@ TokenStreamChars<char16_t, AnyCharsAccess>::ungetCodePointIgnoreEOL(uint32_t cod
|
|||
MOZ_ASSERT(numUnits == 1 || numUnits == 2);
|
||||
|
||||
while (numUnits-- > 0)
|
||||
ungetCharIgnoreEOL(units[numUnits]);
|
||||
ungetCodeUnit(units[numUnits]);
|
||||
}
|
||||
|
||||
template<class AnyCharsAccess>
|
||||
void
|
||||
TokenStreamChars<char16_t, AnyCharsAccess>::ungetLineTerminator()
|
||||
{
|
||||
sourceUnits.ungetCodeUnit();
|
||||
|
||||
char16_t last = sourceUnits.peekCodeUnit();
|
||||
MOZ_ASSERT(SourceUnits::isRawEOLChar(last));
|
||||
|
||||
if (last == '\n')
|
||||
sourceUnits.ungetOptionalCRBeforeLF();
|
||||
|
||||
anyCharsAccess().undoInternalUpdateLineInfoForEOL();
|
||||
}
|
||||
|
||||
// Return true iff |n| raw characters can be read from this without reading past
|
||||
|
@ -612,7 +675,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::peekChars(int n, CharT* cp)
|
|||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
int32_t c = getCharIgnoreEOL();
|
||||
int32_t c = getCodeUnit();
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
|
@ -620,7 +683,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::peekChars(int n, CharT* cp)
|
|||
}
|
||||
|
||||
for (int j = i - 1; j >= 0; j--)
|
||||
ungetCharIgnoreEOL(cp[j]);
|
||||
ungetCodeUnit(cp[j]);
|
||||
|
||||
return i == n;
|
||||
}
|
||||
|
@ -655,7 +718,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::advance(size_t position)
|
|||
const CharT* end = sourceUnits.codeUnitPtrAt(position);
|
||||
while (sourceUnits.addressOfNextCodeUnit() < end) {
|
||||
int32_t c;
|
||||
if (!getChar(&c))
|
||||
if (!getCodePoint(&c))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1009,15 +1072,15 @@ template<typename CharT, class AnyCharsAccess>
|
|||
uint32_t
|
||||
TokenStreamSpecific<CharT, AnyCharsAccess>::peekUnicodeEscape(uint32_t* codePoint)
|
||||
{
|
||||
int32_t c = getCharIgnoreEOL();
|
||||
int32_t c = getCodeUnit();
|
||||
if (c != 'u') {
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CharT cp[3];
|
||||
uint32_t length;
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
if (JS7_ISHEX(c) && peekChars(3, cp) &&
|
||||
JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) && JS7_ISHEX(cp[2]))
|
||||
{
|
||||
|
@ -1032,8 +1095,8 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::peekUnicodeEscape(uint32_t* codePoin
|
|||
length = 0;
|
||||
}
|
||||
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCharIgnoreEOL('u');
|
||||
ungetCodeUnit(c);
|
||||
ungetCodeUnit('u');
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -1042,13 +1105,13 @@ uint32_t
|
|||
TokenStreamSpecific<CharT, AnyCharsAccess>::peekExtendedUnicodeEscape(uint32_t* codePoint)
|
||||
{
|
||||
// The opening brace character was already read.
|
||||
int32_t c = getCharIgnoreEOL();
|
||||
int32_t c = getCodeUnit();
|
||||
|
||||
// Skip leading zeros.
|
||||
uint32_t leadingZeros = 0;
|
||||
while (c == '0') {
|
||||
leadingZeros++;
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
}
|
||||
|
||||
CharT cp[6];
|
||||
|
@ -1057,7 +1120,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::peekExtendedUnicodeEscape(uint32_t*
|
|||
while (JS7_ISHEX(c) && i < 6) {
|
||||
cp[i++] = c;
|
||||
code = code << 4 | JS7_UNHEX(c);
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
}
|
||||
|
||||
uint32_t length;
|
||||
|
@ -1068,11 +1131,11 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::peekExtendedUnicodeEscape(uint32_t*
|
|||
length = 0;
|
||||
}
|
||||
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
while (i--)
|
||||
ungetCharIgnoreEOL(cp[i]);
|
||||
ungetCodeUnit(cp[i]);
|
||||
while (leadingZeros--)
|
||||
ungetCharIgnoreEOL('0');
|
||||
ungetCodeUnit('0');
|
||||
|
||||
return length;
|
||||
}
|
||||
|
@ -1194,9 +1257,9 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getDirective(bool isMultiline,
|
|||
// Debugging directives can occur in both single- and multi-line
|
||||
// comments. If we're currently inside a multi-line comment, we also
|
||||
// need to recognize multi-line comment terminators.
|
||||
if (isMultiline && c == '*' && matchChar('/')) {
|
||||
ungetCharIgnoreEOL('/');
|
||||
ungetCharIgnoreEOL('*');
|
||||
if (isMultiline && c == '*' && matchCodeUnit('/')) {
|
||||
ungetCodeUnit('/');
|
||||
ungetCodeUnit('*');
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1319,11 +1382,11 @@ TokenStreamChars<char16_t, AnyCharsAccess>::matchMultiUnitCodePointSlow(char16_t
|
|||
"matchMultiUnitCodepoint should have ensured |lead| is a lead "
|
||||
"surrogate");
|
||||
|
||||
int32_t maybeTrail = getCharIgnoreEOL();
|
||||
int32_t maybeTrail = getCodeUnit();
|
||||
if (MOZ_LIKELY(unicode::IsTrailSurrogate(maybeTrail))) {
|
||||
*codePoint = unicode::UTF16Decode(lead, maybeTrail);
|
||||
} else {
|
||||
ungetCharIgnoreEOL(maybeTrail);
|
||||
ungetCodeUnit(maybeTrail);
|
||||
*codePoint = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1342,7 +1405,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::putIdentInTokenbuf(const CharT* iden
|
|||
|
||||
tokenbuf.clear();
|
||||
for (;;) {
|
||||
int32_t c = getCharIgnoreEOL();
|
||||
int32_t c = getCodeUnit();
|
||||
|
||||
uint32_t codePoint;
|
||||
if (!matchMultiUnitCodePoint(c, &codePoint))
|
||||
|
@ -1381,7 +1444,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::identifierName(TokenStart start,
|
|||
|
||||
int c;
|
||||
while (true) {
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
|
@ -1402,7 +1465,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::identifierName(TokenStart start,
|
|||
escaping = IdentifierEscapes::SawUnicodeEscape;
|
||||
}
|
||||
}
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
|
||||
const CharT* chars;
|
||||
size_t length;
|
||||
|
@ -1525,10 +1588,10 @@ GeneralTokenStreamChars<CharT, AnyCharsAccess>::consumeRestOfSingleLineComment()
|
|||
{
|
||||
int32_t c;
|
||||
do {
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
} while (c != EOF && !SourceUnits::isRawEOLChar(c));
|
||||
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
}
|
||||
|
||||
template<typename CharT, class AnyCharsAccess>
|
||||
|
@ -1545,13 +1608,13 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::decimalNumber(int c, TokenStart star
|
|||
|
||||
// Consume integral component digits.
|
||||
while (IsAsciiDigit(c))
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
|
||||
// Numbers contain no escapes, so we can read directly from |sourceUnits|.
|
||||
double dval;
|
||||
DecimalPoint decimalPoint = NoDecimal;
|
||||
if (c != '.' && c != 'e' && c != 'E') {
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
|
||||
// Most numbers are pure decimal integers without fractional component
|
||||
// or exponential notation. Handle that with optimized code.
|
||||
|
@ -1565,30 +1628,30 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::decimalNumber(int c, TokenStart star
|
|||
if (c == '.') {
|
||||
decimalPoint = HasDecimal;
|
||||
do {
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
} while (IsAsciiDigit(c));
|
||||
}
|
||||
|
||||
// Consume any exponential notation.
|
||||
if (c == 'e' || c == 'E') {
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
if (c == '+' || c == '-')
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
|
||||
// Exponential notation must contain at least one digit.
|
||||
if (!IsAsciiDigit(c)) {
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
error(JSMSG_MISSING_EXPONENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Consume exponential digits.
|
||||
do {
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
} while (IsAsciiDigit(c));
|
||||
}
|
||||
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
|
||||
const CharT* dummy;
|
||||
if (!js_strtod(anyCharsAccess().cx, numStart, sourceUnits.addressOfNextCodeUnit(), &dummy,
|
||||
|
@ -1625,7 +1688,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::decimalNumber(int c, TokenStart star
|
|||
} else {
|
||||
// If not a multi-unit code point, we only need to unget the single
|
||||
// code unit consumed.
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1634,6 +1697,116 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::decimalNumber(int c, TokenStart star
|
|||
return true;
|
||||
}
|
||||
|
||||
template<typename CharT, class AnyCharsAccess>
|
||||
MOZ_MUST_USE bool
|
||||
TokenStreamSpecific<CharT, AnyCharsAccess>::regexpLiteral(TokenStart start, TokenKind* out)
|
||||
{
|
||||
MOZ_ASSERT(sourceUnits.previousCodeUnit() == '/');
|
||||
tokenbuf.clear();
|
||||
|
||||
auto ProcessNonAsciiCodePoint = [this](CharT lead) {
|
||||
int32_t codePoint;
|
||||
if (!this->getNonAsciiCodePoint(lead, &codePoint))
|
||||
return false;
|
||||
|
||||
if (codePoint == '\n') {
|
||||
this->ungetLineTerminator();
|
||||
this->reportError(JSMSG_UNTERMINATED_REGEXP);
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->appendCodePointToTokenbuf(codePoint);
|
||||
};
|
||||
|
||||
auto ReportUnterminatedRegExp = [this](CharT unit) {
|
||||
this->ungetCodeUnit(unit);
|
||||
this->error(JSMSG_UNTERMINATED_REGEXP);
|
||||
};
|
||||
|
||||
bool inCharClass = false;
|
||||
do {
|
||||
int32_t unit = getCodeUnit();
|
||||
if (unit == EOF) {
|
||||
ReportUnterminatedRegExp(unit);
|
||||
return badToken();
|
||||
}
|
||||
|
||||
if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
|
||||
if (unit == '\\') {
|
||||
if (!tokenbuf.append(unit))
|
||||
return badToken();
|
||||
|
||||
unit = getCodeUnit();
|
||||
if (unit == EOF) {
|
||||
ReportUnterminatedRegExp(unit);
|
||||
return badToken();
|
||||
}
|
||||
|
||||
// Fallthrough only handles ASCII code points, so
|
||||
// deal with non-ASCII and skip everything else.
|
||||
if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
|
||||
if (!ProcessNonAsciiCodePoint(unit))
|
||||
return badToken();
|
||||
|
||||
continue;
|
||||
}
|
||||
} else if (unit == '[') {
|
||||
inCharClass = true;
|
||||
} else if (unit == ']') {
|
||||
inCharClass = false;
|
||||
} else if (unit == '/' && !inCharClass) {
|
||||
// For IE compat, allow unescaped / in char classes.
|
||||
break;
|
||||
}
|
||||
|
||||
if (unit == '\r' || unit == '\n') {
|
||||
ReportUnterminatedRegExp(unit);
|
||||
return badToken();
|
||||
}
|
||||
|
||||
if (!tokenbuf.append(unit))
|
||||
return badToken();
|
||||
} else {
|
||||
if (!ProcessNonAsciiCodePoint(unit))
|
||||
return badToken();
|
||||
}
|
||||
} while (true);
|
||||
|
||||
int32_t unit;
|
||||
RegExpFlag reflags = NoFlags;
|
||||
while (true) {
|
||||
RegExpFlag flag;
|
||||
unit = getCodeUnit();
|
||||
if (unit == 'g')
|
||||
flag = GlobalFlag;
|
||||
else if (unit == 'i')
|
||||
flag = IgnoreCaseFlag;
|
||||
else if (unit == 'm')
|
||||
flag = MultilineFlag;
|
||||
else if (unit == 'y')
|
||||
flag = StickyFlag;
|
||||
else if (unit == 'u')
|
||||
flag = UnicodeFlag;
|
||||
else if (IsAsciiAlpha(unit))
|
||||
flag = NoFlags;
|
||||
else
|
||||
break;
|
||||
|
||||
if ((reflags & flag) || flag == NoFlags) {
|
||||
ungetCodeUnit(unit);
|
||||
char buf[2] = { char(unit), '\0' };
|
||||
error(JSMSG_BAD_REGEXP_FLAG, buf);
|
||||
return badToken();
|
||||
}
|
||||
|
||||
reflags = RegExpFlag(reflags | flag);
|
||||
}
|
||||
ungetCodeUnit(unit);
|
||||
|
||||
newRegExpToken(reflags, start, out);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename CharT, class AnyCharsAccess>
|
||||
MOZ_MUST_USE bool
|
||||
TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp,
|
||||
|
@ -1785,12 +1958,12 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
|
||||
int radix;
|
||||
const CharT* numStart;
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
if (c == 'x' || c == 'X') {
|
||||
radix = 16;
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
if (!JS7_ISHEX(c)) {
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
reportError(JSMSG_MISSING_HEXDIGITS);
|
||||
return badToken();
|
||||
}
|
||||
|
@ -1799,12 +1972,12 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
numStart = sourceUnits.addressOfNextCodeUnit() - 1;
|
||||
|
||||
while (JS7_ISHEX(c))
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
} else if (c == 'b' || c == 'B') {
|
||||
radix = 2;
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
if (c != '0' && c != '1') {
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
reportError(JSMSG_MISSING_BINARY_DIGITS);
|
||||
return badToken();
|
||||
}
|
||||
|
@ -1813,12 +1986,12 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
numStart = sourceUnits.addressOfNextCodeUnit() - 1;
|
||||
|
||||
while (c == '0' || c == '1')
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
} else if (c == 'o' || c == 'O') {
|
||||
radix = 8;
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
if (c < '0' || c > '7') {
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
reportError(JSMSG_MISSING_OCTAL_DIGITS);
|
||||
return badToken();
|
||||
}
|
||||
|
@ -1827,7 +2000,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
numStart = sourceUnits.addressOfNextCodeUnit() - 1;
|
||||
|
||||
while ('0' <= c && c <= '7')
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
} else if (IsAsciiDigit(c)) {
|
||||
radix = 8;
|
||||
// one past the '0'
|
||||
|
@ -1851,7 +2024,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
return decimalNumber(c, start, numStart, modifier, ttp);
|
||||
}
|
||||
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
} while (IsAsciiDigit(c));
|
||||
} else {
|
||||
// '0' not followed by [XxBbOo0-9]; scan as a decimal number.
|
||||
|
@ -1859,7 +2032,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
|
||||
return decimalNumber(c, start, numStart, modifier, ttp);
|
||||
}
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
|
||||
if (c != EOF) {
|
||||
if (unicode::IsIdentifierStart(char16_t(c))) {
|
||||
|
@ -1886,7 +2059,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
} else {
|
||||
// If not a multi-unit code point, we only need to unget
|
||||
// the single code unit consumed.
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1916,37 +2089,37 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
#endif
|
||||
switch (c) {
|
||||
case '.':
|
||||
c = getCharIgnoreEOL();
|
||||
c = getCodeUnit();
|
||||
if (IsAsciiDigit(c)) {
|
||||
return decimalNumber('.', start, sourceUnits.addressOfNextCodeUnit() - 2, modifier,
|
||||
ttp);
|
||||
}
|
||||
|
||||
if (c == '.') {
|
||||
if (matchChar('.')) {
|
||||
if (matchCodeUnit('.')) {
|
||||
simpleKind = TokenKind::TripleDot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
|
||||
simpleKind = TokenKind::Dot;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
if (matchChar('='))
|
||||
simpleKind = matchChar('=') ? TokenKind::StrictEq : TokenKind::Eq;
|
||||
else if (matchChar('>'))
|
||||
if (matchCodeUnit('='))
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::StrictEq : TokenKind::Eq;
|
||||
else if (matchCodeUnit('>'))
|
||||
simpleKind = TokenKind::Arrow;
|
||||
else
|
||||
simpleKind = TokenKind::Assign;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
if (matchChar('+'))
|
||||
if (matchCodeUnit('+'))
|
||||
simpleKind = TokenKind::Inc;
|
||||
else
|
||||
simpleKind = matchChar('=') ? TokenKind::AddAssign : TokenKind::Add;
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::AddAssign : TokenKind::Add;
|
||||
break;
|
||||
|
||||
case '\\': {
|
||||
|
@ -1961,36 +2134,36 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
// could point at the 'H'. But we don't do that now, so the
|
||||
// character after the '\' isn't necessarily bad, so just point at
|
||||
// the start of the actually-invalid escape.
|
||||
ungetCharIgnoreEOL('\\');
|
||||
ungetCodeUnit('\\');
|
||||
error(JSMSG_BAD_ESCAPE);
|
||||
return badToken();
|
||||
}
|
||||
|
||||
case '|':
|
||||
if (matchChar('|'))
|
||||
if (matchCodeUnit('|'))
|
||||
simpleKind = TokenKind::Or;
|
||||
#ifdef ENABLE_PIPELINE_OPERATOR
|
||||
else if (matchChar('>'))
|
||||
else if (matchCodeUnit('>'))
|
||||
simpleKind = TokenKind::Pipeline;
|
||||
#endif
|
||||
else
|
||||
simpleKind = matchChar('=') ? TokenKind::BitOrAssign : TokenKind::BitOr;
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::BitOrAssign : TokenKind::BitOr;
|
||||
break;
|
||||
|
||||
case '^':
|
||||
simpleKind = matchChar('=') ? TokenKind::BitXorAssign : TokenKind::BitXor;
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::BitXorAssign : TokenKind::BitXor;
|
||||
break;
|
||||
|
||||
case '&':
|
||||
if (matchChar('&'))
|
||||
if (matchCodeUnit('&'))
|
||||
simpleKind = TokenKind::And;
|
||||
else
|
||||
simpleKind = matchChar('=') ? TokenKind::BitAndAssign : TokenKind::BitAnd;
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::BitAndAssign : TokenKind::BitAnd;
|
||||
break;
|
||||
|
||||
case '!':
|
||||
if (matchChar('='))
|
||||
simpleKind = matchChar('=') ? TokenKind::StrictNe : TokenKind::Ne;
|
||||
if (matchCodeUnit('='))
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::StrictNe : TokenKind::Ne;
|
||||
else
|
||||
simpleKind = TokenKind::Not;
|
||||
break;
|
||||
|
@ -1998,51 +2171,51 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
case '<':
|
||||
if (anyCharsAccess().options().allowHTMLComments) {
|
||||
// Treat HTML begin-comment as comment-till-end-of-line.
|
||||
if (matchChar('!')) {
|
||||
if (matchChar('-')) {
|
||||
if (matchChar('-')) {
|
||||
if (matchCodeUnit('!')) {
|
||||
if (matchCodeUnit('-')) {
|
||||
if (matchCodeUnit('-')) {
|
||||
consumeRestOfSingleLineComment();
|
||||
continue;
|
||||
}
|
||||
ungetCharIgnoreEOL('-');
|
||||
ungetCodeUnit('-');
|
||||
}
|
||||
ungetCharIgnoreEOL('!');
|
||||
ungetCodeUnit('!');
|
||||
}
|
||||
}
|
||||
if (matchChar('<'))
|
||||
simpleKind = matchChar('=') ? TokenKind::LshAssign : TokenKind::Lsh;
|
||||
if (matchCodeUnit('<'))
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::LshAssign : TokenKind::Lsh;
|
||||
else
|
||||
simpleKind = matchChar('=') ? TokenKind::Le : TokenKind::Lt;
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::Le : TokenKind::Lt;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
if (matchChar('>')) {
|
||||
if (matchChar('>'))
|
||||
simpleKind = matchChar('=') ? TokenKind::UrshAssign : TokenKind::Ursh;
|
||||
if (matchCodeUnit('>')) {
|
||||
if (matchCodeUnit('>'))
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::UrshAssign : TokenKind::Ursh;
|
||||
else
|
||||
simpleKind = matchChar('=') ? TokenKind::RshAssign : TokenKind::Rsh;
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::RshAssign : TokenKind::Rsh;
|
||||
} else {
|
||||
simpleKind = matchChar('=') ? TokenKind::Ge : TokenKind::Gt;
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::Ge : TokenKind::Gt;
|
||||
}
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if (matchChar('*'))
|
||||
simpleKind = matchChar('=') ? TokenKind::PowAssign : TokenKind::Pow;
|
||||
if (matchCodeUnit('*'))
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::PowAssign : TokenKind::Pow;
|
||||
else
|
||||
simpleKind = matchChar('=') ? TokenKind::MulAssign : TokenKind::Mul;
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::MulAssign : TokenKind::Mul;
|
||||
break;
|
||||
|
||||
case '/':
|
||||
// Look for a single-line comment.
|
||||
if (matchChar('/')) {
|
||||
c = getCharIgnoreEOL();
|
||||
if (matchCodeUnit('/')) {
|
||||
c = getCodeUnit();
|
||||
if (c == '@' || c == '#') {
|
||||
bool shouldWarn = c == '@';
|
||||
if (!getDirectives(false, shouldWarn))
|
||||
return false;
|
||||
} else {
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
}
|
||||
|
||||
consumeRestOfSingleLineComment();
|
||||
|
@ -2050,26 +2223,32 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
}
|
||||
|
||||
// Look for a multi-line comment.
|
||||
if (matchChar('*')) {
|
||||
if (matchCodeUnit('*')) {
|
||||
TokenStreamAnyChars& anyChars = anyCharsAccess();
|
||||
unsigned linenoBefore = anyChars.lineno;
|
||||
|
||||
do {
|
||||
if (!getChar(&c))
|
||||
return badToken();
|
||||
|
||||
if (c == EOF) {
|
||||
int32_t unit = getCodeUnit();
|
||||
if (unit == EOF) {
|
||||
reportError(JSMSG_UNTERMINATED_COMMENT);
|
||||
return badToken();
|
||||
}
|
||||
|
||||
if (c == '*' && matchChar('/'))
|
||||
if (unit == '*' && matchCodeUnit('/'))
|
||||
break;
|
||||
|
||||
if (c == '@' || c == '#') {
|
||||
bool shouldWarn = c == '@';
|
||||
if (unit == '@' || unit == '#') {
|
||||
bool shouldWarn = unit == '@';
|
||||
if (!getDirectives(true, shouldWarn))
|
||||
return false;
|
||||
return badToken();
|
||||
} else if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
|
||||
int32_t codePoint;
|
||||
if (!getFullAsciiCodePoint(unit, &codePoint))
|
||||
return badToken();
|
||||
} else {
|
||||
int32_t codePoint;
|
||||
if (!getNonAsciiCodePoint(unit, &codePoint))
|
||||
return badToken();
|
||||
}
|
||||
} while (true);
|
||||
|
||||
|
@ -2080,86 +2259,22 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
}
|
||||
|
||||
// Look for a regexp.
|
||||
if (modifier == Operand) {
|
||||
tokenbuf.clear();
|
||||
if (modifier == Operand)
|
||||
return regexpLiteral(start, ttp);
|
||||
|
||||
bool inCharClass = false;
|
||||
do {
|
||||
if (!getChar(&c))
|
||||
return badToken();
|
||||
|
||||
if (c == '\\') {
|
||||
if (!tokenbuf.append(c))
|
||||
return badToken();
|
||||
|
||||
if (!getChar(&c))
|
||||
return badToken();
|
||||
} else if (c == '[') {
|
||||
inCharClass = true;
|
||||
} else if (c == ']') {
|
||||
inCharClass = false;
|
||||
} else if (c == '/' && !inCharClass) {
|
||||
// For IE compat, allow unescaped / in char classes.
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '\n' || c == EOF) {
|
||||
ungetChar(c);
|
||||
reportError(JSMSG_UNTERMINATED_REGEXP);
|
||||
return badToken();
|
||||
}
|
||||
|
||||
if (!tokenbuf.append(c))
|
||||
return badToken();
|
||||
} while (true);
|
||||
|
||||
RegExpFlag reflags = NoFlags;
|
||||
while (true) {
|
||||
RegExpFlag flag;
|
||||
c = getCharIgnoreEOL();
|
||||
if (c == 'g')
|
||||
flag = GlobalFlag;
|
||||
else if (c == 'i')
|
||||
flag = IgnoreCaseFlag;
|
||||
else if (c == 'm')
|
||||
flag = MultilineFlag;
|
||||
else if (c == 'y')
|
||||
flag = StickyFlag;
|
||||
else if (c == 'u')
|
||||
flag = UnicodeFlag;
|
||||
else if (IsAsciiAlpha(c))
|
||||
flag = NoFlags;
|
||||
else
|
||||
break;
|
||||
|
||||
if ((reflags & flag) || flag == NoFlags) {
|
||||
MOZ_ASSERT(sourceUnits.offset() > 0);
|
||||
char buf[2] = { char(c), '\0' };
|
||||
errorAt(sourceUnits.offset() - 1, JSMSG_BAD_REGEXP_FLAG, buf);
|
||||
return badToken();
|
||||
}
|
||||
|
||||
reflags = RegExpFlag(reflags | flag);
|
||||
}
|
||||
ungetCharIgnoreEOL(c);
|
||||
|
||||
newRegExpToken(reflags, start, modifier, ttp);
|
||||
return true;
|
||||
}
|
||||
|
||||
simpleKind = matchChar('=') ? TokenKind::DivAssign : TokenKind::Div;
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::DivAssign : TokenKind::Div;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
simpleKind = matchChar('=') ? TokenKind::ModAssign : TokenKind::Mod;
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::ModAssign : TokenKind::Mod;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
if (matchChar('-')) {
|
||||
if (matchCodeUnit('-')) {
|
||||
if (anyCharsAccess().options().allowHTMLComments &&
|
||||
!anyCharsAccess().flags.isDirtyLine)
|
||||
{
|
||||
if (matchChar('>')) {
|
||||
if (matchCodeUnit('>')) {
|
||||
consumeRestOfSingleLineComment();
|
||||
continue;
|
||||
}
|
||||
|
@ -2167,7 +2282,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const tt
|
|||
|
||||
simpleKind = TokenKind::Dec;
|
||||
} else {
|
||||
simpleKind = matchChar('=') ? TokenKind::SubAssign : TokenKind::Sub;
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::SubAssign : TokenKind::Sub;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2213,10 +2328,10 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getStringOrTemplateToken(char untilC
|
|||
|
||||
// We need to detect any of these chars: " or ', \n (or its
|
||||
// equivalents), \\, EOF. Because we detect EOL sequences here and
|
||||
// put them back immediately, we can use getCharIgnoreEOL().
|
||||
while ((c = getCharIgnoreEOL()) != untilChar) {
|
||||
// put them back immediately, we can use getCodeUnit().
|
||||
while ((c = getCodeUnit()) != untilChar) {
|
||||
if (c == EOF) {
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
const char delimiters[] = { untilChar, untilChar, '\0' };
|
||||
error(JSMSG_EOF_BEFORE_END_OF_LITERAL, delimiters);
|
||||
return false;
|
||||
|
@ -2251,14 +2366,14 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getStringOrTemplateToken(char untilC
|
|||
|
||||
// Unicode character specification.
|
||||
case 'u': {
|
||||
int32_t c2 = getCharIgnoreEOL();
|
||||
int32_t c2 = getCodeUnit();
|
||||
if (c2 == '{') {
|
||||
uint32_t start = sourceUnits.offset() - 3;
|
||||
uint32_t code = 0;
|
||||
bool first = true;
|
||||
bool valid = true;
|
||||
do {
|
||||
int32_t c = getCharIgnoreEOL();
|
||||
int32_t c = getCodeUnit();
|
||||
if (c == EOF) {
|
||||
if (parsingTemplate) {
|
||||
TokenStreamAnyChars& anyChars = anyCharsAccess();
|
||||
|
@ -2290,7 +2405,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getStringOrTemplateToken(char untilC
|
|||
// We put the character back so that we read
|
||||
// it on the next pass, which matters if it
|
||||
// was '`' or '\'.
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
|
||||
TokenStreamAnyChars& anyChars = anyCharsAccess();
|
||||
anyChars.setInvalidTemplateEscape(start,
|
||||
|
@ -2342,7 +2457,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getStringOrTemplateToken(char untilC
|
|||
JS7_UNHEX(cp[2]);
|
||||
skipChars(3);
|
||||
} else {
|
||||
ungetCharIgnoreEOL(c2);
|
||||
ungetCodeUnit(c2);
|
||||
uint32_t start = sourceUnits.offset() - 2;
|
||||
if (parsingTemplate) {
|
||||
TokenStreamAnyChars& anyChars = anyCharsAccess();
|
||||
|
@ -2417,7 +2532,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getStringOrTemplateToken(char untilC
|
|||
} else if (c == '\r' || c == '\n') {
|
||||
if (!parsingTemplate) {
|
||||
// String literals don't allow ASCII line breaks.
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetCodeUnit(c);
|
||||
const char delimiters[] = { untilChar, untilChar, '\0' };
|
||||
error(JSMSG_EOL_BEFORE_END_OF_STRING, delimiters);
|
||||
return false;
|
||||
|
@ -2444,7 +2559,7 @@ TokenStreamSpecific<CharT, AnyCharsAccess>::getStringOrTemplateToken(char untilC
|
|||
return false;
|
||||
|
||||
anyCharsAccess().updateFlagsForEOL();
|
||||
} else if (parsingTemplate && c == '$' && matchChar('{')) {
|
||||
} else if (parsingTemplate && c == '$' && matchCodeUnit('{')) {
|
||||
templateHead = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -166,6 +166,7 @@
|
|||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/MemoryChecking.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/TextUtils.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
|
@ -855,7 +856,30 @@ class TokenStreamAnyChars
|
|||
const char* filename_; // input filename or null
|
||||
UniqueTwoByteChars displayURL_; // the user's requested source URL or null
|
||||
UniqueTwoByteChars sourceMapURL_; // source map's filename or null
|
||||
uint8_t isExprEnding[size_t(TokenKind::Limit)];// which tokens definitely terminate exprs?
|
||||
|
||||
/**
|
||||
* An array storing whether a TokenKind observed while attempting to extend
|
||||
* a valid AssignmentExpression into an even longer AssignmentExpression
|
||||
* (e.g., extending '3' to '3 + 5') will terminate it without error.
|
||||
*
|
||||
* For example, ';' always ends an AssignmentExpression because it ends a
|
||||
* Statement or declaration. '}' always ends an AssignmentExpression
|
||||
* because it terminates BlockStatement, FunctionBody, and embedded
|
||||
* expressions in TemplateLiterals. Therefore both entries are set to true
|
||||
* in TokenStreamAnyChars construction.
|
||||
*
|
||||
* But e.g. '+' *could* extend an AssignmentExpression, so its entry here
|
||||
* is false. Meanwhile 'this' can't extend an AssignmentExpression, but
|
||||
* it's only valid after a line break, so its entry here must be false.
|
||||
*
|
||||
* NOTE: This array could be static, but without C99's designated
|
||||
* initializers it's easier zeroing here and setting the true entries
|
||||
* in the constructor body. (Having this per-instance might also aid
|
||||
* locality.) Don't worry! Initialization time for each TokenStream
|
||||
* is trivial. See bug 639420.
|
||||
*/
|
||||
bool isExprEnding[size_t(TokenKind::Limit)] = {}; // all-false initially
|
||||
|
||||
JSContext* const cx;
|
||||
bool mutedErrors;
|
||||
StrictModeGetter* strictModeGetter; // used to test for strict mode
|
||||
|
@ -910,6 +934,12 @@ class SourceUnits
|
|||
return limit_;
|
||||
}
|
||||
|
||||
CharT previousCodeUnit() {
|
||||
MOZ_ASSERT(ptr, "can't get previous code unit if poisoned");
|
||||
MOZ_ASSERT(!atStart(), "must have a previous code unit to get");
|
||||
return *(ptr - 1);
|
||||
}
|
||||
|
||||
CharT getCodeUnit() {
|
||||
return *ptr++; // this will nullptr-crash if poisoned
|
||||
}
|
||||
|
@ -942,6 +972,7 @@ class SourceUnits
|
|||
}
|
||||
|
||||
void ungetCodeUnit() {
|
||||
MOZ_ASSERT(!atStart(), "can't unget if currently at start");
|
||||
MOZ_ASSERT(ptr); // make sure it hasn't been poisoned
|
||||
ptr--;
|
||||
}
|
||||
|
@ -993,7 +1024,7 @@ template<typename CharT>
|
|||
class TokenStreamCharsBase
|
||||
{
|
||||
protected:
|
||||
void ungetCharIgnoreEOL(int32_t c);
|
||||
void ungetCodeUnit(int32_t c);
|
||||
|
||||
public:
|
||||
using CharBuffer = Vector<CharT, 32>;
|
||||
|
@ -1012,6 +1043,13 @@ class TokenStreamCharsBase
|
|||
|
||||
MOZ_MUST_USE bool appendCodePointToTokenbuf(uint32_t codePoint);
|
||||
|
||||
// |expect| cannot be an EOL char.
|
||||
bool matchCodeUnit(int32_t expect) {
|
||||
MOZ_ASSERT(expect != EOF, "shouldn't be matching EOFs");
|
||||
MOZ_ASSERT(!SourceUnits::isRawEOLChar(expect));
|
||||
return MOZ_LIKELY(sourceUnits.hasRawChars()) && sourceUnits.matchCodeUnit(expect);
|
||||
}
|
||||
|
||||
protected:
|
||||
MOZ_MUST_USE bool
|
||||
fillWithTemplateStringContents(CharBuffer& charbuf, const CharT* cur, const CharT* end) {
|
||||
|
@ -1036,6 +1074,15 @@ class TokenStreamCharsBase
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a code unit constitutes a complete ASCII code point.
|
||||
* (The code point's exact value might not be used, however, if subsequent
|
||||
* code observes that |unit| is part of a LineTerminatorSequence.)
|
||||
*/
|
||||
static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool isAsciiCodePoint(CharT unit) {
|
||||
return mozilla::IsAscii(unit);
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Code units in the source code being tokenized. */
|
||||
SourceUnits sourceUnits;
|
||||
|
@ -1104,7 +1151,6 @@ class GeneralTokenStreamChars
|
|||
using typename CharsSharedBase::SourceUnits;
|
||||
|
||||
using CharsSharedBase::sourceUnits;
|
||||
using CharsSharedBase::ungetCharIgnoreEOL;
|
||||
|
||||
public:
|
||||
using CharsSharedBase::CharsSharedBase;
|
||||
|
@ -1157,16 +1203,21 @@ class GeneralTokenStreamChars
|
|||
token->setName(name);
|
||||
}
|
||||
|
||||
void newRegExpToken(RegExpFlag reflags, TokenStart start,
|
||||
TokenStreamShared::Modifier modifier, TokenKind* out)
|
||||
void newRegExpToken(RegExpFlag reflags, TokenStart start, TokenKind* out)
|
||||
{
|
||||
Token* token = newToken(TokenKind::RegExp, start, modifier, out);
|
||||
Token* token = newToken(TokenKind::RegExp, start, TokenStreamShared::Operand, out);
|
||||
token->setRegExpFlags(reflags);
|
||||
}
|
||||
|
||||
MOZ_COLD bool badToken();
|
||||
|
||||
int32_t getCharIgnoreEOL();
|
||||
int32_t getCodeUnit();
|
||||
|
||||
void ungetCodeUnit(int32_t c) {
|
||||
MOZ_ASSERT_IF(c == EOF, anyCharsAccess().flags.isEOF);
|
||||
|
||||
CharsSharedBase::ungetCodeUnit(c);
|
||||
}
|
||||
|
||||
void ungetChar(int32_t c);
|
||||
|
||||
|
@ -1200,11 +1251,14 @@ class TokenStreamChars<char16_t, AnyCharsAccess>
|
|||
|
||||
protected:
|
||||
using GeneralCharsBase::anyCharsAccess;
|
||||
using GeneralCharsBase::getCharIgnoreEOL;
|
||||
using GeneralCharsBase::getCodeUnit;
|
||||
using CharsSharedBase::isAsciiCodePoint;
|
||||
using GeneralCharsBase::sourceUnits;
|
||||
using CharsSharedBase::ungetCharIgnoreEOL;
|
||||
using CharsSharedBase::ungetCodeUnit;
|
||||
using GeneralCharsBase::updateLineInfoForEOL;
|
||||
|
||||
using typename GeneralCharsBase::SourceUnits;
|
||||
|
||||
using GeneralCharsBase::GeneralCharsBase;
|
||||
|
||||
// |c| must be the code unit just gotten. If it and the subsequent code
|
||||
|
@ -1232,13 +1286,73 @@ class TokenStreamChars<char16_t, AnyCharsAccess>
|
|||
return true;
|
||||
}
|
||||
|
||||
// Try to get the next character, normalizing '\r', '\r\n', and '\n' into
|
||||
// '\n'. Also updates internal line-counter state. Return true on success
|
||||
// and store the character in |*c|. Return false and leave |*c| undefined
|
||||
// on failure.
|
||||
MOZ_MUST_USE bool getChar(int32_t* cp);
|
||||
// Try to get the next code point, normalizing '\r', '\r\n', '\n', and the
|
||||
// Unicode line/paragraph separators into '\n'. Also updates internal
|
||||
// line-counter state. Return true on success and store the character in
|
||||
// |*c|. Return false and leave |*c| undefined on failure.
|
||||
MOZ_MUST_USE bool getCodePoint(int32_t* cp);
|
||||
|
||||
// A deprecated alias for |getCodePoint|: most code using this is being
|
||||
// replaced with different approaches.
|
||||
MOZ_MUST_USE bool getChar(int32_t* cp) {
|
||||
return getCodePoint(cp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a just-consumed ASCII code unit/point |lead|, consume a full code
|
||||
* point or LineTerminatorSequence (normalizing it to '\n') and store it in
|
||||
* |*codePoint|. Return true on success, otherwise return false and leave
|
||||
* |*codePoint| undefined on failure.
|
||||
*
|
||||
* If a LineTerminatorSequence was consumed, also update line/column info.
|
||||
*
|
||||
* This may change the current |sourceUnits| offset.
|
||||
*/
|
||||
MOZ_MUST_USE bool getFullAsciiCodePoint(char16_t lead, int32_t* codePoint) {
|
||||
MOZ_ASSERT(isAsciiCodePoint(lead),
|
||||
"non-ASCII code units must be handled separately");
|
||||
MOZ_ASSERT(lead == sourceUnits.previousCodeUnit(),
|
||||
"getFullAsciiCodePoint called incorrectly");
|
||||
|
||||
if (MOZ_UNLIKELY(lead == '\r')) {
|
||||
if (MOZ_LIKELY(sourceUnits.hasRawChars()))
|
||||
sourceUnits.matchCodeUnit('\n');
|
||||
} else if (MOZ_LIKELY(lead != '\n')) {
|
||||
*codePoint = lead;
|
||||
return true;
|
||||
}
|
||||
|
||||
*codePoint = '\n';
|
||||
bool ok = updateLineInfoForEOL();
|
||||
if (!ok) {
|
||||
#ifdef DEBUG
|
||||
*codePoint = EOF; // sentinel value to hopefully cause errors
|
||||
#endif
|
||||
MOZ_MAKE_MEM_UNDEFINED(codePoint, sizeof(*codePoint));
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a just-consumed non-ASCII code unit (and maybe point) |lead|,
|
||||
* consume a full code point or LineTerminatorSequence (normalizing it to
|
||||
* '\n') and store it in |*codePoint|. Return true on success, otherwise
|
||||
* return false and leave |*codePoint| undefined on failure.
|
||||
*
|
||||
* If a LineTerminatorSequence was consumed, also update line/column info.
|
||||
*
|
||||
* This may change the current |sourceUnits| offset.
|
||||
*/
|
||||
MOZ_MUST_USE bool getNonAsciiCodePoint(char16_t lead, int32_t* cp);
|
||||
|
||||
void ungetCodePointIgnoreEOL(uint32_t codePoint);
|
||||
|
||||
/**
|
||||
* Unget a just-gotten LineTerminator sequence: '\r', '\n', '\r\n', or
|
||||
* a Unicode line/paragraph separator, also undoing line/column information
|
||||
* changes reflecting that LineTerminator.
|
||||
*/
|
||||
void ungetLineTerminator();
|
||||
};
|
||||
|
||||
// TokenStream is the lexical scanner for JavaScript source text.
|
||||
|
@ -1322,7 +1436,12 @@ class MOZ_STACK_CLASS TokenStreamSpecific
|
|||
using CharsSharedBase::copyTokenbufTo;
|
||||
using CharsSharedBase::fillWithTemplateStringContents;
|
||||
using CharsBase::getChar;
|
||||
using GeneralCharsBase::getCharIgnoreEOL;
|
||||
using CharsBase::getCodePoint;
|
||||
using GeneralCharsBase::getCodeUnit;
|
||||
using CharsBase::getFullAsciiCodePoint;
|
||||
using CharsBase::getNonAsciiCodePoint;
|
||||
using CharsSharedBase::isAsciiCodePoint;
|
||||
using CharsSharedBase::matchCodeUnit;
|
||||
using CharsBase::matchMultiUnitCodePoint;
|
||||
using GeneralCharsBase::newAtomToken;
|
||||
using GeneralCharsBase::newNameToken;
|
||||
|
@ -1332,8 +1451,8 @@ class MOZ_STACK_CLASS TokenStreamSpecific
|
|||
using CharsSharedBase::sourceUnits;
|
||||
using CharsSharedBase::tokenbuf;
|
||||
using GeneralCharsBase::ungetChar;
|
||||
using CharsSharedBase::ungetCharIgnoreEOL;
|
||||
using CharsBase::ungetCodePointIgnoreEOL;
|
||||
using CharsSharedBase::ungetCodeUnit;
|
||||
using GeneralCharsBase::updateLineInfoForEOL;
|
||||
|
||||
template<typename CharU> friend class TokenStreamPosition;
|
||||
|
@ -1480,29 +1599,29 @@ class MOZ_STACK_CLASS TokenStreamSpecific
|
|||
* not starting with '0' or '.', e.g. '1' for "17", '3' for "3.14", or
|
||||
* '8' for "8.675309e6".
|
||||
*
|
||||
* In this case, the next |getCharIgnoreEOL()| must return the code unit
|
||||
* after |c| in the overall number.
|
||||
* In this case, the next |getCodeUnit()| must return the code unit after
|
||||
* |c| in the overall number.
|
||||
*
|
||||
* 2. The '.' in a "."/"0."-prefixed decimal number or the 'e'/'E' in a
|
||||
* "0e"/"0E"-prefixed decimal number, e.g. ".17", "0.42", or "0.1e3".
|
||||
*
|
||||
* In this case, the next |getCharIgnoreEOL()| must return the code unit
|
||||
* In this case, the next |getCodeUnit()| must return the code unit
|
||||
* *after* the first decimal digit *after* the '.'. So the next code
|
||||
* unit would be '7' in ".17", '2' in "0.42", 'e' in "0.4e+8", or '/' in
|
||||
* "0.5/2" (three separate tokens).
|
||||
*
|
||||
* 3. The code unit after the '0' where "0" is the entire number token.
|
||||
*
|
||||
* In this case, the next |getCharIgnoreEOL()| returns the code unit
|
||||
* after |c|.
|
||||
* In this case, the next |getCodeUnit()| returns the code unit after
|
||||
* |c|.
|
||||
*
|
||||
* 4. (Non-strict mode code only) The first '8' or '9' in a "noctal"
|
||||
* number that begins with a '0' but contains a non-octal digit in its
|
||||
* integer part so is interpreted as decimal, e.g. '9' in "09.28" or
|
||||
* '8' in "0386" or '9' in "09+7" (three separate tokens").
|
||||
*
|
||||
* In this case, the next |getCharIgnoreEOL()| returns the code unit
|
||||
* after |c|: '.', '6', or '+' in the examples above.
|
||||
* In this case, the next |getCodeUnit()| returns the code unit after
|
||||
* |c|: '.', '6', or '+' in the examples above.
|
||||
*
|
||||
* This interface is super-hairy and horribly stateful. Unfortunately, its
|
||||
* hair merely reflects the intricacy of ECMAScript numeric literal syntax.
|
||||
|
@ -1511,6 +1630,9 @@ class MOZ_STACK_CLASS TokenStreamSpecific
|
|||
MOZ_MUST_USE bool decimalNumber(int c, TokenStart start, const CharT* numStart,
|
||||
Modifier modifier, TokenKind* out);
|
||||
|
||||
/** Tokenize a regular expression literal beginning at |start|. */
|
||||
MOZ_MUST_USE bool regexpLiteral(TokenStart start, TokenKind* out);
|
||||
|
||||
public:
|
||||
// Advance to the next token. If the token stream encountered an error,
|
||||
// return false. Otherwise return true and store the token kind in |*ttp|.
|
||||
|
@ -1692,12 +1814,6 @@ class MOZ_STACK_CLASS TokenStreamSpecific
|
|||
MOZ_MUST_USE bool getDisplayURL(bool isMultiline, bool shouldWarnDeprecated);
|
||||
MOZ_MUST_USE bool getSourceMappingURL(bool isMultiline, bool shouldWarnDeprecated);
|
||||
|
||||
// |expect| cannot be an EOL char.
|
||||
bool matchChar(int32_t expect) {
|
||||
MOZ_ASSERT(!SourceUnits::isRawEOLChar(expect));
|
||||
return MOZ_LIKELY(sourceUnits.hasRawChars()) && sourceUnits.matchCodeUnit(expect);
|
||||
}
|
||||
|
||||
void consumeKnownChar(int32_t expect) {
|
||||
int32_t c;
|
||||
MOZ_ALWAYS_TRUE(getChar(&c));
|
||||
|
@ -1708,7 +1824,7 @@ class MOZ_STACK_CLASS TokenStreamSpecific
|
|||
#ifdef DEBUG
|
||||
auto c =
|
||||
#endif
|
||||
getCharIgnoreEOL();
|
||||
getCodeUnit();
|
||||
MOZ_ASSERT(c == expect);
|
||||
}
|
||||
|
||||
|
@ -1722,7 +1838,7 @@ class MOZ_STACK_CLASS TokenStreamSpecific
|
|||
void skipChars(uint32_t n) {
|
||||
while (n-- > 0) {
|
||||
MOZ_ASSERT(sourceUnits.hasRawChars());
|
||||
mozilla::DebugOnly<int32_t> c = getCharIgnoreEOL();
|
||||
mozilla::DebugOnly<int32_t> c = getCodeUnit();
|
||||
MOZ_ASSERT(!SourceUnits::isRawEOLChar(c));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
var setSharedArrayBuffer = global.setSharedArrayBuffer;
|
||||
var getSharedArrayBuffer = global.getSharedArrayBuffer;
|
||||
var evalInWorker = global.evalInWorker;
|
||||
var monotonicNow = global.monotonicNow;
|
||||
|
||||
var hasCreateIsHTMLDDA = "createIsHTMLDDA" in global;
|
||||
var hasThreads = ("helperThreadCount" in global ? global.helperThreadCount() > 0 : true);
|
||||
|
@ -128,7 +129,9 @@ $262.agent = (function () {
|
|||
Atomics.wait(_ia, ${_SLEEP_LOC}, 0, s);
|
||||
},
|
||||
|
||||
leaving() {}
|
||||
leaving() {},
|
||||
|
||||
monotonicNow,
|
||||
};
|
||||
Atomics.add(_ia, ${_RDY_LOC}, 1);
|
||||
return agent;
|
||||
|
@ -190,6 +193,8 @@ $262.agent = (function () {
|
|||
this._bailIfNotAvailable();
|
||||
Atomics.wait(_ia, _SLEEP_LOC, 0, s);
|
||||
},
|
||||
|
||||
monotonicNow,
|
||||
};
|
||||
})()
|
||||
};
|
||||
|
|
|
@ -993,13 +993,11 @@ GlobalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope)
|
|||
if (mode == XDR_DECODE)
|
||||
uniqueData.emplace(cx, data);
|
||||
|
||||
MOZ_TRY(xdr->codeUint32(&data->varStart));
|
||||
MOZ_TRY(xdr->codeUint32(&data->letStart));
|
||||
MOZ_TRY(xdr->codeUint32(&data->constStart));
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
if (!data->length) {
|
||||
MOZ_ASSERT(!data->varStart);
|
||||
MOZ_ASSERT(!data->letStart);
|
||||
MOZ_ASSERT(!data->constStart);
|
||||
}
|
||||
|
@ -1418,7 +1416,7 @@ BindingIter::init(LexicalScope::Data& data, uint32_t firstFrameSlot, uint8_t fla
|
|||
if (flags & IsNamedLambda) {
|
||||
// Named lambda binding is weird. Normal BindingKind ordering rules
|
||||
// don't apply.
|
||||
init(0, 0, 0, 0, 0, 0,
|
||||
init(0, 0, 0, 0, 0,
|
||||
CanHaveEnvironmentSlots | flags,
|
||||
firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_),
|
||||
data.trailingNames.start(), data.length);
|
||||
|
@ -1426,11 +1424,10 @@ BindingIter::init(LexicalScope::Data& data, uint32_t firstFrameSlot, uint8_t fla
|
|||
// imports - [0, 0)
|
||||
// positional formals - [0, 0)
|
||||
// other formals - [0, 0)
|
||||
// top-level funcs - [0, 0)
|
||||
// vars - [0, 0)
|
||||
// lets - [0, data.constStart)
|
||||
// consts - [data.constStart, data.length)
|
||||
init(0, 0, 0, 0, 0, data.constStart,
|
||||
init(0, 0, 0, 0, data.constStart,
|
||||
CanHaveFrameSlots | CanHaveEnvironmentSlots | flags,
|
||||
firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_),
|
||||
data.trailingNames.start(), data.length);
|
||||
|
@ -1447,11 +1444,10 @@ BindingIter::init(FunctionScope::Data& data, uint8_t flags)
|
|||
// imports - [0, 0)
|
||||
// positional formals - [0, data.nonPositionalFormalStart)
|
||||
// other formals - [data.nonPositionalParamStart, data.varStart)
|
||||
// top-level funcs - [data.varStart, data.varStart)
|
||||
// vars - [data.varStart, data.length)
|
||||
// lets - [data.length, data.length)
|
||||
// consts - [data.length, data.length)
|
||||
init(0, data.nonPositionalFormalStart, data.varStart, data.varStart, data.length, data.length,
|
||||
init(0, data.nonPositionalFormalStart, data.varStart, data.length, data.length,
|
||||
flags,
|
||||
0, JSSLOT_FREE(&CallObject::class_),
|
||||
data.trailingNames.start(), data.length);
|
||||
|
@ -1463,11 +1459,10 @@ BindingIter::init(VarScope::Data& data, uint32_t firstFrameSlot)
|
|||
// imports - [0, 0)
|
||||
// positional formals - [0, 0)
|
||||
// other formals - [0, 0)
|
||||
// top-level funcs - [0, 0)
|
||||
// vars - [0, data.length)
|
||||
// lets - [data.length, data.length)
|
||||
// consts - [data.length, data.length)
|
||||
init(0, 0, 0, 0, data.length, data.length,
|
||||
init(0, 0, 0, data.length, data.length,
|
||||
CanHaveFrameSlots | CanHaveEnvironmentSlots,
|
||||
firstFrameSlot, JSSLOT_FREE(&VarEnvironmentObject::class_),
|
||||
data.trailingNames.start(), data.length);
|
||||
|
@ -1479,11 +1474,10 @@ BindingIter::init(GlobalScope::Data& data)
|
|||
// imports - [0, 0)
|
||||
// positional formals - [0, 0)
|
||||
// other formals - [0, 0)
|
||||
// top-level funcs - [0, data.varStart)
|
||||
// vars - [data.varStart, data.letStart)
|
||||
// vars - [0, data.letStart)
|
||||
// lets - [data.letStart, data.constStart)
|
||||
// consts - [data.constStart, data.length)
|
||||
init(0, 0, 0, data.varStart, data.letStart, data.constStart,
|
||||
init(0, 0, 0, data.letStart, data.constStart,
|
||||
CannotHaveSlots,
|
||||
UINT32_MAX, UINT32_MAX,
|
||||
data.trailingNames.start(), data.length);
|
||||
|
@ -1508,11 +1502,10 @@ BindingIter::init(EvalScope::Data& data, bool strict)
|
|||
// imports - [0, 0)
|
||||
// positional formals - [0, 0)
|
||||
// other formals - [0, 0)
|
||||
// top-level funcs - [0, data.varStart)
|
||||
// vars - [data.varStart, data.length)
|
||||
// vars - [0, data.length)
|
||||
// lets - [data.length, data.length)
|
||||
// consts - [data.length, data.length)
|
||||
init(0, 0, 0, data.varStart, data.length, data.length,
|
||||
init(0, 0, 0, data.length, data.length,
|
||||
flags, firstFrameSlot, firstEnvironmentSlot,
|
||||
data.trailingNames.start(), data.length);
|
||||
}
|
||||
|
@ -1523,11 +1516,10 @@ BindingIter::init(ModuleScope::Data& data)
|
|||
// imports - [0, data.varStart)
|
||||
// positional formals - [data.varStart, data.varStart)
|
||||
// other formals - [data.varStart, data.varStart)
|
||||
// top-level funcs - [data.varStart, data.varStart)
|
||||
// vars - [data.varStart, data.letStart)
|
||||
// lets - [data.letStart, data.constStart)
|
||||
// consts - [data.constStart, data.length)
|
||||
init(data.varStart, data.varStart, data.varStart, data.varStart, data.letStart, data.constStart,
|
||||
init(data.varStart, data.varStart, data.varStart, data.letStart, data.constStart,
|
||||
CanHaveFrameSlots | CanHaveEnvironmentSlots,
|
||||
0, JSSLOT_FREE(&ModuleEnvironmentObject::class_),
|
||||
data.trailingNames.start(), data.length);
|
||||
|
@ -1539,11 +1531,10 @@ BindingIter::init(WasmInstanceScope::Data& data)
|
|||
// imports - [0, 0)
|
||||
// positional formals - [0, 0)
|
||||
// other formals - [0, 0)
|
||||
// top-level funcs - [0, 0)
|
||||
// vars - [0, data.length)
|
||||
// lets - [data.length, data.length)
|
||||
// consts - [data.length, data.length)
|
||||
init(0, 0, 0, 0, data.length, data.length,
|
||||
init(0, 0, 0, data.length, data.length,
|
||||
CanHaveFrameSlots | CanHaveEnvironmentSlots,
|
||||
UINT32_MAX, UINT32_MAX,
|
||||
data.trailingNames.start(), data.length);
|
||||
|
@ -1555,11 +1546,10 @@ BindingIter::init(WasmFunctionScope::Data& data)
|
|||
// imports - [0, 0)
|
||||
// positional formals - [0, 0)
|
||||
// other formals - [0, 0)
|
||||
// top-level funcs - [0, 0)
|
||||
// vars - [0, data.length)
|
||||
// lets - [data.length, data.length)
|
||||
// consts - [data.length, data.length)
|
||||
init(0, 0, 0, 0, data.length, data.length,
|
||||
init(0, 0, 0, data.length, data.length,
|
||||
CanHaveFrameSlots | CanHaveEnvironmentSlots,
|
||||
UINT32_MAX, UINT32_MAX,
|
||||
data.trailingNames.start(), data.length);
|
||||
|
|
|
@ -104,20 +104,27 @@ const char* ScopeKindString(ScopeKind kind);
|
|||
|
||||
class BindingName
|
||||
{
|
||||
// A JSAtom* with its low bit used as a tag for whether it is closed over
|
||||
// (i.e., exists in the environment shape).
|
||||
// A JSAtom* with its low bit used as a tag for the:
|
||||
// * whether it is closed over (i.e., exists in the environment shape)
|
||||
// * whether it is a top-level function binding in global or eval scope,
|
||||
// instead of var binding (both are in the same range in Scope data)
|
||||
uintptr_t bits_;
|
||||
|
||||
static const uintptr_t ClosedOverFlag = 0x1;
|
||||
static const uintptr_t FlagMask = 0x1;
|
||||
// TODO: We should reuse this bit for let vs class distinction to
|
||||
// show the better redeclaration error message (bug 1428672).
|
||||
static const uintptr_t TopLevelFunctionFlag = 0x2;
|
||||
static const uintptr_t FlagMask = 0x3;
|
||||
|
||||
public:
|
||||
BindingName()
|
||||
: bits_(0)
|
||||
{ }
|
||||
|
||||
BindingName(JSAtom* name, bool closedOver)
|
||||
: bits_(uintptr_t(name) | (closedOver ? ClosedOverFlag : 0x0))
|
||||
BindingName(JSAtom* name, bool closedOver, bool isTopLevelFunction = false)
|
||||
: bits_(uintptr_t(name) |
|
||||
(closedOver ? ClosedOverFlag : 0x0) |
|
||||
(isTopLevelFunction? TopLevelFunctionFlag : 0x0))
|
||||
{ }
|
||||
|
||||
JSAtom* name() const {
|
||||
|
@ -128,6 +135,15 @@ class BindingName
|
|||
return bits_ & ClosedOverFlag;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class BindingIter;
|
||||
// This method should be called only for binding names in `vars` range in
|
||||
// BindingIter.
|
||||
bool isTopLevelFunction() const {
|
||||
return bits_ & TopLevelFunctionFlag;
|
||||
}
|
||||
|
||||
public:
|
||||
void trace(JSTracer* trc);
|
||||
};
|
||||
|
||||
|
@ -747,12 +763,12 @@ class GlobalScope : public Scope
|
|||
struct Data
|
||||
{
|
||||
// Bindings are sorted by kind.
|
||||
// `vars` includes top-level functions which is distinguished by a bit
|
||||
// on the BindingName.
|
||||
//
|
||||
// top-level funcs - [0, varStart)
|
||||
// vars - [varStart, letStart)
|
||||
// vars - [0, letStart)
|
||||
// lets - [letStart, constStart)
|
||||
// consts - [constStart, length)
|
||||
uint32_t varStart = 0;
|
||||
uint32_t letStart = 0;
|
||||
uint32_t constStart = 0;
|
||||
uint32_t length = 0;
|
||||
|
@ -853,11 +869,11 @@ class EvalScope : public Scope
|
|||
{
|
||||
// All bindings in an eval script are 'var' bindings. The implicit
|
||||
// lexical scope around the eval is present regardless of strictness
|
||||
// and is its own LexicalScope. However, we need to track top-level
|
||||
// functions specially for redeclaration checks.
|
||||
// and is its own LexicalScope.
|
||||
// `vars` includes top-level functions which is distinguished by a bit
|
||||
// on the BindingName.
|
||||
//
|
||||
// top-level funcs - [0, varStart)
|
||||
// vars - [varStart, length)
|
||||
// vars - [0, length)
|
||||
uint32_t varStart = 0;
|
||||
uint32_t length = 0;
|
||||
|
||||
|
@ -1152,8 +1168,7 @@ class BindingIter
|
|||
//
|
||||
// imports - [0, positionalFormalStart)
|
||||
// positional formals - [positionalFormalStart, nonPositionalFormalStart)
|
||||
// other formals - [nonPositionalParamStart, topLevelFunctionStart)
|
||||
// top-level funcs - [topLevelFunctionStart, varStart)
|
||||
// other formals - [nonPositionalParamStart, varStart)
|
||||
// vars - [varStart, letStart)
|
||||
// lets - [letStart, constStart)
|
||||
// consts - [constStart, length)
|
||||
|
@ -1163,7 +1178,6 @@ class BindingIter
|
|||
// imports - name
|
||||
// positional formals - argument slot
|
||||
// other formals - frame slot
|
||||
// top-level funcs - frame slot
|
||||
// vars - frame slot
|
||||
// lets - frame slot
|
||||
// consts - frame slot
|
||||
|
@ -1173,13 +1187,11 @@ class BindingIter
|
|||
// imports - name
|
||||
// positional formals - environment slot or name
|
||||
// other formals - environment slot or name
|
||||
// top-level funcs - environment slot or name
|
||||
// vars - environment slot or name
|
||||
// lets - environment slot or name
|
||||
// consts - environment slot or name
|
||||
MOZ_INIT_OUTSIDE_CTOR uint32_t positionalFormalStart_;
|
||||
MOZ_INIT_OUTSIDE_CTOR uint32_t nonPositionalFormalStart_;
|
||||
MOZ_INIT_OUTSIDE_CTOR uint32_t topLevelFunctionStart_;
|
||||
MOZ_INIT_OUTSIDE_CTOR uint32_t varStart_;
|
||||
MOZ_INIT_OUTSIDE_CTOR uint32_t letStart_;
|
||||
MOZ_INIT_OUTSIDE_CTOR uint32_t constStart_;
|
||||
|
@ -1211,14 +1223,12 @@ class BindingIter
|
|||
MOZ_INIT_OUTSIDE_CTOR BindingName* names_;
|
||||
|
||||
void init(uint32_t positionalFormalStart, uint32_t nonPositionalFormalStart,
|
||||
uint32_t topLevelFunctionStart, uint32_t varStart,
|
||||
uint32_t letStart, uint32_t constStart,
|
||||
uint32_t varStart, uint32_t letStart, uint32_t constStart,
|
||||
uint8_t flags, uint32_t firstFrameSlot, uint32_t firstEnvironmentSlot,
|
||||
BindingName* names, uint32_t length)
|
||||
{
|
||||
positionalFormalStart_ = positionalFormalStart;
|
||||
nonPositionalFormalStart_ = nonPositionalFormalStart;
|
||||
topLevelFunctionStart_ = topLevelFunctionStart;
|
||||
varStart_ = varStart;
|
||||
letStart_ = letStart;
|
||||
constStart_ = constStart;
|
||||
|
@ -1385,7 +1395,7 @@ class BindingIter
|
|||
MOZ_ASSERT(!done());
|
||||
if (index_ < positionalFormalStart_)
|
||||
return BindingKind::Import;
|
||||
if (index_ < topLevelFunctionStart_) {
|
||||
if (index_ < varStart_) {
|
||||
// When the parameter list has expressions, the parameters act
|
||||
// like lexical bindings and have TDZ.
|
||||
if (hasFormalParameterExprs())
|
||||
|
@ -1403,7 +1413,9 @@ class BindingIter
|
|||
|
||||
bool isTopLevelFunction() const {
|
||||
MOZ_ASSERT(!done());
|
||||
return index_ >= topLevelFunctionStart_ && index_ < varStart_;
|
||||
bool result = names_[index_].isTopLevelFunction();
|
||||
MOZ_ASSERT_IF(result, kind() == BindingKind::Var);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool hasArgumentSlot() const {
|
||||
|
|
|
@ -90,6 +90,23 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = [ "XPCOMUtils" ];
|
||||
|
||||
let global = Cu.getGlobalForObject({});
|
||||
|
||||
/**
|
||||
* Redefines the given property on the given object with the given
|
||||
* value. This can be used to redefine getter properties which do not
|
||||
* implement setters.
|
||||
*/
|
||||
function redefine(object, prop, value) {
|
||||
Object.defineProperty(object, prop, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
value,
|
||||
writable: true,
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
var XPCOMUtils = {
|
||||
/**
|
||||
* Generate a QueryInterface implementation. The returned function must be
|
||||
|
@ -173,21 +190,15 @@ var XPCOMUtils = {
|
|||
*/
|
||||
defineLazyGetter: function XPCU_defineLazyGetter(aObject, aName, aLambda)
|
||||
{
|
||||
let redefining = false;
|
||||
Object.defineProperty(aObject, aName, {
|
||||
get: function () {
|
||||
// Redefine this accessor property as a data property.
|
||||
// Delete it first, to rule out "too much recursion" in case aObject is
|
||||
// a proxy whose defineProperty handler might unwittingly trigger this
|
||||
// getter again.
|
||||
delete aObject[aName];
|
||||
let value = aLambda.apply(aObject);
|
||||
Object.defineProperty(aObject, aName, {
|
||||
value,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
});
|
||||
return value;
|
||||
if (!redefining) {
|
||||
// Make sure we don't get into an infinite recursion loop if
|
||||
// the getter lambda does something shady.
|
||||
redefining = true;
|
||||
return redefine(aObject, aName, aLambda.apply(aObject));
|
||||
}
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
|
@ -217,18 +228,41 @@ var XPCOMUtils = {
|
|||
for (let name of aNames) {
|
||||
Object.defineProperty(aObject, name, {
|
||||
get: function() {
|
||||
for (let n of aNames) {
|
||||
delete aObject[n];
|
||||
}
|
||||
Services.scriptloader.loadSubScript(aResource, aObject);
|
||||
return aObject[name];
|
||||
},
|
||||
set(value) {
|
||||
redefine(aObject, name, value);
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Defines a getter property on the given object for each of the given
|
||||
* global names as accepted by Cu.importGlobalProperties. These
|
||||
* properties are imported into the shared JSM module global, and then
|
||||
* copied onto the given object, no matter which global the object
|
||||
* belongs to.
|
||||
*
|
||||
* @param {object} aObject
|
||||
* The object on which to define the properties.
|
||||
* @param {string[]} aNames
|
||||
* The list of global properties to define.
|
||||
*/
|
||||
defineLazyGlobalGetters(aObject, aNames) {
|
||||
for (let name of aNames) {
|
||||
this.defineLazyGetter(aObject, name, () => {
|
||||
if (!(name in global)) {
|
||||
Cu.importGlobalProperties([name]);
|
||||
}
|
||||
return global[name];
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Defines a getter on a specified object for a service. The service will not
|
||||
* be obtained until first use.
|
||||
|
|
|
@ -1689,19 +1689,7 @@ HasNativeProperty(JSContext* cx, HandleObject wrapper, HandleId id, bool* hasPro
|
|||
}
|
||||
|
||||
// Try the holder.
|
||||
bool found = false;
|
||||
if (!JS_AlreadyHasOwnPropertyById(cx, holder, id, &found))
|
||||
return false;
|
||||
if (found) {
|
||||
*hasProp = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try resolveNativeProperty.
|
||||
if (!traits->resolveNativeProperty(cx, wrapper, holder, id, &desc))
|
||||
return false;
|
||||
*hasProp = !!desc.object();
|
||||
return true;
|
||||
return JS_AlreadyHasOwnPropertyById(cx, holder, id, hasProp);
|
||||
}
|
||||
|
||||
} // namespace XrayUtils
|
||||
|
@ -1758,9 +1746,6 @@ XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext* cx, HandleObject wra
|
|||
// depending on how ephemeral it decides the property is. This means that we have to
|
||||
// first check the result of resolveOwnProperty, and _then_, if that comes up blank,
|
||||
// check the holder for any cached native properties.
|
||||
//
|
||||
// Finally, we call resolveNativeProperty, which checks non-own properties,
|
||||
// and unconditionally caches what it finds on the holder.
|
||||
|
||||
// Check resolveOwnProperty.
|
||||
if (!Traits::singleton.resolveOwnProperty(cx, wrapper, target, holder, id, desc))
|
||||
|
@ -1774,16 +1759,12 @@ XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext* cx, HandleObject wra
|
|||
return true;
|
||||
}
|
||||
|
||||
// Nothing in the cache. Call through, and cache the result.
|
||||
if (!Traits::singleton.resolveNativeProperty(cx, wrapper, holder, id, desc))
|
||||
return false;
|
||||
|
||||
// We need to handle named access on the Window somewhere other than
|
||||
// Traits::resolveOwnProperty, because per spec it happens on the Global
|
||||
// Scope Polluter and thus the resulting properties are non-|own|. However,
|
||||
// we're set up (above) to cache (on the holder) anything that comes out of
|
||||
// resolveNativeProperty, which we don't want for something dynamic like
|
||||
// named access. So we just handle it separately here. Note that this is
|
||||
// we're set up (above) to cache (on the holder),
|
||||
// which we don't want for something dynamic like named access.
|
||||
// So we just handle it separately here. Note that this is
|
||||
// only relevant for CrossOriginXrayWrapper, which calls
|
||||
// getPropertyDescriptor from getOwnPropertyDescriptor.
|
||||
nsGlobalWindowInner* win = nullptr;
|
||||
|
@ -1806,17 +1787,8 @@ XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext* cx, HandleObject wra
|
|||
}
|
||||
}
|
||||
|
||||
// If we still have nothing, we're done.
|
||||
if (!desc.object())
|
||||
return true;
|
||||
|
||||
if (!JS_DefinePropertyById(cx, holder, id, desc) ||
|
||||
!JS_GetOwnPropertyDescriptorById(cx, holder, id, desc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(desc.object());
|
||||
desc.object().set(wrapper);
|
||||
// We found nothing, we're done.
|
||||
MOZ_ASSERT(!desc.object());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,9 +61,6 @@ public:
|
|||
return target;
|
||||
}
|
||||
|
||||
virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
|
||||
JS::HandleObject holder, JS::HandleId id,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc) = 0;
|
||||
// NB: resolveOwnProperty may decide whether or not to cache what it finds
|
||||
// on the holder. If the result is not cached, the lookup will happen afresh
|
||||
// for each access, which is the right thing for things like dynamic NodeList
|
||||
|
@ -145,21 +142,6 @@ public:
|
|||
|
||||
static const XrayType Type = XrayForDOMObject;
|
||||
|
||||
virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
|
||||
JS::HandleObject holder, JS::HandleId id,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc) override
|
||||
{
|
||||
// Xrays for DOM binding objects have a prototype chain that consists of
|
||||
// Xrays for the prototypes of the DOM binding object (ignoring changes
|
||||
// in the prototype chain made by script, plugins or XBL). All properties for
|
||||
// these Xrays are really own properties, either of the instance object or
|
||||
// of the prototypes.
|
||||
// FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=1072482
|
||||
// This should really be:
|
||||
// MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
|
||||
// but we can't do that yet because XrayUtils::HasNativeProperty calls this.
|
||||
return true;
|
||||
}
|
||||
virtual bool resolveOwnProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject target,
|
||||
JS::HandleObject holder, JS::HandleId id,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc) override;
|
||||
|
@ -197,13 +179,6 @@ class JSXrayTraits : public XrayTraits
|
|||
public:
|
||||
static const XrayType Type = XrayForJSObject;
|
||||
|
||||
virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
|
||||
JS::HandleObject holder, JS::HandleId id,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc) override
|
||||
{
|
||||
MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
|
||||
}
|
||||
|
||||
virtual bool resolveOwnProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject target,
|
||||
JS::HandleObject holder, JS::HandleId id,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc) override;
|
||||
|
@ -311,13 +286,6 @@ class OpaqueXrayTraits : public XrayTraits
|
|||
public:
|
||||
static const XrayType Type = XrayForOpaqueObject;
|
||||
|
||||
virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
|
||||
JS::HandleObject holder, JS::HandleId id,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc) override
|
||||
{
|
||||
MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
|
||||
}
|
||||
|
||||
virtual bool resolveOwnProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject target,
|
||||
JS::HandleObject holder, JS::HandleId id,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc) override;
|
||||
|
|
|
@ -86,6 +86,7 @@ nsPresArena::ClearArenaRefPtrs(ArenaObjectID aObjectID)
|
|||
void*
|
||||
nsPresArena::Allocate(uint32_t aCode, size_t aSize)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aSize > 0, "PresArena cannot allocate zero bytes");
|
||||
MOZ_ASSERT(aCode < ArrayLength(mFreeLists));
|
||||
|
||||
|
@ -150,6 +151,7 @@ nsPresArena::Allocate(uint32_t aCode, size_t aSize)
|
|||
void
|
||||
nsPresArena::Free(uint32_t aCode, void* aPtr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aCode < ArrayLength(mFreeLists));
|
||||
|
||||
// Try to recycle this entry.
|
||||
|
|
|
@ -57,7 +57,7 @@ enum {
|
|||
NS_MATHML_OPERATOR_RSPACE_ATTR = 1<<16
|
||||
};
|
||||
|
||||
#define NS_MATHML_OPERATOR_SIZE_INFINITY NS_IEEEPositiveInfinity()
|
||||
#define NS_MATHML_OPERATOR_SIZE_INFINITY (mozilla::PositiveInfinity<float>())
|
||||
|
||||
class nsMathMLOperators {
|
||||
public:
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "nsComputedDOMStyle.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
|
@ -7152,15 +7153,7 @@ nsComputedDOMStyle::DoGetAnimationIterationCount()
|
|||
RefPtr<nsROCSSPrimitiveValue> iterationCount = new nsROCSSPrimitiveValue;
|
||||
|
||||
float f = animation->GetIterationCount();
|
||||
/* Need a nasty hack here to work around an optimizer bug in gcc
|
||||
4.2 on Mac, which somehow gets confused when directly comparing
|
||||
a float to the return value of NS_IEEEPositiveInfinity when
|
||||
building 32-bit builds. */
|
||||
#ifdef XP_MACOSX
|
||||
volatile
|
||||
#endif
|
||||
float inf = NS_IEEEPositiveInfinity();
|
||||
if (f == inf) {
|
||||
if (f == PositiveInfinity<float>()) {
|
||||
iterationCount->SetIdent(eCSSKeyword_infinite);
|
||||
} else {
|
||||
iterationCount->SetNumber(f);
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <limits.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -43,13 +45,19 @@ BitwiseCast(const From aFrom, To* aResult)
|
|||
{
|
||||
static_assert(sizeof(From) == sizeof(To),
|
||||
"To and From must have the same size");
|
||||
union
|
||||
{
|
||||
From mFrom;
|
||||
To mTo;
|
||||
} u;
|
||||
u.mFrom = aFrom;
|
||||
*aResult = u.mTo;
|
||||
|
||||
// We could maybe downgrade these to std::is_trivially_copyable, but the
|
||||
// various STLs we use don't all provide it.
|
||||
static_assert(std::is_trivial<From>::value,
|
||||
"shouldn't bitwise-copy a type having non-trivial "
|
||||
"initialization");
|
||||
static_assert(std::is_trivial<To>::value,
|
||||
"shouldn't bitwise-copy a type having non-trivial "
|
||||
"initialization");
|
||||
|
||||
std::memcpy(static_cast<void*>(aResult),
|
||||
static_cast<const void*>(&aFrom),
|
||||
sizeof(From));
|
||||
}
|
||||
|
||||
template<typename To, typename From>
|
||||
|
|
|
@ -8,14 +8,36 @@
|
|||
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
#include <cfloat> // for FLT_MAX
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
bool
|
||||
IsFloat32Representable(double aFloat32)
|
||||
IsFloat32Representable(double aValue)
|
||||
{
|
||||
float asFloat = static_cast<float>(aFloat32);
|
||||
double floatAsDouble = static_cast<double>(asFloat);
|
||||
return floatAsDouble == aFloat32;
|
||||
// NaNs and infinities are representable.
|
||||
if (!IsFinite(aValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If it exceeds finite |float| range, casting to |double| is always undefined
|
||||
// behavior per C++11 [conv.double]p1 last sentence.
|
||||
if (Abs(aValue) > FLT_MAX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// But if it's within finite range, then either it's 1) an exact value and so
|
||||
// representable, or 2) it's "between two adjacent destination values" and
|
||||
// safe to cast to "an implementation-defined choice of either of those
|
||||
// values".
|
||||
auto valueAsFloat = static_cast<float>(aValue);
|
||||
|
||||
// Per [conv.fpprom] this never changes value.
|
||||
auto valueAsFloatAsDouble = static_cast<double>(valueAsFloat);
|
||||
|
||||
// Finally, in 1) exact representable value equals exact representable value,
|
||||
// or 2) *changed* value does not equal original value, ergo unrepresentable.
|
||||
return valueAsFloatAsDouble == aValue;
|
||||
}
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
|
|
@ -562,16 +562,14 @@ FuzzyEqualsMultiplicative(T aValue1, T aValue2,
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given value can be losslessly represented as an IEEE-754
|
||||
* single format number, false otherwise. All NaN values are considered
|
||||
* representable (notwithstanding that the exact bit pattern of a double format
|
||||
* NaN value can't be exactly represented in single format).
|
||||
*
|
||||
* This function isn't inlined to avoid buggy optimizations by MSVC.
|
||||
* Returns true if |aValue| can be losslessly represented as an IEEE-754 single
|
||||
* precision number, false otherwise. All NaN values are considered
|
||||
* representable (even though the bit patterns of double precision NaNs can't
|
||||
* all be exactly represented in single precision).
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
extern MFBT_API bool
|
||||
IsFloat32Representable(double aFloat32);
|
||||
IsFloat32Representable(double aValue);
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
||||
|
|
|
@ -5,18 +5,21 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* A vector of pointers space-optimized for a small number of elements. */
|
||||
|
||||
#ifndef mozilla_SmallPointerArray_h
|
||||
#define mozilla_SmallPointerArray_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <new>
|
||||
#include <vector>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Array class for situations where a small number of elements (<= 2) is
|
||||
// expected, a large number of elements must be accomodated if necessary,
|
||||
// Array class for situations where a small number of NON-NULL elements (<= 2)
|
||||
// is expected, a large number of elements must be accomodated if necessary,
|
||||
// and the size of the class must be minimal. Typical vector implementations
|
||||
// will fulfill the first two requirements by simply adding inline storage
|
||||
// alongside the rest of their member variables. While this strategy works,
|
||||
|
@ -36,30 +39,28 @@ class SmallPointerArray
|
|||
public:
|
||||
SmallPointerArray()
|
||||
{
|
||||
mInlineElements[0] = mInlineElements[1] = nullptr;
|
||||
static_assert(sizeof(SmallPointerArray<T>) == (2 * sizeof(void*)),
|
||||
"SmallPointerArray must compile to the size of 2 pointers");
|
||||
static_assert(offsetof(SmallPointerArray<T>, mArray) ==
|
||||
offsetof(SmallPointerArray<T>, mInlineElements) + sizeof(T*),
|
||||
"mArray and mInlineElements[1] are expected to overlap in memory");
|
||||
static_assert(offsetof(SmallPointerArray<T>, mPadding) ==
|
||||
offsetof(SmallPointerArray<T>, mInlineElements),
|
||||
"mPadding and mInlineElements[0] are expected to overlap in memory");
|
||||
// List-initialization would be nicer, but it only lets you initialize the
|
||||
// first union member.
|
||||
mArray[0].mValue = nullptr;
|
||||
mArray[1].mVector = nullptr;
|
||||
}
|
||||
|
||||
~SmallPointerArray()
|
||||
{
|
||||
if (!mInlineElements[0] && mArray) {
|
||||
delete mArray;
|
||||
if (!first()) {
|
||||
delete maybeVector();
|
||||
}
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
if (!mInlineElements[0] && mArray) {
|
||||
delete mArray;
|
||||
mArray = nullptr;
|
||||
if (first()) {
|
||||
first() = nullptr;
|
||||
new (&mArray[1].mValue) std::vector<T*>*(nullptr);
|
||||
return;
|
||||
}
|
||||
mInlineElements[0] = mInlineElements[1] = nullptr;
|
||||
|
||||
delete maybeVector();
|
||||
mArray[1].mVector = nullptr;
|
||||
}
|
||||
|
||||
void AppendElement(T* aElement) {
|
||||
|
@ -69,32 +70,30 @@ public:
|
|||
// In addition to this we assert in debug builds to point out mistakes to
|
||||
// users of the class.
|
||||
MOZ_ASSERT(aElement != nullptr);
|
||||
if (!mInlineElements[0]) {
|
||||
if (!mArray) {
|
||||
mInlineElements[0] = aElement;
|
||||
// Harmless if aElement == nullptr;
|
||||
if (aElement == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!first()) {
|
||||
auto* vec = maybeVector();
|
||||
if (!vec) {
|
||||
first() = aElement;
|
||||
new (&mArray[1].mValue) T*(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
mArray->push_back(aElement);
|
||||
vec->push_back(aElement);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aElement) {
|
||||
if (!second()) {
|
||||
second() = aElement;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mInlineElements[1]) {
|
||||
mInlineElements[1] = aElement;
|
||||
return;
|
||||
}
|
||||
|
||||
mArray = new std::vector<T*>({ mInlineElements[0], mInlineElements[1], aElement });
|
||||
mInlineElements[0] = nullptr;
|
||||
auto* vec = new std::vector<T*>({ first(), second(), aElement });
|
||||
first() = nullptr;
|
||||
new (&mArray[1].mVector) std::vector<T*>*(vec);
|
||||
}
|
||||
|
||||
bool RemoveElement(T* aElement) {
|
||||
|
@ -103,25 +102,31 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
if (mInlineElements[0] == aElement) {
|
||||
// Expectected case.
|
||||
mInlineElements[0] = mInlineElements[1];
|
||||
mInlineElements[1] = nullptr;
|
||||
if (first() == aElement) {
|
||||
// Expected case.
|
||||
T* maybeSecond = second();
|
||||
first() = maybeSecond;
|
||||
if (maybeSecond) {
|
||||
second() = nullptr;
|
||||
} else {
|
||||
new (&mArray[1].mVector) std::vector<T*>*(nullptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mInlineElements[0]) {
|
||||
if (mInlineElements[1] == aElement) {
|
||||
mInlineElements[1] = nullptr;
|
||||
if (first()) {
|
||||
if (second() == aElement) {
|
||||
second() = nullptr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mArray) {
|
||||
for (auto iter = mArray->begin(); iter != mArray->end(); iter++) {
|
||||
if (auto* vec = maybeVector()) {
|
||||
for (auto iter = vec->begin(); iter != vec->end(); iter++) {
|
||||
if (*iter == aElement) {
|
||||
mArray->erase(iter);
|
||||
vec->erase(iter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -135,35 +140,25 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
if (mInlineElements[0] == aElement) {
|
||||
return true;
|
||||
if (T* v = first()) {
|
||||
return v == aElement || second() == aElement;
|
||||
}
|
||||
|
||||
if (mInlineElements[0]) {
|
||||
if (mInlineElements[1] == aElement) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (auto* vec = maybeVector()) {
|
||||
return std::find(vec->begin(), vec->end(), aElement) != vec->end();
|
||||
}
|
||||
|
||||
if (mArray) {
|
||||
return std::find(mArray->begin(), mArray->end(), aElement) != mArray->end();
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
size_t Length() const
|
||||
{
|
||||
if (mInlineElements[0]) {
|
||||
if (!mInlineElements[1]) {
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
if (first()) {
|
||||
return second() ? 2 : 1;
|
||||
}
|
||||
|
||||
if (mArray) {
|
||||
return mArray->size();
|
||||
if (auto* vec = maybeVector()) {
|
||||
return vec->size();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -171,11 +166,13 @@ public:
|
|||
|
||||
T* ElementAt(size_t aIndex) const {
|
||||
MOZ_ASSERT(aIndex < Length());
|
||||
if (mInlineElements[0]) {
|
||||
return mInlineElements[aIndex];
|
||||
if (first()) {
|
||||
return mArray[aIndex].mValue;
|
||||
}
|
||||
|
||||
return (*mArray)[aIndex];
|
||||
auto* vec = maybeVector();
|
||||
MOZ_ASSERT(vec, "must have backing vector if accessing an element");
|
||||
return (*vec)[aIndex];
|
||||
}
|
||||
|
||||
T* operator[](size_t aIndex) const
|
||||
|
@ -183,8 +180,8 @@ public:
|
|||
return ElementAt(aIndex);
|
||||
}
|
||||
|
||||
typedef T** iterator;
|
||||
typedef const T** const_iterator;
|
||||
using iterator = T**;
|
||||
using const_iterator = const T**;
|
||||
|
||||
// Methods for range-based for loops. Manipulation invalidates these.
|
||||
iterator begin() {
|
||||
|
@ -204,37 +201,71 @@ public:
|
|||
|
||||
private:
|
||||
T** beginInternal() const {
|
||||
if (mInlineElements[0] || !mArray) {
|
||||
return const_cast<T**>(&mInlineElements[0]);
|
||||
if (first()) {
|
||||
static_assert(sizeof(T*) == sizeof(Element),
|
||||
"pointer ops on &first() must produce adjacent "
|
||||
"Element::mValue arms");
|
||||
return &first();
|
||||
}
|
||||
|
||||
if (mArray->empty()) {
|
||||
auto* vec = maybeVector();
|
||||
if (!vec) {
|
||||
return &first();
|
||||
}
|
||||
|
||||
if (vec->empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &(*mArray)[0];
|
||||
return &(*vec)[0];
|
||||
}
|
||||
|
||||
// mArray and mInlineElements[1] share the same area in memory.
|
||||
// Accessors for |mArray| element union arms.
|
||||
|
||||
T*& first() const {
|
||||
return const_cast<T*&>(mArray[0].mValue);
|
||||
}
|
||||
|
||||
T*& second() const {
|
||||
MOZ_ASSERT(first(), "first() must be non-null to have a T* second pointer");
|
||||
return const_cast<T*&>(mArray[1].mValue);
|
||||
}
|
||||
|
||||
std::vector<T*>* maybeVector() const {
|
||||
MOZ_ASSERT(!first(),
|
||||
"function must only be called when this is either empty or has "
|
||||
"std::vector-backed elements");
|
||||
return mArray[1].mVector;
|
||||
}
|
||||
|
||||
// In C++ active-union-arm terms:
|
||||
//
|
||||
// When !mInlineElements[0] && !mInlineElements[1] the array is empty.
|
||||
// - mArray[0].mValue is always active: a possibly null T*;
|
||||
// - if mArray[0].mValue is null, mArray[1].mVector is active: a possibly
|
||||
// null std::vector<T*>*; if mArray[0].mValue isn't null, mArray[1].mValue
|
||||
// is active: a possibly null T*.
|
||||
//
|
||||
// When mInlineElements[0] && !mInlineElements[1], mInlineElements[0]
|
||||
// contains the first element. The array is of size 1.
|
||||
// SmallPointerArray begins empty, with mArray[1].mVector active and null.
|
||||
// Code that makes mArray[0].mValue non-null, i.e. assignments to first(),
|
||||
// must placement-new mArray[1].mValue with the proper value; code that goes
|
||||
// the opposite direction, making mArray[0].mValue null, must placement-new
|
||||
// mArray[1].mVector with the proper value.
|
||||
//
|
||||
// When mInlineElements[0] && mInlineElements[1], mInlineElements[0]
|
||||
// contains the first element and mInlineElements[1] the second. The
|
||||
// array is of size 2.
|
||||
// When !mArray[0].mValue && !mArray[1].mVector, the array is empty.
|
||||
//
|
||||
// When !mInlineElements[0] && mArray, mArray contains the full contents
|
||||
// of the array and is of arbitrary size.
|
||||
union {
|
||||
T* mInlineElements[2];
|
||||
struct {
|
||||
void* mPadding;
|
||||
std::vector<T*>* mArray;
|
||||
};
|
||||
};
|
||||
// When mArray[0].mValue && !mArray[1].mValue, the array has size 1 and
|
||||
// contains mArray[0].mValue.
|
||||
//
|
||||
// When mArray[0] && mArray[1], the array has size 2 and contains
|
||||
// mArray[0].mValue and mArray[1].mValue.
|
||||
//
|
||||
// When !mArray[0].mValue && mArray[1].mVector, mArray[1].mVector contains
|
||||
// the contents of an array of arbitrary size (even less than two if it ever
|
||||
// contained three elements and elements were removed).
|
||||
union Element {
|
||||
T* mValue;
|
||||
std::vector<T*>* mVector;
|
||||
} mArray[2];
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -37,6 +37,16 @@ public:
|
|||
|
||||
} // namespace detail
|
||||
|
||||
/** Returns true iff |aChar| is ASCII, i.e. in the range [0, 0x80). */
|
||||
template<typename Char>
|
||||
constexpr bool
|
||||
IsAscii(Char aChar)
|
||||
{
|
||||
using UnsignedChar = typename detail::MakeUnsignedChar<Char>::Type;
|
||||
auto uc = static_cast<UnsignedChar>(aChar);
|
||||
return uc < 0x80;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff |aChar| matches [a-z].
|
||||
*
|
||||
|
|
|
@ -314,7 +314,7 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() const { return *get(); }
|
||||
typename AddLvalueReference<T>::Type operator*() const { return *get(); }
|
||||
Pointer operator->() const
|
||||
{
|
||||
MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr");
|
||||
|
|
|
@ -15,6 +15,7 @@ using mozilla::FloatingPoint;
|
|||
using mozilla::FuzzyEqualsAdditive;
|
||||
using mozilla::FuzzyEqualsMultiplicative;
|
||||
using mozilla::IsFinite;
|
||||
using mozilla::IsFloat32Representable;
|
||||
using mozilla::IsInfinite;
|
||||
using mozilla::IsNaN;
|
||||
using mozilla::IsNegative;
|
||||
|
@ -630,6 +631,80 @@ TestAreApproximatelyEqual()
|
|||
TestDoublesAreApproximatelyEqual();
|
||||
}
|
||||
|
||||
static void
|
||||
TestIsFloat32Representable()
|
||||
{
|
||||
// Zeroes are representable.
|
||||
A(IsFloat32Representable(+0.0));
|
||||
A(IsFloat32Representable(-0.0));
|
||||
|
||||
// NaN and infinities are representable.
|
||||
A(IsFloat32Representable(UnspecifiedNaN<double>()));
|
||||
A(IsFloat32Representable(SpecificNaN<double>(0, 1)));
|
||||
A(IsFloat32Representable(SpecificNaN<double>(0, 71389)));
|
||||
A(IsFloat32Representable(SpecificNaN<double>(0, (uint64_t(1) << 52) - 2)));
|
||||
A(IsFloat32Representable(SpecificNaN<double>(1, 1)));
|
||||
A(IsFloat32Representable(SpecificNaN<double>(1, 71389)));
|
||||
A(IsFloat32Representable(SpecificNaN<double>(1, (uint64_t(1) << 52) - 2)));
|
||||
A(IsFloat32Representable(PositiveInfinity<double>()));
|
||||
A(IsFloat32Representable(NegativeInfinity<double>()));
|
||||
|
||||
// MSVC seems to compile 2**-1075, which should be half of the smallest
|
||||
// IEEE-754 double precision value, to equal 2**-1074 right now. This might
|
||||
// be the result of a missing compiler flag to force more-accurate floating
|
||||
// point calculations; bug 1440184 has been filed as a followup to fix this,
|
||||
// so that only the first half of this condition is necessary.
|
||||
A(pow(2.0, -1075.0) == 0.0 ||
|
||||
(MOZ_IS_MSVC && pow(2.0, -1075.0) == pow(2.0, -1074.0)));
|
||||
|
||||
A(powf(2.0f, -150.0f) == 0.0);
|
||||
A(powf(2.0f, -149.0f) != 0.0);
|
||||
|
||||
for (double littleExp = -1074.0; littleExp < -149.0; littleExp++) {
|
||||
// Powers of two below the available range aren't representable.
|
||||
A(!IsFloat32Representable(pow(2.0, littleExp)));
|
||||
}
|
||||
|
||||
// Exact powers of two within the available range are representable.
|
||||
for (double exponent = -149.0; exponent < 128.0; exponent++) {
|
||||
A(IsFloat32Representable(pow(2.0, exponent)));
|
||||
}
|
||||
|
||||
// Powers of two above the available range aren't representable.
|
||||
for (double bigExp = 128.0; bigExp < 1024.0; bigExp++) {
|
||||
A(!IsFloat32Representable(pow(2.0, bigExp)));
|
||||
}
|
||||
|
||||
// Various denormal (i.e. super-small) doubles with MSB and LSB as far apart
|
||||
// as possible are representable (but taken one bit further apart are not
|
||||
// representable).
|
||||
//
|
||||
// Note that the final iteration tests non-denormal with exponent field
|
||||
// containing (biased) 1, as |oneTooSmall| and |widestPossible| happen still
|
||||
// to be correct for that exponent due to the extra bit of precision in the
|
||||
// implicit-one bit.
|
||||
double oneTooSmall = pow(2.0, -150.0);
|
||||
for (double denormExp = -149.0;
|
||||
denormExp < 1 - double(FloatingPoint<double>::kExponentBias) + 1;
|
||||
denormExp++)
|
||||
{
|
||||
double baseDenorm = pow(2.0, denormExp);
|
||||
double tooWide = baseDenorm + oneTooSmall;
|
||||
A(!IsFloat32Representable(tooWide));
|
||||
|
||||
double widestPossible = baseDenorm;
|
||||
if (oneTooSmall * 2.0 != baseDenorm) {
|
||||
widestPossible += oneTooSmall * 2.0;
|
||||
}
|
||||
|
||||
A(IsFloat32Representable(widestPossible));
|
||||
}
|
||||
|
||||
// Finally, check certain interesting/special values for basic sanity.
|
||||
A(!IsFloat32Representable(2147483647.0));
|
||||
A(!IsFloat32Representable(-2147483647.0));
|
||||
}
|
||||
|
||||
#undef A
|
||||
|
||||
int
|
||||
|
@ -639,5 +714,6 @@ main()
|
|||
TestExponentComponent();
|
||||
TestPredicates();
|
||||
TestAreApproximatelyEqual();
|
||||
TestIsFloat32Representable();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,12 +8,101 @@
|
|||
#include "mozilla/TextUtils.h"
|
||||
|
||||
using mozilla::AsciiAlphanumericToNumber;
|
||||
using mozilla::IsAscii;
|
||||
using mozilla::IsAsciiAlpha;
|
||||
using mozilla::IsAsciiAlphanumeric;
|
||||
using mozilla::IsAsciiDigit;
|
||||
using mozilla::IsAsciiLowercaseAlpha;
|
||||
using mozilla::IsAsciiUppercaseAlpha;
|
||||
|
||||
static void
|
||||
TestIsAscii()
|
||||
{
|
||||
// char
|
||||
|
||||
static_assert(!IsAscii(char(-1)), "char(-1) isn't ASCII");
|
||||
|
||||
static_assert(IsAscii('\0'), "nul is ASCII");
|
||||
|
||||
static_assert(IsAscii('A'), "'A' is ASCII");
|
||||
static_assert(IsAscii('B'), "'B' is ASCII");
|
||||
static_assert(IsAscii('M'), "'M' is ASCII");
|
||||
static_assert(IsAscii('Y'), "'Y' is ASCII");
|
||||
static_assert(IsAscii('Z'), "'Z' is ASCII");
|
||||
|
||||
static_assert(IsAscii('['), "'[' is ASCII");
|
||||
static_assert(IsAscii('`'), "'`' is ASCII");
|
||||
|
||||
static_assert(IsAscii('a'), "'a' is ASCII");
|
||||
static_assert(IsAscii('b'), "'b' is ASCII");
|
||||
static_assert(IsAscii('m'), "'m' is ASCII");
|
||||
static_assert(IsAscii('y'), "'y' is ASCII");
|
||||
static_assert(IsAscii('z'), "'z' is ASCII");
|
||||
|
||||
static_assert(IsAscii('{'), "'{' is ASCII");
|
||||
|
||||
static_assert(IsAscii('5'), "'5' is ASCII");
|
||||
|
||||
static_assert(IsAscii('\x7F'), "'\\x7F' is ASCII");
|
||||
static_assert(!IsAscii('\x80'), "'\\x80' isn't ASCII");
|
||||
|
||||
// char16_t
|
||||
|
||||
static_assert(!IsAscii(char16_t(-1)), "char16_t(-1) isn't ASCII");
|
||||
|
||||
static_assert(IsAscii(u'\0'), "nul is ASCII");
|
||||
|
||||
static_assert(IsAscii(u'A'), "u'A' is ASCII");
|
||||
static_assert(IsAscii(u'B'), "u'B' is ASCII");
|
||||
static_assert(IsAscii(u'M'), "u'M' is ASCII");
|
||||
static_assert(IsAscii(u'Y'), "u'Y' is ASCII");
|
||||
static_assert(IsAscii(u'Z'), "u'Z' is ASCII");
|
||||
|
||||
static_assert(IsAscii(u'['), "u'[' is ASCII");
|
||||
static_assert(IsAscii(u'`'), "u'`' is ASCII");
|
||||
|
||||
static_assert(IsAscii(u'a'), "u'a' is ASCII");
|
||||
static_assert(IsAscii(u'b'), "u'b' is ASCII");
|
||||
static_assert(IsAscii(u'm'), "u'm' is ASCII");
|
||||
static_assert(IsAscii(u'y'), "u'y' is ASCII");
|
||||
static_assert(IsAscii(u'z'), "u'z' is ASCII");
|
||||
|
||||
static_assert(IsAscii(u'{'), "u'{' is ASCII");
|
||||
|
||||
static_assert(IsAscii(u'5'), "u'5' is ASCII");
|
||||
|
||||
static_assert(IsAscii(u'\x7F'), "u'\\x7F' is ASCII");
|
||||
static_assert(!IsAscii(u'\x80'), "u'\\x80' isn't ASCII");
|
||||
|
||||
// char32_t
|
||||
|
||||
static_assert(!IsAscii(char32_t(-1)), "char32_t(-1) isn't ASCII");
|
||||
|
||||
static_assert(IsAscii(U'\0'), "nul is ASCII");
|
||||
|
||||
static_assert(IsAscii(U'A'), "U'A' is ASCII");
|
||||
static_assert(IsAscii(U'B'), "U'B' is ASCII");
|
||||
static_assert(IsAscii(U'M'), "U'M' is ASCII");
|
||||
static_assert(IsAscii(U'Y'), "U'Y' is ASCII");
|
||||
static_assert(IsAscii(U'Z'), "U'Z' is ASCII");
|
||||
|
||||
static_assert(IsAscii(U'['), "U'[' is ASCII");
|
||||
static_assert(IsAscii(U'`'), "U'`' is ASCII");
|
||||
|
||||
static_assert(IsAscii(U'a'), "U'a' is ASCII");
|
||||
static_assert(IsAscii(U'b'), "U'b' is ASCII");
|
||||
static_assert(IsAscii(U'm'), "U'm' is ASCII");
|
||||
static_assert(IsAscii(U'y'), "U'y' is ASCII");
|
||||
static_assert(IsAscii(U'z'), "U'z' is ASCII");
|
||||
|
||||
static_assert(IsAscii(U'{'), "U'{' is ASCII");
|
||||
|
||||
static_assert(IsAscii(U'5'), "U'5' is ASCII");
|
||||
|
||||
static_assert(IsAscii(U'\x7F'), "U'\\x7F' is ASCII");
|
||||
static_assert(!IsAscii(U'\x80'), "U'\\x80' isn't ASCII");
|
||||
}
|
||||
|
||||
static void
|
||||
TestIsAsciiAlpha()
|
||||
{
|
||||
|
@ -709,6 +798,7 @@ TestIsAsciiDigit()
|
|||
int
|
||||
main()
|
||||
{
|
||||
TestIsAscii();
|
||||
TestIsAsciiAlpha();
|
||||
TestIsAsciiUppercaseAlpha();
|
||||
TestIsAsciiLowercaseAlpha();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "mozilla/Move.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
@ -18,6 +19,7 @@ using mozilla::IsSame;
|
|||
using mozilla::MakeUnique;
|
||||
using mozilla::Swap;
|
||||
using mozilla::UniquePtr;
|
||||
using mozilla::UniqueFreePtr;
|
||||
using mozilla::Vector;
|
||||
|
||||
#define CHECK(c) \
|
||||
|
@ -562,6 +564,36 @@ TestMakeUnique()
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TestVoid()
|
||||
{
|
||||
// UniquePtr<void> supports all operations except operator*() and
|
||||
// operator->().
|
||||
UniqueFreePtr<void> p1(malloc(1));
|
||||
UniqueFreePtr<void> p2;
|
||||
|
||||
auto x = p1.get();
|
||||
CHECK(x != nullptr);
|
||||
CHECK((IsSame<decltype(x), void*>::value));
|
||||
|
||||
p2.reset(p1.release());
|
||||
CHECK(p1.get() == nullptr);
|
||||
CHECK(p2.get() != nullptr);
|
||||
|
||||
p1 = std::move(p2);
|
||||
CHECK(p1);
|
||||
CHECK(!p2);
|
||||
|
||||
p1.swap(p2);
|
||||
CHECK(!p1);
|
||||
CHECK(p2);
|
||||
|
||||
p2 = nullptr;
|
||||
CHECK(!p2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
@ -588,5 +620,8 @@ main()
|
|||
if (!TestMakeUnique()) {
|
||||
return 1;
|
||||
}
|
||||
if (!TestVoid()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Messaging.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["File"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["File"]);
|
||||
|
||||
function FilePicker() {
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["XMLHttpRequest"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// // Constants
|
||||
|
|
|
@ -6,7 +6,7 @@ ChromeUtils.import("resource://gre/modules/Accounts.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["XMLHttpRequest"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Home", "resource://gre/modules/Home.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
|
|
|
@ -543,10 +543,9 @@ class AndroidEmulatorCommands(MachCommandBase):
|
|||
conditions=[],
|
||||
description='Run the Android emulator with an AVD from test automation.')
|
||||
@CommandArgument('--version', metavar='VERSION',
|
||||
choices=['4.3', '6.0', '7.0', 'x86', 'x86-6.0', 'x86-7.0'],
|
||||
choices=['4.3', '7.0', 'x86', 'x86-7.0'],
|
||||
help='Specify Android version to run in emulator. '
|
||||
'One of "4.3", "6.0", "7.0", "x86", "x86-6.0", or "x86-7.0".',
|
||||
default='4.3')
|
||||
'One of "4.3", "7.0", "x86", or "x86-7.0".')
|
||||
@CommandArgument('--wait', action='store_true',
|
||||
help='Wait for emulator to be closed.')
|
||||
@CommandArgument('--force-update', action='store_true',
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["XMLHttpRequest"]);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
|
||||
|
||||
var EXPORTED_SYMBOLS = ["SSLExceptions"];
|
||||
|
||||
|
|
|
@ -38,246 +38,10 @@
|
|||
|
||||
using namespace mozilla;
|
||||
|
||||
#define ALL_VERSIONS ((unsigned long long)-1LL)
|
||||
|
||||
// DLLs sometimes ship without a version number, particularly early
|
||||
// releases. Blocking "version <= 0" has the effect of blocking unversioned
|
||||
// DLLs (since the call to get version info fails), but not blocking
|
||||
// any versioned instance.
|
||||
#define UNVERSIONED ((unsigned long long)0LL)
|
||||
|
||||
// Convert the 4 (decimal) components of a DLL version number into a
|
||||
// single unsigned long long, as needed by the blocklist
|
||||
#define MAKE_VERSION(a,b,c,d)\
|
||||
((a##ULL << 48) + (b##ULL << 32) + (c##ULL << 16) + d##ULL)
|
||||
|
||||
struct DllBlockInfo {
|
||||
// The name of the DLL -- in LOWERCASE! It will be compared to
|
||||
// a lowercase version of the DLL name only.
|
||||
const char *name;
|
||||
|
||||
// If maxVersion is ALL_VERSIONS, we'll block all versions of this
|
||||
// dll. Otherwise, we'll block all versions less than or equal to
|
||||
// the given version, as queried by GetFileVersionInfo and
|
||||
// VS_FIXEDFILEINFO's dwFileVersionMS and dwFileVersionLS fields.
|
||||
//
|
||||
// Note that the version is usually 4 components, which is A.B.C.D
|
||||
// encoded as 0x AAAA BBBB CCCC DDDD ULL (spaces added for clarity),
|
||||
// but it's not required to be of that format.
|
||||
//
|
||||
// If the USE_TIMESTAMP flag is set, then we use the timestamp from
|
||||
// the IMAGE_FILE_HEADER in lieu of a version number.
|
||||
//
|
||||
// If the CHILD_PROCESSES_ONLY flag is set, then the dll is blocked
|
||||
// only when we are a child process.
|
||||
unsigned long long maxVersion;
|
||||
|
||||
enum {
|
||||
FLAGS_DEFAULT = 0,
|
||||
BLOCK_WIN8PLUS_ONLY = 1,
|
||||
BLOCK_WIN8_ONLY = 2,
|
||||
USE_TIMESTAMP = 4,
|
||||
CHILD_PROCESSES_ONLY = 8
|
||||
} flags;
|
||||
};
|
||||
|
||||
static const DllBlockInfo sWindowsDllBlocklist[] = {
|
||||
// EXAMPLE:
|
||||
// { "uxtheme.dll", ALL_VERSIONS },
|
||||
// { "uxtheme.dll", 0x0000123400000000ULL },
|
||||
// The DLL name must be in lowercase!
|
||||
// The version field is a maximum, that is, we block anything that is
|
||||
// less-than or equal to that version.
|
||||
|
||||
// NPFFAddon - Known malware
|
||||
{ "npffaddon.dll", ALL_VERSIONS},
|
||||
|
||||
// AVG 8 - Antivirus vendor AVG, old version, plugin already blocklisted
|
||||
{"avgrsstx.dll", MAKE_VERSION(8,5,0,401)},
|
||||
|
||||
// calc.dll - Suspected malware
|
||||
{"calc.dll", MAKE_VERSION(1,0,0,1)},
|
||||
|
||||
// hook.dll - Suspected malware
|
||||
{"hook.dll", ALL_VERSIONS},
|
||||
|
||||
// GoogleDesktopNetwork3.dll - Extremely old, unversioned instances
|
||||
// of this DLL cause crashes
|
||||
{"googledesktopnetwork3.dll", UNVERSIONED},
|
||||
|
||||
// rdolib.dll - Suspected malware
|
||||
{"rdolib.dll", MAKE_VERSION(6,0,88,4)},
|
||||
|
||||
// fgjk4wvb.dll - Suspected malware
|
||||
{"fgjk4wvb.dll", MAKE_VERSION(8,8,8,8)},
|
||||
|
||||
// radhslib.dll - Naomi internet filter - unmaintained since 2006
|
||||
{"radhslib.dll", UNVERSIONED},
|
||||
|
||||
// Music download filter for vkontakte.ru - old instances
|
||||
// of this DLL cause crashes
|
||||
{"vksaver.dll", MAKE_VERSION(2,2,2,0)},
|
||||
|
||||
// Topcrash in Firefox 4.0b1
|
||||
{"rlxf.dll", MAKE_VERSION(1,2,323,1)},
|
||||
|
||||
// psicon.dll - Topcrashes in Thunderbird, and some crashes in Firefox
|
||||
// Adobe photoshop library, now redundant in later installations
|
||||
{"psicon.dll", ALL_VERSIONS},
|
||||
|
||||
// Topcrash in Firefox 4 betas (bug 618899)
|
||||
{"accelerator.dll", MAKE_VERSION(3,2,1,6)},
|
||||
|
||||
// Topcrash with Roboform in Firefox 8 (bug 699134)
|
||||
{"rf-firefox.dll", MAKE_VERSION(7,6,1,0)},
|
||||
{"roboform.dll", MAKE_VERSION(7,6,1,0)},
|
||||
|
||||
// Topcrash with Babylon Toolbar on FF16+ (bug 721264)
|
||||
{"babyfox.dll", ALL_VERSIONS},
|
||||
|
||||
// sprotector.dll crashes, bug 957258
|
||||
{"sprotector.dll", ALL_VERSIONS},
|
||||
|
||||
// leave these two in always for tests
|
||||
{ "mozdllblockingtest.dll", ALL_VERSIONS },
|
||||
{ "mozdllblockingtest_versioned.dll", 0x0000000400000000ULL },
|
||||
|
||||
// Windows Media Foundation FLAC decoder and type sniffer (bug 839031).
|
||||
{ "mfflac.dll", ALL_VERSIONS },
|
||||
|
||||
// Older Relevant Knowledge DLLs cause us to crash (bug 904001).
|
||||
{ "rlnx.dll", MAKE_VERSION(1, 3, 334, 9) },
|
||||
{ "pmnx.dll", MAKE_VERSION(1, 3, 334, 9) },
|
||||
{ "opnx.dll", MAKE_VERSION(1, 3, 334, 9) },
|
||||
{ "prnx.dll", MAKE_VERSION(1, 3, 334, 9) },
|
||||
|
||||
// Older belgian ID card software causes Firefox to crash or hang on
|
||||
// shutdown, bug 831285 and 918399.
|
||||
{ "beid35cardlayer.dll", MAKE_VERSION(3, 5, 6, 6968) },
|
||||
|
||||
// bug 925459, bitguard crashes
|
||||
{ "bitguard.dll", ALL_VERSIONS },
|
||||
|
||||
// bug 812683 - crashes in Windows library when Asus Gamer OSD is installed
|
||||
// Software is discontinued/unsupported
|
||||
{ "atkdx11disp.dll", ALL_VERSIONS },
|
||||
|
||||
// Topcrash with Conduit SearchProtect, bug 944542
|
||||
{ "spvc32.dll", ALL_VERSIONS },
|
||||
|
||||
// Topcrash with V-bates, bug 1002748 and bug 1023239
|
||||
{ "libinject.dll", UNVERSIONED },
|
||||
{ "libinject2.dll", 0x537DDC93, DllBlockInfo::USE_TIMESTAMP },
|
||||
{ "libredir2.dll", 0x5385B7ED, DllBlockInfo::USE_TIMESTAMP },
|
||||
|
||||
// Crashes with RoboForm2Go written against old SDK, bug 988311/1196859
|
||||
{ "rf-firefox-22.dll", ALL_VERSIONS },
|
||||
{ "rf-firefox-40.dll", ALL_VERSIONS },
|
||||
|
||||
// Crashes with DesktopTemperature, bug 1046382
|
||||
{ "dtwxsvc.dll", 0x53153234, DllBlockInfo::USE_TIMESTAMP },
|
||||
|
||||
// Startup crashes with Lenovo Onekey Theater, bug 1123778
|
||||
{ "activedetect32.dll", UNVERSIONED },
|
||||
{ "activedetect64.dll", UNVERSIONED },
|
||||
{ "windowsapihookdll32.dll", UNVERSIONED },
|
||||
{ "windowsapihookdll64.dll", UNVERSIONED },
|
||||
|
||||
// Flash crashes with RealNetworks RealDownloader, bug 1132663
|
||||
{ "rndlnpshimswf.dll", ALL_VERSIONS },
|
||||
{ "rndlmainbrowserrecordplugin.dll", ALL_VERSIONS },
|
||||
|
||||
// Startup crashes with RealNetworks Browser Record Plugin, bug 1170141
|
||||
{ "nprpffbrowserrecordext.dll", ALL_VERSIONS },
|
||||
{ "nprndlffbrowserrecordext.dll", ALL_VERSIONS },
|
||||
|
||||
// Crashes with CyberLink YouCam, bug 1136968
|
||||
{ "ycwebcamerasource.ax", MAKE_VERSION(2, 0, 0, 1611) },
|
||||
|
||||
// Old version of WebcamMax crashes WebRTC, bug 1130061
|
||||
{ "vwcsource.ax", MAKE_VERSION(1, 5, 0, 0) },
|
||||
|
||||
// NetOp School, discontinued product, bug 763395
|
||||
{ "nlsp.dll", MAKE_VERSION(6, 23, 2012, 19) },
|
||||
|
||||
// Orbit Downloader, bug 1222819
|
||||
{ "grabdll.dll", MAKE_VERSION(2, 6, 1, 0) },
|
||||
{ "grabkernel.dll", MAKE_VERSION(1, 0, 0, 1) },
|
||||
|
||||
// ESET, bug 1229252
|
||||
{ "eoppmonitor.dll", ALL_VERSIONS },
|
||||
|
||||
// SS2OSD, bug 1262348
|
||||
{ "ss2osd.dll", ALL_VERSIONS },
|
||||
{ "ss2devprops.dll", ALL_VERSIONS },
|
||||
|
||||
// NHASUSSTRIXOSD.DLL, bug 1269244
|
||||
{ "nhasusstrixosd.dll", ALL_VERSIONS },
|
||||
{ "nhasusstrixdevprops.dll", ALL_VERSIONS },
|
||||
|
||||
// Crashes with PremierOpinion/RelevantKnowledge, bug 1277846
|
||||
{ "opls.dll", ALL_VERSIONS },
|
||||
{ "opls64.dll", ALL_VERSIONS },
|
||||
{ "pmls.dll", ALL_VERSIONS },
|
||||
{ "pmls64.dll", ALL_VERSIONS },
|
||||
{ "prls.dll", ALL_VERSIONS },
|
||||
{ "prls64.dll", ALL_VERSIONS },
|
||||
{ "rlls.dll", ALL_VERSIONS },
|
||||
{ "rlls64.dll", ALL_VERSIONS },
|
||||
|
||||
// Vorbis DirectShow filters, bug 1239690.
|
||||
{ "vorbis.acm", MAKE_VERSION(0, 0, 3, 6) },
|
||||
|
||||
// AhnLab Internet Security, bug 1311969
|
||||
{ "nzbrcom.dll", ALL_VERSIONS },
|
||||
|
||||
// K7TotalSecurity, bug 1339083.
|
||||
{ "k7pswsen.dll", MAKE_VERSION(15, 2, 2, 95) },
|
||||
|
||||
// smci*.dll - goobzo crashware (bug 1339908)
|
||||
{ "smci32.dll", ALL_VERSIONS },
|
||||
{ "smci64.dll", ALL_VERSIONS },
|
||||
|
||||
// Crashes with Internet Download Manager, bug 1333486
|
||||
{ "idmcchandler7.dll", ALL_VERSIONS },
|
||||
{ "idmcchandler7_64.dll", ALL_VERSIONS },
|
||||
{ "idmcchandler5.dll", ALL_VERSIONS },
|
||||
{ "idmcchandler5_64.dll", ALL_VERSIONS },
|
||||
|
||||
// Nahimic 2 breaks applicaton update (bug 1356637)
|
||||
{ "nahimic2devprops.dll", MAKE_VERSION(2, 5, 19, 0xffff) },
|
||||
// Nahimic is causing crashes, bug 1233556
|
||||
{ "nahimicmsiosd.dll", UNVERSIONED },
|
||||
// Nahimic is causing crashes, bug 1360029
|
||||
{ "nahimicvrdevprops.dll", UNVERSIONED },
|
||||
{ "nahimic2osd.dll", MAKE_VERSION(2, 5, 19, 0xffff) },
|
||||
{ "nahimicmsidevprops.dll", UNVERSIONED },
|
||||
|
||||
// Bug 1268470 - crashes with Kaspersky Lab on Windows 8
|
||||
{ "klsihk64.dll", MAKE_VERSION(14, 0, 456, 0xffff), DllBlockInfo::BLOCK_WIN8_ONLY },
|
||||
|
||||
// Bug 1407337, crashes with OpenSC < 0.16.0
|
||||
{ "onepin-opensc-pkcs11.dll", MAKE_VERSION(0, 15, 0xffff, 0xffff) },
|
||||
|
||||
// Avecto Privilege Guard causes crashes, bug 1385542
|
||||
{ "pghook.dll", ALL_VERSIONS },
|
||||
|
||||
// Old versions of G DATA BankGuard, bug 1421991
|
||||
{ "banksafe64.dll", MAKE_VERSION(1, 2, 15299, 65535) },
|
||||
|
||||
// Old versions of G DATA, bug 1043775
|
||||
{ "gdkbfltdll64.dll", MAKE_VERSION(1, 0, 14141, 240) },
|
||||
|
||||
// Dell Backup and Recovery tool causes crashes, bug 1433408
|
||||
{ "dbroverlayiconnotbackuped.dll", MAKE_VERSION(1, 8, 0, 9) },
|
||||
{ "dbroverlayiconbackuped.dll", MAKE_VERSION(1, 8, 0, 9) },
|
||||
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
#ifndef STATUS_DLL_NOT_FOUND
|
||||
#define STATUS_DLL_NOT_FOUND ((DWORD)0xC0000135L)
|
||||
#endif
|
||||
#define DLL_BLOCKLIST_ENTRY(name, ...) \
|
||||
{ name, __VA_ARGS__ },
|
||||
#define DLL_BLOCKLIST_CHAR_TYPE char
|
||||
#include "mozilla/WindowsDllBlocklistDefs.h"
|
||||
|
||||
// define this for very verbose dll load debug spew
|
||||
#undef DEBUG_very_verbose
|
||||
|
@ -504,7 +268,7 @@ private:
|
|||
{
|
||||
}
|
||||
|
||||
const char* mName; // points into the sWindowsDllBlocklist string
|
||||
const char* mName; // points into the gWindowsDllBlocklist string
|
||||
unsigned long long mVersion;
|
||||
DllBlockSet* mNext;
|
||||
|
||||
|
@ -623,8 +387,6 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam
|
|||
wchar_t *fname = moduleFileName->Buffer;
|
||||
UniquePtr<wchar_t[]> full_fname;
|
||||
|
||||
const DllBlockInfo* info = &sWindowsDllBlocklist[0];
|
||||
|
||||
// The filename isn't guaranteed to be null terminated, but in practice
|
||||
// it always will be; ensure that this is so, and bail if not.
|
||||
// This is done instead of the more robust approach because of bug 527122,
|
||||
|
@ -683,114 +445,117 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam
|
|||
printf_stderr("LdrLoadDll: dll name '%s'\n", dllName);
|
||||
#endif
|
||||
|
||||
// Block a suspicious binary that uses various 12-digit hex strings
|
||||
// e.g. MovieMode.48CA2AEFA22D.dll (bug 973138)
|
||||
dot = strchr(dllName, '.');
|
||||
if (dot && (strchr(dot+1, '.') == dot+13)) {
|
||||
char * end = nullptr;
|
||||
_strtoui64(dot+1, &end, 16);
|
||||
if (end == dot+13) {
|
||||
return STATUS_DLL_NOT_FOUND;
|
||||
if (!(sInitFlags & eDllBlocklistInitFlagWasBootstrapped)) {
|
||||
// Block a suspicious binary that uses various 12-digit hex strings
|
||||
// e.g. MovieMode.48CA2AEFA22D.dll (bug 973138)
|
||||
dot = strchr(dllName, '.');
|
||||
if (dot && (strchr(dot+1, '.') == dot+13)) {
|
||||
char * end = nullptr;
|
||||
_strtoui64(dot+1, &end, 16);
|
||||
if (end == dot+13) {
|
||||
return STATUS_DLL_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Block binaries where the filename is at least 16 hex digits
|
||||
if (dot && ((dot - dllName) >= 16)) {
|
||||
char * current = dllName;
|
||||
while (current < dot && isxdigit(*current)) {
|
||||
current++;
|
||||
// Block binaries where the filename is at least 16 hex digits
|
||||
if (dot && ((dot - dllName) >= 16)) {
|
||||
char * current = dllName;
|
||||
while (current < dot && isxdigit(*current)) {
|
||||
current++;
|
||||
}
|
||||
if (current == dot) {
|
||||
return STATUS_DLL_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
if (current == dot) {
|
||||
return STATUS_DLL_NOT_FOUND;
|
||||
|
||||
// then compare to everything on the blocklist
|
||||
DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(info);
|
||||
while (info->name) {
|
||||
if (strcmp(info->name, dllName) == 0)
|
||||
break;
|
||||
|
||||
info++;
|
||||
}
|
||||
}
|
||||
|
||||
// then compare to everything on the blocklist
|
||||
while (info->name) {
|
||||
if (strcmp(info->name, dllName) == 0)
|
||||
break;
|
||||
|
||||
info++;
|
||||
}
|
||||
|
||||
if (info->name) {
|
||||
bool load_ok = false;
|
||||
if (info->name) {
|
||||
bool load_ok = false;
|
||||
|
||||
#ifdef DEBUG_very_verbose
|
||||
printf_stderr("LdrLoadDll: info->name: '%s'\n", info->name);
|
||||
printf_stderr("LdrLoadDll: info->name: '%s'\n", info->name);
|
||||
#endif
|
||||
|
||||
if ((info->flags & DllBlockInfo::BLOCK_WIN8PLUS_ONLY) &&
|
||||
!IsWin8OrLater()) {
|
||||
goto continue_loading;
|
||||
}
|
||||
|
||||
if ((info->flags & DllBlockInfo::BLOCK_WIN8_ONLY) &&
|
||||
(!IsWin8OrLater() || IsWin8Point1OrLater())) {
|
||||
goto continue_loading;
|
||||
}
|
||||
|
||||
if ((info->flags & DllBlockInfo::CHILD_PROCESSES_ONLY) &&
|
||||
!(sInitFlags & eDllBlocklistInitFlagIsChildProcess)) {
|
||||
goto continue_loading;
|
||||
}
|
||||
|
||||
unsigned long long fVersion = ALL_VERSIONS;
|
||||
|
||||
if (info->maxVersion != ALL_VERSIONS) {
|
||||
ReentrancySentinel sentinel(dllName);
|
||||
if (sentinel.BailOut()) {
|
||||
if ((info->flags & DllBlockInfo::BLOCK_WIN8PLUS_ONLY) &&
|
||||
!IsWin8OrLater()) {
|
||||
goto continue_loading;
|
||||
}
|
||||
|
||||
full_fname = getFullPath(filePath, fname);
|
||||
if (!full_fname) {
|
||||
// uh, we couldn't find the DLL at all, so...
|
||||
printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
|
||||
return STATUS_DLL_NOT_FOUND;
|
||||
if ((info->flags & DllBlockInfo::BLOCK_WIN8_ONLY) &&
|
||||
(!IsWin8OrLater() || IsWin8Point1OrLater())) {
|
||||
goto continue_loading;
|
||||
}
|
||||
|
||||
if (info->flags & DllBlockInfo::USE_TIMESTAMP) {
|
||||
fVersion = GetTimestamp(full_fname.get());
|
||||
if (fVersion > info->maxVersion) {
|
||||
load_ok = true;
|
||||
if ((info->flags & DllBlockInfo::CHILD_PROCESSES_ONLY) &&
|
||||
!(sInitFlags & eDllBlocklistInitFlagIsChildProcess)) {
|
||||
goto continue_loading;
|
||||
}
|
||||
|
||||
unsigned long long fVersion = ALL_VERSIONS;
|
||||
|
||||
if (info->maxVersion != ALL_VERSIONS) {
|
||||
ReentrancySentinel sentinel(dllName);
|
||||
if (sentinel.BailOut()) {
|
||||
goto continue_loading;
|
||||
}
|
||||
} else {
|
||||
DWORD zero;
|
||||
DWORD infoSize = GetFileVersionInfoSizeW(full_fname.get(), &zero);
|
||||
|
||||
// If we failed to get the version information, we block.
|
||||
full_fname = getFullPath(filePath, fname);
|
||||
if (!full_fname) {
|
||||
// uh, we couldn't find the DLL at all, so...
|
||||
printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
|
||||
return STATUS_DLL_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (infoSize != 0) {
|
||||
auto infoData = MakeUnique<unsigned char[]>(infoSize);
|
||||
VS_FIXEDFILEINFO *vInfo;
|
||||
UINT vInfoLen;
|
||||
if (info->flags & DllBlockInfo::USE_TIMESTAMP) {
|
||||
fVersion = GetTimestamp(full_fname.get());
|
||||
if (fVersion > info->maxVersion) {
|
||||
load_ok = true;
|
||||
}
|
||||
} else {
|
||||
DWORD zero;
|
||||
DWORD infoSize = GetFileVersionInfoSizeW(full_fname.get(), &zero);
|
||||
|
||||
if (GetFileVersionInfoW(full_fname.get(), 0, infoSize, infoData.get()) &&
|
||||
VerQueryValueW(infoData.get(), L"\\", (LPVOID*) &vInfo, &vInfoLen))
|
||||
{
|
||||
fVersion =
|
||||
((unsigned long long)vInfo->dwFileVersionMS) << 32 |
|
||||
((unsigned long long)vInfo->dwFileVersionLS);
|
||||
// If we failed to get the version information, we block.
|
||||
|
||||
// finally do the version check, and if it's greater than our block
|
||||
// version, keep loading
|
||||
if (fVersion > info->maxVersion)
|
||||
load_ok = true;
|
||||
if (infoSize != 0) {
|
||||
auto infoData = MakeUnique<unsigned char[]>(infoSize);
|
||||
VS_FIXEDFILEINFO *vInfo;
|
||||
UINT vInfoLen;
|
||||
|
||||
if (GetFileVersionInfoW(full_fname.get(), 0, infoSize, infoData.get()) &&
|
||||
VerQueryValueW(infoData.get(), L"\\", (LPVOID*) &vInfo, &vInfoLen))
|
||||
{
|
||||
fVersion =
|
||||
((unsigned long long)vInfo->dwFileVersionMS) << 32 |
|
||||
((unsigned long long)vInfo->dwFileVersionLS);
|
||||
|
||||
// finally do the version check, and if it's greater than our block
|
||||
// version, keep loading
|
||||
if (fVersion > info->maxVersion)
|
||||
load_ok = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!load_ok) {
|
||||
printf_stderr("LdrLoadDll: Blocking load of '%s' -- see http://www.mozilla.com/en-US/blocklist/\n", dllName);
|
||||
DllBlockSet::Add(info->name, fVersion);
|
||||
return STATUS_DLL_NOT_FOUND;
|
||||
if (!load_ok) {
|
||||
printf_stderr("LdrLoadDll: Blocking load of '%s' -- see http://www.mozilla.com/en-US/blocklist/\n", dllName);
|
||||
DllBlockSet::Add(info->name, fVersion);
|
||||
return STATUS_DLL_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue_loading:
|
||||
#ifdef DEBUG_very_verbose
|
||||
printf_stderr("LdrLoadDll: continuing load... ('%S')\n", moduleFileName->Buffer);
|
||||
printf_stderr("LdrLoadDll: continuing load... ('%S')\n", moduleFileName->Buffer);
|
||||
#endif
|
||||
|
||||
// A few DLLs such as xul.dll and nss3.dll get loaded before mozglue's
|
||||
|
@ -861,6 +626,9 @@ patched_BaseThreadInitThunk(BOOL aIsInitialThread, void* aStartAddress,
|
|||
static WindowsDllInterceptor NtDllIntercept;
|
||||
static WindowsDllInterceptor Kernel32Intercept;
|
||||
|
||||
static void
|
||||
GetNativeNtBlockSetWriter();
|
||||
|
||||
MFBT_API void
|
||||
DllBlocklist_Initialize(uint32_t aInitFlags)
|
||||
{
|
||||
|
@ -868,6 +636,11 @@ DllBlocklist_Initialize(uint32_t aInitFlags)
|
|||
return;
|
||||
}
|
||||
sInitFlags = aInitFlags;
|
||||
|
||||
if (sInitFlags & eDllBlocklistInitFlagWasBootstrapped) {
|
||||
GetNativeNtBlockSetWriter();
|
||||
}
|
||||
|
||||
sBlocklistInitAttempted = true;
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
gStartAddressesToBlock = new mozilla::Vector<void*, 4>;
|
||||
|
@ -923,7 +696,7 @@ DllBlocklist_Initialize(uint32_t aInitFlags)
|
|||
reinterpret_cast<intptr_t>(patched_BaseThreadInitThunk),
|
||||
(void**) &stub_BaseThreadInitThunk)) {
|
||||
#ifdef DEBUG
|
||||
printf_stderr("BaseThreadInitThunk hook failed\n");
|
||||
printf_stderr("BaseThreadInitThunk hook failed\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -957,8 +730,8 @@ DllBlocklist_Initialize(uint32_t aInitFlags)
|
|||
#endif
|
||||
}
|
||||
|
||||
MFBT_API void
|
||||
DllBlocklist_WriteNotes(HANDLE file)
|
||||
static void
|
||||
InternalWriteNotes(HANDLE file)
|
||||
{
|
||||
DWORD nBytes;
|
||||
|
||||
|
@ -977,6 +750,26 @@ DllBlocklist_WriteNotes(HANDLE file)
|
|||
}
|
||||
}
|
||||
|
||||
using WriterFn = void (*)(HANDLE);
|
||||
static WriterFn gWriterFn = &InternalWriteNotes;
|
||||
|
||||
static void
|
||||
GetNativeNtBlockSetWriter()
|
||||
{
|
||||
auto nativeWriter = reinterpret_cast<WriterFn>(
|
||||
::GetProcAddress(::GetModuleHandleW(nullptr), "NativeNtBlockSet_Write"));
|
||||
if (nativeWriter) {
|
||||
gWriterFn = nativeWriter;
|
||||
}
|
||||
}
|
||||
|
||||
MFBT_API void
|
||||
DllBlocklist_WriteNotes(HANDLE file)
|
||||
{
|
||||
MOZ_ASSERT(gWriterFn);
|
||||
gWriterFn(file);
|
||||
}
|
||||
|
||||
MFBT_API bool
|
||||
DllBlocklist_CheckStatus()
|
||||
{
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
enum DllBlocklistInitFlags
|
||||
{
|
||||
eDllBlocklistInitFlagDefault = 0,
|
||||
eDllBlocklistInitFlagIsChildProcess = 1
|
||||
eDllBlocklistInitFlagIsChildProcess = 1,
|
||||
eDllBlocklistInitFlagWasBootstrapped = 2
|
||||
};
|
||||
|
||||
MFBT_API void DllBlocklist_Initialize(uint32_t aInitFlags = eDllBlocklistInitFlagDefault);
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_WindowsDllBlocklistCommon_h
|
||||
#define mozilla_WindowsDllBlocklistCommon_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template <typename CharType>
|
||||
struct DllBlockInfoT {
|
||||
// The name of the DLL -- in LOWERCASE! It will be compared to
|
||||
// a lowercase version of the DLL name only.
|
||||
const CharType* name;
|
||||
|
||||
// If maxVersion is ALL_VERSIONS, we'll block all versions of this
|
||||
// dll. Otherwise, we'll block all versions less than or equal to
|
||||
// the given version, as queried by GetFileVersionInfo and
|
||||
// VS_FIXEDFILEINFO's dwFileVersionMS and dwFileVersionLS fields.
|
||||
//
|
||||
// Note that the version is usually 4 components, which is A.B.C.D
|
||||
// encoded as 0x AAAA BBBB CCCC DDDD ULL (spaces added for clarity),
|
||||
// but it's not required to be of that format.
|
||||
uint64_t maxVersion;
|
||||
|
||||
// If the USE_TIMESTAMP flag is set, then we use the timestamp from
|
||||
// the IMAGE_FILE_HEADER in lieu of a version number.
|
||||
//
|
||||
// If the CHILD_PROCESSES_ONLY flag is set, then the dll is blocked
|
||||
// only when we are a child process.
|
||||
enum Flags {
|
||||
FLAGS_DEFAULT = 0,
|
||||
BLOCK_WIN8PLUS_ONLY = 1,
|
||||
BLOCK_WIN8_ONLY = 2,
|
||||
USE_TIMESTAMP = 4,
|
||||
CHILD_PROCESSES_ONLY = 8
|
||||
} flags;
|
||||
|
||||
static const uint64_t ALL_VERSIONS = (uint64_t) -1LL;
|
||||
|
||||
// DLLs sometimes ship without a version number, particularly early
|
||||
// releases. Blocking "version <= 0" has the effect of blocking unversioned
|
||||
// DLLs (since the call to get version info fails), but not blocking
|
||||
// any versioned instance.
|
||||
static const uint64_t UNVERSIONED = 0ULL;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
// Convert the 4 (decimal) components of a DLL version number into a
|
||||
// single unsigned long long, as needed by the blocklist
|
||||
static inline constexpr uint64_t
|
||||
MAKE_VERSION(uint16_t a, uint16_t b, uint16_t c, uint16_t d)
|
||||
{
|
||||
return static_cast<uint64_t>(a) << 48 |
|
||||
static_cast<uint64_t>(b) << 32 |
|
||||
static_cast<uint64_t>(c) << 16 |
|
||||
static_cast<uint64_t>(d);
|
||||
}
|
||||
|
||||
#if !defined(DLL_BLOCKLIST_CHAR_TYPE)
|
||||
#error "You must define DLL_BLOCKLIST_CHAR_TYPE"
|
||||
#endif // !defined(DLL_BLOCKLIST_CHAR_TYPE)
|
||||
|
||||
#define DLL_BLOCKLIST_DEFINITIONS_BEGIN \
|
||||
using DllBlockInfo = mozilla::DllBlockInfoT<DLL_BLOCKLIST_CHAR_TYPE>; \
|
||||
static const DllBlockInfo gWindowsDllBlocklist[] = {
|
||||
|
||||
#define ALL_VERSIONS DllBlockInfo::ALL_VERSIONS
|
||||
#define UNVERSIONED DllBlockInfo::UNVERSIONED
|
||||
|
||||
#define DLL_BLOCKLIST_DEFINITIONS_END \
|
||||
{nullptr, 0} \
|
||||
};
|
||||
|
||||
#define DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(name) \
|
||||
const DllBlockInfo* name = &gWindowsDllBlocklist[0]
|
||||
|
||||
#endif // mozilla_WindowsDllBlocklistCommon_h
|
|
@ -0,0 +1,206 @@
|
|||
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_WindowsDllBlocklistDefs_h
|
||||
#define mozilla_WindowsDllBlocklistDefs_h
|
||||
|
||||
#include "mozilla/WindowsDllBlocklistCommon.h"
|
||||
|
||||
DLL_BLOCKLIST_DEFINITIONS_BEGIN
|
||||
|
||||
// EXAMPLE:
|
||||
// DLL_BLOCKLIST_ENTRY("uxtheme.dll", ALL_VERSIONS)
|
||||
// DLL_BLOCKLIST_ENTRY("uxtheme.dll", 0x0000123400000000ULL)
|
||||
// The DLL name must be in lowercase!
|
||||
// The version field is a maximum, that is, we block anything that is
|
||||
// less-than or equal to that version.
|
||||
|
||||
// NPFFAddon - Known malware
|
||||
DLL_BLOCKLIST_ENTRY("npffaddon.dll", ALL_VERSIONS)
|
||||
|
||||
// AVG 8 - Antivirus vendor AVG, old version, plugin already blocklisted
|
||||
DLL_BLOCKLIST_ENTRY("avgrsstx.dll", MAKE_VERSION(8,5,0,401))
|
||||
|
||||
// calc.dll - Suspected malware
|
||||
DLL_BLOCKLIST_ENTRY("calc.dll", MAKE_VERSION(1,0,0,1))
|
||||
|
||||
// hook.dll - Suspected malware
|
||||
DLL_BLOCKLIST_ENTRY("hook.dll", ALL_VERSIONS)
|
||||
|
||||
// GoogleDesktopNetwork3.dll - Extremely old, unversioned instances
|
||||
// of this DLL cause crashes
|
||||
DLL_BLOCKLIST_ENTRY("googledesktopnetwork3.dll", UNVERSIONED)
|
||||
|
||||
// rdolib.dll - Suspected malware
|
||||
DLL_BLOCKLIST_ENTRY("rdolib.dll", MAKE_VERSION(6,0,88,4))
|
||||
|
||||
// fgjk4wvb.dll - Suspected malware
|
||||
DLL_BLOCKLIST_ENTRY("fgjk4wvb.dll", MAKE_VERSION(8,8,8,8))
|
||||
|
||||
// radhslib.dll - Naomi internet filter - unmaintained since 2006
|
||||
DLL_BLOCKLIST_ENTRY("radhslib.dll", UNVERSIONED)
|
||||
|
||||
// Music download filter for vkontakte.ru - old instances
|
||||
// of this DLL cause crashes
|
||||
DLL_BLOCKLIST_ENTRY("vksaver.dll", MAKE_VERSION(2,2,2,0))
|
||||
|
||||
// Topcrash in Firefox 4.0b1
|
||||
DLL_BLOCKLIST_ENTRY("rlxf.dll", MAKE_VERSION(1,2,323,1))
|
||||
|
||||
// psicon.dll - Topcrashes in Thunderbird, and some crashes in Firefox
|
||||
// Adobe photoshop library, now redundant in later installations
|
||||
DLL_BLOCKLIST_ENTRY("psicon.dll", ALL_VERSIONS)
|
||||
|
||||
// Topcrash in Firefox 4 betas (bug 618899)
|
||||
DLL_BLOCKLIST_ENTRY("accelerator.dll", MAKE_VERSION(3,2,1,6))
|
||||
|
||||
// Topcrash with Roboform in Firefox 8 (bug 699134)
|
||||
DLL_BLOCKLIST_ENTRY("rf-firefox.dll", MAKE_VERSION(7,6,1,0))
|
||||
DLL_BLOCKLIST_ENTRY("roboform.dll", MAKE_VERSION(7,6,1,0))
|
||||
|
||||
// Topcrash with Babylon Toolbar on FF16+ (bug 721264)
|
||||
DLL_BLOCKLIST_ENTRY("babyfox.dll", ALL_VERSIONS)
|
||||
|
||||
// sprotector.dll crashes, bug 957258
|
||||
DLL_BLOCKLIST_ENTRY("sprotector.dll", ALL_VERSIONS)
|
||||
|
||||
// leave these two in always for tests
|
||||
DLL_BLOCKLIST_ENTRY("mozdllblockingtest.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("mozdllblockingtest_versioned.dll", 0x0000000400000000ULL)
|
||||
|
||||
// Windows Media Foundation FLAC decoder and type sniffer (bug 839031).
|
||||
DLL_BLOCKLIST_ENTRY("mfflac.dll", ALL_VERSIONS)
|
||||
|
||||
// Older Relevant Knowledge DLLs cause us to crash (bug 904001).
|
||||
DLL_BLOCKLIST_ENTRY("rlnx.dll", MAKE_VERSION(1, 3, 334, 9))
|
||||
DLL_BLOCKLIST_ENTRY("pmnx.dll", MAKE_VERSION(1, 3, 334, 9))
|
||||
DLL_BLOCKLIST_ENTRY("opnx.dll", MAKE_VERSION(1, 3, 334, 9))
|
||||
DLL_BLOCKLIST_ENTRY("prnx.dll", MAKE_VERSION(1, 3, 334, 9))
|
||||
|
||||
// Older belgian ID card software causes Firefox to crash or hang on
|
||||
// shutdown, bug 831285 and 918399.
|
||||
DLL_BLOCKLIST_ENTRY("beid35cardlayer.dll", MAKE_VERSION(3, 5, 6, 6968))
|
||||
|
||||
// bug 925459, bitguard crashes
|
||||
DLL_BLOCKLIST_ENTRY("bitguard.dll", ALL_VERSIONS)
|
||||
|
||||
// bug 812683 - crashes in Windows library when Asus Gamer OSD is installed
|
||||
// Software is discontinued/unsupported
|
||||
DLL_BLOCKLIST_ENTRY("atkdx11disp.dll", ALL_VERSIONS)
|
||||
|
||||
// Topcrash with Conduit SearchProtect, bug 944542
|
||||
DLL_BLOCKLIST_ENTRY("spvc32.dll", ALL_VERSIONS)
|
||||
|
||||
// Topcrash with V-bates, bug 1002748 and bug 1023239
|
||||
DLL_BLOCKLIST_ENTRY("libinject.dll", UNVERSIONED)
|
||||
DLL_BLOCKLIST_ENTRY("libinject2.dll", 0x537DDC93, DllBlockInfo::USE_TIMESTAMP)
|
||||
DLL_BLOCKLIST_ENTRY("libredir2.dll", 0x5385B7ED, DllBlockInfo::USE_TIMESTAMP)
|
||||
|
||||
// Crashes with RoboForm2Go written against old SDK, bug 988311/1196859
|
||||
DLL_BLOCKLIST_ENTRY("rf-firefox-22.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("rf-firefox-40.dll", ALL_VERSIONS)
|
||||
|
||||
// Crashes with DesktopTemperature, bug 1046382
|
||||
DLL_BLOCKLIST_ENTRY("dtwxsvc.dll", 0x53153234, DllBlockInfo::USE_TIMESTAMP)
|
||||
|
||||
// Startup crashes with Lenovo Onekey Theater, bug 1123778
|
||||
DLL_BLOCKLIST_ENTRY("activedetect32.dll", UNVERSIONED)
|
||||
DLL_BLOCKLIST_ENTRY("activedetect64.dll", UNVERSIONED)
|
||||
DLL_BLOCKLIST_ENTRY("windowsapihookdll32.dll", UNVERSIONED)
|
||||
DLL_BLOCKLIST_ENTRY("windowsapihookdll64.dll", UNVERSIONED)
|
||||
|
||||
// Flash crashes with RealNetworks RealDownloader, bug 1132663
|
||||
DLL_BLOCKLIST_ENTRY("rndlnpshimswf.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("rndlmainbrowserrecordplugin.dll", ALL_VERSIONS)
|
||||
|
||||
// Startup crashes with RealNetworks Browser Record Plugin, bug 1170141
|
||||
DLL_BLOCKLIST_ENTRY("nprpffbrowserrecordext.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("nprndlffbrowserrecordext.dll", ALL_VERSIONS)
|
||||
|
||||
// Crashes with CyberLink YouCam, bug 1136968
|
||||
DLL_BLOCKLIST_ENTRY("ycwebcamerasource.ax", MAKE_VERSION(2, 0, 0, 1611))
|
||||
|
||||
// Old version of WebcamMax crashes WebRTC, bug 1130061
|
||||
DLL_BLOCKLIST_ENTRY("vwcsource.ax", MAKE_VERSION(1, 5, 0, 0))
|
||||
|
||||
// NetOp School, discontinued product, bug 763395
|
||||
DLL_BLOCKLIST_ENTRY("nlsp.dll", MAKE_VERSION(6, 23, 2012, 19))
|
||||
|
||||
// Orbit Downloader, bug 1222819
|
||||
DLL_BLOCKLIST_ENTRY("grabdll.dll", MAKE_VERSION(2, 6, 1, 0))
|
||||
DLL_BLOCKLIST_ENTRY("grabkernel.dll", MAKE_VERSION(1, 0, 0, 1))
|
||||
|
||||
// ESET, bug 1229252
|
||||
DLL_BLOCKLIST_ENTRY("eoppmonitor.dll", ALL_VERSIONS)
|
||||
|
||||
// SS2OSD, bug 1262348
|
||||
DLL_BLOCKLIST_ENTRY("ss2osd.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("ss2devprops.dll", ALL_VERSIONS)
|
||||
|
||||
// NHASUSSTRIXOSD.DLL, bug 1269244
|
||||
DLL_BLOCKLIST_ENTRY("nhasusstrixosd.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("nhasusstrixdevprops.dll", ALL_VERSIONS)
|
||||
|
||||
// Crashes with PremierOpinion/RelevantKnowledge, bug 1277846
|
||||
DLL_BLOCKLIST_ENTRY("opls.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("opls64.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("pmls.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("pmls64.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("prls.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("prls64.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("rlls.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("rlls64.dll", ALL_VERSIONS)
|
||||
|
||||
// Vorbis DirectShow filters, bug 1239690.
|
||||
DLL_BLOCKLIST_ENTRY("vorbis.acm", MAKE_VERSION(0, 0, 3, 6))
|
||||
|
||||
// AhnLab Internet Security, bug 1311969
|
||||
DLL_BLOCKLIST_ENTRY("nzbrcom.dll", ALL_VERSIONS)
|
||||
|
||||
// K7TotalSecurity, bug 1339083.
|
||||
DLL_BLOCKLIST_ENTRY("k7pswsen.dll", MAKE_VERSION(15, 2, 2, 95))
|
||||
|
||||
// smci*.dll - goobzo crashware (bug 1339908)
|
||||
DLL_BLOCKLIST_ENTRY("smci32.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("smci64.dll", ALL_VERSIONS)
|
||||
|
||||
// Crashes with Internet Download Manager, bug 1333486
|
||||
DLL_BLOCKLIST_ENTRY("idmcchandler7.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("idmcchandler7_64.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("idmcchandler5.dll", ALL_VERSIONS)
|
||||
DLL_BLOCKLIST_ENTRY("idmcchandler5_64.dll", ALL_VERSIONS)
|
||||
|
||||
// Nahimic 2 breaks applicaton update (bug 1356637)
|
||||
DLL_BLOCKLIST_ENTRY("nahimic2devprops.dll", MAKE_VERSION(2, 5, 19, 0xffff))
|
||||
// Nahimic is causing crashes, bug 1233556
|
||||
DLL_BLOCKLIST_ENTRY("nahimicmsiosd.dll", UNVERSIONED)
|
||||
// Nahimic is causing crashes, bug 1360029
|
||||
DLL_BLOCKLIST_ENTRY("nahimicvrdevprops.dll", UNVERSIONED)
|
||||
DLL_BLOCKLIST_ENTRY("nahimic2osd.dll", MAKE_VERSION(2, 5, 19, 0xffff))
|
||||
DLL_BLOCKLIST_ENTRY("nahimicmsidevprops.dll", UNVERSIONED)
|
||||
|
||||
// Bug 1268470 - crashes with Kaspersky Lab on Windows 8
|
||||
DLL_BLOCKLIST_ENTRY("klsihk64.dll", MAKE_VERSION(14, 0, 456, 0xffff), DllBlockInfo::BLOCK_WIN8_ONLY)
|
||||
|
||||
// Bug 1407337, crashes with OpenSC < 0.16.0
|
||||
DLL_BLOCKLIST_ENTRY("onepin-opensc-pkcs11.dll", MAKE_VERSION(0, 15, 0xffff, 0xffff))
|
||||
|
||||
// Avecto Privilege Guard causes crashes, bug 1385542
|
||||
DLL_BLOCKLIST_ENTRY("pghook.dll", ALL_VERSIONS)
|
||||
|
||||
// Old versions of G DATA BankGuard, bug 1421991
|
||||
DLL_BLOCKLIST_ENTRY("banksafe64.dll", MAKE_VERSION(1, 2, 15299, 65535))
|
||||
|
||||
// Old versions of G DATA, bug 1043775
|
||||
DLL_BLOCKLIST_ENTRY("gdkbfltdll64.dll", MAKE_VERSION(1, 0, 14141, 240))
|
||||
|
||||
// Dell Backup and Recovery tool causes crashes, bug 1433408
|
||||
DLL_BLOCKLIST_ENTRY("dbroverlayiconnotbackuped.dll", MAKE_VERSION(1, 8, 0, 9))
|
||||
DLL_BLOCKLIST_ENTRY("dbroverlayiconbackuped.dll", MAKE_VERSION(1, 8, 0, 9))
|
||||
|
||||
DLL_BLOCKLIST_DEFINITIONS_END
|
||||
|
||||
#endif // mozilla_WindowsDllBlocklistDefs_h
|
|
@ -72,6 +72,8 @@ if CONFIG['MOZ_WIDGET_TOOLKIT']:
|
|||
]
|
||||
EXPORTS.mozilla += [
|
||||
'Authenticode.h',
|
||||
'WindowsDllBlocklistCommon.h',
|
||||
'WindowsDllBlocklistDefs.h',
|
||||
]
|
||||
EXPORTS.mozilla.glue += [
|
||||
'WindowsDllServices.h',
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче