Merge inbound to mozilla-central a=merge

This commit is contained in:
arthur.iakab 2018-06-08 12:55:49 +03:00
Родитель de2889e000 784f62bdc2
Коммит edbf2c0099
181 изменённых файлов: 4312 добавлений и 2483 удалений

Просмотреть файл

@ -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',

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше